From 84332ab81c1b445195f1d9be8bbeae0725c8e758 Mon Sep 17 00:00:00 2001 From: Valerio Virgillito Date: Tue, 6 Mar 2012 10:58:25 -0800 Subject: 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 --- 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() + { + return this._fillColor; + } + +// this.setFillColor = function(c) +// { +// this._fillColor = c; +// } + + this.getStrokeColor = function() + { + return this._strokeColor; + } + +// this.setStrokeColor = function(c) +// { +// this._strokeColor = c; +// } + /////////////////////////////////////////////////////////////////////// + + this.buildBuffers = function() { + // get the world + var world = this.getWorld(); + if (!world) throw( "null world in buildBuffers" ); + + if (!world._useWebGL) return; + + // make sure RDGE has the correct context + g_Engine.setContext( world.getCanvas().rdgeid ); + + // create the gl buffer + var gl = world.getGLContext(); + + // determine the number of triangles to generate + var nTriangles = 60; // yes, we will do better than this + + // get the normalized device coordinates (NDC) for + // all position and dimensions. + var vpw = world.getViewportWidth(), vph = world.getViewportHeight(); + var xNDC = 2*this._xOffset/vpw, yNDC = 2*this._yOffset/vph, + xRadNDC = this._width/vpw, yRadNDC = this._height/vph, + xStrokeNDC = 2*this._strokeWidth/vpw, yStrokeNDC = 2*this._strokeWidth/vph, + xInnRadNDC = this._innerRadius*xRadNDC, yInnRadNDC = this._innerRadius*yRadNDC; + + var aspect = world.getAspect(); + var zn = world.getZNear(), zf = world.getZFar(); + var t = zn * Math.tan(world.getFOV() * Math.PI / 360.0), + b = -t, + r = aspect*t, + l = -r; + + // calculate the object coordinates from their NDC coordinates + var z = -world.getViewDistance(); + + // get the position of the origin + var x = -z*(r-l)/(2.0*zn)*xNDC, + y = -z*(t-b)/(2.0*zn)*yNDC; + + // get the x and y radii + var xRad = -z*(r-l)/(2.0*zn)*xRadNDC, + yRad = -z*(t-b)/(2.0*zn)*yRadNDC; + + // save the overall dimensions to be used in the uv calculations + this._ovalWidth = xRad; this._ovalHeight = yRad; + + // get the x & y stroke size + var xStroke = -z*(r-l)/(2.0*zn)*xStrokeNDC, + yStroke = -z*(t-b)/(2.0*zn)*yStrokeNDC; + + // get the inner radius + var xInnRad = -z*(r-l)/(2.0*zn)*xInnRadNDC, + yInnRad = -z*(t-b)/(2.0*zn)*yInnRadNDC; + + // get a matrix to rotate a point around the circle + var angle = 2.0 * Math.PI/Number(nTriangles); + var mat = Matrix.RotationZ( angle ); + var reverseRotMat = Matrix.RotationZ( -angle ); + + // calculate matrices to scale the circle and stroke to fit the bounds of the ellipse + var strokeScaleMat = Matrix.I(4); + strokeScaleMat[0] = xRad; + strokeScaleMat[5] = yRad; + + var fillScaleMat = Matrix.I(4); + fillScaleMat[0] = xRad - xStroke; + fillScaleMat[5] = yRad - yStroke; + + var innerRadiusScaleMat = Matrix.I(4); + innerRadiusScaleMat[0] = xInnRad; + innerRadiusScaleMat[5] = yInnRad; + + var innerStrokeScaleMat = Matrix.I(4); + innerStrokeScaleMat[0] = xInnRad - xStroke; + innerStrokeScaleMat[5] = yInnRad - yStroke; + + var fillPrim, strokePrim0, strokePrim1; + var fillMaterial, strokeMaterial0, strokeMaterial2; + + this._primArray = []; + this._materialArray = []; + this._materialTypeArray = []; + this._materialNodeArray = []; + + ///////////////////////////////////////////////////////////// + // Strokes + if(this._strokeWidth > 0) { + var numStrokes = 1; + if(this._innerRadius !== 0) { + strokePrim0 = this.generateOvalRing(x, y, reverseRotMat, innerStrokeScaleMat, innerRadiusScaleMat, nTriangles); + } + + strokePrim1 = this.generateOvalRing(x, y, reverseRotMat, fillScaleMat, strokeScaleMat, nTriangles); + } + + ///////////////////////////////////////////////////////////// + // Fill + if(this._innerRadius === 0) { + fillPrim = this.generateOval(x, y, mat, fillScaleMat, nTriangles); + } else { + fillPrim = this.generateOvalRing(x, y, reverseRotMat, innerRadiusScaleMat, fillScaleMat, nTriangles); + } + + if (fillPrim) { + fillMaterial = this.makeFillMaterial(); + + this._primArray.push( fillPrim ); + this._materialNodeArray.push( fillMaterial.getMaterialNode() ); + } + + if (strokePrim0) { + strokeMaterial0 = this.makeStrokeMaterial(); + + this._primArray.push( strokePrim0 ); + this._materialNodeArray.push( strokeMaterial0.getMaterialNode() ); + } + + if (strokePrim1) { + strokeMaterial2 = this.makeStrokeMaterial(); + + this._primArray.push( strokePrim1 ); + this._materialNod