From de2479b00777f90f390f929900459ea18e25bf29 Mon Sep 17 00:00:00 2001 From: Nicola <47360416+unsettledgames@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:54:29 +0100 Subject: [PATCH] Started making selection tools more generic Will also hopefully remove MoveSelection.js and put its functions in SelectionTool --- js/layers/Layer.js | 7 +- js/tools/EraserTool.js | 2 +- js/tools/LassoSelectionTool.js | 117 +--------------------- js/tools/MoveSelectionTool.js | 4 +- js/tools/RectangularSelectionTool.js | 73 +++++++------- js/tools/SelectionTool.js | 143 ++++++++++++++++++++++++++- 6 files changed, 187 insertions(+), 159 deletions(-) diff --git a/js/layers/Layer.js b/js/layers/Layer.js index 3922f5c..501953b 100644 --- a/js/layers/Layer.js +++ b/js/layers/Layer.js @@ -283,7 +283,7 @@ class Layer { previewWidth, previewHeight); } - drawLine(x0,y0,x1,y1, brushSize) { + drawLine(x0,y0,x1,y1, brushSize, clear=false) { var dx = Math.abs(x1-x0); var dy = Math.abs(y1-y0); var sx = (x0 < x1 ? 1 : -1); @@ -294,11 +294,10 @@ class Layer { //set pixel // If the current tool is the brush // REFACTOR: this is terrible - if (ToolManager.currentTool().name == 'brush' || ToolManager.currentTool().name == 'rectangle' || ToolManager.currentTool().name == 'ellipse' - || ToolManager.currentTool().name == 'lassoselect') { + if (!clear) { // I fill the rect this.context.fillRect(x0-Math.floor(brushSize/2), y0-Math.floor(brushSize/2), brushSize, brushSize); - } else if (ToolManager.currentTool().name == 'eraser') { + } else { // In case I'm using the eraser I must clear the rect this.context.clearRect(x0-Math.floor(brushSize/2), y0-Math.floor(brushSize/2), brushSize, brushSize); } diff --git a/js/tools/EraserTool.js b/js/tools/EraserTool.js index 7a296c2..58ef57a 100644 --- a/js/tools/EraserTool.js +++ b/js/tools/EraserTool.js @@ -23,7 +23,7 @@ class EraserTool extends ResizableTool { Math.floor(this.prevMousePos[1]/currFile.zoom), Math.floor(this.currMousePos[0]/currFile.zoom), Math.floor(this.currMousePos[1]/currFile.zoom), - this.currSize + this.currSize, true ); } diff --git a/js/tools/LassoSelectionTool.js b/js/tools/LassoSelectionTool.js index b99e82e..de369c0 100644 --- a/js/tools/LassoSelectionTool.js +++ b/js/tools/LassoSelectionTool.js @@ -1,7 +1,5 @@ class LassoSelectionTool extends SelectionTool { currentPixels = []; - currSelection = {}; - boundingBox = {minX: 9999999, maxX: -1, minY: 9999999, maxY: -1}; constructor (name, options, switchFunc, moveTool) { super(name, options, switchFunc, moveTool); @@ -14,30 +12,19 @@ class LassoSelectionTool extends SelectionTool { // Putting the vfx layer on top of everything currFile.VFXLayer.canvas.style.zIndex = MAX_Z_INDEX; // clearSelection(); - this.boundingBox = {minX: 9999999, maxX: -1, minY: 9999999, maxY: -1}; + this.currentPixels = []; this.drawSelection(); this.currentPixels.push([mousePos[0] / currFile.zoom, mousePos[1] / currFile.zoom]); } onDrag(mousePos) { - super.onDrag(mousePos); - - let mouseX = mousePos[0] / currFile.zoom; - let mouseY = mousePos[1] / currFile.zoom; + super.onDrag(mousePos); if (this.currentPixels[this.currentPixels.length - 1] != mousePos) this.currentPixels.push([mousePos[0] / currFile.zoom, mousePos[1] / currFile.zoom]); + this.drawSelection(); - - if (mouseX > this.boundingBox.maxX) - this.boundingBox.maxX = Math.floor(mouseX); - if (mouseX < this.boundingBox.minX) - this.boundingBox.minX = Math.floor(mouseX); - if (mouseY < this.boundingBox.minY) - this.boundingBox.minY = Math.floor(mouseY); - if (mouseY > this.boundingBox.maxY) - this.boundingBox.maxY = Math.floor(mouseY); } onEnd(mousePos) { @@ -79,106 +66,12 @@ class LassoSelectionTool extends SelectionTool { currFile.VFXLayer.context.moveTo(point[0], point[1]); else { prevPoint = this.currentPixels[index- 1]; - currFile.VFXLayer.context.lineTo(point[0], point[1]); currFile.VFXLayer.drawLine(Math.floor(prevPoint[0]), Math.floor(prevPoint[1]), Math.floor(point[0]), Math.floor(point[1]), 1); } } - currFile.VFXLayer.drawLine(Math.floor(prevPoint[0]), Math.floor(prevPoint[1]), - Math.floor(this.startMousePos[0] / currFile.zoom), Math.floor(this.startMousePos[1] / currFile.zoom), 1); - currFile.VFXLayer.context.lineTo(this.startMousePos[0] / currFile.zoom, this.startMousePos[1] / currFile.zoom); - - currFile.VFXLayer.context.fillStyle = 'rgba(0,0,0,0.3)'; - currFile.VFXLayer.context.fill(); - currFile.VFXLayer.context.closePath(); - } - - cursorInSelectedArea(mousePos) { - - } - - isBorderOfBox(pixel) { - return pixel[0] == this.boundingBox.minX || pixel[0] == this.boundingBox.maxX || - pixel[1] == this.boundingBox.minY || pixel[1] == this.boundingBox.maxY; - } - - visit(pixel, visited, data) { - let toVisit = [pixel]; - let selected = []; - let currVisited = {}; - - while (toVisit.length > 0) { - pixel = toVisit.pop(); - selected.push(pixel); - - visited[pixel] = true; - currVisited[pixel] = true; - - let col = Util.getPixelColor(data, pixel[0], pixel[1], currFile.canvasSize[0]); - if (col[3] == 255) - continue; - if (this.isBorderOfBox(pixel)) - return []; - - let top, bottom, left, right; - if (pixel[1] > 0) - top = [pixel[0], pixel[1] - 1]; - else - top = undefined; - - if (pixel[0] > 0) - left = [pixel[0] - 1, pixel[1]]; - else - left = undefined; - - if (pixel[1] < currFile.canvasSize[1]) - bottom = [pixel[0], pixel[1] + 1]; - else - bottom = undefined; - - if (pixel[0] < currFile.canvasSize[0]) - right = [pixel[0] + 1, pixel[1]]; - else - right = undefined; - - // The include problem: https://stackoverflow.com/questions/19543514/check-whether-an-array-exists-in-an-array-of-arrays - if (right != undefined && currVisited[right] == undefined) - toVisit.push(right); - if (left != undefined && currVisited[left] == undefined) - toVisit.push(left); - if (top != undefined && currVisited[top] == undefined) - toVisit.push(top); - if (bottom != undefined && currVisited[bottom] == undefined) - toVisit.push(bottom); - } - - return selected; - } - - getSelection() { - let selected = []; - let visited = {}; - let data = currFile.VFXLayer.context.getImageData(0, 0, currFile.canvasSize[0], currFile.canvasSize[1]).data; - if (this.currentPixels.length <= 1){ - return; - } - - for (let x=this.boundingBox.minX; x<=this.boundingBox.maxX; x++) { - for (let y=this.boundingBox.minY; y<=this.boundingBox.maxY; y++) { - if (visited[[x, y]] == undefined) { - let insidePixels = this.visit([x,y], visited, data); - - for (let i=0; i= this.currSelection.top) { - return true; - } - return false; - } - return false; - } } \ No newline at end of file diff --git a/js/tools/SelectionTool.js b/js/tools/SelectionTool.js index 23a080c..693eab8 100644 --- a/js/tools/SelectionTool.js +++ b/js/tools/SelectionTool.js @@ -1,7 +1,21 @@ +/** TODO + * - Once the selected pixels have been obtained, save the selection outline in an image data + * - At the same time, create another image data and put the selected pixels in it + * - The move tool will then move those image datas and they'll be pasted on the right layer + * at the end of the selection + * + */ + class SelectionTool extends Tool { switchFunc = undefined; moveTool = undefined; + boundingBox = {minX: 9999999, maxX: -1, minY: 9999999, maxY: -1}; + currSelection = {}; + + previewData = undefined; + selectedPixel = undefined; + constructor(name, options, switchFunc, moveTool) { super(name, options); @@ -9,11 +23,138 @@ class SelectionTool extends Tool { this.switchFunc = switchFunc; } + onStart(mousePos) { + super.onStart(mousePos); + + let mouseX = mousePos[0] / currFile.zoom; + let mouseY = mousePos[1] / currFile.zoom; + + this.boundingBox = {minX: 9999999, maxX: -1, minY: 9999999, maxY: -1}; + this.currSelection = {}; + + this.updateBoundingBox(mouseX, mouseY); + } + + onDrag(mousePos) { + let mouseX = mousePos[0] / currFile.zoom; + let mouseY = mousePos[1] / currFile.zoom; + + this.updateBoundingBox(mouseX, mouseY); + } + cutSelection() {} pasteSelection(){} copySelection(){} - cursorInSelectedArea(){} + cursorInSelectedArea(mousePos) { + let floored = [Math.floor(mousePos[0] / currFile.zoom), Math.floor(mousePos[1] / currFile.zoom)]; + + if (this.currSelection[floored] != undefined) + return true; + return false; + } + + visit(pixel, visited, data) { + let toVisit = [pixel]; + let selected = []; + let currVisited = {}; + + currFile.TMPLayer.context.clearRect(0, 0, 512, 512); + + while (toVisit.length > 0) { + pixel = toVisit.pop(); + selected.push(pixel); + + visited[pixel] = true; + currVisited[pixel] = true; + + let col = Util.getPixelColor(data, pixel[0], pixel[1], currFile.canvasSize[0]); + if (col[3] == 255) + continue; + if (this.isBorderOfBox(pixel)) + return []; + + let top, bottom, left, right; + if (pixel[1] > 0) + top = [pixel[0], pixel[1] - 1]; + else + top = undefined; + + if (pixel[0] > 0) + left = [pixel[0] - 1, pixel[1]]; + else + left = undefined; + + if (pixel[1] < currFile.canvasSize[1]) + bottom = [pixel[0], pixel[1] + 1]; + else + bottom = undefined; + + if (pixel[0] < currFile.canvasSize[0]) + right = [pixel[0] + 1, pixel[1]]; + else + right = undefined; + + if (right != undefined && currVisited[right] == undefined) + toVisit.push(right); + if (left != undefined && currVisited[left] == undefined) + toVisit.push(left); + if (top != undefined && currVisited[top] == undefined) + toVisit.push(top); + if (bottom != undefined && currVisited[bottom] == undefined) + toVisit.push(bottom); + } + + return selected; + } + + getSelection() { + let selected = []; + let visited = {}; + let data = currFile.VFXLayer.context.getImageData(0, 0, currFile.canvasSize[0], currFile.canvasSize[1]).data; + + /* + currFile.VFXLayer.context.fillStyle = "red"; + currFile.VFXLayer.context.fillRect(this.boundingBox.minX, this.boundingBox.minY, 1, 1); + currFile.VFXLayer.context.fillRect(this.boundingBox.maxX, this.boundingBox.minY, 1, 1); + currFile.VFXLayer.context.fillRect(this.boundingBox.minX, this.boundingBox.maxY, 1, 1); + currFile.VFXLayer.context.fillRect(this.boundingBox.maxX, this.boundingBox.maxY, 1, 1); + */ + + for (let x=this.boundingBox.minX-1; x<=this.boundingBox.maxX+1; x++) { + for (let y=this.boundingBox.minY-1; y<=this.boundingBox.maxY+1; y++) { + if (visited[[x, y]] == undefined) { + let insidePixels = this.visit([x,y], visited, data); + + for (let i=0; i this.boundingBox.maxX) + this.boundingBox.maxX = Math.floor(mouseX); + if (mouseX < this.boundingBox.minX) + this.boundingBox.minX = Math.floor(mouseX); + if (mouseY < this.boundingBox.minY) + this.boundingBox.minY = Math.floor(mouseY); + if (mouseY > this.boundingBox.maxY) + this.boundingBox.maxY = Math.floor(mouseY); + } } \ No newline at end of file