|
- import Utils from "/app/js/common/Utils.js";
- import GlobalEvents from "/app/js/common/EventCaller.js";
-
- import Input from "/app/js/ui/Input.js";
- import Renderer from "/app/js/ui/Renderer.js";
-
- import NESPalette from "/app/js/models/NESPalette.js";
- import ISurface from "/app/js/ifaces/ISurface.js";
-
- const EL_CANVAS_ID = "painter";
-
-
- /* --------------------------------------------------------------------
- * Univeral data and functions.
- ------------------------------------------------------------------- */
-
- var canvas = null;
- var context = null;
- var ctximg = null;
-
-
- function ResizeCanvasImg(w, h){
- if (canvas !== null){
- canvas.width = w;
- canvas.height = h;
- }
- };
-
- // Handling window resize events...
- var HANDLE_Resize = Utils.debounce(function(e){
- if (canvas !== null){
- ResizeCanvasImg(
- canvas.clientWidth,
- canvas.clientHeight
- );
- GlobalEvents.emit("resize", canvas.clientWidth, canvas.clientHeight);
- }
- }, 250);
- window.addEventListener("resize", HANDLE_Resize);
-
-
- // Setting-up Input controls.
- var input = new Input();
- input.enableKeyboardInput(true);
- input.preventDefaults = true;
-
-
- /* --------------------------------------------------------------------
- * CTRLPainter
- * Actual controlling class.
- ------------------------------------------------------------------- */
-
- // For reference...
- // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/stroke
- class CTRLPainter {
- constructor(){
- this.__scale = 1.0; // This is the scale the painter will display source information.
- this.__offset = [0.0, 0.0]; // This is the X,Y offset from origin to display source information.
- this.__onePaletteMode = true; // If true, ALL tiles will be drawing using the same palette.
-
- this.__brushSize = 1;
- this.__brushLastPos = [0.0, 0.0];
- this.__brushPos = [0.0, 0.0];
- this.__brushColor = 0;
- this.__brushPalette = 0;
-
- this.__gridEnabled = false;
- this.__gridSize = 1;
-
- this.__surface = null;
- this.__palette = null;
-
-
- this.__snapshotTriggered = false;
-
- // var self = this;
-
- var RenderD = Utils.throttle((function(){
- this.render();
- }).bind(this), 20);
-
- var LineToSurface = (function(x0, y0, x1, y1, ci, pi){
- var dx = x1 - x0;
- var ix = Math.sign(dx);
- dx = 2 * Math.abs(dx);
-
- var dy = y1 - y0;
- var iy = Math.sign(dy);
- dy = 2 * Math.abs(dy);
-
- if (dx > dy){
- var err = dy - (dx/2);
- var y = y0;
-
- Utils.range(x0, x1, 1).forEach((x) => {
- this.__surface.setColorIndex(x, y, ci, pi);
- if (err > 0 || (err == 0 && ix > 0)){
- err -= dx;
- y += iy;
- }
- err += dy;
- });
- } else {
- var err = dx - (dy/2);
- var x = x0;
-
- Utils.range(y0, y1, 1).forEach((y) => {
- this.__surface.setColorIndex(x, y, ci, pi);
- if (err > 0 || (err == 0 && iy > 0)){
- err -= dy;
- x += ix;
- }
- err += dx;
- });
- }
- }).bind(this);
-
- var handle_resize = (function(w,h){
- RenderD();
- }).bind(this);
- GlobalEvents.listen("resize", handle_resize);
-
- var handle_palinfochanged = (function(pdat){
- RenderD();
- }).bind(this);
-
- var handle_setapppalette = (function(pal){
- if (this.__palette !== null)
- this.__palette.unlisten("palettes_changed", handle_palinfochanged);
- this.__palette = pal;
- this.__palette.listen("palettes_changed", handle_palinfochanged);
- if (this.__surface !== null){
- this.__surface.palette = pal;
- if (this.__onePaletteMode === false)
- RenderD();
- }
- }).bind(this);
- GlobalEvents.listen("set_app_palette", handle_setapppalette);
-
- var handle_surface_data_changed = (function(){
- RenderD();
- }).bind(this);
-
- var handle_change_surface = (function(surf){
- if (surf !== null && !(surf instanceof ISurface)){
- console.log("WARNING: Attempted to set painter to non-surface instance.");
- return;
- }
- if (surf !== this.__surface){
- if (this.__surface !== null){
- this.__surface.unlisten("data_changed", handle_surface_data_changed);
- }
- this.__surface = surf;
- if (this.__surface !== null){
- this.__surface.listen("data_changed", handle_surface_data_changed);
- if (this.__palette === null && this.__surface.palette !== null){
- this.__palette = this.__surface.palette;
- } else if (this.__palette !== null && this.__surface.palette !== this.__palette){
- this.__surface.palette = this.__palette;
- }
- this.scale_to_fit();
- this.center_surface();
- }
- }
- RenderD();
- }).bind(this);
- GlobalEvents.listen("change_surface", handle_change_surface);
-
- var handle_color_change = (function(pi, ci){
- this.__brushPalette = pi;
- this.__brushColor = ci;
- }).bind(this);
- GlobalEvents.listen("active_palette_color", handle_color_change);
-
- var handle_mousemove = (function(e){
- this.__brushLastPos[0] = this.__brushPos[0];
- this.__brushLastPos[1] = this.__brushPos[1];
- this.__brushPos[0] = e.x;
- this.__brushPos[1] = e.y;
- if (this.__surface !== null){
- var x = Math.floor((this.__brushPos[0] - this.__offset[0]) * (1.0 / this.__scale));
- var y = Math.floor((this.__brushPos[1] - this.__offset[1]) * (1.0 / this.__scale));
- if (x >= 0 && x < this.__surface.width && y >= 0 && y < this.__surface.height){
- RenderD();
- }
- }
- }).bind(this);
- input.listen("mousemove", handle_mousemove);
- input.listen("mouseleft+mousemove", handle_mousemove);
-
- var handle_draw = (function(e){
- if (e.isCombo || e.button == 0){
- if (this.__surface !== null){
- //console.log(this.__brushPos);
- //console.log(this.__brushLastPos);
- var x = Math.floor((this.__brushPos[0] - this.__offset[0]) * (1.0 / this.__scale));
- var y = Math.floor((this.__brushPos[1] - this.__offset[1]) * (1.0 / this.__scale));
- var sx = (e.isCombo) ? Math.floor((this.__brushLastPos[0] - this.__offset[0]) * (1.0 / this.__scale)) : x;
- var sy = (e.isCombo) ? Math.floor((this.__brushLastPos[1] - this.__offset[1]) * (1.0 / this.__scale)) : y;
- if (x >= 0 && x < this.__surface.width && y >= 0 && y < this.__surface.height){
- if (!this.__snapshotTriggered){
- this.__snapshotTriggered = true;
- this.__surface.snapshot();
- }
- LineToSurface(sx, sy, x, y, this.__brushColor, this.__brushPalette);
- }
- }
- }
- }).bind(this);
- input.listen("mouseclick", handle_draw);
- input.listen("mouseleft+mousemove", handle_draw);
-
- var handle_mouseup = (function(e){
- this.__snapshotTriggered = false;
- }).bind(this);
- input.listen("mouseup", handle_mouseup);
-
- var handle_undo = (function(e){
- if (this.__surface !== null){
- this.__surface.undo();
- }
- }).bind(this);
- input.listen("ctrl+z", handle_undo);
-
- var handle_redo = (function(e){
- if (this.__surface !== null){
- this.__surface.redo();
- }
- }).bind(this);
- input.listen("ctrl+y", handle_redo);
-
- var handle_offset = (function(e){
- this.__offset[0] += e.x - e.lastX;
- this.__offset[1] += e.y - e.lastY;
- RenderD();
- }).bind(this);
- input.listen("shift+mouseleft+mousemove", handle_offset);
-
- var handle_scale = (function(e){
- if (e.delta < 0){
- this.scale_down();
- } else if (e.delta > 0){
- this.scale_up();
- }
- if (e.delta !== 0)
- RenderD();
- }).bind(this);
- input.listen("wheel", handle_scale);
-
-
- var elscale = document.querySelector("#painter_scale");
- if (elscale){
- var self = this;
- elscale.addEventListener("change", function(e){
- var val = Number(this.value);
- self.scale = val;
- RenderD();
- });
- elscale.value = this.__scale;
- }
-
- var handle_fittocanvas = (function(){
- this.scale_to_fit();
- this.center_surface();
- RenderD();
- }).bind(this);
- GlobalEvents.listen("painter-fit-to-canvas", handle_fittocanvas);
-
- var handle_togglegrid = (function(target, args){
- var elgridops = document.querySelector(".painter-grid-options");
- if (args.show){
- target.classList.add("pure-button-active");
- target.setAttribute("emit-args", JSON.stringify({show:false}));
- if (elgridops)
- elgridops.classList.remove("hidden");
- this.__gridEnabled = true;
- } else {
- target.classList.remove("pure-button-active");
- target.setAttribute("emit-args", JSON.stringify({show:true}));
- if (elgridops)
- elgridops.classList.add("hidden");
- this.__gridEnabled = false;
- }
- RenderD();
- }).bind(this);
- GlobalEvents.listen("painter-togglegrid", handle_togglegrid);
-
- var elgridops = document.querySelector(".painter-grid-options");
- if (elgridops){
- let self = this;
- elgridops.addEventListener("change", function(e){
- self.__gridSize = parseInt(this.value);
- if (self.__gridSize < 1 || self.__gridSize > 6)
- self.__gridSize = 1;
- RenderD();
- });
- }
-
-
- var handle_colormode = (function(target, args){
- if (args.onePaletteMode){
- target.classList.remove("pure-button-active");
- target.setAttribute("emit-args", JSON.stringify({onePaletteMode:false}));
- this.__onePaletteMode = true;
- } else {
- target.classList.add("pure-button-active");
- target.setAttribute("emit-args", JSON.stringify({onePaletteMode:true}));
- this.__onePaletteMode = false;
- }
- RenderD();
- }).bind(this);
- GlobalEvents.listen("painter-colormode", handle_colormode);
- }
-
-
-
-
- get onePaletteMode(){return this.__onePaletteMode;}
- set onePaletteMode(e){
- this.__onePaletteMode = (e === true);
- this.render();
- }
-
- get scale(){
- return this.__scale;
- }
-
- set scale(s){
- if (typeof(s) !== 'number')
- throw new TypeError("Expected number value.");
- this.__scale = Math.max(0.1, Math.min(100.0, s));
- var elscale = document.querySelector("#painter_scale");
- if (elscale){
- elscale.value = this.__scale;
- }
- }
-
- get showGrid(){return this.__gridEnabled;}
- set showGrid(e){
- this.__gridEnabled = (e === true);
- }
-
-
-
-
- initialize(){
- if (canvas === null){
- canvas = document.getElementById(EL_CANVAS_ID);
- if (!canvas)
- throw new Error("Failed to obtain the canvas element.");
- context = canvas.getContext("2d");
- if (!context)
- throw new Error("Failed to obtain canvas context.");
- context.imageSmoothingEnabled = false;
- ResizeCanvasImg(canvas.clientWidth, canvas.clientHeight); // A forced "resize".
- input.enableMouseInput(true, canvas);
- input.enableKeyboardInput(true);
- //input.mouseTargetElement = canvas;
-
- this.scale_to_fit();
- this.center_surface();
- }
- return this;
- }
-
- scale_up(amount=1){
- this.scale = this.scale + (amount*0.1);
- return this;
- }
-
- scale_down(amount=1){
- this.scale = this.scale - (amount*0.1);
- return this;
- }
-
- center_surface(){
- if (canvas === null || this.__surface === null)
- return;
-
- this.__offset[0] = Math.floor((canvas.clientWidth - (this.__surface.width * this.__scale)) * 0.5);
- this.__offset[1] = Math.floor((canvas.clientHeight - (this.__surface.height * this.__scale)) * 0.5);
- return this;
- }
-
- scale_to_fit(){
- if (canvas === null || this.__surface === null)
- return;
-
- var sw = canvas.clientWidth / this.__surface.width;
- var sh = canvas.clientHeight / this.__surface.height;
- var s = Math.min(sw, sh).toString();
- var di = s.indexOf(".");
- if (di >= 0)
- s = s.slice(0, di+2);
- this.scale = Number(s);
- }
-
- renderCursor(){
- if (context === null || this.__surface === null){return this;}
-
- // Draw the mouse position... if mouse is currently in bounds.
- if (input.isMouseInBounds()){
- context.save();
- context.fillStyle = "#AA9900";
- var x = Math.floor((this.__brushPos[0] - this.__offset[0]) * (1.0/this.__scale));
- var y = Math.floor((this.__brushPos[1] - this.__offset[1]) * (1.0/this.__scale));
- if (x >= 0 && x < this.__surface.width && y >= 0 && y < this.__surface.height){
- context.beginPath();
- context.rect(
- this.__offset[0] + (x*this.__scale),
- this.__offset[1] + (y*this.__scale),
- Math.ceil(this.__scale),
- Math.ceil(this.__scale)
- );
- context.fill();
- context.closePath();
- }
- context.restore();
- }
-
- return this;
- }
-
- renderGrid(){
- if (context === null || this.__surface === null || this.__gridEnabled === false){return this;}
-
- switch (this.__gridSize){
- case 1: // 8x8
- Renderer.renderGridNxN(
- context,
- 8,
- this.__surface.width, this.__surface.height,
- this.__scale, this.__offset,
- "#00FF00"
- ); break;
- case 2: // 16x8
- Renderer.renderGridMxN(
- context,
- 16, 8,
- this.__surface.width, this.__surface.height,
- this.__scale, this.__offset,
- "#00FF00"
- ); break;
- case 3: // 16x16
- Renderer.renderGridNxN(
- context,
- 16,
- this.__surface.width, this.__surface.height,
- this.__scale, this.__offset,
- "#00FF00"
- ); break;
- case 4:
- Renderer.renderGridNxN(
- context,
- 32,
- this.__surface.width, this.__surface.height,
- this.__scale, this.__offset,
- "#00FF00"
- ); break;
- case 5: // 16x16 Major | 8x8 Minor
- Renderer.renderGridMajorMinor(
- context,
- 16, 8,
- this.__surface.width, this.__surface.height,
- this.__scale, this.__offset,
- "#00FF00", "#008800"
- ); break;
- case 6: // 32x32 Major | 16x16 Minor
- Renderer.renderGridMajorMinor(
- context,
- 32, 16,
- this.__surface.width, this.__surface.height,
- this.__scale, this.__offset,
- "#00FF00", "#008800"
- ); break;
- }
-
- return this;
- }
-
- render(){
- if (context === null){return this;}
- if (this.__surface === null){
- Renderer.clear(context, NESPalette.Default[4]);
- return this;
- }
-
- // Drawing the surface to the canvas.
- Renderer.render(
- this.__surface,
- 0, 0,
- this.__surface.width, this.__surface.height,
- this.__scale,
- context,
- this.__offset[0], this.__offset[1],
- !this.__onePaletteMode
- );
-
- return this.renderCursor().renderGrid();
- }
- }
-
-
- const instance = new CTRLPainter();
- export default instance;
-
-
|