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 <valerio@motorola.com> --- js/lib/geom/circle.js | 751 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 751 insertions(+) create mode 100755 js/lib/geom/circle.js (limited to 'js/lib/geom/circle.js') 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 @@ +/* <copyright> +This file contains proprietary software owned by Motorola Mobility, Inc.<br/> +No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/> +(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +</copyright> */ + +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._materialNodeArray.push( strokeMaterial2.getMaterialNode() ); + } + + world.updateObject(this); + }; + + this.generateOval = function(xOff, yOff, rotationMat, scaleMat, nTriangles) { + var pt = [1.0, 0.0, 0.0]; + //var pts = scaleMat.multiply(pt); + var pts = glmat4.multiplyVec3( scaleMat, pt, []); + var x = pts[0], y = pts[1], z = 0; + var xs = scaleMat[0], ys = scaleMat[4]; + + var vrts = [], nrms = [], uvs = [], indices = []; + var index = 0; + for (var i=0; i<nTriangles; i++) { + //pt = rotationMat.multiply( pt ); + //pts = scaleMat.multiply(pt); + glmat4.multiplyVec3( rotationMat, pt ); + glmat4.multiplyVec3( scaleMat, pt, pts ); + + // push the 3 vertices for the next triangle + vrts.push(pts[0]+xOff); + vrts.push(pts[1]+yOff); + vrts.push(z); + + vrts.push(x+xOff); + vrts.push(y+yOff); + vrts.push(z); + + vrts.push(xOff); + vrts.push(yOff); + vrts.push(z); + + // push a texture coordinate pair for each vertex + uvs.push(0.5); + uvs.push(0.5); + uvs.push(x/(2.0 * xs) + 0.5, y/(2.0 * ys) + 0.5); + uvs.push(pts[0]/(2.0 * xs) + 0.5, pts[1]/(2.0 * ys) + 0.5); + + // push a normal for each vertex + nrms.push(0.0); + nrms.push(0.0); + nrms.push(1); + nrms.push(0.0); + nrms.push(0.0); + nrms.push(1); + nrms.push(0.0); + nrms.push(0.0); + nrms.push(1); + + x = pts[0]; y = pts[1]; + + indices[index] = index++; + indices[index] = index++; + indices[index] = index++; + } + + this.recalcTexMapCoords( vrts, uvs ); + + return ShapePrimitive.create(vrts, nrms, uvs, indices, g_Engine.getContext().renderer.TRIANGLES, index); + }; + + this.generateOvalRing = function(xOff, yOff, rotationMat, innerScaleMat, outerScaleMat, nTriangles) { + var pt = [1.0, 0.0, 0.0]; + + var z = 0; + var pt0s, pt1s; + //pt0s = innerScaleMat.multiply(pt); + //pt1s = outerScaleMat.multiply(pt); + pt0s = glmat4.multiplyVec3(innerScaleMat, pt, []); + pt1s = glmat4.multiplyVec3(outerScaleMat, pt, []); + + var vrts = [], nrms = [], uvs = [], indices = []; + + // normals + var insideAngle = -15.0*Math.PI/180.0, + outsideAngle = 15.0*Math.PI/180.0; + var cs1 = Math.cos(insideAngle), sn0 = Math.sin(insideAngle), + cs0 = Math.cos(outsideAngle), sn1 = Math.sin(outsideAngle); + var nrm0 = [-sn0, 0, cs0], + nrm1 = [-sn1, 0, cs1]; + + var index = 0; + vrts.push( pt0s[0]+xOff); vrts.push(pt0s[1]+yOff); vrts.push(z); + vrts.push( pt1s[0]+xOff); vrts.push(pt1s[1]+yOff); vrts.push(z); + uvs.push(0.5*pt0s[0] + 0.5); uvs.push(0.5*pt0s[1] + 0.5); + uvs.push(0.5*pt1s[0] + 0.5); uvs.push(0.5*pt1s[1] + 0.5); + nrms.push( nrm0[0] ); nrms.push(nrm0[1] ); nrms.push(nrm0[2] ); + nrms.push( nrm1[0] ); nrms.push(nrm1[1] ); nrms.push(nrm1[2] ); + indices[index] = index++; + indices[index] = index++; + + for (var i=0; i<nTriangles; i++) { + pt = glmat4.multiplyVec3( rotationMat, pt ); + glmat4.multiplyVec3( innerScaleMat, pt, pt0s ); + glmat4.multiplyVec3( outerScaleMat, pt, pt1s ); + + // vertices + vrts.push( pt0s[0]+xOff); vrts.push(pt0s[1]+yOff); vrts.push(z); + vrts.push( pt1s[0]+xOff); vrts.push(pt1s[1]+yOff); vrts.push(z); + + // textures + uvs.push(0.5*pt0s[0] + 0.5); uvs.push(0.5*pt0s[1] + 0.5); + uvs.push(0.5*pt1s[0] + 0.5); uvs.push(0.5*pt1s[1] + 0.5); + + // normals + glmat4.multiplyVec3( rotationMat, nrm0 ); + glmat4.multiplyVec3( rotationMat, nrm1 ); + nrms.push( nrm0[0]); nrms.push(nrm0[1]); nrms.push(nrm0[2] ); + nrms.push( nrm1[0]); nrms.push(nrm1[1]); nrms.push(nrm1[2] ); + indices[index] = index++; + indices[index] = index++; + } + + this.recalcTexMapCoords( vrts, uvs ); + + return ShapePrimitive.create(vrts, nrms, uvs, indices, g_Engine.getContext().renderer.TRIANGLE_STRIP, indices.length); + }; + + this.render = function() { + // get the world + var world = this.getWorld(); + if (!world) throw( "null world in buildBuffers" ); + + // get the context + var ctx = world.get2DContext(); + if (!ctx) return; + + // declare some variables + var p0, p1; + var x0, y1, x1, y1; + + // create the matrix + var lineWidth = this._strokeWidth; + var innerRad = this.getInnerRadius(); + var xScale = 0.5*this._width - lineWidth, + yScale = 0.5*this._height - lineWidth; + + // translate + var xCtr = 0.5*world.getViewportWidth() + this._xOffset, + yCtr = 0.5*world.getViewportHeight() + this._yOffset; + //ctx.setTransform( xScale, 0.0, 0.0, yScale, xCtr, yCtr ); + var mat = Matrix.create( [ + [ xScale, 0.0, 0.0, xCtr], + [ 0.0, yScale, 0.0, yCtr], + [ 0.0, 0.0, 1.0, 0.0], + [ 0.0, 0.0, 0.0, 1.0] + ] ); + + // get a bezier representation of the circle + var bezPts = MathUtils.circularArcToBezier( [0,0,0], [1,0,0], 2.0*Math.PI ); + if (bezPts) { + var n = bezPts.length; + + // set up the fill style + ctx.beginPath(); + ctx.lineWidth = 0; + if (this._fillColor) { + var c = "rgba(" + 255*this._fillColor[0] + "," + 255*this._fillColor[1] + "," + 255*this._fillColor[2] + "," + this._fillColor[3] + ")"; + ctx.fillStyle = c; + + // draw the fill + ctx.beginPath(); + var p = MathUtils.transformPoint( bezPts[0], mat ); + ctx.moveTo( p[0], p[1] ); + var index = 1; + while (index < n) { + p0 = MathUtils.transformPoint( bezPts[index], mat ); + p1 = MathUtils.transformPoint( bezPts[index+1], mat ); + + x0 = p0[0]; y0 = p0[1]; + x1 = p1[0]; y1 = p1[1]; + ctx.quadraticCurveTo( x0, y0, x1, y1 ); + index += 2; + } + + if (MathUtils.fpSign(innerRad) > 0) { + xScale = 0.5*innerRad*this._width; + yScale = 0.5*innerRad*this._height; + mat[0] = xScale; + mat[5] = yScale; + + // get the bezier points + var bezPts = MathUtils.circularArcToBezier( [0,0,0], [1,0,0], -2.0*Math.PI ); + if (bezPts) { + var n = bezPts.length; + p = MathUtils.transformPoint( bezPts[0], mat ); + ctx.moveTo( p[0], p[1] ); + index = 1; + while (index < n) { + p0 = MathUtils.transformPoint( bezPts[index], mat ); + p1 = MathUtils.transformPoint( bezPts[index+1], mat ); + + var x0 = p0[0], y0 = p0[1], + x1 = p1[0], y1 = p1[1]; + ctx.quadraticCurveTo( x0, y0, x1, y1 ); + index += 2; + } + } + } + + // fill the path + ctx.fill(); + } + + // calculate the stroke matrix + xScale = 0.5*this._width - 0.5*lineWidth; + yScale = 0.5*this._height - 0.5*lineWidth; + mat[0] = xScale; + mat[5] = yScale; + + // set up the stroke style + ctx.beginPath(); + ctx.lineWidth = lineWidth; + if (this._strokeColor) { + var c = "rgba(" + 255*this._strokeColor[0] + "," + 255*this._strokeColor[1] + "," + 255*this._strokeColor[2] + "," + this._strokeColor[3] + ")"; + ctx.strokeStyle = c; + + // draw the stroke + p = MathUtils.transformPoint( bezPts[0], mat ); + ctx.moveTo( p[0], p[1] ); + index = 1; + while (index < n) { + var p0 = MathUtils.transformPoint( bezPts[index], mat ); + var p1 = MathUtils.transformPoint( bezPts[index+1], mat ); + + var x0 = p0[0], y0 = p0[1], + x1 = p1[0], y1 = p1[1]; + ctx.quadraticCurveTo( x0, y0, x1, y1 ); + index += 2; + } + + if (MathUtils.fpSign(innerRad) > 0) { + // calculate the stroke matrix + xScale = 0.5*innerRad*this._width - 0.5*lineWidth; + yScale = 0.5*innerRad*this._height - 0.5*lineWidth; + mat[0] = xScale; + mat[5] = yScale; + + // draw the stroke + p = MathUtils.transformPoint( bezPts[0], mat ); + ctx.moveTo( p[0], p[1] ); + index = 1; + while (index < n) { + var p0 = MathUtils.transformPoint( bezPts[index], mat ); + var p1 = MathUtils.transformPoint( bezPts[index+1], mat ); + + var x0 = p0[0], y0 = p0[1], + x1 = p1[0], y1 = p1[1]; + ctx.quadraticCurveTo( x0, y0, x1, y1 ); + index += 2; + } + } + + // render the stroke + ctx.stroke(); + } + } + }; + + this.export = function() { + var rtnStr = "type: " + this.geomType() + "\n"; + + rtnStr += "xoff: " + this._xOffset + "\n"; + rtnStr += "yoff: " + this._yOffset + "\n"; + rtnStr += "width: " + this._width + "\n"; + rtnStr += "height: " + this._height + "\n"; + rtnStr += "strokeWidth: " + this._strokeWidth + "\n"; + rtnStr += "innerRadius: " + this._innerRadius + "\n"; + rtnStr += "strokeStyle: " + this._strokeStyle + "\n"; + rtnStr += "strokeColor: " + String(this._strokeColor) + "\n"; + rtnStr += "fillColor: " + String(this._fillColor) + "\n"; + + rtnStr += "strokeMat: "; + if (this._strokeMaterial) { + rtnStr += this._strokeMaterial.getName(); + } else { + rtnStr += "flatMaterial"; + } + + rtnStr += "\n"; + + rtnStr += "fillMat: "; + if (this._fillMaterial) { + rtnStr += this._fillMaterial.getName(); + } else { + rtnStr += "flatMaterial"; + } + + rtnStr += "\n"; + + return rtnStr; + }; + + this.import = function( importStr ) { + this._xOffset = Number( this.getPropertyFromString( "xoff: ", importStr ) ); + this._yOffset = Number( this.getPropertyFromString( "yoff: ", importStr ) ); + this._width = Number( this.getPropertyFromString( "width: ", importStr ) ); + this._height = Number( this.getPropertyFromString( "height: ", importStr ) ); + this._strokeWidth = Number( this.getPropertyFromString( "strokeWidth: ", importStr ) ); + this._innerRadius = Number( this.getPropertyFromString( "innerRadius: ", importStr ) ); + this._strokeStyle = this.getPropertyFromString( "strokeStyle: ", importStr ); + var strokeMaterialName = this.getPropertyFromString( "strokeMat: ", importStr ); + var fillMaterialName = this.getPropertyFromString( "fillMat: ", importStr ); + this._fillColor = eval( "[" + this.getPropertyFromString( "fillColor: ", importStr ) + "]" ); + this._strokeColor = eval( "[" + this.getPropertyFromString( "strokeColor: ", importStr ) + "]" ); + + var strokeMat = MaterialsModel.getMaterial( strokeMaterialName ); + if (!strokeMat) { + console.log( "object material not found in library: " + strokeMaterialName ); + strokeMat = MaterialsModel.exportFlatMaterial(); + } + + this._strokeMaterial = strokeMat; + + var fillMat = MaterialsModel.getMaterial( fillMaterialName ); + if (!fillMat) { + console.log( "object material not found in library: " + fillMaterialName ); + fillMat = MaterialsModel.exportFlatMaterial(); + } + + this._fillMaterial = fillMat; + }; + + this.collidesWithPoint = function( x, y ) { +// if(x < this._xOffset) return false; +// if(x > (this._xOffset + this._width)) return false; +// if(y < this._yOffset) return false; +// if(y > (this._yOffset + this._height)) return false; + + return true; + }; + + this.containsPoint = function( pt, dir ) { + var world = this.getWorld(); + if (!world) throw( "null world in containsPoint" ); + + // get a point on the plane of the circle + // the point is in NDC, as is the input parameters + var mat = this.getMatrix(); + var plane = [0,0,1,0]; + plane = MathUtils.transformPlane( plane, mat ); + var projPt = MathUtils.vecIntersectPlane ( pt, dir, plane ); + + // transform the projected point back to the XY plane + //var invMat = mat.inverse(); + var invMat = glmat4.inverse( mat, [] ); + var planePt = MathUtils.transformPoint( projPt, invMat ); + + // get the normalized device coordinates (NDC) for + // the position and radii. + 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; + var projMat = world.makePerspectiveMatrix(); + var z = -world.getViewDistance(); + var planePtNDC = planePt.slice(0); + planePtNDC[2] = z; + planePtNDC = MathUtils.transformHomogeneousPoint( planePtNDC, projMat ); + planePtNDC = MathUtils.applyHomogeneousCoordinate( planePtNDC ); + + // get the gl coordinates + 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; + + var angle = Math.atan2( planePtNDC[1] - yNDC, planePtNDC[0] - xNDC ); + var degrees = angle*180.0/Math.PI; + var objPtNDC = [Math.cos(angle)*xRadNDC + xNDC, Math.sin(angle)*yRadNDC + yNDC, 0]; + + var ctrNDC = [xNDC, yNDC]; + + var distToBoundary = VecUtils.vecDist( 2, ctrNDC, objPtNDC ), + distToPt = VecUtils.vecDist( 2, ctrNDC, planePtNDC ); + + return (MathUtils.fpCmp(distToPt,distToBoundary) <= 0); + }; + + this.getNearPoint = function( pt, dir ) { + var world = this.getWorld(); + if (!world) throw( "null world in getNearPoint" ); + + // get a point on the plane of the circle + // the point is in NDC, as is the input parameters + var mat = this.getMatrix(); + var plane = [0,0,1,0]; + plane = MathUtils.transformPlane( plane, mat ); + var projPt = MathUtils.vecIntersectPlane ( pt, dir, plane ); + + // transform the projected point back to the XY plane + //var invMat = mat.inverse(); + var invMat = glmat4.inverse( mat, [] ); + var planePt = MathUtils.transformPoint( projPt, invMat ); + + // get the normalized device coordinates (NDC) for + // the position and radii. + 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; + var projMat = world.makePerspectiveMatrix(); + var z = -world.getViewDistance(); + var planePtNDC = planePt.slice(0); + planePtNDC[2] = z; + planePtNDC = MathUtils.transformHomogeneousPoint( planePtNDC, projMat ); + planePtNDC = MathUtils.applyHomogeneousCoordinate( planePtNDC ); + + // get the gl coordinates + 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; + + var angle = Math.atan2( planePtNDC[1] - yNDC, planePtNDC[0] - xNDC ); + var degrees = angle*180.0/Math.PI; + var objPt = [Math.cos(angle)*xRadNDC + xNDC, Math.sin(angle)*yRadNDC + yNDC, 0]; + + // convert to GL coordinates + objPt[0] = -z*(r-l)/(2.0*zn)*objPt[0]; + objPt[1] = -z*(t-b)/(2.0*zn)*objPt[1]; + + // re-apply the transform + objPt = MathUtils.transformPoint( objPt, mat ); + + return objPt; + }; + + this.recalcTexMapCoords = function( vrts, uvs ) { + var n = vrts.length/3; + var ivrt = 0, iuv = 0; + var uMin = 1.e8, uMax = -1.e8, + vMin = 1.e8, vMax = -1.e8; + + for (var i=0; i<n; i++) { + uvs[iuv] = 0.5*(vrts[ivrt]/this._ovalWidth + 1); + if (uvs[iuv] < uMin) uMin = uvs[iuv]; + if (uvs[iuv] > uMax) uMax = uvs[iuv]; + + iuv++; ivrt++; + uvs[iuv] = 0.5*(vrts[ivrt]/this._ovalHeight + 1); + if (uvs[iuv] < vMin) vMin = uvs[iuv]; + if (uvs[iuv] > vMax) vMax = uvs[iuv]; + iuv++; ivrt += 2; + } + + //console.log( "remap: " + uvs ); + //console.log( "uRange: " + uMin + " => " + uMax ); + //console.log( "vRange: " + vMin + " => " + vMax ); + }; + }; + +Circle.prototype = new GeomObj(); + +if (typeof exports === "object") { + exports.Circle = Circle; +} \ No newline at end of file -- cgit v1.2.3