diff options
-rwxr-xr-x | js/components/tools-properties/brush-properties.reel/brush-properties.html | 23 | ||||
-rwxr-xr-x | js/components/tools-properties/brush-properties.reel/brush-properties.js | 8 | ||||
-rwxr-xr-x | js/lib/geom/brush-stroke.js | 147 | ||||
-rw-r--r-- | js/tools/BrushTool.js | 18 |
4 files changed, 129 insertions, 67 deletions
diff --git a/js/components/tools-properties/brush-properties.reel/brush-properties.html b/js/components/tools-properties/brush-properties.reel/brush-properties.html index 6d4852e6..d96bd1ba 100755 --- a/js/components/tools-properties/brush-properties.reel/brush-properties.html +++ b/js/components/tools-properties/brush-properties.reel/brush-properties.html | |||
@@ -37,6 +37,19 @@ | |||
37 | } | 37 | } |
38 | }, | 38 | }, |
39 | 39 | ||
40 | "strokeAngleHT": { | ||
41 | "module": "js/components/hottextunit.reel", | ||
42 | "name": "HotTextUnit", | ||
43 | "properties": { | ||
44 | "element": {"#": "strokeAngle"}, | ||
45 | "minValue": -90, | ||
46 | "maxValue": 90, | ||
47 | "value": 0, | ||
48 | "decimalPlace": 10, | ||
49 | "acceptableUnits" : ["px", "pt"] | ||
50 | } | ||
51 | }, | ||
52 | |||
40 | "owner": { | 53 | "owner": { |
41 | "module": "js/components/tools-properties/brush-properties.reel", | 54 | "module": "js/components/tools-properties/brush-properties.reel", |
42 | "name": "BrushProperties", | 55 | "name": "BrushProperties", |
@@ -44,7 +57,9 @@ | |||
44 | "element": {"#": "brushProperties"}, | 57 | "element": {"#": "brushProperties"}, |
45 | "_strokeSize": {"@": "strokeSizeHT"}, | 58 | "_strokeSize": {"@": "strokeSizeHT"}, |
46 | "_strokeHardness": {"@": "strokeHardnessHT"}, | 59 | "_strokeHardness": {"@": "strokeHardnessHT"}, |
47 | "_doSmoothing": {"@": "doSmoothing"} | 60 | "_doSmoothing": {"#": "doSmoothing"}, |
61 | "_useCalligraphic":{"#": "useCalligraphic"}, | ||
62 | "_strokeAngle": {"@": "strokeAngleHT"} | ||
48 | } | 63 | } |
49 | } | 64 | } |
50 | } | 65 | } |
@@ -59,7 +74,11 @@ | |||
59 | <div id="strokeSize" class="label"></div> | 74 | <div id="strokeSize" class="label"></div> |
60 | <label class="label"> Hardness:</label> | 75 | <label class="label"> Hardness:</label> |
61 | <div id="strokeHardness" class="label"></div> | 76 | <div id="strokeHardness" class="label"></div> |
62 | <label class="label subOption optionLabel"><input id="doSmoothing" type="checkbox" name="doSmoothingControl" class="checkBoxAlign"/>Smoothing</label> | 77 | <label class="label"><input id="doSmoothing" type="checkbox" name="doSmoothingControl" class="checkBoxAlign"/>Smoothing</label> |
78 | <label class="label"><input id="useCalligraphic" type="checkbox" name="useCalligraphicControl" class="checkBoxAlign"/>Calligraphic</label> | ||
79 | <label class="label"> Angle:</label> | ||
80 | <div id="strokeAngle" class="label"></div> | ||
81 | |||
63 | </div> | 82 | </div> |
64 | </div> | 83 | </div> |
65 | </body> | 84 | </body> |
diff --git a/js/components/tools-properties/brush-properties.reel/brush-properties.js b/js/components/tools-properties/brush-properties.reel/brush-properties.js index 0ce685b5..e6faa0f0 100755 --- a/js/components/tools-properties/brush-properties.reel/brush-properties.js +++ b/js/components/tools-properties/brush-properties.reel/brush-properties.js | |||
@@ -16,6 +16,12 @@ exports.BrushProperties = Montage.create(ToolProperties, { | |||
16 | get: function() { return this._strokeHardness; } | 16 | get: function() { return this._strokeHardness; } |
17 | }, | 17 | }, |
18 | doSmoothing:{ | 18 | doSmoothing:{ |
19 | get: function() {return this._doSmoothing; } | 19 | get: function() {return this._doSmoothing.checked; } |
20 | }, | ||
21 | useCalligraphic: { | ||
22 | get: function() {return this._useCalligraphic.checked;} | ||
23 | }, | ||
24 | strokeAngle: { | ||
25 | get: function() {return this._strokeAngle;} | ||
20 | } | 26 | } |
21 | }); | 27 | }); |
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 3e64e730..a92657a4 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js | |||
@@ -37,6 +37,8 @@ var BrushStroke = function GLBrushStroke() { | |||
37 | this._strokeMaterial = null; | 37 | this._strokeMaterial = null; |
38 | this._strokeStyle = "Solid"; | 38 | this._strokeStyle = "Solid"; |
39 | this._strokeDoSmoothing = false; | 39 | this._strokeDoSmoothing = false; |
40 | this._strokeUseCalligraphic = false; | ||
41 | this._strokeAngle = 0; | ||
40 | 42 | ||
41 | //the wetness of the brush (currently this is multiplied to the square of the stroke width, but todo should be changed to not depend on stroke width entirely | 43 | //the wetness of the brush (currently this is multiplied to the square of the stroke width, but todo should be changed to not depend on stroke width entirely |
42 | //smaller value means more samples for the path | 44 | //smaller value means more samples for the path |
@@ -117,7 +119,7 @@ var BrushStroke = function GLBrushStroke() { | |||
117 | //add the point only if it is some epsilon away from the previous point | 119 | //add the point only if it is some epsilon away from the previous point |
118 | var numPoints = this._Points.length; | 120 | var numPoints = this._Points.length; |
119 | if (numPoints>0) { | 121 | if (numPoints>0) { |
120 | var threshold = 1;//this._WETNESS_FACTOR*this._strokeWidth; | 122 | var threshold = 2;//this._WETNESS_FACTOR*this._strokeWidth; |
121 | var prevPt = this._Points[numPoints-1]; | 123 | var prevPt = this._Points[numPoints-1]; |
122 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; | 124 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; |
123 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); | 125 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); |
@@ -188,6 +190,14 @@ var BrushStroke = function GLBrushStroke() { | |||
188 | this._strokeDoSmoothing = s; | 190 | this._strokeDoSmoothing = s; |
189 | } | 191 | } |
190 | 192 | ||
193 | this.setStrokeUseCalligraphic = function(c){ | ||
194 | this._strokeUseCalligraphic = c; | ||
195 | } | ||
196 | |||
197 | this.setStrokeAngle = function(a){ | ||
198 | this._strokeAngle = a; | ||
199 | } | ||
200 | |||
191 | this.getStrokeStyle = function () { | 201 | this.getStrokeStyle = function () { |
192 | return this._strokeStyle; | 202 | return this._strokeStyle; |
193 | }; | 203 | }; |
@@ -266,6 +276,8 @@ var BrushStroke = function GLBrushStroke() { | |||
266 | } | 276 | } |
267 | } | 277 | } |
268 | } | 278 | } |
279 | //todo 4-point subdivision iterations over continuous regions of 'long' segments | ||
280 | // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula | ||
269 | //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation | 281 | //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation |
270 | if (this._strokeDoSmoothing && numPoints>1) { | 282 | if (this._strokeDoSmoothing && numPoints>1) { |
271 | var numInsertedPoints = 0; | 283 | var numInsertedPoints = 0; |
@@ -496,75 +508,84 @@ var BrushStroke = function GLBrushStroke() { | |||
496 | } | 508 | } |
497 | */ | 509 | */ |
498 | 510 | ||
499 | /* | ||
500 | //build the stamp for the brush stroke | ||
501 | //todo get this directly from the UI | ||
502 | var t=0; | ||
503 | var numTraces = this._strokeWidth; | ||
504 | var halfNumTraces = numTraces/2; | ||
505 | var startPos = [-this._strokeWidth/2,0]; | ||
506 | var brushStamp = []; | ||
507 | |||
508 | //build an angled (calligraphic) brush stamp | ||
509 | var deltaDisplacement = [1,1];//[this._strokeWidth/numTraces, 0]; //a horizontal line brush | ||
510 | for (t=0;t<numTraces;t++){ | ||
511 | var brushPt = [startPos[0]+t*deltaDisplacement[0], startPos[1]+t*deltaDisplacement[1]]; | ||
512 | brushStamp.push(brushPt); | ||
513 | } | ||
514 | 511 | ||
515 | for (t=0;t<numTraces;t++){ | 512 | if (this._strokeUseCalligraphic) { |
516 | var disp = [brushStamp[t][0], brushStamp[t][1]]; | 513 | //build the stamp for the brush stroke |
517 | //ctx.globalCompositeOperation = 'source-over'; | 514 | var t=0; |
518 | var distFromMiddle = Math.abs(halfNumTraces-t); | 515 | var numTraces = this._strokeWidth; |
519 | var alphaVal = 1.0 - (100-this._strokeHardness)*(distFromMiddle/halfNumTraces)/100; | 516 | var halfNumTraces = numTraces/2; |
520 | alphaVal = 0.2; | 517 | var opaqueRegionHalfWidth = 0.5*this._strokeHardness*numTraces*0.01; |
521 | ctx.save(); | 518 | var maxTransparentRegionHalfWidth = halfNumTraces-opaqueRegionHalfWidth; |
522 | ctx.lineWidth=this._strokeWidth/10;//todo figure out the correct formula for the line width | 519 | var startPos = [-this._strokeWidth/2,0]; |
523 | if (ctx.lineWidth<2) | 520 | var brushStamp = []; |
524 | ctx.lineWidth=2; | ||
525 | if (t===numTraces-1){ | ||
526 | ctx.lineWidth = 1; | ||
527 | } | ||
528 | ctx.lineJoin="bevel"; | ||
529 | ctx.lineCap="butt"; | ||
530 | //if (t<numTraces/2) | ||
531 | ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; | ||
532 | //else | ||
533 | // ctx.strokeStyle="rgba("+parseInt(255*this._secondStrokeColor[0])+","+parseInt(255*this._secondStrokeColor[1])+","+parseInt(255*this._secondStrokeColor[2])+","+alphaVal+")"; | ||
534 | ctx.translate(disp[0],disp[1]); | ||
535 | ctx.beginPath(); | ||
536 | ctx.moveTo(this._Points[0][0]-bboxMin[0], this._Points[0][1]-bboxMin[1]); | ||
537 | for (var i=0;i<numPoints;i++){ | ||
538 | ctx.lineTo(this._Points[i][0]-bboxMin[0], this._Points[i][1]-bboxMin[1]); | ||
539 | } | ||
540 | ctx.stroke(); | ||
541 | ctx.restore(); | ||
542 | } | ||
543 | */ | ||
544 | 521 | ||
522 | //build an angled (calligraphic) brush stamp | ||
523 | var deltaDisplacement = [Math.cos(this._strokeAngle),Math.sin(this._strokeAngle)]; | ||
524 | deltaDisplacement = VecUtils.vecNormalize(2, deltaDisplacement, 1); | ||
545 | 525 | ||
546 | var minStrokeWidth = (this._strokeHardness*this._strokeWidth)/100; //the hardness is the percentage of the stroke width that's fully opaque | 526 | for (t=0;t<numTraces;t++){ |
547 | var numlayers = 1 + (this._strokeWidth-minStrokeWidth)/2; | 527 | var brushPt = [startPos[0]+t*deltaDisplacement[0], startPos[1]+t*deltaDisplacement[1]]; |
548 | var alphaVal = 1.0/(numlayers); | 528 | brushStamp.push(brushPt); |
549 | ctx.lineCap = "round"; | ||
550 | ctx.lineJoin="round"; | ||
551 | ctx.strokeStyle="rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+alphaVal+")"; | ||
552 | ctx.globalCompositeOperation = 'lighter'; //we wish to add up the colors | ||
553 | ctx.globalAlpha = this._strokeColor[3]; | ||
554 | for (var l=0;l<numlayers;l++){ | ||
555 | ctx.beginPath(); | ||
556 | ctx.moveTo(this._Points[0][0]-bboxMin[0], this._Points[0][1]-bboxMin[1]); | ||
557 | if (numPoints===1){ | ||
558 | ctx.lineTo(this._Points[0][0]-bboxMin[0], this._Points[0][1]-bboxMin[1]+0.01); | ||
559 | } | 529 | } |
560 | for (var i=1;i<numPoints;i++){ | 530 | |
561 | ctx.lineTo(this._Points[i][0]-bboxMin[0], this._Points[i][1]-bboxMin[1]); | 531 | for (t=0;t<numTraces;t++){ |
532 | var disp = [brushStamp[t][0], brushStamp[t][1]]; | ||
533 | //ctx.globalCompositeOperation = 'source-over'; | ||
534 | var alphaVal = 1.0; | ||
535 | var distFromOpaqueRegion = Math.abs(t-halfNumTraces) - opaqueRegionHalfWidth; | ||
536 | if (distFromOpaqueRegion>0) { | ||
537 | alphaVal = 1.0 - distFromOpaqueRegion/maxTransparentRegionHalfWidth; | ||
538 | } | ||
539 |