A pixel art painter geared specifically at NES pixel art. Includes export for .chr binary file as well as palette and namespace data.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

213 lines
5.7KB

  1. import Utils from "/app/js/common/Utils.js";
  2. import GlobalEvents from "/app/js/common/EventCaller.js";
  3. import Renderer from "/app/js/ui/Renderer.js";
  4. import NESNameTable from "/app/js/models/NESNameTable.js";
  5. import CTRLBanksStore from "/app/js/ctrls/CTRLBanksStore.js";
  6. const TILE_SELECT_CLS = "canvas-item-selected";
  7. var ELCtrl = null;
  8. var SURF = null;
  9. var TileIndex = -1;
  10. function UpdateBankList(curbankname){
  11. var elsel = ELCtrl.querySelector(".nametable-bank-select");
  12. if (elsel){
  13. var child = elsel.firstChild;
  14. // Clear old bank names...
  15. while(child !== null){
  16. let nchild = child.nextSibling;
  17. let drop = true;
  18. if (Utils.isElement(child)){
  19. if (child.hasAttribute("value")){
  20. if (child.getAttribute("value") === "NULL_BANK"){
  21. drop = false;
  22. }
  23. }
  24. }
  25. if (drop){
  26. elsel.removeChild(child);
  27. }
  28. child = nchild;
  29. }
  30. // Get the only remaining option...
  31. var elop = elsel.querySelector("option");
  32. // Get the current list of bank names...
  33. var banknames = CTRLBanksStore.keys;
  34. // Loop through bank names, if there are any, and add new options to the list...
  35. if (elop && banknames.length > 0){
  36. banknames.forEach((name) => {
  37. var newop = elop.cloneNode(true);
  38. newop.setAttribute("value", name);
  39. newop.innerHTML = name;
  40. elsel.appendChild(newop);
  41. });
  42. elsel.value = curbankname;
  43. }
  44. }
  45. }
  46. function UpdateBankTileList(){
  47. var el = ELCtrl.querySelector(".nametable-tile");
  48. if (el){
  49. if (SURF.bank === null){
  50. el.classList.add("hidden");
  51. } else {
  52. var elsel = ELCtrl.querySelector(".nametable-tile-select");
  53. if (elsel){
  54. el.classList.remove("hidden");
  55. let tiles = SURF.bank.rp;
  56. for (let i=0; i < tiles.length; i++){
  57. let cnv = elsel.querySelector('canvas[value="' + i + '"]');
  58. if (cnv){
  59. var psize = Math.floor(cnv.parentNode.clientWidth * 0.9);
  60. if (cnv.clientWidth !== psize){
  61. cnv.width = psize;
  62. cnv.height = psize;
  63. }
  64. let ctx = cnv.getContext("2d");
  65. let tsurf = new Renderer.NESTileSurface(tiles[i], SURF.palette, 0);
  66. Renderer.renderToFit(tsurf, ctx);
  67. }
  68. }
  69. }
  70. }
  71. }
  72. }
  73. function OpenControls(){
  74. if (ELCtrl !== null && SURF !== null){
  75. var curbankname = (SURF.bank !== null) ? CTRLBanksStore.getBankName(SURF.bank) : "NULL_BANK";
  76. if (curbankname === null){
  77. SURF.bank = null;
  78. curbankname = "NULL_BANK";
  79. }
  80. ELCtrl.classList.remove("hidden");
  81. UpdateBankList(curbankname);
  82. UpdateBankTileList();
  83. }
  84. }
  85. function CloseControls(){
  86. if (ELCtrl !== null){
  87. ELCtrl.classList.add("hidden");
  88. }
  89. }
  90. function HANDLE_PaintNametable(x, y){
  91. if (TileIndex >= 0 && TileIndex < 256){
  92. SURF.setTileIndex(x, y, TileIndex);
  93. }
  94. }
  95. function ResetSelectedTile(){
  96. var eltilesel = ELCtrl.querySelector(".nametable-tile-select");
  97. if (eltilesel){
  98. var op = eltilesel.querySelector('canvas[selected="True"]');
  99. if (op){
  100. op.classList.remove(TILE_SELECT_CLS);
  101. op.removeAttribute("selected");
  102. }
  103. }
  104. TileIndex = -1;
  105. }
  106. function HANDLE_SurfChange(surf){
  107. if (surf instanceof NESNameTable){
  108. if (SURF !== null)
  109. SURF.unlisten("paint_nametable", HANDLE_PaintNametable);
  110. SURF = surf;
  111. SURF.listen("paint_nametable", HANDLE_PaintNametable);
  112. ResetSelectedTile();
  113. OpenControls();
  114. } else {
  115. if (SURF !== null)
  116. SURF.unlisten("paint_nametable", HANDLE_PaintNametable);
  117. SURF = null;
  118. CloseControls();
  119. }
  120. }
  121. class CTRLNametableTools{
  122. constructor(){
  123. GlobalEvents.listen("change_surface", HANDLE_SurfChange);
  124. }
  125. initialize(){
  126. ELCtrl = document.querySelector(".toolbar-nametable-control");
  127. if (!ELCtrl)
  128. throw new Error("Failed to find element class 'toolbar-nametable-control'.");
  129. var elbanksel = ELCtrl.querySelector(".nametable-bank-select");
  130. if (!elbanksel)
  131. throw new Error("Failed to find element class 'nametable-bank-select' within toolbar.");
  132. // Building out and setting up the tile selections.
  133. var eltilesel = ELCtrl.querySelector(".nametable-tile-select");
  134. if (!eltilesel)
  135. throw new Error("Failed to find element class 'nametable-tile-select' within toolbar.");
  136. var HANDLE_TileSelect = function(){
  137. var oop = eltilesel.querySelector('canvas[selected="True"]');
  138. if (oop){
  139. oop.classList.remove(TILE_SELECT_CLS);
  140. oop.removeAttribute("selected");
  141. }
  142. this.setAttribute("selected", "True");
  143. this.classList.add(TILE_SELECT_CLS);
  144. TileIndex = parseInt(this.getAttribute("value"));
  145. };
  146. var op0 = eltilesel.querySelector('canvas[value="0"]');
  147. if (!op0)
  148. throw new Error("Failed to find initial canvas element within 'nametable-tile-select'.");
  149. op0.addEventListener("click", HANDLE_TileSelect);
  150. for (let i=1; i < 256; i++){
  151. let op = eltilesel.querySelector('canvas[value="' + i + '"]');
  152. if (!op){
  153. op = op0.cloneNode(true);
  154. op.setAttribute("value", i);
  155. eltilesel.appendChild(op);
  156. op.addEventListener("click", HANDLE_TileSelect);
  157. }
  158. }
  159. elbanksel.addEventListener("change", function(){
  160. if (SURF !== null){
  161. var bankname = this.value;
  162. if (bankname === "NULL_BANK"){
  163. SURF.bank = null;
  164. } else {
  165. var bank = CTRLBanksStore.getBank(bankname);
  166. if (bank !== null){
  167. if (SURF.bank === null || (SURF.bank.eq(bank) === false)){
  168. SURF.bank = bank;
  169. UpdateBankTileList();
  170. }
  171. }
  172. }
  173. }
  174. });
  175. }
  176. }
  177. const instance = new CTRLNametableTools();
  178. export default instance;