diff options
-rwxr-xr-x | js/lib/geom/brush-stroke.js | 156 |
1 files changed, 38 insertions, 118 deletions
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index f0925ba5..70429ca9 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js | |||
@@ -28,20 +28,12 @@ var BrushStroke = function GLBrushStroke() { | |||
28 | this._BBoxMax = [0, 0, 0]; | 28 | this._BBoxMax = [0, 0, 0]; |
29 | this._isDirty = true; | 29 | this._isDirty = true; |
30 | this._isInit = false; | 30 | this._isInit = false; |
31 | 31 | ||
32 | |||
33 | //whether or not to use the canvas drawing to stroke/fill | ||
34 | this._useCanvasDrawing = true; | ||
35 | |||
36 | //the HTML5 canvas that holds this brush stroke | 32 | //the HTML5 canvas that holds this brush stroke |
37 | this._canvas = null; | 33 | this._canvas = null; |
38 | 34 | ||
39 | //the X and Y location of this brush stroke canvas in stage world space of Ninja | ||
40 | this._canvasX = 0; | ||
41 | this._canvasY = 0; | ||
42 | |||
43 | //stroke information | 35 | //stroke information |
44 | this._strokeWidth = 0.0; | 36 | this._strokeWidth = 1.0; |
45 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; | 37 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; |
46 | this._secondStrokeColor = [1, 0.4, 0.4, 1.0]; | 38 | this._secondStrokeColor = [1, 0.4, 0.4, 1.0]; |
47 | this._strokeHardness = 100; | 39 | this._strokeHardness = 100; |
@@ -114,22 +106,6 @@ var BrushStroke = function GLBrushStroke() { | |||
114 | this._dragPlane = p; | 106 | this._dragPlane = p; |
115 | }; | 107 | }; |
116 | 108 | ||
117 | this.getCanvasX = function(){ | ||
118 | return this._canvasX; | ||
119 | }; | ||
120 | |||
121 | this.getCanvasY = function(){ | ||
122 | return this._canvasY; | ||
123 | }; | ||
124 | |||
125 | this.setCanvasX = function(cx){ | ||
126 | this._canvasX=cx; | ||
127 | }; | ||
128 | |||
129 | this.setCanvasY = function(cy){ | ||
130 | this._canvasY=cy; | ||
131 | }; | ||
132 | |||
133 | this.getNumPoints = function () { | 109 | this.getNumPoints = function () { |
134 | return this._Points.length; | 110 | return this._Points.length; |
135 | }; | 111 | }; |
@@ -190,6 +166,9 @@ var BrushStroke = function GLBrushStroke() { | |||
190 | 166 | ||
191 | this.setStrokeWidth = function (w) { | 167 | this.setStrokeWidth = function (w) { |
192 | this._strokeWidth = w; | 168 | this._strokeWidth = w; |
169 | if (this._strokeWidth<1) { | ||
170 | this._strokeWidth = 1; | ||
171 | } | ||
193 | this._isDirty=true; | 172 | this._isDirty=true; |
194 | }; | 173 | }; |
195 | 174 | ||
@@ -402,83 +381,37 @@ var BrushStroke = function GLBrushStroke() { | |||
402 | this._stageWorldCenter = VecUtils.vecInterpolate(3, bboxMin, bboxMax, 0.5); | 381 | this._stageWorldCenter = VecUtils.vecInterpolate(3, bboxMin, bboxMax, 0.5); |
403 | 382 | ||
404 | // ***** center the input stageworld data about the center of the bbox ***** | 383 | // ***** center the input stageworld data about the center of the bbox ***** |
405 | this._LocalPoints = this._Points.slice(0); | 384 | this._LocalPoints = []; |
406 | for (i=0;i<numPoints;i++){ | 385 | for (i=0;i<numPoints;i++){ |
407 | this._LocalPoints[i][0]-= this._stageWorldCenter[0]; | 386 | var localPoint = [this._Points[i][0],this._Points[i][1],this._Points[i][2]]; |
408 | this._LocalPoints[i][1]-= this._stageWorldCenter[1]; | 387 | localPoint[0]-= this._stageWorldCenter[0]; |
409 | } | 388 | localPoint[1]-= this._stageWorldCenter[1]; |
410 | 389 | ||
411 | // ***** unproject all the centered points and convert them to 2D (plane space)***** | 390 | // ***** unproject all the centered points and convert them to 2D (plane space)***** |
412 | // (undo the projection step performed by the browser) | 391 | // (undo the projection step performed by the browser) |
413 | for (i=0;i<numPoints;i++) { | 392 | localPoint = this._unprojectPt(localPoint, 1400); //todo get the perspective distance from the canvas |
414 | this._LocalPoints[i] = this._unprojectPt(this._LocalPoints[i], 1400); //todo get the perspective distance from the canvas | 393 | localPoint = MathUtils.transformPoint(localPoint, this._planeMatInv); |
415 | this._LocalPoints[i] = MathUtils.transformPoint(this._LocalPoints[i], this._planeMatInv); | 394 | |
395 | //add to the list of local points | ||
396 | this._LocalPoints.push(localPoint); | ||
416 | } | 397 | } |
417 | 398 | ||
418 | // ***** compute width, height, and midpoint position (in stage world position) of the canvas | 399 | // ***** compute width, height, and midpoint position (in stage world position) of the canvas |
419 | this._updateBoundingBox(); //compute the bbox to obtain the width and height used below | 400 | this._updateBoundingBox(); //compute the bbox to obtain the width and height used below |
420 | var halfwidth = 0.5*(this._BBoxMax[0]-this._BBoxMin[0]); | 401 | var halfwidth = 0.5*(this._BBoxMax[0]-this._BBoxMin[0]); |
421 | var halfheight = 0.5*(this._BBoxMax[1]-this._BBoxMin[1]); | 402 | var halfheight = 0.5*(this._BBoxMax[1]-this._BBoxMin[1]); |
403 | this._OrigPoints = []; | ||
422 | for (i=0;i<numPoints;i++) { | 404 | for (i=0;i<numPoints;i++) { |
423 | this._LocalPoints[i][0]+= halfwidth; | 405 | this._LocalPoints[i][0]+= halfwidth; |
424 | this._LocalPoints[i][1]+= halfheight; | 406 | this._LocalPoints[i][1]+= halfheight; |
425 | } | ||
426 | //store the original points | ||
427 | this._OrigPoints = this._LocalPoints.slice(0); | ||
428 | |||
429 | //var midPt = stageWorldBBoxCenter; //todo should I compute the instead as the midpoint of the plane-space bbox, transformed by this._planeMat | ||
430 | // The following offset seems to not match what was being done successfully for the brush tool, so I'm commenting this out | ||
431 | // the mid point is now relative to the center of the 3D space. To | ||
432 | // calculate the left and top offsets, this must be offset by the stage dimensions | ||
433 | //var wh = ViewUtils.getStageDimension(); | ||
434 | //midPt[0] += wh[0]/ 2.0; | ||
435 | //midPt[1] += wh[1]/ 2.0; | ||
436 | }; | ||
437 | /*this.translate = function (tx, ty, tz) { | ||
438 | for (var i=0;i<this._Points.length;i++){ | ||
439 | this._Points[i][0]+=tx; | ||
440 | this._Points[i][1]+=ty; | ||
441 | this._Points[i][2]+=tz; | ||
442 | } | ||
443 | this._isDirty = true; | ||
444 | };*/ | ||
445 | |||
446 | //build coordinates for the brush stroke in local space of the canvas...will assume that the canvas width, height, left and top will not be changed now | ||
447 | this.buildLocalCoord = function(){ | ||
448 | /* | ||
449 | if (this._isLocalDirty) { | ||
450 | //DEBUGGING | ||
451 | //confirm that localToStageWorld produces the same coordinates as those I used for rendering currently | ||
452 | var numPoints = this._Points.length; | ||
453 | var objToStageWorldMat = ViewUtils.getObjToStageWorldMatrix(this._canvas, true); | ||
454 | var stageworldToObjMat = glmat4.inverse(objToStageWorldMat, []); | ||
455 | var wh = ViewUtils.getStageDimension(); | ||
456 | for (var i=0;i<numPoints;i++) { | ||
457 | var origStageWorldPt = this._Points[i]; | ||
458 | //var localPt = [origStageWorldPt[0]-bboxMin[0], origStageWorldPt[1]-bboxMin[1],0]; //this is how the brush tool currently renders points in stage world | ||
459 | |||
460 | //check using ObjToStageWorldMatrix --- works | ||
461 | //var tmp = MathUtils.transformHomogeneousPoint(localPt,objToStageWorldMat); | ||
462 | //var newStageWorldPt = MathUtils.applyHomogeneousCoordinate(tmp); | ||
463 | //newStageWorldPt = VecUtils.vecAdd(3, newStageWorldPt, [wh[0]/2, wh[1]/2, 0]); | ||
464 | //var diffPt = VecUtils.vecDist(3,origStageWorldPt,newStageWorldPt); | ||
465 | |||
466 | //now go the other way, to recover localPt | ||
467 | var offsetedStageWorldPt = VecUtils.vecSubtract(3, origStageWorldPt, [wh[0]/2, wh[1]/2, 0]); | ||
468 | var tmp = MathUtils.transformHomogeneousPoint(offsetedStageWorldPt,stageworldToObjMat); | ||
469 | var newLocalPt = MathUtils.applyHomogeneousCoordinate(tmp); | ||
470 | //var diffPt2 = VecUtils.vecDist(3,localPt,newLocalPt); | ||
471 | this._LocalPoints[i] = newLocalPt; | ||
472 | } | ||
473 | 407 | ||
474 | 408 | //store the original points | |
475 | //end DEBUGGING | 409 | this._OrigPoints.push([this._LocalPoints[i][0],this._LocalPoints[i][1],this._LocalPoints[i][2]]); |
476 | this._isLocalDirty=false; | 410 | } |
477 | } //if this._isLocalDirty | 411 | //update the bbox with the same adjustment as was made for the local points above |
478 | */ | 412 | this._BBoxMax[0]+= halfwidth;this._BBoxMin[0]+= halfwidth; |
413 | this._BBoxMax[1]+= halfheight;this._BBoxMin[1]+= halfheight; | ||
479 | }; | 414 | }; |
480 | |||
481 | |||
482 | 415 | ||
483 | this.update = function() { | 416 | this.update = function() { |
484 | if (this._isDirty){ | 417 | if (this._isDirty){ |
@@ -486,10 +419,10 @@ var BrushStroke = function GLBrushStroke() { | |||
486 | this._doSmoothing(); | 419 | this._doSmoothing(); |
487 | 420 | ||
488 | // **** recompute the bounding box **** | 421 | // **** recompute the bounding box **** |
489 | var deltaWH = this._updateBoundingBox(); | 422 | this._updateBoundingBox(); |
490 | 423 | ||
491 | // **** offset the local coords to account for the change in bbox **** | 424 | // **** offset the local coords to account for the change in bbox **** |
492 | this._offsetLocalCoord(deltaWH[0]*0.5, deltaWH[1]*0.5); | 425 | this._offsetLocalCoord(-this._BBoxMin[0], -this._BBoxMin[1]); |
493 | 426 | ||
494 | // **** turn off the dirty flag **** | 427 | // **** turn off the dirty flag **** |
495 | this._isDirty = false; | 428 | this._isDirty = false; |
@@ -503,21 +436,30 @@ var BrushStroke = function GLBrushStroke() { | |||
503 | this._LocalPoints[i][1]+= deltaH; | 436 | this._LocalPoints[i][1]+= deltaH; |
504 | } | 437 | } |
505 | }; | 438 | }; |
439 | |||
440 | //I had to write this function to do a deep copy because I think slice(0) creates a copy by reference | ||
441 | this._copyCoordinates3D = function(srcCoord, destCoord){ | ||
442 | var i=0; | ||
443 | var numPoints = srcCoord.length; | ||
444 | for (i=0;i<numPoints;i++){ | ||
445 | destCoord[i] = [srcCoord[i][0],srcCoord[i][1],srcCoord[i][2]]; | ||
446 | } | ||
447 | }; | ||
506 | this._doSmoothing = function() { | 448 | this._doSmoothing = function() { |
507 | var numPoints = this._LocalPoints.length; | 449 | var numPoints = this._LocalPoints.length; |
508 | if (this._strokeDoSmoothing && numPoints>1) { | 450 | if (this._strokeDoSmoothing && numPoints>1) { |
509 | this._LocalPoints = this._OrigPoints.slice(0); | 451 | this._copyCoordinates3D(this._OrigPoints, this._LocalPoints); |
510 | //iterations of Laplacian smoothing (setting the points to the average of their neighbors) | 452 | //iterations of Laplacian smoothing (setting the points to the average of their neighbors) |
511 | var numLaplacianIterations = this._strokeAmountSmoothing; | 453 | var numLaplacianIterations = this._strokeAmountSmoothing; |
512 | for (var n=0;n<numLaplacianIterations;n++){ | 454 | for (var n=0;n<numLaplacianIterations;n++){ |
513 | var newPoints = this._LocalPoints;//.slice(0); | 455 | var newPoints = this._LocalPoints.slice(0); //I think this performs a copy by reference, which would make the following a SOR step |
514 | for (var i=1;i<numPoints-1;i++) { | 456 | for (var i=1;i<numPoints-1;i++) { |
515 | var avgPos = [ 0.5*(this._LocalPoints[i-1][0] + this._LocalPoints[i+1][0]), | 457 | var avgPos = [ 0.5*(this._LocalPoints[i-1][0] + this._LocalPoints[i+1][0]), |
516 | 0.5*(this._LocalPoints[i-1][1] + this._LocalPoints[i+1][1]), | 458 | 0.5*(this._LocalPoints[i-1][1] + this._LocalPoints[i+1][1]), |
517 | 0.5*(this._LocalPoints[i-1][2] + this._LocalPoints[i+1][2])] ; | 459 | 0.5*(this._LocalPoints[i-1][2] + this._LocalPoints[i+1][2])] ; |
518 | newPoints[i] = avgPos; | 460 | newPoints[i] = avgPos; |
519 | } | 461 | } |
520 | this._LocalPoints = newPoints;//.slice(0); | 462 | this._LocalPoints = newPoints.slice(0); |
521 | } | 463 | } |
522 | } | 464 | } |
523 | }; | 465 | }; |
@@ -526,8 +468,6 @@ var BrushStroke = function GLBrushStroke() { | |||
526 | // *** compute the bounding box ********* | 468 | // *** compute the bounding box ********* |
527 | var points = this._LocalPoints; | 469 | var |