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

218 行
5.6KB

  1. import GlobalEvents from "/app/js/common/EventCaller.js";
  2. import Utils from "/app/js/common/Utils.js";
  3. import JSONSchema from "/app/js/common/JSONSchema.js";
  4. import NESBank from "/app/js/models/NESBank.js";
  5. import NESPalette from "/app/js/models/NESPalette.js";
  6. import CTRLPalettesStore from "/app/js/ctrls/CTRLPalettesStore.js";
  7. import CTRLBanksStore from "/app/js/ctrls/CTRLBanksStore.js";
  8. const SUPPORTED_PROJECT_VERSIONS=[
  9. "0.1"
  10. ];
  11. const SCHEMA_ID = "http://nespaint/Project.json";
  12. JSONSchema.add({
  13. "$schema": "http://json-schema.org/draft-07/schema#",
  14. "$id": SCHEMA_ID,
  15. "type":"object",
  16. "properties":{
  17. "id":{
  18. "type":"string",
  19. "enum":["NESPProj"]
  20. },
  21. "version":{
  22. "type":"string",
  23. "pattern":"^[0-9]{1,}\.[0-9]{1,}$"
  24. },
  25. "paletteStore":{"$ref":"http://nespaint/PalettesStoreSchema.json"},
  26. "bankStore":{"$ref":"http://nespaint/BanksStoreSchema.json"}
  27. },
  28. "required":["id","version","paletteStore","bankStore"]
  29. });
  30. var SURF = null;
  31. function JSONFromProject(){
  32. var proj = {
  33. id:"NESPProj",
  34. version:SUPPORTED_PROJECT_VERSIONS[SUPPORTED_PROJECT_VERSIONS.length - 1],
  35. paletteStore:CTRLPalettesStore.obj,
  36. bankStore:CTRLBanksStore.obj
  37. };
  38. return JSON.stringify(proj);
  39. }
  40. function RequestDownload(filename, datblob){
  41. var a = document.createElement("a");
  42. a.href = window.URL.createObjectURL(datblob);
  43. a.download = filename;
  44. var body = document.querySelector("body");
  45. body.appendChild(a);
  46. a.click();
  47. setTimeout(function(){ // fixes firefox html removal bug
  48. window.URL.revokeObjectURL(a.href);
  49. a.remove();
  50. }, 500);
  51. }
  52. function LoadFile(file){
  53. if (SURF !== null){
  54. var reader = new FileReader();
  55. if (SURF instanceof NESBank){
  56. reader.onload = function(e){
  57. try {
  58. SURF.chr = new Uint8Array(e.target.result);
  59. } catch (e) {
  60. console.log(e.toString());
  61. }
  62. }
  63. reader.readAsArrayBuffer(file);
  64. }
  65. }
  66. }
  67. function HANDLE_DragOver(e){
  68. e.stopPropagation();
  69. e.preventDefault();
  70. e.dataTransfer.dropEffect = 'copy';
  71. };
  72. function HANDLE_FileDrop(e){
  73. e.stopPropagation();
  74. e.preventDefault();
  75. var files = e.dataTransfer.files;
  76. for (let i=0; i < files.length; i++){
  77. LoadFile(files[i]);
  78. }
  79. }
  80. function HANDLE_SaveProject(e){
  81. //var a = document.createElement("a");
  82. var file = new Blob([JSONFromProject()], {type: "text/plain"});
  83. RequestDownload("nesproject.json", file);
  84. }
  85. function HANDLE_ExportCHR(e){
  86. e.preventDefault();
  87. var bank = CTRLBanksStore.currentBank;
  88. if (bank !== null){
  89. var dat = null;
  90. var size = document.querySelector('input[name="exportchr-size"]:checked').value;
  91. switch (size){
  92. case "full":
  93. dat = bank.getCHR(0,0);
  94. break;
  95. case "current":
  96. dat = bank.chr;
  97. }
  98. if (dat !== null){
  99. var file = new Blob([dat], {type:"application/octet-stream"});
  100. var filename = CTRLBanksStore.currentBankName.replace(/[^a-z0-9\-_.]/gi, '_').toLowerCase() + ".chr";
  101. RequestDownload(filename, file);
  102. }
  103. }
  104. GlobalEvents.emit("modal-close");
  105. }
  106. function HANDLE_ExportPalASM(e){
  107. var pal = CTRLPalettesStore.currentPalette;
  108. var palname = CTRLPalettesStore.currentPaletteName.replace(/[^a-z0-9\-_.]/gi, '_');
  109. if (pal !== null && palname !== ""){
  110. var asmtxt = pal.to_asm(palname);
  111. var file = new Blob([asmtxt], {type: "text/plain"});
  112. RequestDownload(palname + ".asm", file);
  113. }
  114. }
  115. function HANDLE_LoadProjectRequest(){
  116. var input = document.querySelectorAll("input.project-loader");
  117. if (input.length > 0){
  118. input[0].click();
  119. }
  120. }
  121. function HANDLE_LoadProject(e){
  122. if (this.files && this.files.length > 0){
  123. var reader = new FileReader();
  124. reader.onload = (function(e) {
  125. var o = null;
  126. var validator = JSONSchema.getValidator(SCHEMA_ID);
  127. try {
  128. o = JSON.parse(e.target.result);
  129. } catch (e) {
  130. console.log("Failed to parse JSON string. " + e.toString());
  131. }
  132. if (validator !== null && validator(o)){
  133. // TODO: Validate 'id' and 'version' properties.
  134. CTRLPalettesStore.obj = o.paletteStore;
  135. CTRLBanksStore.obj = o.bankStore;
  136. }
  137. if (this.parentNode.nodeName.toLowerCase() === "form"){
  138. this.parentNode.reset();
  139. } else {
  140. console.log("WARNING: Parent node is NOT a <form> element.");
  141. }
  142. }).bind(this);
  143. reader.readAsText(this.files[0]);
  144. } else {
  145. console.log("Project file not found or no file selected.");
  146. }
  147. }
  148. function HANDLE_SurfChange(surf){
  149. if (surf instanceof NESBank){
  150. SURF = surf;
  151. } else {
  152. SURF = null;
  153. }
  154. }
  155. class CTRLIO{
  156. constructor(){
  157. GlobalEvents.listen("change_surface", HANDLE_SurfChange);
  158. GlobalEvents.listen("save-project", HANDLE_SaveProject);
  159. GlobalEvents.listen("load-project", HANDLE_LoadProjectRequest);
  160. GlobalEvents.listen("export-pal-asm", HANDLE_ExportPalASM);
  161. var input = document.querySelectorAll("input.project-loader");
  162. if (input.length > 0){
  163. input[0].addEventListener("change", HANDLE_LoadProject);
  164. }
  165. }
  166. initialize(){
  167. // Connecting drag/drop ability.
  168. var e = document.querySelectorAll(".drop-zone");
  169. for (let i=0; i < e.length; e++){
  170. e[i].addEventListener("dragover", HANDLE_DragOver);
  171. e[i].addEventListener("drop", HANDLE_FileDrop);
  172. }
  173. // Connecting to button for export request.
  174. var e = document.querySelectorAll(".export-chr-btn");
  175. for (let i=0; i < e.length; i++){
  176. e[i].addEventListener("click", HANDLE_ExportCHR);
  177. }
  178. CTRLPalettesStore.initialize();
  179. CTRLBanksStore.initialize();
  180. }
  181. }
  182. const instance = new CTRLIO();
  183. export default instance;