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

169 行
4.2KB

  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 LoadFile(file){
  41. if (SURF !== null){
  42. var reader = new FileReader();
  43. if (SURF instanceof NESBank){
  44. reader.onload = function(e){
  45. try {
  46. SURF.chr = new Uint8Array(e.target.result);
  47. } catch (e) {
  48. console.log(e.toString());
  49. }
  50. }
  51. reader.readAsArrayBuffer(file);
  52. }
  53. }
  54. }
  55. function HANDLE_DragOver(e){
  56. e.stopPropagation();
  57. e.preventDefault();
  58. e.dataTransfer.dropEffect = 'copy';
  59. };
  60. function HANDLE_FileDrop(e){
  61. e.stopPropagation();
  62. e.preventDefault();
  63. var files = e.dataTransfer.files;
  64. for (let i=0; i < files.length; i++){
  65. LoadFile(files[i]);
  66. }
  67. }
  68. function HANDLE_SaveProject(e){
  69. var a = document.createElement("a");
  70. var file = new Blob([JSONFromProject()], {type: "text/plain"});
  71. a.href = window.URL.createObjectURL(file);
  72. a.download = "nesproject.json";
  73. var body = document.querySelector("body");
  74. body.appendChild(a);
  75. a.click();
  76. setTimeout(function(){ // fixes firefox html removal bug
  77. window.URL.revokeObjectURL(url);
  78. a.remove();
  79. }, 500);
  80. }
  81. function HANDLE_LoadProjectRequest(){
  82. var input = document.querySelectorAll("input.project-loader");
  83. if (input.length > 0){
  84. input[0].click();
  85. }
  86. }
  87. function HANDLE_LoadProject(e){
  88. if (this.files && this.files.length > 0){
  89. var reader = new FileReader();
  90. reader.onload = (function(e) {
  91. var o = null;
  92. var validator = JSONSchema.getValidator(SCHEMA_ID);
  93. try {
  94. o = JSON.parse(e.target.result);
  95. } catch (e) {
  96. console.log("Failed to parse JSON string. " + e.toString());
  97. }
  98. if (validator !== null && validator(o)){
  99. // TODO: Validate 'id' and 'version' properties.
  100. CTRLPalettesStore.obj = o.paletteStore;
  101. CTRLBanksStore.obj = o.bankStore;
  102. }
  103. if (this.parentNode.nodeName.toLowerCase() === "form"){
  104. this.parentNode.reset();
  105. } else {
  106. console.log("WARNING: Parent node is NOT a <form> element.");
  107. }
  108. }).bind(this);
  109. reader.readAsText(this.files[0]);
  110. } else {
  111. console.log("Project file not found or no file selected.");
  112. }
  113. }
  114. function HANDLE_SurfChange(surf){
  115. if (surf instanceof NESBank){
  116. SURF = surf;
  117. } else {
  118. SURF = null;
  119. }
  120. }
  121. class CTRLIO{
  122. constructor(){
  123. GlobalEvents.listen("change_surface", HANDLE_SurfChange);
  124. GlobalEvents.listen("save-project", HANDLE_SaveProject);
  125. GlobalEvents.listen("load-project", HANDLE_LoadProjectRequest);
  126. var input = document.querySelectorAll("input.project-loader");
  127. if (input.length > 0){
  128. input[0].addEventListener("change", HANDLE_LoadProject);
  129. }
  130. }
  131. initialize(){
  132. var e = document.querySelectorAll(".drop-zone");
  133. for (let i=0; i < e.length; e++){
  134. e[i].addEventListener("dragover", HANDLE_DragOver);
  135. e[i].addEventListener("drop", HANDLE_FileDrop);
  136. }
  137. CTRLPalettesStore.initialize();
  138. CTRLBanksStore.initialize();
  139. }
  140. }
  141. const instance = new CTRLIO();
  142. export default instance;