A pixel art painter geared specifically at NES pixel art. Includes export for .chr binary file as well as palette and namespace data.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

213 行
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;