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

191 行
5.0KB

  1. import Utils from "/app/js/common/Utils.js";
  2. import GlobalEvents from "/app/js/common/EventCaller.js";
  3. import Input from "/app/js/ui/Input.js";
  4. import NESPalette from "/app/js/models/NESPalette.js";
  5. //import NESTile from "/app/js/models/NESTile.js";
  6. //import NESBank from "/app/js/models/NESBank.js";
  7. import ISurface from "/app/js/ifaces/ISurface.js";
  8. const EL_CANVAS_ID = "painter";
  9. /* --------------------------------------------------------------------
  10. * Univeral data and functions.
  11. ------------------------------------------------------------------- */
  12. var canvas = null;
  13. var context = null;
  14. // Handling window resize events...
  15. var HANDLE_Resize = Utils.debounce(function(e){
  16. if (canvas !== null){
  17. var w = canvas.clientWidth;
  18. var h = canvas.clientHeight;
  19. canvas.width = w;
  20. canvas.height = h;
  21. GlobalEvents.emit("resize", w, h);
  22. }
  23. }, 250);
  24. window.addEventListener("resize", HANDLE_Resize);
  25. // Setting-up Input controls.
  26. var input = new Input();
  27. input.preventDefaults = true;
  28. // Mouse handling...
  29. /*input.listen("mousemove", handle_mouseevent);
  30. input.listen("mousedown", handle_mouseevent);
  31. input.listen("mouseup", handle_mouseevent);
  32. input.listen("mouseclick", handle_mouseclickevent);
  33. */
  34. /* --------------------------------------------------------------------
  35. * CTRLPainter
  36. * Actual controlling class.
  37. ------------------------------------------------------------------- */
  38. // For reference...
  39. // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/stroke
  40. class CTRLPainter {
  41. constructor(){
  42. this.__scale = 1.0; // This is the scale the painter will display source information.
  43. this.__offset = [0.0, 0.0]; // This is the X,Y offset from origin to display source information.
  44. this.__onePaletteMode = true; // If true, ALL tiles will be drawing using the same palette.
  45. this.__brushSize = 1;
  46. this.__brushColor = 0;
  47. this.__brushPalette = 0;
  48. this.__gridEnabled = false;
  49. this.__gridSize = 1;
  50. this.__surface = null;
  51. var self = this;
  52. var handle_resize = (function(w,h){
  53. this.render();
  54. }).bind(this);
  55. GlobalEvents.listen("resize", handle_resize);
  56. var handle_change_surface = (function(surf){
  57. if (!(surf instanceof ISurface)){
  58. console.log("WARNING: Attempted to set painter to non-surface instance.");
  59. return;
  60. }
  61. this.__surface = surf;
  62. this.render();
  63. }).bind(this);
  64. GlobalEvents.listen("change_surface", handle_change_surface);
  65. var handle_color_change = (function(pi, ci){
  66. this.__brushPalette = pi;
  67. this.__brushColor = ci;
  68. }).bind(this);
  69. GlobalEvents.listen("active_palette_color", handle_color_change);
  70. }
  71. get onePaletteMode(){return this.__onePaletteMode;}
  72. set onePaletteMode(e){
  73. this.__onePaletteMode = (e === true);
  74. this.render();
  75. }
  76. get scale(){
  77. return this.__scale;
  78. }
  79. set scale(s){
  80. if (typeof(s) !== 'number')
  81. throw new TypeError("Expected number value.");
  82. this.__scale = Math.max(0.1, Math.min(100.0, s));
  83. }
  84. get showGrid(){return this.__gridEnabled;}
  85. set showGrid(e){
  86. this.__gridEnabled = (e === true);
  87. }
  88. initialize(){
  89. if (canvas === null){
  90. canvas = document.getElementById(EL_CANVAS_ID);
  91. if (!canvas)
  92. throw new Error("Failed to obtain the canvas element.");
  93. context = canvas.getContext("2d");
  94. if (!context)
  95. throw new Error("Failed to obtain canvas context.");
  96. context.imageSmoothingEnabled = false;
  97. input.mouseTargetElement = canvas;
  98. }
  99. }
  100. scale_up(amount=1){
  101. this.scale = this.scale + (amount*0.1);
  102. }
  103. scale_down(amount=1){
  104. this.scale = this.scale - (amount*0.1);
  105. }
  106. render(){
  107. if (context === null || this.__surface === null)
  108. return;
  109. // Get the contexts initial fillStyle. Don't want the render operation to override it.
  110. var fillStyle = context.fillStyle;
  111. var ie = this.__surface.width - this.__offset[0];
  112. var je = this.__surface.height - this.__offset[1];
  113. var scalemult = 1.0/this.__scale;
  114. // Clearing the context surface...
  115. context.fillStyle = NESPalette.Default[4];
  116. context.fillRect(
  117. 0,0,
  118. Math.floor(canvas.clientWidth),
  119. Math.floor(canvas.clientHeight)
  120. );
  121. for (var j = -this.__offset[1]; j < je; j++){
  122. var y = Math.floor(j*scalemult);
  123. for (var i = -this.__offset[0]; i < ie; i++){
  124. var x = Math.floor(i*scalemult);
  125. var color = "#666666";
  126. if (this.__onePaletteMode){
  127. var pinfo = this.__surface.getColorIndex(x, y);
  128. if (pinfo.ci >= 0)
  129. color = NESPalette.Default[pinfo.ci];
  130. } else {
  131. color = this.__surface.getColor(x, y);
  132. }
  133. context.fillStyle = color;
  134. context.fillRect(
  135. i + this.__offset[0],
  136. j + this.__offset[1],
  137. 1, 1
  138. );
  139. }
  140. }
  141. if (this.__gridEnabled && this.__scale > 0.5){
  142. // TODO: render the grid!
  143. }
  144. // Return to the context's initial fillStyle.
  145. context.fillStyle = fillStyle;
  146. }
  147. }
  148. const instance = new CTRLPainter();
  149. export default instance;