From 342fb451bd251358068a0dcb10e9dc218b79a176 Mon Sep 17 00:00:00 2001 From: Jonathan Duran Date: Tue, 6 Mar 2012 11:38:39 -0800 Subject: Squashed commit of the following: commit 1cd89d4d06e3a8f2c221628b19cf26a2c69f5d3f Author: Jose Antonio Marquez Date: Tue Mar 6 11:24:25 2012 -0800 Fixing WebGL not available bug commit 84332ab81c1b445195f1d9be8bbeae0725c8e758 Author: Valerio Virgillito Date: Tue Mar 6 10:58:25 2012 -0800 Squashed commit of preload-fix into Master - Requiring all the previously pre-loaded files - RDGE, Codemirror and gl-matrix are not included via a script tag. Signed-off-by: Valerio Virgillito commit 13f52cf0c74f53a919fa864f86669e8155f82961 Merge: dced508 abc04f3 Author: Valerio Virgillito Date: Fri Mar 2 15:46:11 2012 -0800 Merge pull request #93 from imix23ways/Timeline Timeline: Critical bug fixes commit dced508bb19a7bcd467ff1b86b5df5bbec4be794 Merge: 0aeb400 cc772ef Author: Valerio Virgillito Date: Fri Mar 2 15:45:35 2012 -0800 Merge pull request #92 from mqg734/WebGLFixes Selection Tool Fixes for elements flying off into space when they overlap commit 0aeb400070762cf01d83cf9f9ee25a5595098b7f Merge: ff0a956 aabb48a Author: Valerio Virgillito Date: Fri Mar 2 14:05:21 2012 -0800 Merge pull request #94 from ericguzman/PresetsPanel Presets Panel - Fix single-click activation, and transition cut-off bug. commit cc772ef3333ed419d269a2bda7aea5b0150a7bd9 Author: Nivesh Rajbhandari Date: Fri Mar 2 11:34:58 2012 -0800 Fixing flying off into space bug for translate tool too. Signed-off-by: Nivesh Rajbhandari commit abc04f3d50311ed1c21067344bc7e448686f8c5c Author: Jonathan Duran Date: Fri Mar 2 11:26:25 2012 -0800 Timeline Fix timing function Signed-off-by: Jonathan Duran commit aabb48a1c8d34bc968f4c6b0ffee4e31c1d5d286 Author: Eric Guzman Date: Fri Mar 2 11:22:44 2012 -0800 Presets Panel - Fix single-click activation, and transition cut-off bug. Use double-click as the activation event for transition presets. Also fixed the bug when applying a style preset before the transition preset, which disabled transitions after the first one. commit f3207f39ea9d8c1c34246217a23d3a689671903d Author: Nivesh Rajbhandari Date: Fri Mar 2 11:21:29 2012 -0800 Don't draw transform handles if the stage is the target element. Signed-off-by: Nivesh Rajbhandari commit 5425be91e7125c22955b4459a62412ff574e49a8 Author: Jonathan Duran Date: Fri Mar 2 11:11:48 2012 -0800 Timeline: Fix for animation iteration count Add default webkit css properties to allow animations with integer iteration counts. Signed-off-by: Jonathan Duran commit 1760bac1da9218315ad1bacdcf3a157495a049e8 Author: Nivesh Rajbhandari Date: Fri Mar 2 10:48:41 2012 -0800 Fix for jumping issue when moving items that have any 3d on them. We can't translate 3d moves into 2d space due to perspective, so we must update the matrix3d values instead of the top-left values if items have 3d. Signed-off-by: Nivesh Rajbhandari commit 2c04935f0ccb1cb7c98371fc10b43155f2d956c4 Author: Nivesh Rajbhandari Date: Thu Mar 1 22:20:06 2012 -0800 Fix for elements flying off into space when moving elements that overlap. This was happening because our hit record's element and the browser's element from point did not match. Signed-off-by: Nivesh Rajbhandari commit 50058746779f714ed9b0287f49e56c9f0d35593e Merge: 500426d ff0a956 Author: Nivesh Rajbhandari Date: Thu Mar 1 21:49:44 2012 -0800 Merge branch 'refs/heads/ninja-internal' into WebGLFixes commit 500426dea0ca95a6b45be8ea8d132cfdb4d2c940 Author: Nivesh Rajbhandari Date: Thu Mar 1 10:11:39 2012 -0800 Fixed logic error when resizing with the top-left transform handles. Signed-off-by: Nivesh Rajbhandari commit 7980d9bde2b43aa5a494ddf6f1db5c4959a57b91 Author: Nivesh Rajbhandari Date: Thu Mar 1 10:04:15 2012 -0800 Re-fixing IKNinja-940 - Can't select objects when in side/top view. Signed-off-by: Nivesh Rajbhandari commit f04cc0146d8f7573628678613a99c270116768e4 Author: Nivesh Rajbhandari Date: Wed Feb 29 16:45:40 2012 -0800 Last-used material (instead of FlatMaterial) is applied to shape when turning on use WebGL checkbox in the PI. Signed-off-by: Nivesh Rajbhandari Signed-off-by: Jonathan Duran --- js/lib/drawing/world.js | 917 +++++++++++++++ js/lib/geom/anchor-point.js | 242 ++++ js/lib/geom/brush-stroke.js | 482 ++++++++ js/lib/geom/circle.js | 751 ++++++++++++ js/lib/geom/geom-obj.js | 280 +++++ js/lib/geom/line.js | 488 ++++++++ js/lib/geom/rectangle.js | 1165 +++++++++++++++++++ js/lib/geom/shape-primitive.js | 54 + js/lib/geom/sub-path.js | 1288 +++++++++++++++++++++ js/lib/math/matrix.js | 104 ++ js/lib/rdge/materials/bump-metal-material.js | 314 +++++ js/lib/rdge/materials/deform-material.js | 127 ++ js/lib/rdge/materials/flat-material.js | 159 +++ js/lib/rdge/materials/fly-material.js | 119 ++ js/lib/rdge/materials/julia-material.js | 136 +++ js/lib/rdge/materials/keleidoscope-material.js | 144 +++ js/lib/rdge/materials/linear-gradient-material.js | 434 +++++++ js/lib/rdge/materials/mandel-material.js | 147 +++ js/lib/rdge/materials/material-parser.js | 73 ++ js/lib/rdge/materials/material.js | 346 ++++++ js/lib/rdge/materials/plasma-material.js | 132 +++ js/lib/rdge/materials/pulse-material.js | 258 +++++ js/lib/rdge/materials/radial-blur-material.js | 244 ++++ js/lib/rdge/materials/radial-gradient-material.js | 351 ++++++ js/lib/rdge/materials/relief-tunnel-material.js | 122 ++ js/lib/rdge/materials/square-tunnel-material.js | 120 ++ js/lib/rdge/materials/star-material.js | 124 ++ js/lib/rdge/materials/taper-material.js | 223 ++++ js/lib/rdge/materials/tunnel-material.js | 125 ++ js/lib/rdge/materials/twist-material.js | 139 +++ js/lib/rdge/materials/twist-vert-material.js | 248 ++++ js/lib/rdge/materials/uber-material.js | 614 ++++++++++ js/lib/rdge/materials/water-material.js | 126 ++ js/lib/rdge/materials/z-invert-material.js | 125 ++ 34 files changed, 10721 insertions(+) create mode 100755 js/lib/drawing/world.js create mode 100755 js/lib/geom/anchor-point.js create mode 100755 js/lib/geom/brush-stroke.js create mode 100755 js/lib/geom/circle.js create mode 100755 js/lib/geom/geom-obj.js create mode 100755 js/lib/geom/line.js create mode 100755 js/lib/geom/rectangle.js create mode 100644 js/lib/geom/shape-primitive.js create mode 100755 js/lib/geom/sub-path.js create mode 100755 js/lib/math/matrix.js create mode 100755 js/lib/rdge/materials/bump-metal-material.js create mode 100644 js/lib/rdge/materials/deform-material.js create mode 100755 js/lib/rdge/materials/flat-material.js create mode 100644 js/lib/rdge/materials/fly-material.js create mode 100644 js/lib/rdge/materials/julia-material.js create mode 100644 js/lib/rdge/materials/keleidoscope-material.js create mode 100755 js/lib/rdge/materials/linear-gradient-material.js create mode 100644 js/lib/rdge/materials/mandel-material.js create mode 100755 js/lib/rdge/materials/material-parser.js create mode 100755 js/lib/rdge/materials/material.js create mode 100644 js/lib/rdge/materials/plasma-material.js create mode 100644 js/lib/rdge/materials/pulse-material.js create mode 100644 js/lib/rdge/materials/radial-blur-material.js create mode 100755 js/lib/rdge/materials/radial-gradient-material.js create mode 100644 js/lib/rdge/materials/relief-tunnel-material.js create mode 100644 js/lib/rdge/materials/square-tunnel-material.js create mode 100644 js/lib/rdge/materials/star-material.js create mode 100644 js/lib/rdge/materials/taper-material.js create mode 100644 js/lib/rdge/materials/tunnel-material.js create mode 100644 js/lib/rdge/materials/twist-material.js create mode 100644 js/lib/rdge/materials/twist-vert-material.js create mode 100755 js/lib/rdge/materials/uber-material.js create mode 100644 js/lib/rdge/materials/water-material.js create mode 100644 js/lib/rdge/materials/z-invert-material.js (limited to 'js/lib') diff --git a/js/lib/drawing/world.js b/js/lib/drawing/world.js new file mode 100755 index 00000000..3d6c6fc4 --- /dev/null +++ b/js/lib/drawing/world.js @@ -0,0 +1,917 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +// Useless Global variables. +// TODO: Remove this as soon as QE test pass +/* +var shaderProgramArray = new Array; +var glContextArray = new Array; +var vertexShaderSource = ""; +var fragmentShaderSource = ""; +var rdgeStarted = false; +*/ + +var nodeCounter = 0; + +var GeomObj = require("js/lib/geom/geom-obj").GeomObj; +var Line = require("js/lib/geom/line").Line; +var Rectangle = require("js/lib/geom/rectangle").Rectangle; +var Circle = require("js/lib/geom/circle").Circle; +var MaterialsModel = require("js/models/materials-model").MaterialsModel; + +/////////////////////////////////////////////////////////////////////// +// Class GLWorld +// Manages display in a canvas +/////////////////////////////////////////////////////////////////////// +var World = function GLWorld( canvas, use3D ) { + /////////////////////////////////////////////////////////////////////// + // Instance variables + /////////////////////////////////////////////////////////////////////// + + // flag to do the drawing with WebGL + this._useWebGL = false; + if(use3D) { + this._useWebGL = use3D; + } + + this._canvas = canvas; + if (this._useWebGL) { + this._glContext = canvas.getContext("experimental-webgl"); + } else { + this._2DContext = canvas.getContext( "2d" ); + } + + this._viewportWidth = canvas.width; + this._viewportHeight = canvas.height; + + // view parameters + this._fov = 45.0; + this._zNear = 0.1; + this._zFar = 100.0; + this._viewDist = 5.0; + + // default light parameters + this._ambientLightColor = [0.1, 0.1, 0.1, 1.0]; + this._diffuseLightColor = [0.1, 0.1, 0.1, 1.0]; + this._specularLightColor = [0.6, 0.6, 0.6, 1.0]; + this._pointLightLoc = [0.0, 0.0, 0.05]; + + // default material properties. Material properties should be overridden + // by the materials used by the objects + this._materialShininess = 20.0; + + this._geomRoot = undefined; + + this._cameraMat = Matrix.I(4); + this._cameraMat[14] = 5.0; + this._cameraMatInv = Matrix.I(4); + this._cameraMatInv[14] = -5.0; + + this._camera = null; + // keep a flag indicating whether a render has been completed. + // this allows us to turn off automatic updating if there are + // no animated materials + this._firstRender = true; + + /////////////////////////////////////////////////////////////////////// + // Property accessors + /////////////////////////////////////////////////////////////////////// + this.getGLContext = function() { return this._glContext; }; + this.setGLContext = function(gl) { this._glContext = gl; }; + + this.get2DContext = function() { return this._2DContext; }; + this.set2DContext = function(c) { this._2DContext = c; }; + + this.getCanvas = function() { return this._canvas; }; + this.setCanvas = function(c) { this._canvas = c; }; + + this.getShaderProgram = function() { return this._shaderProgram; }; + + this.getViewportWidth = function() { return this._viewportWidth; }; + this.getViewportHeight = function() { return this._viewportHeight; }; + + this.getAspect = function() { return this._viewportWidth/this._viewportHeight; }; + + this.getGeomRoot = function() { return this._geomRoot; }; + this.getZNear = function() { return this._zNear; }; + this.getZFar = function() { return this._zFar; }; + this.getFOV = function() { return this._fov; }; + + this.getCamera = function() { return this._camera; }; + + this.getCameraMat = function() { return this._cameraMat.slice(0); }; + this.setCameraMat = function(c) { this._cameraMat = c.slice(0); this._cameraMatInv = glmat4.inverse(c, []); }; + + this.getCameraMatInverse = function() { return this._cameraMatInv.slice(0); }; + + this.getViewDistance = function() { return this._viewDist; }; + + this.getRootNode = function() { return this._rootNode; }; + this.setRootNode = function(r) { this._rootNode = r; }; + + this.isWebGL = function() { return this._useWebGL; }; + + this.getRenderer = function() { return this.renderer; }; + + //////////////////////////////////////////////////////////////////////////////////// + // RDGE + // local variables + this.myScene = null; + this.elapsed = 0; + this.light = null; + this.light2 = null; + this.fillShader = null; + this.strokeShader = null; + this.renderer = null; + + // keep an array of texture maps that need to be loaded + this._texMapsToLoad = []; + this._allMapsLoaded = true; + + // this is the node to which objects get hung + this._rootNode = null; + + // set up the camera matrix + var camMat = Matrix.I(4); + camMat[14] = this.getViewDistance(); + this.setCameraMat( camMat ); + + // post-load processing of the scene + this.init = function() { + var ctx1 = g_Engine.ctxMan.handleToObject(this._canvas.rdgeCtxHandle), + ctx2 = g_Engine.getContext(); + if (ctx1 != ctx2) console.log( "***** different contexts *****" ); + this.renderer = ctx1.renderer; + this.renderer._world = this; + + // create a camera, set its perspective, and then point it at the origin + var cam = new camera(); + this._camera = cam; + cam.setPerspective(this.getFOV(), this.getAspect(), this.getZNear(), this.getZFar()); + cam.setLookAt([0, 0, this.getViewDistance()], [0, 0, 0], vec3.up()); + + // make this camera the active camera + this.renderer.cameraManager().setActiveCamera(cam); + + // change clear color + //this.renderer.setClearFlags(g_Engine.getContext().DEPTH_BUFFER_BIT); + this.renderer.setClearColor([0.0, 0.0, 0.0, 0.0]); + //this.renderer.NinjaWorld = this; + + // create an empty scene graph + this.myScene = new SceneGraph(); + + // create some lights + // light 1 + this.light = createLightNode("myLight"); + this.light.setPosition([0,0,1.2]); + this.light.setDiffuseColor([0.75,0.9,1.0,1.0]); + + // light 2 + this.light2 = createLightNode("myLight2"); + this.light2.setPosition([-0.5,0,1.2]); + this.light2.setDiffuseColor([1.0,0.9,0.75,1.0]); + + // create a light transform + var lightTr = createTransformNode("lightTr"); + + // create and attach a material - materials hold the light data + lightTr.attachMaterial(createMaterialNode("lights")); + + // enable light channels 1, 2 - channel 0 is used by the default shader + lightTr.materialNode.enableLightChannel(1, this.light); + lightTr.materialNode.enableLightChannel(2, this.light2); + + // all added objects are parented to the light node + this._rootNode = lightTr; + + // add the light node to the scene + this.myScene.addNode(lightTr); + + // Add the scene to the engine - necessary if you want the engine to draw for you + //g_Engine.AddScene("myScene" + this._canvas.id, this.myScene); + var name = this._canvas.getAttribute( "data-RDGE-id" ); + g_Engine.AddScene("myScene" + name, this.myScene); + }; + + // main code for handling user interaction and updating the scene + this.update = function(dt) { + if (!dt) dt = 0.2; + + dt = 0.01; // use our own internal throttle + this.elapsed += dt; + + if (this._useWebGL) { + // changed the global position uniform of light 0, another way to change behavior of a light + rdgeGlobalParameters.u_light0Pos.set( [5*Math.cos(this.elapsed), 5*Math.sin(this.elapsed), 20]); + + // orbit the light nodes around the boxes + this.light.setPosition([1.2*Math.cos(this.elapsed*2.0), 1.2*Math.sin(this.elapsed*2.0), 1.2*Math.cos(this.elapsed*2.0)]); + this.light2.setPosition([-1.2*Math.cos(this.elapsed*2.0), 1.2*Math.sin(this.elapsed*2.0), -1.2*Math.cos(this.elapsed)]); + } + + this.updateMaterials( this.getGeomRoot(), this.elapsed ); + + // now update all the nodes in the scene + if (this._useWebGL) + this.myScene.update(dt); + }; + + // defining the draw function to control how the scene is rendered + this.draw = function() { + if (this._useWebGL) { + g_Engine.setContext( this._canvas.rdgeid ); + var ctx = g_Engine.getContext(); + var renderer = ctx.renderer; + if (renderer.unloadedTextureCount <= 0) { + renderer.disableCulling(); + renderer._clear(); + this.myScene.render(); + + if (this._firstRender) { + if (this._canvas.task) { + this._firstRender = false; + + if (!this.hasAnimatedMaterials()) { + this._canvas.task.stop(); + //this._renderCount = 10; + } + } + } else if (this._renderCount >= 0) { + if (this._canvas.task) { + this._renderCount--; + if (this._renderCount <= 0) { + this._canvas.task.stop(); + } + } + } + } + } else { + this.render(); + } + }; + + this.onRunState = function() { +// console.log( "GLWorld.onRunState" ); + this.restartRenderLoop(); + }; + + this.onLoadState = function() { +// console.log( "GLWorld.onLoadState" ); + }; + + this.textureToLoad = function( texture ) { + if (!texture.previouslyReferenced) { + var name = texture.lookUpName; + texture._world = this; + texture.callback = this.textureMapLoaded; + this._texMapsToLoad[name] = true; + this._allMapsLoaded = false; + + // stop the draw loop until all textures have been loaded + this._canvas.task.stop(); + } + }; + + this.textureMapLoaded = function( texture ) { + var world = texture._world; + if (!world) { + console.log( "**** loaded texture does not have world defined ****" ); + return; + } + + var name = texture.lookUpName; + if (!world._texMapsToLoad[name]) { + console.log( "loaded an unregistered texture map: " + name ); + } else { + //console.log( "loaded a registered texture map: " + name ); + world._texMapsToLoad[name] = undefined; + } + + // check if all the texture maps are loaded. if so, resume the render loop + world._allMapsLoaded = world.allTextureMapsLoaded(); + if (world._allMapsLoaded) { + world._canvas.task.start(); + } + }; + + this.allTextureMapsLoaded = function() { + for (var name in this._texMapsToLoad) { + var needsLoad = this._texMapsToLoad[name]; + if (needsLoad) return false; + } + + return true; + }; + + this.textureLoadedCallback = function( name ) { +// console.log( "*** material texture loaded: " + name ); + + var world = this._world; + if (!world) { + console.log( "**** world not defined for loaded texture map: " + name ); + } else { + world.textureMapLoaded( name ); + } + }; + + this.hasAnimatedMaterials = function() { + var root = this.getGeomRoot(); + var rtnVal = false; + if (root) { + rtnVal = this.hHasAnimatedMaterials( root ); + } + + return rtnVal; + }; + + this.hHasAnimatedMaterials = function( obj ) { + if (obj) { + if (obj.getFillMaterial()) { + if (obj.getFillMaterial().isAnimated()) return true; + } + + if (obj.getStrokeMaterial()) { + if (obj.getStrokeMaterial().isAnimated()) return true; + } + + + // do the sibling + var hasAnim = false; + if (obj.getNext()) hasAnim = this.hHasAnimatedMaterials( obj.getNext() ); + if (hasAnim) return true; + if (obj.getChild()) hasAnim = this.hHasAnimatedMaterials( obj.getChild() ); + if (hasAnim) return true; + } + + return false; + }; + + + // END RDGE + //////////////////////////////////////////////////////////////////////////////////// + + + // start RDGE passing your runtime object, and false to indicate we don't need a an initialization state + // in the case of a procedurally built scene an init state is not needed for loading data + if (this._useWebGL) { + rdgeStarted = true; + var id = this._canvas.getAttribute( "data-RDGE-id" ); + this._canvas.rdgeid = id; + g_Engine.registerCanvas(this._canvas, this); + RDGEStart( this._canvas ); + this._canvas.task.stop() + } +}; + + +/////////////////////////////////////////////////////////////////////// +// Property Accessors +/////////////////////////////////////////////////////////////////////// +World.prototype.getGeomRoot = function() { + return this._geomRoot; +}; + + +/////////////////////////////////////////////////////////////////////// +// Methods +/////////////////////////////////////////////////////////////////////// +World.prototype.updateObject = function (obj) { + if (!this._useWebGL) return; + + var prims = obj.getPrimitiveArray(); + var materialNodes = obj.getMaterialNodeArray(); + if (prims.length != materialNodes.length) + throw new Error("inconsistent material and primitive counts"); + var nPrims = prims.length; + var ctrTrNode; + if (nPrims > 0) { + ctrTrNode = obj.getTransformNode(); + if (ctrTrNode == null) { + ctrTrNode = createTransformNode("objRootNode_" + nodeCounter++); + this._rootNode.insertAsChild( ctrTrNode ); + obj.setTransformNode( ctrTrNode ); + } + + ctrTrNode.meshes.forEach(function(thisMesh) { + g_meshMan.deleteMesh(thisMesh.mesh.name); + }); + ctrTrNode.meshes = []; + + ctrTrNode.attachMeshNode(this.renderer.id + "_prim_" + nodeCounter++, prims[0]); + ctrTrNode.attachMaterial(materialNodes[0]); + } + + var children = ctrTrNode.children; + for (var i = 1; i < nPrims; i++) { + // get the next primitive + var prim = prims[i]; + + // get a previously created transform node. If the transform has not been created, create it + var childTrNode; + if (children && children.length >= i) { + childTrNode = children[i-1].transformNode; + + childTrNode.meshes.forEach(function(thisMesh) { + g_meshMan.deleteMesh(thisMesh.mesh.name); + }); + childTrNode.meshes = []; + } else { + childTrNode = createTransformNode("objNode_" + nodeCounter++); + ctrTrNode.insertAsChild(childTrNode); + } + + // attach the instanced box goe + childTrNode.attachMeshNode(this.renderer.id + "_prim_" + nodeCounter++, prim); + childTrNode.attachMaterial(materialNodes[i]); + } +}; + +World.prototype.addObject = function( obj ) { + if (!obj) return; + + try { + // undefine all the links of the object + obj.setChild( undefined ); + obj.setNext( undefined ); + obj.setPrev( undefined ); + obj.setParent( undefined ); + + obj.setWorld( this ); + + if (this._geomRoot == null) { + this._geomRoot = obj; + } else { + var go = this._geomRoot; + while (go.getNext()) go = go.getNext(); + go.setNext( obj ); + obj.setPrev( go ); + } + + // build the WebGL buffers + if (this._useWebGL) { + obj.buildBuffers(); + this.restartRenderLoop(); + } + } + + catch(e) { + alert( "Exception in GLWorld.addObject " + e ); + } +} + +World.prototype.restartRenderLoop = function() { + //console.log( "restartRenderLoop" ); + + this._firstRender = true; + this._renderCount = -1; + if (this._canvas.task) { + if (this._allMapsLoaded) { + //console.log( "starting task" ); + this._canvas.task.start(); + } else { + //console.log( "stopping task" ); + this._canvas.task.stop(); + } + } +}; + +//append to the list of objects if obj doesn't already exist +//if obj exists, then don't add to list of objects +World.prototype.addIfNewObject = function (obj) { + if (!obj) return; + + try { + obj.setWorld(this); + + if (this._geomRoot == null) { + this._geomRoot = obj; + } else if (this._geomRoot !== obj) { + var go = this._geomRoot; + while (go.getNext() && go.getNext() !== obj) { + go = go.getNext(); + } + + if (go.getNext() === null) { + // undefine all the links of the object + obj.setChild(undefined); + obj.setNext(undefined); + obj.setPrev(undefined); + obj.setParent(undefined); + + go.setNext(obj); + obj.setPrev(go); + + } + } + + // build the WebGL buffers + if (this._useWebGL) { + obj.buildBuffers(); + this.restartRenderLoop(); + } + } catch (e) { + alert("Exception in GLWorld.addIfNewObject " + e); + } +}; + +World.prototype.clearTree = function() { + if (this._useWebGL) { + var root = this._rootNode; + root.children = new Array(); + g_Engine.unregisterCanvas( this._canvas.rdgeid ) + + this.update( 0 ); + this.draw(); + } +}; + +World.prototype.updateMaterials = function( obj, time ) { + if (!obj) return; + + var matArray = obj.getMaterialArray(); + if (matArray) { + var n = matArray.length; + for (var i=0; i 0)) { + mat = this._matStack[ this._matStack.length-1]; + } + + return mat; +}; + +World.prototype.popMatrix = function() { + if (this._matStack.length == 0) { + throw "Invalid popMatrix!"; + } + + return this._matStack.pop(); +}; + +World.prototype.setMVMatrix = function() { + var mat = this.stackTop(); + if (mat) { + var gl = this._glContext; + + //var mvMatrix = this._cameraMatInv.multiply(mat); + var mvMatrix = glmat4.multiply( this._cameraMatInv, mat, []); + //var mat2 = mat.multiply( this._cameraMatInv ); + gl.uniformMatrix4fv(this._shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix)); + + var normalMatrix = mat3.create(); + // mat4.toInverseMat3(mvMatrix, normalMatrix); + // mat4.toInverseMat3(new Float32Array(mvMatrix.flatten()), normalMatrix); + mat4.toInverseMat3(new Float32Array(mvMatrix), normalMatrix); + mat3.transpose(normalMatrix); + gl.uniformMatrix3fv(this._shaderProgram.nMatrixUniform, false, normalMatrix); + } +}; + +World.prototype.makePerspectiveMatrix = function() { + return Matrix.makePerspective( this.getFOV(), this.getAspect(), this.getZNear(), this.getZFar() ); +}; + +World.prototype.render = function() { + if (!this._useWebGL) { + // clear the context + var ctx = this.get2DContext(); + if (!ctx) return; + ctx.clearRect(0, 0, this.getViewportWidth(), this.getViewportHeight()); + + // render the geometry + var root = this.getGeomRoot(); + this.hRender( root ); + } else { + g_Engine.setContext( this._canvas.rdgeId ); + //this.draw(); + this.restartRenderLoop(); + } +}; + +World.prototype.hRender = function( obj ) { + if (!obj) return; + obj.render(); + + this.hRender( obj.getChild() ); + this.hRender( obj.getNext() ); +}; + +World.prototype.setViewportFromCanvas = function(canvas) { + this._viewportWidth = canvas.width; + this._viewportHeight = canvas.height; + + if (this._useWebGL) { + this._glContext.viewportWidth = canvas.width; + this._glContext.viewportHeight = canvas.height; + + this.getCamera().setPerspective(this.getFOV(), this.getAspect(), this.getZNear(), this.getZFar()); + + this.renderer.setViewPort(0, 0, canvas.width, canvas.height); + } +}; + +World.prototype.getShapeFromPoint = function( offsetX, offsetY ) { + var x = offsetX/this._canvas.width; + var y = offsetY/this._canvas.height; + + var go = this._geomRoot; + if(go.collidesWithPoint(x,y)) { +// console.log("collision found"); + return go; + } + + while (go.getNext()) { + go = go.getNext(); + if(go.collidesWithPoint(x,y)) { +// console.log("collision found"); + return go; + } + } +}; + +World.prototype.export = function() { + var exportStr = "GLWorld 1.0\n"; + var id = this.getCanvas().getAttribute( "data-RDGE-id" ); + exportStr += "id: " + id + "\n"; + //exportStr += "id: " + this._canvas.rdgeid + "\n"; + exportStr += "fov: " + this._fov + "\n"; + exportStr += "zNear: " + this._zNear + "\n"; + exportStr += "zFar: " + this._zFar + "\n"; + exportStr += "viewDist: " + this._viewDist + "\n"; + + // we need 2 export modes: One for save/restore, one for publish. + // hardcoding for now + var exportForPublish = false; + exportStr += "publish: " + exportForPublish + "\n"; + + if (exportForPublish) { + exportStr += "scenedata: " + this.myScene.exportJSON() + "endscene\n"; + } else { + // output the material library + exportStr += MaterialsModel.exportMaterials(); + + // write out all of the objects + exportStr += "tree\n"; + exportStr += this.exportObjects( this._geomRoot ); + exportStr += "endtree\n"; + } + + return exportStr; +}; + +World.prototype.exportObjects = function( obj ) { + if (!obj) return; + + var rtnStr = "OBJECT\n"; + rtnStr += obj.export(); + + if (obj.getChild()) { + rtnStr += this.exportObjects( obj.getChild () ); + } + + // the end object goes outside the children + rtnStr += "ENDOBJECT\n"; + + if (obj.getNext()) { + rtnStr += this.exportObjects( obj.getNext() ); + } + + return rtnStr; +}; + +World.prototype.findTransformNodeByMaterial = function( materialNode, trNode ) { + //if (trNode == null) trNode = this._ctrNode; + if (trNode == null) trNode = this._rootNode; + if ( trNode.transformNode && (materialNode == trNode.transformNode.materialNode)) return trNode; + + var rtnNode; + if (trNode.children != null) { + var nKids = trNode.children.length; + for (var i=0; i= 0) { + var rdgeStr = importStr.substr( index+11 ); + var endIndex = rdgeStr.indexOf( "endscene\n" ); + if (endIndex < 0) throw new Error( "ill-formed WebGL data" ); + var len = endIndex - index + 11; + rdgeStr = rdgeStr.substr( 0, endIndex ); + + this.myScene.importJSON( rdgeStr ); + } else { + // load the material library + importStr = MaterialsModel.importMaterials( importStr ); + + // import the objects + this.importObjects( importStr, this._rootNode ); + } +}; + +World.prototype.importObjects = function( importStr, parentNode ) { + var index = importStr.indexOf( "OBJECT\n", 0 ); + while (index >= 0) { + // update the string to the current object + importStr = importStr.substr( index+7 ); + + // read the next object + this.importObject( importStr, parentNode ); + + // determine if we have children + var endIndex = importStr.indexOf( "ENDOBJECT\n" ), + childIndex = importStr.indexOf( "OBJECT\n" ); + if (endIndex < 0) throw new Error( "ill-formed object data" ); + if ((childIndex >= 0) && (childIndex < endIndex)) { + importStr = importStr.substr( childIndex + 7 ); + importStr = this.importObjects( importStr, node ); + endIndex = importStr.indexOf( "ENDOBJECT\n" ) + } + + // remove the string for the object(s) just created + importStr = importStr.substr( endIndex ); + + // get the location of the next object + index = importStr.indexOf( "OBJECT\n", endIndex ); + } + + return importStr; +}; + +World.prototype.importObject = function( objStr, parentNode ) { + var go = new GeomObj(); + var type = Number( go.getPropertyFromString( "type: ", objStr ) ); + + var obj; + switch (type) + { + case 1: + obj = new Rectangle(); + obj.import( objStr ); + break; + + case 2: // circle + obj = new Circle(); + obj.import( objStr ); + break; + + case 3: // line + obj = new Line(); + obj.import( objStr ); + break; + + default: + throw new Error( "Unrecognized object type: " + type ); + break; + } + + if (obj) { + this.addObject( obj ); + } +}; + +World.prototype.importSubObject = function( objStr, parentNode ) { + // get the mesh text + var i0 = objStr.indexOf( "mesh: " ), + i1 = objStr.indexOf( "endMesh\n" ); + if ((i0 < 0) || (i1 < 0)) throw new Error( "ill-formed sub object" ); + i0 += 6; + var meshText = objStr.substr( i0, i1 - i0 ); + var meshObj = JSON.parse(meshText); + + // get the material text + var i0 = objStr.indexOf( "material: " ), + i1 = objStr.indexOf( "endMat\n" ); + if ((i0 < 0) || (i1 < 0)) throw new Error( "ill-formed sub object" ); + i0 += 10; + var matText = objStr.substr( i0, i1 - i0 ); + var shaderDef = JSON.parse( matText ); + var shader = new jshader(); + shader.def = shaderDef; + shader.init(); + + // set the shader for this material + var matNode = createMaterialNode("objMat") + matNode.setShader(shader); + + // create the transformation node + var trNode = createTransformNode("subObjNode_" ); + trNode.attachMeshNode(this.renderer.id + "_prim_", meshObj); + trNode.attachMaterial(matNode); + parentNode.insertAsChild(trNode); + + return trNode; +}; + +if (typeof exports === "object") { + exports.World = World; +} \ No newline at end of file diff --git a/js/lib/geom/anchor-point.js b/js/lib/geom/anchor-point.js new file mode 100755 index 00000000..0e9f65ea --- /dev/null +++ b/js/lib/geom/anchor-point.js @@ -0,0 +1,242 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +///////////////////////////////////////////// +// Class GLAnchorPoint +// GL representation of a point clicked +// and dragged during pen tool +// +// +///////////////////////////////////////////// +var GLAnchorPoint = function GLAnchorPoint() { + ///////////////////////////////////////// + // Instance variables + ///////////////////////////////////////// + this._x = 0.0; + this._y = 0.0; + this._z = 0.0; + + this._prevX = 0.0; + this._prevY = 0.0; + this._prevZ = 0.0; + + this._nextX = 0.0; + this._nextY = 0.0; + this._nextZ = 0.0; +}; + // *********** setters ************ +GLAnchorPoint.prototype.setPos = function (x, y, z) { + this._x = x; + this._y = y; + this._z = z; +}; + +GLAnchorPoint.prototype.setPrevPos = function (x, y, z) { + this._prevX = x; + this._prevY = y; + this._prevZ = z; +}; + +GLAnchorPoint.prototype.setNextPos = function (x, y, z) { + this._nextX = x; + this._nextY = y; + this._nextZ = z; +}; + +GLAnchorPoint.prototype.setPrevFromNext = function () { + //set the previous control point by reflecting the next control point + var dispX = this._nextX - this._x; + var dispY = this._nextY - this._y; + var dispZ = this._nextZ - this._z; + + this._prevX = this._x - dispX; + this._prevY = this._y - dispY; + this._prevZ = this._z - dispZ; +}; + +GLAnchorPoint.prototype.setNextFromPrev = function () { + //set the previous control point by reflecting the next control point + var dispX = this._prevX - this._x; + var dispY = this._prevY - this._y; + var dispZ = this._prevZ - this._z; + + this._nextX = this._x - dispX; + this._nextY = this._y - dispY; + this._nextZ = this._z - dispZ; +}; + +//translate the next point from the translation that was applied to the prev. point +GLAnchorPoint.prototype.translateNextFromPrev = function (tx, ty, tz) { + //do nothing if the total translation is zero + var totalTransSq = (tx*tx) + (ty*ty) + (tz*tz); + if (totalTransSq < 0.0000001) { + return; + } + + // *** compute the rotation of the prev vector *** + var oldP = [this._prevX + tx - this._x, this._prevY + ty - this._y, this._prevZ + tz - this._z]; + var newP = [this._prevX - this._x, this._prevY - this._y, this._prevZ - this._z]; + //compute angle between the two vectors + var axis = [0, 0, 0]; + var angle = MathUtils.getAxisAngleBetween3DVectors(oldP, newP, axis); + if (angle === 0) { + return; + } + + // *** compute the vector from anchor to next + var oldN = [this._nextX - this._x, this._nextY - this._y, this._nextZ - this._z]; + var rotMat = Matrix.Rotation(-angle, axis); + var newN = MathUtils.transformVector(oldN, rotMat); + + //TEMP for some situations the axis angle computation returns NaNs + if (isNaN(newN[0]) || isNaN(newN[1]) || isNaN(newN[2])) { + console.log("NaN in translateNextFromPrev"); + return; + } + //end TEMP + this._nextX = this._x + newN[0]; + this._nextY = this._y + newN[1]; + this._nextZ = this._z + newN[2]; +}; + +//translate the next point from the translation that was applied to the prev. point +GLAnchorPoint.prototype.translatePrevFromNext = function (tx, ty, tz) { + //do nothing if the total translation is zero + var totalTransSq = (tx*tx) + (ty*ty) + (tz*tz); + if (totalTransSq < 0.0000001) { + return; + } + + // *** compute the rotation of the next vector *** + var oldN = [this._nextX + tx - this._x, this._nextY + ty - this._y, this._nextZ + tz - this._z]; + var newN = [this._nextX - this._x, this._nextY - this._y, this._nextZ - this._z]; + //compute angle between the two vectors + var axis = [0, 0, 0]; + var angle = MathUtils.getAxisAngleBetween3DVectors(oldN, newN, axis); + if (angle === 0) { + return; + } + + // *** compute the vector from anchor to prev + var oldP = [this._prevX - this._x, this._prevY - this._y, this._prevZ - this._z]; + var rotMat = Matrix.Rotation(-angle, axis); + var newP = MathUtils.transformVector(oldP, rotMat); + + //TEMP for some situations the axis angle computation returns NaNs + if (isNaN(newP[0]) || isNaN(newP[1]) || isNaN(newP[2])) { + return; + } + //end TEMP + this._prevX = this._x + newP[0]; + this._prevY = this._y + newP[1]; + this._prevZ = this._z + newP[2]; +}; + +// ******* modifiers ******* +GLAnchorPoint.prototype.translatePrev = function (x, y, z) { + this._prevX += x; + this._prevY += y; + this._prevZ += z; +}; + +GLAnchorPoint.prototype.translateNext = function (x, y, z) { + this._nextX += x; + this._nextY += y; + this._nextZ += z; +}; + +GLAnchorPoint.prototype.translate = function (x, y, z) { + this._x += x; + this._y += y; + this._z += z; +}; + +GLAnchorPoint.prototype.translateAll = function (x, y, z) { + this.translate(x, y, z); + this.translatePrev(x, y, z); + this.translateNext(x, y, z); +}; + +GLAnchorPoint.prototype.scaleAll = function(sx,sy,sz){ + this._x *= sx; + this._prevX *= sx; + this._nextX *= sx; + this._y *= sy; + this._prevY *= sy; + this._nextY *= sy; + this._z *= sz; + this._prevZ *= sz; + this._nextZ *= sz; +}; + +// ********* getters ********** +GLAnchorPoint.prototype.getPosX = function () { + return this._x; +}; + +GLAnchorPoint.prototype.getPosY = function () { + return this._y; +}; + +GLAnchorPoint.prototype.getPosZ = function () { + return this._z; +}; + +GLAnchorPoint.prototype.getPrevX = function () { + return this._prevX; +}; + +GLAnchorPoint.prototype.getPrevY = function () { + return this._prevY; +}; + +GLAnchorPoint.prototype.getPrevZ = function () { + return this._prevZ; +}; + +GLAnchorPoint.prototype.getNextX = function () { + return this._nextX; +}; + +GLAnchorPoint.prototype.getNextY = function () { + return this._nextY; +}; + +GLAnchorPoint.prototype.getNextZ = function () { + return this._nextZ; +}; + +GLAnchorPoint.prototype.getPos = function() { + return [this._x, this._y, this._z]; +}; + +GLAnchorPoint.prototype.getPrev = function() { + return [this._prevX, this._prevY, this._prevZ]; +}; + +GLAnchorPoint.prototype.getNext = function() { + return [this._nextX, this._nextY, this._nextZ]; +}; + +//return the square of distance from passed in point to the anchor position +GLAnchorPoint.prototype.getDistanceSq = function (x, y, z) { + return (this._x - x) * (this._x - x) + (this._y - y) * (this._y - y) + (this._z - z) * (this._z - z); +}; + +//return sq. of distance to prev. +GLAnchorPoint.prototype.getPrevDistanceSq = function (x, y, z) { + return (this._prevX - x) * (this._prevX - x) + (this._prevY - y) * (this._prevY - y) + (this._prevZ - z) * (this._prevZ - z); +}; + +//return sq. of distance to next +GLAnchorPoint.prototype.getNextDistanceSq = function (x, y, z) { + return (this._nextX - x) * (this._nextX - x) + (this._nextY - y) * (this._nextY - y) + (this._nextZ - z) * (this._nextZ - z); +}; + +if (typeof exports === "object") { + exports.AnchorPoint = GLAnchorPoint; +} + diff --git a/js/lib/geom/brush-stroke.js b/js/lib/geom/brush-stroke.js new file mode 100755 index 00000000..9a934928 --- /dev/null +++ b/js/lib/geom/brush-stroke.js @@ -0,0 +1,482 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +// Todo: This entire class should be converted to a module +var VecUtils = require("js/helper-classes/3D/vec-utils").VecUtils; +var GeomObj = require("js/lib/geom/geom-obj").GeomObj; + +/////////////////////////////////////////////////////////////////////// +// Class GLBrushStroke +// representation a sequence points (polyline) created by brush tool. +// Derived from class GLGeomObj +/////////////////////////////////////////////////////////////////////// +var BrushStroke = function GLBrushStroke() { + /////////////////////////////////////////////////// + // Instance variables + /////////////////////////////////////////////////// + this._Points = []; + this._BBoxMin = [0, 0, 0]; + this._BBoxMax = [0, 0, 0]; + this._dirty = true; + + //whether or not to use the canvas drawing to stroke/fill + this._useCanvasDrawing = true; + + //the X and Y location of this subpath's canvas in stage world space of Ninja + this._canvasX = 0; + this._canvasY = 0; + + //stroke information + this._strokeWidth = 0.0; + this._strokeColor = [0.4, 0.4, 0.4, 1.0]; + this._strokeMaterial = null; + this._strokeStyle = "Solid"; + + //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 + //smaller value means more samples for the path + this._WETNESS_FACTOR = 0.25; + + //prevent extremely long paths that can take a long time to render + this._MAX_ALLOWED_SAMPLES = 500; + + //drawing context + this._world = null; + + //tool that owns this brushstroke + this._drawingTool = null; + this._planeMat = null; + this._planeMatInv = null; + this._planeCenter = null; + + ///////////////////////////////////////////////////////// + // Property Accessors/Setters + ///////////////////////////////////////////////////////// + this.setWorld = function (world) { + this._world = world; + }; + + this.getWorld = function () { + return this._world; + }; + + this.geomType = function () { + return this.GEOM_TYPE_CUBIC_BEZIER; + }; + + this.setDrawingTool = function (tool) { + this._drawingTool = tool; + }; + + this.getDrawingTool = function () { + return this._drawingTool; + }; + + this.setPlaneMatrix = function(planeMat){ + this._planeMat = planeMat; + }; + + this.setPlaneMatrixInverse = function(planeMatInv){ + this._planeMatInv = planeMatInv; + }; + + this.setPlaneCenter = function(pc){ + this._planeCenter = pc; + }; + + this.getCanvasX = function(){ + return this._canvasX; + }; + + this.getCanvasY = function(){ + return this._canvasY; + }; + + this.setCanvasX = function(cx){ + this._canvasX=cx; + }; + + this.setCanvasY = function(cy){ + this._canvasY=cy; + }; + + this.getNumPoints = function () { + return this._Points.length; + }; + + this.getPoint = function (index) { + return this._Points[index]; + }; + + this.addPoint = function (pt) { + //add the point only if it is some epsilon away from the previous point + var numPoints = this._Points.length; + if (numPoints>0) { + var threshold = this._WETNESS_FACTOR*this._strokeWidth; + var prevPt = this._Points[numPoints-1]; + var diffPt = [prevPt[0]-pt[0], prevPt[1]-pt[1]]; + var diffPtMag = Math.sqrt(diffPt[0]*diffPt[0] + diffPt[1]*diffPt[1]); + if (diffPtMag>threshold){ + this._Points.push(pt); + this._dirty=true; + } + } else { + this._Points.push(pt); + this._dirty=true; + } + }; + + this.insertPoint = function(pt, index){ + this._Points.splice(index, 0, pt); this._dirty=true; + }; + + this.isDirty = function(){ + return this._dirty; + }; + + this.makeDirty = function(){ + this._dirty=true; + }; + + this.getBBoxMin = function () { + return this._BBoxMin; + }; + + this.getBBoxMax = function () { + return this._BBoxMax; + }; + + this.getStrokeWidth = function () { + return this._strokeWidth; + }; + + this.setStrokeWidth = function (w) { + this._strokeWidth = w; + this._dirty=true; + }; + + this.getStrokeMaterial = function () { + return this._strokeMaterial; + }; + + this.setStrokeMaterial = function (m) { + this._strokeMaterial = m; + }; + + this.getStrokeColor = function () { + return this._strokeColor; + }; + + this.setStrokeColor = function (c) { + this._strokeColor = c; + }; + + this.getStrokeStyle = function () { + return this._strokeStyle; + }; + + this.setStrokeStyle = function (s) { + this._strokeStyle = s; + }; + + this.setWidth = function () { + + };//NO-OP for now + + this.setHeight = function () { + + };//NO-OP for now + + + //remove and return anchor at specified index, return null on error + this.removePoint = function (index) { + var retAnchor = null; + if (index < this._Points.length) { + retPt = this._Points.splice(index, 1); + this._dirty=true; + } + return retPoint; + }; + + //remove all the points + this.clear = function () { + this._Points = []; + this._dirty=true; + } + + this.translate = function (tx, ty, tz) { + for (var i=0;i1) { + var threshold = this._WETNESS_FACTOR*this._strokeWidth; + var prevPt = this._Points[0]; + var prevIndex = 0; + for (var i=1;ithreshold){ + //insert points along the prev. to current point + var numNewPoints = Math.floor(distance/threshold); + for (var j=0;j this._MAX_ALLOWED_SAMPLES){ + console.log("leaving the resampling because numPoints is greater than limit:"+this._MAX_ALLOWED_SAMPLES); + break; + } + } + } + + // *** compute the bounding box ********* + this._BBoxMin = [Infinity, Infinity, Infinity]; + this._BBoxMax = [-Infinity, -Infinity, -Infinity]; + numPoints = this._Points.length; + if (numPoints === 0) { + this._BBoxMin = [0, 0, 0]; + this._BBoxMax = [0, 0, 0]; + } else { + for (var i=0;i pt[d]) { + this._BBoxMin[d] = pt[d]; + } + if (this._BBoxMax[d] < pt[d]) { + this._BBoxMax[d] = pt[d]; + } + }//for every dimension d from 0 to 2 + } + } + //increase the bbox given the stroke width + for (var d = 0; d < 3; d++) { + this._BBoxMin[d]-= this._strokeWidth/2; + this._BBoxMax[d]+= this._strokeWidth/2; + }//for every dimension d from 0 to 2 + } + this._dirty = false; + }; + + this.buildBuffers = function () { + //return; //no need to do anything for now + };//buildBuffers() + + //render + // specify how to render the subpath in Canvas2D + this.render = function () { + // get the world + var world = this.getWorld(); + if (!world) throw( "null world in brushstroke render" ); + + // get the context + var ctx = world.get2DContext(); + if (!ctx) throw ("null context in brushstroke render") + + var numPoints = this.getNumPoints(); + if (numPoints === 0) { + return; //nothing to do for empty paths + } + + ctx.save(); + + this.computeMetaGeometry(); + var bboxMin = this.getBBoxMin(); + var bboxMax = this.getBBoxMax(); + var bboxWidth = bboxMax[0] - bboxMin[0]; + var bboxHeight = bboxMax[1] - bboxMin[1]; + ctx.clearRect(0, 0, bboxWidth, bboxHeight); + + /* + ctx.lineWidth = this._strokeWidth; + ctx.strokeStyle = "black"; + if (this._strokeColor) + ctx.strokeStyle = MathUtils.colorToHex( this._strokeColor ); + ctx.fillStyle = "blue"; + if (this._fillColor) + ctx.fillStyle = MathUtils.colorToHex( this._fillColor ); + var lineCap = ['butt','round','square']; + ctx.lineCap = lineCap[1]; + ctx.beginPath(); + var firstPoint = this._Points[0]; + ctx.moveTo(firstPoint[0]-bboxMin[0], firstPoint[1]-bboxMin[1]); + for (var i = 1; i < numPoints; i++) { + var pt = this._Points[i]; + ctx.lineTo(pt[0]-bboxMin[0], pt[1]-bboxMin[1]); + } + ctx.stroke(); + */ + + /* + var isDebug = false; + var prevPt = this._Points[0]; + var prevX = prevPt[0]-bboxMin[0]; + var prevY = prevPt[1]-bboxMin[1]; + prevPt = [prevX,prevY]; + for (var i = 1; i < numPoints; i++) { + var pt = this._Points[i]; + ctx.globalCompositeOperation = 'source-over'; + var x = pt[0]-bboxMin[0]; + var y = pt[1]-bboxMin[1]; + pt = [x,y]; + + //vector from prev to current pt + var seg = VecUtils.vecSubtract(2, pt, prevPt); + var segDir = VecUtils.vecNormalize(2, seg, 1.0); + + var segMidPt = VecUtils.vecInterpolate(2, pt, prevPt, 0.5); + var w2 = this._strokeWidth*0.5; + var segDirOrtho = [w2*segDir[1], -w2*segDir[0]]; + + //add half the strokewidth to the segMidPt + var lgStart = VecUtils.vecAdd(2, segMidPt, segDirOrtho); + var lgEnd = VecUtils.vecSubtract(2, segMidPt, segDirOrtho); + + ctx.save(); + ctx.beginPath(); + + if (isDebug) { + ctx.strokeStyle="black"; + ctx.lineWidth = 1; + + ctx.moveTo(lgStart[0], lgStart[1]); + ctx.lineTo(lgEnd[0], lgEnd[1]); + ctx.stroke(); + } + + var lg = ctx.createLinearGradient(lgStart[0], lgStart[1], lgEnd[0], lgEnd[1]); + lg.addColorStop(1, 'rgba(0,0,0,0.0)'); + lg.addColorStop(0.5,'rgba(255,0,0,1.0)'); + lg.addColorStop(0, 'rgba(0,0,0,0.0)'); + ctx.fillStyle = lg; + + if (isDebug){ + ctx.strokeStyle="blue"; + ctx.lineWidth=0.5; + } + ctx.moveTo(prevX-w2, prevY); + ctx.lineTo(prevX+w2, prevY); + ctx.lineTo(x+w2, y); + ctx.lineTo(x-w2, y); + ctx.lineTo(prevX-w2, prevY); + ctx.fill(); + ctx.closePath(); + + ctx.restore(); + + prevPt = pt; + prevX = x; + prevY = y; + } + + + if (isDebug) + ctx.stroke(); + + if (isDebug){ + //draw the skeleton of this stroke + ctx.lineWidth = 1; + ctx.strokeStyle = "black"; + var pt = this._Points[0]; + ctx.beginPath(); + ctx.moveTo(pt[0]-bboxMin[0],pt[1]-bboxMin[1]); + for (var i = 1; i < numPoints; i++) { + pt = this._Points[i]; + var x = pt[0]-bboxMin[0]; + var y = pt[1]-bboxMin[1]; + ctx.lineTo(x,y); + } + ctx.stroke(); + } + */ + + + var R2 = this._strokeWidth; + var R = R2*0.5; + var hardness = 0; //for a pencil, this is always 1 //TODO get hardness parameter from user interface + var innerRadius = (hardness*R)-1; + if (innerRadius<1) + innerRadius=1; + + var r = ctx.createRadialGradient(0,0,innerRadius, 0,0,R); + var midColor = "rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+",1)"; + r.addColorStop(0, midColor); + var endColor = "rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+",0.0)"; + r.addColorStop(1, endColor); + ctx.fillStyle = r; + + for (var i = 0; i < numPoints; i++) { + var pt = this._Points[i]; + ctx.globalCompositeOperation = 'source-over'; + var x = pt[0]-bboxMin[0]; + var y = pt[1]-bboxMin[1]; + ctx.save(); + ctx.translate(x,y); + ctx.arc(0, 0, R, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.restore(); + //ctx.globalCompositeOperation = 'source-in'; + //ctx.rect(x-R, y-R, R2, R2); + } + + ctx.restore(); + }; //render() + + + this.export = function() { + return "type: " + this.geomType() + "\n"; + }; + + this.import = function( importStr ) { + + } + + this.collidesWithPoint = function (x, y, z) { + if (x < this._BBoxMin[0]) return false; + if (x > this._BBoxMax[0]) return false; + if (y < this._BBoxMin[1]) return false; + if (y > this._BBoxMax[1]) return false; + if (z < this._BBoxMin[2]) return false; + if (z > this._BBoxMax[2]) return false; + + return true; + }; + + this.collidesWithPoint = function (x, y) { + if (x < this._BBoxMin[0]) return false; + if (x > this._BBoxMax[0]) return false; + if (y < this._BBoxMin[1]) return false; + if (y > this._BBoxMax[1]) return false; + + return true; + }; + +}; //function GLSubpath ...class definition + +BrushStroke.prototype = new GeomObj(); + +if (typeof exports === "object") { + exports.BrushStroke = BrushStroke; +} \ No newline at end of file diff --git a/js/lib/geom/circle.js b/js/lib/geom/circle.js new file mode 100755 index 00000000..dd82a4cc --- /dev/null +++ b/js/lib/geom/circle.js @@ -0,0 +1,751 @@ +/* +This file contains proprietary software owned by Motorola Mobility, Inc.
+No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + +var GeomObj = require("js/lib/geom/geom-obj").GeomObj; +var ShapePrimitive = require("js/lib/geom/shape-primitive").ShapePrimitive; +var MaterialsModel = require("js/models/materials-model").MaterialsModel; +/////////////////////////////////////////////////////////////////////// +// Class GLCircle +// GL representation of a circle. +// Derived from class GLGeomObj +// The position and dimensions of the stroke, fill, and inner Radius should be in pixels +/////////////////////////////////////////////////////////////////////// +var Circle = function GLCircle() { + + this.init = function( world, xOffset, yOffset, width, height, strokeSize, strokeColor, fillColor, innerRadius, strokeMaterial, fillMaterial, strokeStyle) { + /////////////////////////////////////////////////////////////////////// + // Instance variables + /////////////////////////////////////////////////////////////////////// + this._width = 2.0; + this._height = 2.0; + this._xOffset = 0; + this._yOffset = 0; + + this._radius = 2.0; + this._strokeWidth = 0.25; + this._innerRadius = 0; + + this._ovalHeight = this._ovalHeight = 2.0 * this._radius; + + this._strokeStyle = "Solid"; + + this._aspectRatio = 1.0; + + if (arguments.length > 0) { + this._width = width; + this._height = height; + this._xOffset = xOffset; + this._yOffset = yOffset; + + this._strokeWidth = strokeSize; + this._innerRadius = innerRadius; + if (strokeColor) this._strokeColor = strokeColor; + if (fillColor) this._fillColor = fillColor; + + this._strokeStyle = strokeStyle; + } + + this.m_world = world; + + if(strokeMaterial){ + this._strokeMaterial = strokeMaterial; + } else { + this._strokeMaterial = MaterialsModel.exportFlatMaterial(); + } + + if(fillMaterial) { + this._fillMaterial = fillMaterial; + } else { + this._fillMaterial = MaterialsModel.exportFlatMaterial(); + } + }; + + /////////////////////////////////////////////////////////////////////// + // Property Accessors + /////////////////////////////////////////////////////////////////////// + this.getStrokeWidth = function() { + return this._strokeWidth; + }; + + this.setStrokeWidth = function(w) { + this._strokeWidth = w; + }; + + this.getStrokeMaterial = function() { + return this._strokeMaterial; + }; + + this.setStrokeMaterial = function(m) { + this._strokeMaterial = m; + }; + + this.getFillMaterial = function() { + return this._fillMaterial; + }; + + this.setFillMaterial = function(m) { + this._fillMaterial = m; + }; + + this.getRadius = function() { + return this._radius; + }; + + this.setRadius = function(r) { + this._radius = r; + }; + + this.getWorld = function() { + return this._world; + }; + + this.setWorld = function(w) { + this._world = w; + }; + + this.getInnerRadius = function() { + return this._innerRadius; + }; + + this.setInnerRadius = function(r) { + this._innerRadius = r; + }; + + this.getStrokeStyle = function() { + return this._strokeStyle; + }; + this.setStrokeStyle = function(s) { + this._strokeStyle = s; + }; + + this.getWidth = function() { + return this._width; + }; + + this.setWidth = function(w) { + this._width = w; + }; + + this.getHeight = function() { + return this._height; + }; + + this.setHeight = function(h) { + this._height = h; + }; + + this.geomType = function() { + return this.GEOM_TYPE_CIRCLE; + }; + + /////////////////////////////////////////////////////////////////////// + // Methods + /////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////// + // update the "color of the material + this.getFillColor = function() + { + re