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

CTRLIO.js 5.9KB

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