aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xjs/helper-classes/3D/math-utils.js11
-rwxr-xr-xjs/lib/geom/brush-stroke.js93
-rw-r--r--js/tools/BrushTool.js8
-rwxr-xr-xjs/tools/PenTool.js165
4 files changed, 219 insertions, 58 deletions
diff --git a/js/helper-classes/3D/math-utils.js b/js/helper-classes/3D/math-utils.js
index 2f0283a9..35ee8112 100755
--- a/js/helper-classes/3D/math-utils.js
+++ b/js/helper-classes/3D/math-utils.js
@@ -928,17 +928,18 @@ var MathUtilsClass = exports.MathUtilsClass = Object.create(Object.prototype, {
928 return 0; 928 return 0;
929 } 929 }
930 //TODO testing...remove this block 930 //TODO testing...remove this block
931 console.log("getAxisAngleBetween3DVectors Angle: "+angle);
932 if (isNaN(angle)){ 931 if (isNaN(angle)){
933 console.log("getAxisAngleBetween3DVectors Angle is NaN"); 932 console.log("Warning! getAxisAngleBetween3DVectors Angle is NaN");
934 } 933 }
935 //TODO end testing block 934 //TODO end testing block
936 //optionally, if axis is provided, create the axis of rotation as well 935 //optionally, if axis is provided, create the axis of rotation as well
937 var rotAxis = VecUtils.vecCross(3, v1n, v2n); 936 var rotAxis = VecUtils.vecCross(3, v1n, v2n);
938 rotAxis = VecUtils.vecNormalize(3, rotAxis, 1); 937 rotAxis = VecUtils.vecNormalize(3, rotAxis, 1);
939 axis[0] = rotAxis[0]; 938 if (axis){
940 axis[1] = rotAxis[1]; 939 axis[0] = rotAxis[0];
941 axis[2] = rotAxis[2]; 940 axis[1] = rotAxis[1];
941 axis[2] = rotAxis[2];
942 }
942 return angle; 943 return angle;
943 } 944 }
944 }, 945 },
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js
index 1fae0c1d..519e0433 100755
--- a/js/lib/geom/brush-stroke.js
+++ b/js/lib/geom/brush-stroke.js
@@ -264,13 +264,67 @@ var BrushStroke = function GLBrushStroke() {
264 this._strokeStyle = s; 264 this._strokeStyle = s;
265 }; 265 };
266 266
267 this.setWidth = function () { 267 this.setWidth = function (newW) {
268 if (newW<1) {
269 newW=1; //clamp minimum width to 1
270 }
271
272 //scale the contents of this subpath to lie within this width
273 //determine the scale factor by comparing with the old width
274 var oldWidth = this._BBoxMax[0]-this._BBoxMin[0];
275 if (oldWidth<1) {
276 oldWidth=1;
277 }
278
279 var scaleX = newW/oldWidth;
280 if (scaleX===1) {
281 return; //no need to do anything
282 }
283
284 //scale the local point positions such that the width of the bbox is the newW
285 var origX = this._BBoxMin[0];
286 var numPoints = this._LocalPoints.length;
287 for (var i=0;i<numPoints;i++){
288 //compute the distance from the bboxMin
289 var oldW = this._LocalPoints[i][0] - origX;
290 this._LocalPoints[i] = [(origX + oldW*scaleX),this._LocalPoints[i][1],this._LocalPoints[i][2]];
291
292 oldW = this._OrigLocalPoints[i][0] - origX;
293 this._OrigLocalPoints[i] = [(origX + oldW*scaleX),this._OrigLocalPoints[i][1],this._OrigLocalPoints[i][2]];
294 }
295 this._isDirty = true;
296 };
297
298 this.setHeight = function (newH) {
299 if (newH<1) {
300 newH=1; //clamp minimum width to 1
301 }
268 302
269 };//NO-OP for now 303 //scale the contents of this subpath to lie within this height
304 //determine the scale factor by comparing with the old height
305 var oldHeight = this._BBoxMax[1]-this._BBoxMin[1];
306 if (oldHeight<1) {
307 oldHeight=1;
308 }
309
310 var scaleY = newH/oldHeight;
311 if (scaleY===1) {
312 return; //no need to do anything
313 }
270 314
271 this.setHeight = function () { 315 //scale the local point positions such that the width of the bbox is the newW
316 var origY = this._BBoxMin[1];
317 var numPoints = this._LocalPoints.length;
318 for (var i=0;i<numPoints;i++){
319 //compute the distance from the bboxMin
320 var oldH = this._LocalPoints[i][1] - origY;
321 this._LocalPoints[i] = [this._LocalPoints[i][0],(origY + oldH*scaleY),this._LocalPoints[i][2]];
272 322
273 };//NO-OP for now 323 oldH = this._OrigLocalPoints[i][1] - origY;
324 this._OrigLocalPoints[i] = [this._OrigLocalPoints[i][0],(origY + oldH*scaleY),this._OrigLocalPoints[i][2]];
325 }
326 this._isDirty = true;
327 };
274 328
275 this.getWidth = function() { 329 this.getWidth = function() {
276 if (this._isDirty){ 330 if (this._isDirty){
@@ -583,7 +637,7 @@ var BrushStroke = function GLBrushStroke() {
583 //build the stamp for the brush stroke 637 //build the stamp for the brush stroke
584 var t=0; 638 var t=0;
585 var numTraces = this._strokeWidth; 639 var numTraces = this._strokeWidth;
586 var halfNumTraces = numTraces/2; 640 var halfNumTraces = numTraces*0.5;
587 var opaqueRegionHalfWidth = 0.5*this._strokeHardness*numTraces*0.01; //the 0.01 is to convert the strokeHardness from [0,100] to [0,1] 641 var opaqueRegionHalfWidth = 0.5*this._strokeHardness*numTraces*0.01; //the 0.01 is to convert the strokeHardness from [0,100] to [0,1]
588 var maxTransparentRegionHalfWidth = halfNumTraces-opaqueRegionHalfWidth; 642 var maxTransparentRegionHalfWidth = halfNumTraces-opaqueRegionHalfWidth;
589 643
@@ -603,20 +657,23 @@ var BrushStroke = function GLBrushStroke() {
603 ctx.lineCap="butt"; 657 ctx.lineCap="butt";
604 ctx.globalCompositeOperation = 'source-over'; 658 ctx.globalCompositeOperation = 'source-over';
605 ctx.globalAlpha = this._strokeColor[3]; 659 ctx.globalAlpha = this._strokeColor[3];
606 //todo figure out the correct formula for the line width 660
607 ctx.lineWidth=2;
608 if (t===numTraces-1){
609 ctx.lineWidth = 1;
610 }
611 for (t=0;t<numTraces;t++){ 661 for (t=0;t<numTraces;t++){
612 var disp = [brushStamp[t][0], brushStamp[t][1]]; 662 var disp = [brushStamp[t][0], brushStamp[t][1]];
613 var alphaVal = 1.0; 663 var alphaVal = 1.0;
614 var distFromOpaqueRegion = Math.abs(t-halfNumTraces) - opaqueRegionHalfWidth; 664 var distFromOpaqueRegion = Math.abs(t-halfNumTraces) - opaqueRegionHalfWidth;
615 if (distFromOpaqueRegion>0) { 665 if (distFromOpaqueRegion>0) {
616 alphaVal = 1.0 - distFromOpaqueRegion/maxTransparentRegionHalfWidth; 666 var transparencyFactor = distFromOpaqueRegion/maxTransparentRegionHalfWidth;
617 alphaVal *= 1.0/ctx.lineWidth; //factor that accounts for lineWidth !== 1 667 alphaVal = 1.0 - transparencyFactor;//(transparencyFactor*transparencyFactor);//the square term produces nonlinearly varying alpha values
668 alphaVal *= 0.5; //factor that accounts for lineWidth == 2
618 } 669 }
619 ctx.save(); 670 ctx.save();
671 if (t === (numTraces-1) || t === 0){
672 ctx.lineWidth = 1;
673 } else {
674 //todo figure out the correct formula for the line width
675 ctx.lineWidth=2;
676 }
620 ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; 677 ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")";
621 //linearly interpolate between the two stroke colors 678 //linearly interpolate between the two stroke colors
622 var currStrokeColor = VecUtils.vecInterpolate(4, this._strokeColor, this._secondStrokeColor, t/numTraces); 679 var currStrokeColor = VecUtils.vecInterpolate(4, this._strokeColor, this._secondStrokeColor, t/numTraces);
@@ -650,7 +707,7 @@ var BrushStroke = function GLBrushStroke() {
650 ctx.lineCap = "round"; 707 ctx.lineCap = "round";
651 ctx.lineJoin="round"; 708 ctx.lineJoin="round";
652 var minStrokeWidth = (this._strokeHardness*this._strokeWidth)/100; //the hardness is the percentage of the stroke width that's fully opaque 709 var minStrokeWidth = (this._strokeHardness*this._strokeWidth)/100; //the hardness is the percentage of the stroke width that's fully opaque
653 var numlayers = 1 + (this._strokeWidth-minStrokeWidth)/2; 710 var numlayers = 1 + Math.ceil((this._strokeWidth-minStrokeWidth)*0.5);
654 var alphaVal = 1.0/(numlayers); //this way the alpha at the first path will be 1 711 var alphaVal = 1.0/(numlayers); //this way the alpha at the first path will be 1
655 ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; 712 ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")";
656 for (var l=0;l<numlayers;l++){ 713 for (var l=0;l<numlayers;l++){
@@ -678,6 +735,16 @@ var BrushStroke = function GLBrushStroke() {
678 ctx.lineTo(p[0],p[1]); 735 ctx.lineTo(p[0],p[1]);
679 } 736 }
680 ctx.lineWidth=2*l+minStrokeWidth; 737 ctx.lineWidth=2*l+minStrokeWidth;
738
739
740 //experiments with shadows
741 /*
742 ctx.shadowOffsetX = 10;
743 ctx.shadowOffsetY = 10;
744 ctx.shadowBlur = 10;
745 ctx.shadowColor = //"rgb("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+")";
746 "#FF6666"; //or use rgb(red, green, blue)
747 */
681 ctx.stroke(); 748 ctx.stroke();
682 }//for every layer l 749 }//for every layer l
683 } //if there is no calligraphic stroke 750 } //if there is no calligraphic stroke
diff --git a/js/tools/BrushTool.js b/js/tools/BrushTool.js
index 5c334b92..5d4e8288 100644
--- a/js/tools/BrushTool.js
+++ b/js/tools/BrushTool.js
@@ -225,9 +225,11 @@ exports.BrushTool = Montage.create(ShapeTool, {
225 this._hasDraw = false; 225 this._hasDraw = false;
226 226
227 //finish giving enough info. to the brush stroke 227 //finish giving enough info. to the brush stroke
228 this._selectedBrushStroke.setPlaneMatrix(this._brushStrokePlaneMat); 228 if (this._selectedBrushStroke){
229 this._selectedBrushStroke.setPlaneMatrixInverse(glmat4.inverse(this._brushStrokePlaneMat,[])); 229 this._selectedBrushStroke.setPlaneMatrix(this._brushStrokePlaneMat);
230 this._selectedBrushStroke.setDragPlane(this._draggingPlane); 230 this._selectedBrushStroke.setPlaneMatrixInverse(glmat4.inverse(this._brushStrokePlaneMat,[]));
231 this._selectedBrushStroke.setDragPlane(this._draggingPlane);
232 }
231 233
232 //display the previously drawn stroke in a separate canvas 234 //display the previously drawn stroke in a separate canvas
233 this.RenderCurrentBrushStroke(); 235 this.RenderCurrentBrushStroke();
diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js
index 16990ca7..fd470af7 100755
--- a/js/tools/PenTool.js
+++ b/js/tools/PenTool.js
@@ -273,14 +273,36 @@ exports.PenTool = Montage.create(ShapeTool, {
273 var swMousePos = hitRec.calculateStageWorldPoint(); 273 var swMousePos = hitRec.calculateStageWorldPoint();
274 swMousePos[0]+= snapManager.getStageWidth()*0.5; swMousePos[1]+= snapManager.getStageHeight()*0.5; 274 swMousePos[0]+= snapManager.getStageWidth()*0.5; swMousePos[1]+= snapManager.getStageHeight()*0.5;
275 275
276 this._selectedSubpath.addAnchor(new AnchorPoint()); 276 //check if the mouse click location is close to the existing anchor
277 var newAnchor = this._selectedSubpath.getAnchor(this._selectedSubpath.getSelectedAnchorIndex()); 277 var indexAndCode = this._selectedSubpath.pickAnchor(swMousePos[0], swMousePos[1], swMousePos[2], this._PICK_POINT_RADIUS);
278 newAnchor.setPos(swMousePos[0], swMousePos[1], swMousePos[2]); 278 if (indexAndCode[0]>=0){
279 newAnchor.setPrevPos(swMousePos[0], swMousePos[1], swMousePos[2]); 279 //the anchor point was hit, so we do not add another anchor
280 newAnchor.setNextPos(swMousePos[0], swMousePos[1], swMousePos[2]); 280 switch(indexAndCode[1]){
281 //set the mode so that dragging will update the next and previous locations 281 case this._selectedSubpath.SEL_ANCHOR:
282 this._editMode = this.EDIT_PREV_NEXT; 282 this._editMode = this.EDIT_ANCHOR;
283 }