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.1KB

  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. JSONSchema.add({
  12. "$schema": "http://json-schema.org/draft-07/schema#",
  13. "$id": "NESPainterProject.json",
  14. "type":"object",
  15. "properties":{
  16. "id":{
  17. "type":"string",
  18. "enum":["NESPProj"]
  19. },
  20. "version":{
  21. "type":"string",
  22. "pattern":"^[0-9]{1,}\.[0-9]{1,}$"
  23. },
  24. "paletteStore":{"$ref":"PalettesStoreSchema.json"},
  25. "bankStore":{"$ref":"BanksStoreSchema.json"}
  26. },
  27. "required":["id","version","paletteStore","bankStore"]
  28. });
  29. var SURF = null;
  30. function JSONFromProject(){
  31. var proj = {
  32. id:"NESPProj",
  33. version:SUPPORTED_PROJECT_VERSIONS[SUPPORTED_PROJECT_VERSIONS.length - 1],
  34. paletteStore:CTRLPalettesStore.obj,
  35. bankStore:CTRLBanksStore.obj
  36. };
  37. return JSON.stringify(proj);
  38. }
  39. function LoadFile(file){
  40. if (SURF !== null){
  41. var reader = new FileReader();
  42. if (SURF instanceof NESBank){
  43. reader.onload = function(e){
  44. try {
  45. SURF.chr = new Uint8Array(e.target.result);
  46. } catch (e) {
  47. console.log(e.toString());
  48. }
  49. }
  50. reader.readAsArrayBuffer(file);
  51. }
  52. }
  53. }
  54. function HANDLE_DragOver(e){
  55. e.stopPropagation();
  56. e.preventDefault();
  57. e.dataTransfer.dropEffect = 'copy';
  58. };
  59. function HANDLE_FileDrop(e){
  60. e.stopPropagation();
  61. e.preventDefault();
  62. var files = e.dataTransfer.files;
  63. for (let i=0; i < files.length; i++){
  64. LoadFile(files[i]);
  65. }
  66. }
  67. function HANDLE_SaveProject(e){
  68. var a = document.createElement("a");
  69. var file = new Blob([JSONFromProject()], {type: "text/plain"});
  70. a.href = window.URL.createObjectURL(file);
  71. a.download = "nesproject.json";
  72. var body = document.querySelector("body");
  73. body.appendChild(a);
  74. a.click();
  75. setTimeout(function(){ // fixes firefox html removal bug
  76. window.URL.revokeObjectURL(url);
  77. a.remove();
  78. }, 500);
  79. }
  80. function HANDLE_LoadProjectRequest(){
  81. var input = document.querySelectorAll("input.project-loader");
  82. if (input.length > 0){
  83. input[0].click();
  84. }
  85. }
  86. function HANDLE_LoadProject(e){
  87. if (this.files && this.files.length > 0){
  88. var reader = new FileReader();
  89. reader.onload = (function(e) {
  90. var validator = null;
  91. try{
  92. validator = JSONSchema.getValidator("NESPainterProject.json");
  93. } catch (e) {
  94. console.log("Failed to validate project file. " + e.toString());
  95. return;
  96. }
  97. if (validator(e.target.result)){
  98. var o = JSON.parse(e.target.result);
  99. // TODO: Validate 'id' and 'version' properties.
  100. CTRLPalettesStore.obj = o.paletteStore;
  101. CTRLBanksStore.obj = o.banksStore;
  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;