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文字以内のものにしてください。

262 行
6.5KB

  1. import GlobalEvents from "/app/js/common/EventCaller.js";
  2. import Utils from "/app/js/common/Utils.js";
  3. import NESPalette from "/app/js/models/NESPalette.js";
  4. const PLI_TEMPLATE = ".palette-list-item-template";
  5. const PLI_TITLE = ".title";
  6. const PLI_BG_COLOR = ".pal-bg-color";
  7. const PLI_FG_BASE = ".pal-fg-";
  8. const PLI_BG_BASE = ".pal-bg-";
  9. const PLI_SELECTED = ".item-selected";
  10. const PLI_COLOR_BASE = "nes-color-bg-";
  11. var Palettes = [];
  12. var CurrentPaletteIndex = 0;
  13. var BlockEmits = false;
  14. function HANDLE_PaletteClick(e){
  15. if (!this.hasAttribute("palname")){return;}
  16. var pname = this.getAttribute("palname");
  17. if (Palettes.length > 0 && Palettes[CurrentPaletteIndex][0] !== pname){
  18. var oel = Palettes[CurrentPaletteIndex][2];
  19. oel.classList.remove(PLI_SELECTED);
  20. for (let i=0; i < Palettes.length; i++){
  21. if (Palettes[i][0] === pname){
  22. Palettes[i][2].classList.add(PLI_SELECTED);
  23. GlobalEvents.emit("set_app_palette", Palettes[i][1]);
  24. break;
  25. }
  26. }
  27. }
  28. }
  29. function SetElToColor(el, mode, pi, ci, hex){
  30. var cel = null;
  31. if (ci === 0){
  32. cel = el.querySelectorAll(PLI_BG_COLOR);
  33. } else {
  34. cel = el.querySelectorAll(((mode == 0) ? PLI_FG_BASE : PLI_BG_BASE) + pi + "-" + ci);
  35. }
  36. if (cel !== null && cel.length === 1){
  37. cel = cel[0];
  38. var clist = cel.getAttribute("class").split(" ");
  39. for (let i=0; i < clist.length; i++){
  40. if (clist[i].startsWith(PLI_COLOR_BASE)){
  41. cel.classList.remove(clist[i]);
  42. break;
  43. }
  44. }
  45. cel.classList.add("." + PLI_COLOR_BASE + hex);
  46. }
  47. }
  48. function ColorElementToPalette(el, palette){
  49. for (let p=0; p < 8; p++){
  50. for (let c=1; c < 4; c++){
  51. SetElToColor(
  52. el, (p >= 4) ? 0 : 1,
  53. p%4, c,
  54. palette.get_palette_syscolor_index(p,c,true)
  55. );
  56. }
  57. }
  58. }
  59. function ConnectElementToPalette(el, palette){
  60. palette.listen("palettes_changed", (e) => {
  61. if (e.type == "ALL"){
  62. ColorElementToPalette(el, palette);
  63. } else if (e.type == "SPRITE"){
  64. SetElToColor(
  65. el, 0,
  66. e.pindex%4, e.cindex,
  67. palette.get_palette_syscolor_index(e.pindex, e.cindex, true)
  68. );
  69. } else if (e.type == "TILE"){
  70. SetElToColor(
  71. el, 1,
  72. e.pindex, e.cindex,
  73. palette.get_palette_syscolor_index(e.pindex, e.cindex, true)
  74. );
  75. }
  76. });
  77. }
  78. function CreatePaletteDOMEntry(pname, palette){
  79. var oel = document.querySelectorAll(PLI_TEMPLATE);
  80. if (oel.length == 1){
  81. var el = oel[0].cloneNode(true);
  82. el.classList.remove(PLI_TEMPLATE);
  83. el.classList.remove("hidden");
  84. el.setAttribute("palname", pname);
  85. ConnectElementToPalette(el, palette);
  86. ColorElementToPalette(el, palette);
  87. el.addEventListener("click", HANDLE_PaletteClick);
  88. oel[0].parentNode.appendChild(el);
  89. return el;
  90. } else {
  91. console.log("WARNING: Multiple templates found. Ambigous state.");
  92. }
  93. return null;
  94. }
  95. class CTRLPalettesStore{
  96. constructor(){}
  97. get json(){
  98. var d = {
  99. cpi: CurrentPaletteIndex,
  100. pals: []
  101. };
  102. for (let i=0; i < Palettes.length; i++){
  103. d.pals.push([Palettes[i][0], Palettes[i][1].json]);
  104. }
  105. return JSON.stringify(d);
  106. }
  107. set json(j){
  108. try {
  109. var d = JSON.parse(j);
  110. } catch (e) {
  111. throw e;
  112. }
  113. if (d.hasOwnProperty("cpi") && d.hasOwnProperty("pals")){
  114. if (Utils.isInt(d.cpi) && d.pals instanceof Array){
  115. var newPalettes = []
  116. for (let i=0; i < d.pals.length; i++){
  117. if (d.pals[i] instanceof Array){
  118. if (this.getPalette(d.pals[i][0]) === null){
  119. this.createPalette(d.pals[i][0], d.pals[i][1]);
  120. }
  121. }
  122. }
  123. CurrentPaletteIndex = 0
  124. if (Palettes.length > 0){
  125. if (d.cpi >= 0 && d.cpi < Palettes.length){
  126. CurrentPaletteIndex = d.cpi;
  127. }
  128. GlobalEvents.emit("set_app_palette", Palettes[CurrentPaletteIndex][1]);
  129. }
  130. } else {
  131. throw new TypeError("JSON Property Value types invalid.");
  132. }
  133. } else {
  134. throw new TypeError("JSON missing expected properties.");
  135. }
  136. }
  137. initialize(){
  138. if (Palettes.length <= 0)
  139. this.createPalette("Palette");
  140. return this;
  141. }
  142. paletteIndexFromName(name){
  143. for (let i=1; i < Palettes.length; i++){
  144. if (Palettes[i][0] == name){
  145. return i;
  146. }
  147. }
  148. return -1;
  149. }
  150. getPalette(name){
  151. var i = this.paletteIndexFromName(name);
  152. return (i >= 0) ? Palettes[i][1] : null;
  153. }
  154. createPalette(name, pjson){
  155. var palette = this.getPalette(name);
  156. if (palette === null){
  157. palette = new NESPalette();
  158. if (typeof(pjson) === "string"){
  159. try {
  160. palette.json = pjson;
  161. } catch (e) {
  162. console.log("Failed to create palette.", e.toString());
  163. palette = null;
  164. }
  165. } else {
  166. palette.set_palette([
  167. "0F",
  168. "05","06","07",
  169. "09","0A","0B",
  170. "01","02","03",
  171. "0D","00","20",
  172. "15","16","17",
  173. "19","1A","1B",
  174. "11","21","31",
  175. "1D","10","30"
  176. ]);
  177. }
  178. if (palette !== null){
  179. var el = CreatePaletteDOMEntry(name, palette);
  180. Palettes.push([name, palette, el]);
  181. if (Palettes.length <= 1 && !BlockEmits){
  182. GlobalEvents.emit("set_app_palette", palette);
  183. }
  184. }
  185. }
  186. return this;
  187. }
  188. removePalette(name){
  189. for (let i=0; i < Palettes.length; i++){
  190. if (Palettes[i][0] === name){
  191. if (CurrentPaletteIndex === i){
  192. CurrentPaletteIndex = 0;
  193. this.activatePalette(Palettes[0][0]);
  194. }
  195. Palettes[i][2].parentNode.removeChild(Palettes[i][2]);
  196. Palettes.splice(i, 1);
  197. }
  198. }
  199. return this;
  200. }
  201. renamePalette(oldname, newname){
  202. var i = paletteIndexFromName(oldname);
  203. if (i < 0)
  204. throw new ValueError("Failed to find palette named '" + oldname +"'. Cannot rename.");
  205. Palettes[i][0] = newname;
  206. Palettes[i][2].setAttribute("palname", newname);
  207. return this;
  208. }
  209. activatePalette(name){
  210. var i = this.paletteIndexFromName(name);
  211. if (i >= 0 && CurrentPaletteIndex !== i){
  212. CurrentPaletteIndex = i;
  213. Palettes[CurrentPaletteIndex][2].click();
  214. //if (!BlockEmits){
  215. // GlobalEvents.emit("set_app_palette", Palettes[CurrentPaletteIndex][1]);
  216. //}
  217. }
  218. return this;
  219. }
  220. clear(){
  221. for (let i=0; i < Palettes.length; i++){
  222. Palettes[i][2].parentNode.removeChild(Palettes[i][2]);
  223. }
  224. CurrentPaletteIndex = 0;
  225. }
  226. }
  227. const instance = new CTRLPalettesStore();
  228. export default instance;