From 4290e20e2b2f4536f4365d02e1cd7a1418bc8ea9 Mon Sep 17 00:00:00 2001 From: Pushkar Joshi Date: Tue, 24 Apr 2012 15:40:12 -0700 Subject: allow the realtime drawing of brush strokes drawn off the standard XY plane by passing in the transformation matrix --- js/lib/geom/brush-stroke.js | 34 +- js/tools/BrushTool.js | 744 ++++++++++++++++++++++++-------------------- 2 files changed, 433 insertions(+), 345 deletions(-) (limited to 'js') diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index efd21c4a..89ef79fb 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js @@ -117,7 +117,7 @@ var BrushStroke = function GLBrushStroke() { }; this.getPoint = function (index) { - return this._Points[index]; + return this._Points[index].slice(0); }; this.addPoint = function (pt) { @@ -399,7 +399,7 @@ var BrushStroke = function GLBrushStroke() { // ***** unproject all the centered points and convert them to 2D (plane space)***** // (undo the projection step performed by the browser) - localPoint = this._unprojectPt(localPoint, 1400); //todo get the perspective distance from the canvas + //localPoint = this._unprojectPt(localPoint, 1400); //todo get the perspective distance from the canvas localPoint = MathUtils.transformPoint(localPoint, this._planeMatInv); //add to the list of local points @@ -572,13 +572,13 @@ var BrushStroke = function GLBrushStroke() { ctx.restore(); } //this.render() - this.drawToContext = function(ctx, origX, origY, drawStageWorldPts){ + this.drawToContext = function(ctx, deltaX, deltaY, drawStageWorldPts, stageWorldToScreenMat){ var points = this._LocalPoints; - if (drawStageWorldPts){ + if (drawStageWorldPts){ //this is usually true when we're drawing the brush stroke on the stage (no canvas yet) points = this._Points; } var numPoints = points.length; - + var tempP, p; if (this._strokeUseCalligraphic) { //build the stamp for the brush stroke var t=0; @@ -623,9 +623,9 @@ var BrushStroke = function GLBrushStroke() { //ctx.strokeStyle="rgba("+parseInt(255*currStrokeColor[0])+","+parseInt(255*currStrokeColor[1])+","+parseInt(255*currStrokeColor[2])+","+alphaVal+")"; ctx.translate(disp[0],disp[1]); ctx.beginPath(); - ctx.moveTo(points[0][0]-origX, points[0][1]-origY); + ctx.moveTo(points[0][0]-deltaX, points[0][1]-deltaY); for (var i=0;i0){ var ctx = this.application.ninja.stage.drawingContext;//stageManagerModule.stageManager.drawingContext; if (ctx === null) throw ("null drawing context in Brushtool::ShowCurrentBrushStrokeOnStage"); ctx.save(); - var horizontalOffset = this.application.ninja.stage.userContentLeft; + /*var horizontalOffset = this.application.ninja.stage.userContentLeft; var verticalOffset = this.application.ninja.stage.userContentTop; - var halfStrokeWidth = 0.5*strokeSize; + var origX = -horizontalOffset; + var origY = -verticalOffset;*/ + var deltaX = -snapManager.getStageWidth()*0.5; + var deltaY = -snapManager.getStageHeight()*0.5; + var swToGlobalMat = ViewUtils.getStageWorldToGlobalMatrix(); + this._selectedBrushStroke.drawToContext(ctx, deltaX, deltaY, true, swToGlobalMat); + + /* + origX=0;origY=0; + + ctx.lineWidth = 2; + var numPoints = this._selectedBrushStroke.getNumPoints(); ctx.beginPath(); - if (!useCalligraphic) { - //for round brushes, draw a circle at the current mouse position - ctx.arc(currMousePos[0] + horizontalOffset, currMousePos[1]+ verticalOffset, halfStrokeWidth, 0, 2 * Math.PI, false); - } else { - //draw an angled stroke to represent the brush tip - var strokeAngle = 0; - if (this.options.strokeAngle){ - strokeAngle= this.options.strokeAngle.value; - } - strokeAngle = Math.PI * strokeAngle/180; - var deltaDisplacement = [Math.cos(strokeAngle),Math.sin(strokeAngle)]; - deltaDisplacement = VecUtils.vecNormalize(2, deltaDisplacement, 1); - var startPos = VecUtils.vecSubtract(2, currMousePos, [-horizontalOffset+halfStrokeWidth*deltaDisplacement[0],-verticalOffset+halfStrokeWidth*deltaDisplacement[1]]); - ctx.moveTo(startPos[0], startPos[1]); - var endPos = VecUtils.vecAdd(2, startPos, [strokeSize*deltaDisplacement[0], strokeSize*deltaDisplacement[1]]); - ctx.lineTo(endPos[0], endPos[1]); - ctx.lineWidth = 2; + var tempP = this._selectedBrushStroke.getPoint(0); + tempP[0]-=snapManager.getStageWidth()*0.5; + tempP[1]-=snapManager.getStageHeight()*0.5; + var p = MathUtils.transformAndDivideHomogeneousPoint(tempP, swToGlobalMat); + ctx.moveTo(p[0]-origX, p[1]-origY); + if (numPoints===1){ + //display a tiny segment as a single point + ctx.lineTo(p[0]-origX, p[1]-origY+0.01); + } + for (var i=1;i0){ - var ctx = this.application.ninja.stage.drawingContext;//stageManagerModule.stageManager.drawingContext; - if (ctx === null) - throw ("null drawing context in Brushtool::ShowCurrentBrushStrokeOnStage"); - ctx.save(); - var horizontalOffset = this.application.ninja.stage.userContentLeft; - var verticalOffset = this.application.ninja.stage.userContentTop; - var origX = -horizontalOffset; - var origY = -verticalOffset; - this._selectedBrushStroke.drawToContext(ctx, origX, origY, true); - ctx.restore(); - } - } - }, - - RenderCurrentBrushStroke:{ - value: function() { - if (this._selectedBrushStroke){ - //DEBUGGING - /*var localData = this._selectedBrushStroke.buildLocalDataFromStageWorldCoord(); - var bboxWidth = localData[1]; - var bboxHeight = localData[2]; - var bboxMid = localData[0];*/ - this._selectedBrushStroke.init(); - var bboxWidth = this._selectedBrushStroke.getWidth(); - var bboxHeight = this._selectedBrushStroke.getHeight(); - var bboxMid = this._selectedBrushStroke.getStageWorldCenter(); - //end DEBUGGING - //call render shape with the bbox width and height - this.RenderShape(bboxWidth, bboxHeight, this._brushStrokePlaneMat, bboxMid, this._brushStrokeCanvas); - - /*this._selectedBrushStroke.computeMetaGeometry(); - var bboxMin = this._selectedBrushStroke.getBBoxMin(); - var bboxMax = this._selectedBrushStroke.getBBoxMax(); - var bboxWidth = bboxMax[0] - bboxMin[0]; - var bboxHeight = bboxMax[1] - bboxMin[1]; - var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; - - this._selectedBrushStroke.setCanvasX(bboxMid[0]); - this._selectedBrushStroke.setCanvasY(bboxMid[1]); - //call render shape with the bbox width and height - this.RenderShape(bboxWidth, bboxHeight, this._brushStrokePlaneMat, bboxMid, this._brushStrokeCanvas); - */ - } + } + }, + + RenderCurrentBrushStroke:{ + value: function() { + if (this._selectedBrushStroke){ + //DEBUGGING + /*var localData = this._selectedBrushStroke.buildLocalDataFromStageWorldCoord(); + var bboxWidth = localData[1]; + var bboxHeight = localData[2]; + var bboxMid = localData[0];*/ + this._selectedBrushStroke.init(); + var bboxWidth = this._selectedBrushStroke.getWidth(); + var bboxHeight = this._selectedBrushStroke.getHeight(); + var bboxMid = this._selectedBrushStroke.getStageWorldCenter(); + //end DEBUGGING + //call render shape with the bbox width and height + this.RenderShape(bboxWidth, bboxHeight, this._brushStrokePlaneMat, bboxMid, this._brushStrokeCanvas); + + /*this._selectedBrushStroke.computeMetaGeometry(); + var bboxMin = this._selectedBrushStroke.getBBoxMin(); + var bboxMax = this._selectedBrushStroke.getBBoxMax(); + var bboxWidth = bboxMax[0] - bboxMin[0]; + var bboxHeight = bboxMax[1] - bboxMin[1]; + var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; + + this._selectedBrushStroke.setCanvasX(bboxMid[0]); + this._selectedBrushStroke.setCanvasY(bboxMid[1]); + //call render shape with the bbox width and height + this.RenderShape(bboxWidth, bboxHeight, this._brushStrokePlaneMat, bboxMid, this._brushStrokeCanvas); + */ } - }, - - - RenderShape: { - value: function (w, h, planeMat, midPt, canvas) { - if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) { - return; - } - - var left = Math.round(midPt[0] - 0.5 * w); - var top = Math.round(midPt[1] - 0.5 * h); - - if (!canvas) { - var newCanvas = NJUtils.makeNJElement("canvas", "Brushstroke", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); - var elementModel = TagTool.makeElement(w, h, planeMat, midPt, newCanvas, true); - ElementMediator.addElements(newCanvas, elementModel.data, false); + } + }, - // create all the GL stuff - var world = this.getGLWorld(newCanvas, this._useWebGL); - //store a reference to this newly created canvas - this._brushStrokeCanvas = newCanvas; - var brushStroke = this._selectedBrushStroke; - if (brushStroke){ - brushStroke.setWorld(world); - brushStroke.setCanvas(newCanvas); + RenderShape: { + value: function (w, h, planeMat, midPt, canvas) { + if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) { + return; + } - brushStroke.setPlaneMatrix(planeMat); - var planeMatInv = glmat4.inverse( planeMat, [] ); - brushStroke.setPlaneMatrixInverse(planeMatInv); - brushStroke.setPlaneCenter(midPt); + var left = Math.round(midPt[0] - 0.5 * w); + var top = Math.round(midPt[1] - 0.5 * h); + + if (!canvas) { + var newCanvas = NJUtils.makeNJElement("canvas", "Brushstroke", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); + var elementModel = TagTool.makeElement(w, h, planeMat, midPt, newCanvas, true); + ElementMediator.addElements(newCanvas, elementModel.data, false); + + // create all the GL stuff + var world = this.getGLWorld(newCanvas, this._useWebGL); + //store a reference to this newly created canvas + this._brushStrokeCanvas = newCanvas; + + var brushStroke = this._selectedBrushStroke; + if (brushStroke){ + brushStroke.setWorld(world); + brushStroke.setCanvas(newCanvas); + + brushStroke.setPlaneMatrix(planeMat); + var planeMatInv = glmat4.inverse( planeMat, [] ); + brushStroke.setPlaneMatrixInverse(planeMatInv); + brushStroke.setPlaneCenter(midPt); + + world.addObject(brushStroke); + world.render(); + //TODO this will not work if there are multiple shapes in the same canvas + newCanvas.elementModel.shapeModel.GLGeomObj = brushStroke; + + newCanvas.elementModel.shapeModel.shapeCount++; + if(newCanvas.elementModel.shapeModel.shapeCount === 1) + { + newCanvas.elementModel.selection = "BrushStroke"; + newCanvas.elementModel.pi = "BrushStrokePi"; + newCanvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; - world.addObject(brushStroke); - world.render(); - //TODO this will not work if there are multiple shapes in the same canvas newCanvas.elementModel.shapeModel.GLGeomObj = brushStroke; - - newCanvas.elementModel.shapeModel.shapeCount++; - if(newCanvas.elementModel.shapeModel.shapeCount === 1) - { - newCanvas.elementModel.selection = "BrushStroke"; - newCanvas.elementModel.pi = "BrushStrokePi"; - newCanvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; - - newCanvas.elementModel.shapeModel.GLGeomObj = brushStroke; - newCanvas.elementModel.shapeModel.useWebGl = this.options.use3D; - } - else - { - // TODO - update the shape's info only. shapeModel will likely need an array of shapes. - } - - //if(newCanvas.elementModel.isShape) - if (true) - { - this.application.ninja.selectionController.selectElement(newCanvas); - } + newCanvas.elementModel.shapeModel.useWebGl = this.options.use3D; + } + else + { + // TODO - update the shape's info only. shapeModel will likely need an array of shapes. } - } //if (!canvas) { - else { - - /* - var world = null; - if (canvas.elementModel.shapeModel && canvas.elementModel.shapeModel.GLWorld) { - world = canvas.elementModel.shapeModel.GLWorld; - } else { - world = this.getGLWorld(canvas, this._useWebGL); + + //if(newCanvas.elementModel.isShape) + if (true) + { + this.application.ninja.selectionController.selectElement(newCanvas); } + } + } //if (!canvas) { + else { + /* + var world = null; + if (canvas.elementModel.shapeModel && canvas.elementModel.shapeModel.GLWorld) { + world = canvas.elementModel.shapeModel.GLWorld; + } else { + world = this.getGLWorld(canvas, this._useWebGL); + } - if (this._entryEditMode !== this.ENTRY_SELECT_CANVAS){ - //update the left and top of the canvas element - var canvasArray=[canvas]; - ElementMediator.setProperty(canvasArray, "left", [parseInt(left)+"px"],"Changing", "brushTool"); - ElementMediator.setProperty(canvasArray, "top", [parseInt(top) + "px"],"Changing", "brushTool"); - canvas.width = w; - canvas.height = h; - //update the viewport and projection to reflect the new canvas width and height - world.setViewportFromCanvas(canvas); - if (this._useWebGL){ - var cam = world.renderer.cameraManager().getActiveCamera(); - cam.setPerspective(world.getFOV(), world.getAspect(), world.getZNear(), world.getZFar()); - } + + if (this._entryEditMode !== this.ENTRY_SELECT_CANVAS){ + //update the left and top of the canvas element + var canvasArray=[canvas]; + ElementMediator.setProperty(canvasArray, "left", [parseInt(left)+"px"],"Changing", "brushTool"); + ElementMediator.setProperty(canvasArray, "top", [parseInt(top) + "px"],"Changing", "brushTool"); + canvas.width = w; + canvas.height = h; + //update the viewport and projection to reflect the new canvas width and height + world.setViewportFromCanvas(canvas); + if (this._useWebGL){ + var cam = world.renderer.cameraManager().getActiveCamera(); + cam.setPerspective(world.getFOV(), world.getAspect(), world.getZNear(), world.getZFar()); } + } - var brushStroke = this._selectedBrushStroke; + var brushStroke = this._selectedBrushStroke; - if (brushStroke){ - brushStroke.setDrawingTool(this); + if (brushStroke){ + brushStroke.setDrawingTool(this); - brushStroke.setPlaneMatrix(planeMat); - var planeMatInv = glmat4.inverse( planeMat, [] ); - brushStroke.setPlaneMatrixInverse(planeMatInv); - brushStroke.setPlaneCenter(midPt); + brushStroke.setPlaneMatrix(planeMat); + var planeMatInv = glmat4.inverse( planeMat, [] ); + brushStroke.setPlaneMatrixInverse(planeMatInv); + brushStroke.setPlaneCenter(midPt); - brushStroke.setWorld(world); - world.addIfNewObject(brushStroke); - //world.addObject(subpath); - world.render(); - //TODO this will not work if there are multiple shapes in the same canvas - canvas.elementModel.shapeModel.GLGeomObj = brushStroke; - } - */ - alert("BrushStroke cannot edit existing canvas"); - } //else of if (!canvas) { - } //value: function (w, h, planeMat, midPt, canvas) { - }, //RenderShape: { - - Configure: { - value: function (wasSelected) { - if (wasSelected) { - if (g_DoBrushToolMouseMove){ - NJevent("enableStageMove"); - } + brushStroke.setWorld(world); + world.addIfNewObject(brushStroke); + //world.addObject(subpath); + world.render(); + //TODO this will not work if there are multiple shapes in the same canvas + canvas.elementModel.shapeModel.GLGeomObj = brushStroke; } - else { - if (g_DoBrushToolMouseMove){ - NJevent("disbleStageMove"); - } + */ + alert("BrushStroke cannot edit existing canvas"); + } //else of if (!canvas) { + } //value: function (w, h, planeMat, midPt, canvas) { + }, //RenderShape: { + + Configure: { + value: function (wasSelected) { + if (wasSelected) { + if (g_DoBrushToolMouseMove){ + NJevent("enableStageMove"); + } + } + else { + if (g_DoBrushToolMouseMove){ + NJevent("disbleStageMove"); } } } + } }); \ No newline at end of file -- cgit v1.2.3 From d45b72b0e683d307ce3e798769f19627416015db Mon Sep 17 00:00:00 2001 From: Pushkar Joshi Date: Wed, 25 Apr 2012 10:01:57 -0700 Subject: render the calligraphic brush stroke in realtime on a rotated canvas --- js/lib/geom/brush-stroke.js | 26 ++++++++++++++++++++------ js/tools/BrushTool.js | 2 +- 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'js') diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 89ef79fb..1fae0c1d 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js @@ -568,11 +568,11 @@ var BrushStroke = function GLBrushStroke() { } ctx.save(); ctx.clearRect(0, 0, bboxWidth, bboxHeight); - this.drawToContext(ctx, 0, 0, false); + this.drawToContext(ctx, false); ctx.restore(); } //this.render() - this.drawToContext = function(ctx, deltaX, deltaY, drawStageWorldPts, stageWorldToScreenMat){ + this.drawToContext = function(ctx, drawStageWorldPts, stageWorldDeltaX, stageWorldDeltaY, stageWorldToScreenMat){ var points = this._LocalPoints; if (drawStageWorldPts){ //this is usually true when we're drawing the brush stroke on the stage (no canvas yet) points = this._Points; @@ -623,9 +623,23 @@ var BrushStroke = function GLBrushStroke() { //ctx.strokeStyle="rgba("+parseInt(255*currStrokeColor[0])+","+parseInt(255*currStrokeColor[1])+","+parseInt(255*currStrokeColor[2])+","+alphaVal+")"; ctx.translate(disp[0],disp[1]); ctx.beginPath(); - ctx.moveTo(points[0][0]-deltaX, points[0][1]-deltaY); + if (drawStageWorldPts) { + tempP = points[0].slice(0); + tempP[0]+=stageWorldDeltaX; tempP[1]+=stageWorldDeltaY; + p = MathUtils.transformAndDivideHomogeneousPoint(tempP, stageWorldToScreenMat); + } else { + p = points[0]; + } + ctx.moveTo(p[0],p[1]); for (var i=0;i