A pixel art painter geared specifically at NES pixel art. Includes export for .chr binary file as well as palette and namespace data.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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