diff options
Diffstat (limited to 'js/lib')
-rwxr-xr-x | js/lib/drawing/world.js | 18 | ||||
-rwxr-xr-x | js/lib/geom/brush-stroke.js | 329 | ||||
-rwxr-xr-x | js/lib/geom/circle.js | 95 | ||||
-rwxr-xr-x | js/lib/geom/geom-obj.js | 123 | ||||
-rwxr-xr-x | js/lib/geom/line.js | 57 | ||||
-rwxr-xr-x | js/lib/geom/rectangle.js | 102 | ||||
-rwxr-xr-x | js/lib/geom/sub-path.js | 86 |
7 files changed, 619 insertions, 191 deletions
diff --git a/js/lib/drawing/world.js b/js/lib/drawing/world.js index 44c9e37d..049145ce 100755 --- a/js/lib/drawing/world.js +++ b/js/lib/drawing/world.js | |||
@@ -17,7 +17,7 @@ var worldCounter = 0; | |||
17 | // Class GLWorld | 17 | // Class GLWorld |
18 | // Manages display in a canvas | 18 | // Manages display in a canvas |
19 | /////////////////////////////////////////////////////////////////////// | 19 | /////////////////////////////////////////////////////////////////////// |
20 | var World = function GLWorld( canvas, use3D ) { | 20 | var World = function GLWorld( canvas, use3D, preserveDrawingBuffer ) { |
21 | /////////////////////////////////////////////////////////////////////// | 21 | /////////////////////////////////////////////////////////////////////// |
22 | // Instance variables | 22 | // Instance variables |
23 | /////////////////////////////////////////////////////////////////////// | 23 | /////////////////////////////////////////////////////////////////////// |
@@ -30,7 +30,11 @@ var World = function GLWorld( canvas, use3D ) { | |||
30 | 30 | ||
31 | this._canvas = canvas; | 31 | this._canvas = canvas; |
32 | if (this._useWebGL) { | 32 | if (this._useWebGL) { |
33 | this._glContext = canvas.getContext("experimental-webgl"); | 33 | if(preserveDrawingBuffer) { |
34 | this._glContext = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true}); | ||
35 | } else { | ||
36 | this._glContext = canvas.getContext("experimental-webgl"); | ||
37 | } | ||
34 | } else { | 38 | } else { |
35 | this._2DContext = canvas.getContext( "2d" ); | 39 | this._2DContext = canvas.getContext( "2d" ); |
36 | } | 40 | } |
@@ -347,20 +351,18 @@ var World = function GLWorld( canvas, use3D ) { | |||
347 | return false; | 351 | return false; |
348 | }; | 352 | }; |
349 | 353 | ||
350 | this.generateUniqueNodeID = function() | 354 | this.generateUniqueNodeID = function() { |
351 | { | ||
352 | var str = "" + this._nodeCounter; | 355 | var str = "" + this._nodeCounter; |
353 | this._nodeCounter++; | 356 | this._nodeCounter++; |
354 | return str; | 357 | return str; |
355 | } | 358 | }; |
356 | 359 | ||
357 | 360 | ||
358 | // start RDGE passing your runtime object, and false to indicate we don't need a an initialization state | 361 | // start RDGE passing your runtime object, and false to indicate we don't need a an initialization state |
359 | // in the case of a procedurally built scene an init state is not needed for loading data | 362 | // in the case of a procedurally built scene an init state is not needed for loading data |
360 | if (this._useWebGL) { | 363 | if (this._useWebGL) { |
361 | rdgeStarted = true; | 364 | rdgeStarted = true; |
362 | var id = this._canvas.getAttribute( "data-RDGE-id" ); | 365 | this._canvas.rdgeid = this._canvas.getAttribute( "data-RDGE-id" ); |
363 | this._canvas.rdgeid = id; | ||
364 | g_Engine.registerCanvas(this._canvas, this); | 366 | g_Engine.registerCanvas(this._canvas, this); |
365 | RDGEStart( this._canvas ); | 367 | RDGEStart( this._canvas ); |
366 | this._canvas.task.stop() | 368 | this._canvas.task.stop() |
@@ -680,7 +682,7 @@ World.prototype.render = function() { | |||
680 | var root = this.getGeomRoot(); | 682 | var root = this.getGeomRoot(); |
681 | this.hRender( root ); | 683 | this.hRender( root ); |
682 | } else { | 684 | } else { |
683 | g_Engine.setContext( this._canvas.rdgeId ); | 685 | g_Engine.setContext( this._canvas.rdgeid ); |
684 | //this.draw(); | 686 | //this.draw(); |
685 | this.restartRenderLoop(); | 687 | this.restartRenderLoop(); |
686 | } | 688 | } |
diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js index 9a934928..4c42539a 100755 --- a/js/lib/geom/brush-stroke.js +++ b/js/lib/geom/brush-stroke.js | |||
@@ -32,13 +32,24 @@ var BrushStroke = function GLBrushStroke() { | |||
32 | //stroke information | 32 | //stroke information |
33 | this._strokeWidth = 0.0; | 33 | this._strokeWidth = 0.0; |
34 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; | 34 | this._strokeColor = [0.4, 0.4, 0.4, 1.0]; |
35 | this._secondStrokeColor = [1, 0.4, 0.4, 1.0]; | ||
36 | this._strokeHardness = 100; | ||
35 | this._strokeMaterial = null; | 37 | this._strokeMaterial = null; |
36 | this._strokeStyle = "Solid"; | 38 | this._strokeStyle = "Solid"; |
39 | this._strokeDoSmoothing = false; | ||
40 | this._strokeUseCalligraphic = false; | ||
41 | this._strokeAngle = 0; | ||
37 | 42 | ||
38 | //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 |
39 | //smaller value means more samples for the path | 44 | //smaller value means more samples for the path |
40 | this._WETNESS_FACTOR = 0.25; | 45 | this._WETNESS_FACTOR = 0.25; |
41 | 46 | ||
47 | //threshold that tells us whether two samples are too far apart | ||
48 | this._MAX_SAMPLE_DISTANCE_THRESHOLD = 5; | ||
49 | |||
50 | //threshold that tells us whether two samples are too close | ||
51 | this._MIN_SAMPLE_DISTANCE_THRESHOLD = 2; | ||
52 | |||
42 | //prevent extremely long paths that can take a long time to render | 53 | //prevent extremely long paths that can take a long time to render |
43 | this._MAX_ALLOWED_SAMPLES = 500; | 54 | this._MAX_ALLOWED_SAMPLES = 500; |
44 | 55 | ||
@@ -114,7 +125,7 @@ var BrushStroke = function GLBrushStroke() { | |||
114 | //add the point only if it is some epsilon away from the previous point | 125 | //add the point only if it is some epsilon away from the previous point |
115 | var numPoints = this._Points.length; | 126 | var numPoints = this._Points.length; |
116 | if (numPoints>0) { | 127 | if (numPoints>0) { |
117 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; | 128 | var threshold = this._MIN_SAMPLE_DISTANCE_THRESHOLD;//this._WETNESS_FACTOR*this._strokeWidth; |
118 | var prevPt = this._Points[numPoints-1]; | 129 | var prevPt = this._Points[numPoints-1]; |
119 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; | 130 | var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; |
120 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); | 131 | var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); |
@@ -173,6 +184,26 @@ var BrushStroke = function GLBrushStroke() { | |||
173 | this._strokeColor = c; | 184 | this._strokeColor = c; |
174 | }; | 185 | }; |
175 | 186 | ||
187 | this.setSecondStrokeColor = function(c){ | ||
188 | this._secondStrokeColor=c; | ||
189 | } | ||
190 | |||
191 | this.setStrokeHardness = function(h){ | ||
192 | this._strokeHardness=h; | ||
193 | } | ||
194 | |||
195 | this.setDoSmoothing = function(s){ | ||
196 | this._strokeDoSmoothing = s; | ||
197 | } | ||
198 | |||
199 | this.setStrokeUseCalligraphic = function(c){ | ||
200 | this._strokeUseCalligraphic = c; | ||
201 | } | ||
202 | |||
203 | this.setStrokeAngle = function(a){ | ||
204 | this._strokeAngle = a; | ||
205 | } | ||
206 | |||
176 | this.getStrokeStyle = function () { | 207 | this.getStrokeStyle = function () { |
177 | return this._strokeStyle; | 208 | return this._strokeStyle; |
178 | }; | 209 | }; |
@@ -219,7 +250,8 @@ var BrushStroke = function GLBrushStroke() { | |||
219 | var numPoints = this._Points.length; | 250 | var numPoints = this._Points.length; |
220 | 251 | ||
221 | //**** add samples to the path if needed...linear interpolation for now | 252 | //**** add samples to the path if needed...linear interpolation for now |
222 | if (numPoints>1) { | 253 | //if (numPoints>1) { |
254 | if (0){ | ||
223 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; | 255 | var threshold = this._WETNESS_FACTOR*this._strokeWidth; |
224 | var prevPt = this._Points[0]; | 256 | var prevPt = this._Points[0]; |
225 | var prevIndex = 0; | 257 | var prevIndex = 0; |
@@ -251,6 +283,66 @@ var BrushStroke = function GLBrushStroke() { | |||
251 | } | 283 | } |
252 | } | 284 | } |
253 | 285 | ||
286 | //todo 4-point subdivision iterations over continuous regions of 'long' segments | ||
287 | // look at http://www.gvu.gatech.edu/~jarek/Split&Tweak/ for formula | ||
288 | //**** add samples to the long sections of the path --- Catmull-Rom spline interpolation | ||
289 | if (this._strokeDoSmoothing && numPoints>1) { | ||
290 | var numInsertedPoints = 0; | ||
291 | var newPoints = []; | ||
292 | var threshold = this._MAX_SAMPLE_DISTANCE_THRESHOLD;//this determines whether a segment between two sample is long enough to warrant checking for angle | ||
293 | var prevPt = this._Points[0]; | ||
294 | newPoints.push(this._Points[0]); | ||
295 | for (var i=1;i<numPoints;i++){ | ||
296 | var pt = this._Points[i]; | ||
297 | var diff = [pt[0]-prevPt[0], pt[1]-prevPt[1]]; | ||
298 | var distance = Math.sqrt(diff[0]*diff[0]+diff[1]*diff[1]); | ||
299 | if (distance>threshold){ | ||
300 | //build the control polygon for the Catmull-Rom spline (prev. 2 points and next 2 points) | ||
301 | var prev = (i===1) ? i-1 : i-2; | ||
302 | var next = (i===numPoints-1) ? i : i+1; | ||
303 | var ctrlPts = [this._Points[prev], this._Points[i-1], this._Points[i], this._Points[next]]; | ||
304 | //insert points along the prev. to current point | ||
305 | var numNewPoints = Math.floor(distance/threshold); | ||
306 | for (var j=0;j<numNewPoints;j++){ | ||
307 | var param = (j+1)/(numNewPoints+1); | ||
308 | var newpt = this._CatmullRomSplineInterpolate(ctrlPts, param); | ||
309 | //insert new point before point i | ||
310 | //this._Points.splice(i, 0, newpt); | ||
311 | //i++; | ||
312 | newPoints.push(newpt); | ||
313 | numInsertedPoints++; | ||
314 | } | ||
315 | this._dirty=true; | ||
316 | } | ||
317 | newPoints.push(pt); | ||
318 | prevPt=pt; | ||
319 | //update numPoints to match the new length | ||
320 | numPoints = this._Points.length; | ||
321 | |||
322 | //end this function if the numPoints has gone above the max. size specified | ||
323 | if (numPoints> this._MAX_ALLOWED_SAMPLES){ | ||
324 | console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); | ||
325 | break; | ||
326 | } | ||
327 | } | ||
328 | this._Points = newPoints; | ||
329 | numPoints = this._Points.length; | ||
330 | console.log("Inserted "+numInsertedPoints+" additional CatmullRom points"); | ||
331 | |||
332 | //now do 3-4 iterations of Laplacian smoothing (setting the points to the average of their neighbors) | ||
333 | var numLaplacianIterations = 3; //todo figure out the proper number of Laplacian iterations (perhaps as a function of stroke width) | ||
334 | for (var n=0;n<numLaplacianIterations;n++){ | ||
335 | newPoints = this._Points; | ||
336 | for (var i=1;i<numPoints-1;i++){ | ||
337 | var avgPos = [ 0.5*(this._Points[i-1][0] + this._Points[i+1][0]), | ||
338 | 0.5*(this._Points[i-1][1] + this._Points[i+1][1]), | ||
339 | 0.5*(this._Points[i-1][2] + this._Points[i+1][2])] ; | ||
340 | newPoints[i] = avgPos; | ||
341 | } | ||
342 | this._Points = newPoints; | ||
343 | } | ||
344 | } | ||
345 | |||
254 | // *** compute the bounding box ********* | 346 | // *** compute the bounding box ********* |
255 | this._BBoxMin = [Infinity, Infinity, Infinity]; | 347 |