A pixel art painter geared specifically at NES pixel art. Includes export for .chr binary file as well as palette and namespace data.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

169 Zeilen
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;