/* Copyright (c) 2012, Motorola Mobility LLC. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Motorola Mobility LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 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 GLRectangle // GL representation of a rectangle. // Derived from class GeomObj /////////////////////////////////////////////////////////////////////// exports.Rectangle = Object.create(GeomObj, { // CONSTANTS N_TRIANGLES: { value : 15, writable: false }, // TODO - This is not being used anywhere. Remove? //if (!MaterialsModel) // MaterialsModel = require("js/models/materials-model").MaterialsModel; /////////////////////////////////////////////////////////////////////// // Instance variables /////////////////////////////////////////////////////////////////////// _width: { value : 2.0, writable: true }, _height: { value : 2.0, writable: true }, _xOffset: { value : 0, writable: true }, _yOffset: { value : 0, writable: true }, _tlRadius: { value : 0, writable: true }, _trRadius: { value : 0, writable: true }, _blRadius: { value : 0, writable: true }, _brRadius: { value : 0, writable: true }, _strokeWidth: { value : 0.25, writable: true }, _strokeStyle: { value : "Solid", writable: true }, init: { value: function(world, xOffset, yOffset, width, height, strokeSize, strokeColor, fillColor, tlRadius, trRadius, blRadius, brRadius, strokeMaterial, fillMaterial, strokeStyle) { this.m_world = world; if (arguments.length > 0) { this._width = width; this._height = height; this._xOffset = xOffset; this._yOffset = yOffset; this._strokeWidth = strokeSize; this._strokeColor = strokeColor; this._fillColor = fillColor; this.setTLRadius(tlRadius); this.setTRRadius(trRadius); this.setBLRadius(blRadius); this.setBRRadius(brRadius); this._strokeStyle = strokeStyle; this._matrix = Matrix.I(4); } // the overall radius includes the fill and the stroke. separate the two based on the stroke width // this._fillRad = this._radius - this._strokeWidth; // var err = 0.05; var err = 0; this._fillWidth = this._width - this._strokeWidth + err; this._fillHeight = this._height - this._strokeWidth + err; this._materialAmbient = [0.2, 0.2, 0.2, 1.0]; this._materialDiffuse = [0.4, 0.4, 0.4, 1.0]; this._materialSpecular = [0.4, 0.4, 0.4, 1.0]; if(strokeMaterial) { this._strokeMaterial = strokeMaterial.dup(); } if(fillMaterial) { this._fillMaterial = fillMaterial.dup(); } this.initColors(); } }, /////////////////////////////////////////////////////////////////////// // Property Accessors /////////////////////////////////////////////////////////////////////// // TODO - Use getters/setters in the future getStrokeWidth: { value: function() { return this._strokeWidth; } }, setStrokeWidth: { value: function(w) { this._strokeWidth = w; } }, getStrokeMaterial: { value: function() { return this._strokeMaterial; } }, setStrokeMaterial: { value: function(m) { this._strokeMaterial = m; } }, getFillMaterial: { value: function() { return this._fillMaterial; } }, setFillMaterial: { value: function(m) { this._fillMaterial = m; } }, /////////////////////////////////////////////////////////////////////// // update the "color of the material getFillColor: { value: function() { return this._fillColor; } }, // setFillColor: { // value: function(c) { // this._fillColor = c; // } // }, getStrokeColor: { value: function() { return this._strokeColor; } }, // setStrokeColor: { // value: function(c) { // this._strokeColor = c; // } // }, /////////////////////////////////////////////////////////////////////// getTLRadius: { value: function() { return this._tlRadius; } }, setTLRadius: { value: function(r) { this._tlRadius = Math.min(r, (this._height - this._strokeWidth)/2, (this._width - this._strokeWidth)/2); } }, getTRRadius: { value: function() { return this._trRadius; } }, setTRRadius: { value: function(r) { this._trRadius = Math.min(r, (this._height - this._strokeWidth)/2, (this._width - this._strokeWidth)/2); } }, getBLRadius: { value: function() { return this._blRadius; } }, setBLRadius: { value: function(r) { this._blRadius = Math.min(r, (this._height - this._strokeWidth)/2, (this._width - this._strokeWidth)/2); } }, getBRRadius: { value: function() { return this._brRadius; } }, setBRRadius: { value: function(r) { this._brRadius = Math.min(r, (this._height - this._strokeWidth)/2, (this._width - this._strokeWidth)/2); } }, getStrokeStyle: { value: function() { return this._strokeStyle; } }, setStrokeStyle: { value: function(s) { this._strokeStyle = s; } }, getWidth: { value: function() { return this._width; } }, setWidth: { value: function(w) { this._width = w; } }, getHeight: { value: function() { return this._height; } }, setHeight: { value: function(h) { this._height = h; } }, geomType: { value: function() { return this.GEOM_TYPE_RECTANGLE; } }, /////////////////////////////////////////////////////////////////////// // Methods /////////////////////////////////////////////////////////////////////// // JSON export exportJSON: { value: function() { var jObj = { 'type' : this.geomType(), 'xoff' : this._xOffset, 'yoff' : this._yOffset, 'width' : this._width, 'height' : this._height, 'strokeWidth' : this._strokeWidth, 'strokeColor' : this._strokeColor, 'fillColor' : this._fillColor, 'tlRadius' : this._tlRadius, 'trRadius' : this._trRadius, 'blRadius' : this._blRadius, 'brRadius' : this._brRadius, 'innerRadius' : this._innerRadius, 'strokeStyle' : this._strokeStyle, 'strokeMat' : this._strokeMaterial ? this._strokeMaterial.getName() : null, 'fillMat' : this._fillMaterial ? this._fillMaterial.getName() : null, 'materials' : this.exportMaterialsJSON() }; return jObj; } }, importJSON: { value: function(jObj) { this._xOffset = jObj.xoff; this._yOffset = jObj.yoff; this._width = jObj.width; this._height = jObj.height; this._strokeWidth = jObj.strokeWidth; this._strokeColor = jObj.strokeColor; this._fillColor = jObj.fillColor; this._tlRadius = jObj.tlRadius; this._trRadius = jObj.trRadius; this._blRadius = jObj.blRadius; this._brRadius = jObj.brRadius; this._innerRadius = jObj.innerRadius; this._strokeStyle = jObj.strokeStyle; if(jObj.strokeMat) { var strokeMat = MaterialsModel.getMaterial(jObj.strokeMat).dup(); if (!strokeMat) { console.log("object material not found in library: " + jObj.strokeMat); } else { this._strokeMaterial = strokeMat; } } if(jObj.fillMat) { var fillMat = MaterialsModel.getMaterial(jObj.fillMat).dup(); if (!fillMat) { console.log("object material not found in library: " + jObj.fillMat); } else { this._fillMaterial = fillMat; } } this.initColors(); this.importMaterialsJSON( jObj.materials ); } }, buildBuffers: { value: function() { // get the world var world = this.getWorld(); if (!world) throw( "null world in buildBuffers" ); //console.log( "GLRectangle.buildBuffers " + world._worldCount ); if (!world._useWebGL) return; // make sure RDGE has the correct context RDGE.globals.engine.setContext( world.getCanvas().rdgeid ); // create the gl buffer var gl = world.getGLContext(); var tlRadius = this._tlRadius; //top-left radius var trRadius = this._trRadius; var blRadius = this._blRadius; var brRadius = this._brRadius; // declare the arrays to hold the parts this._primArray = []; this._materialArray = []; this._materialTypeArray = []; this._materialNodeArray = []; // 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, xFillNDC = this._width/vpw, yFillNDC = this._height/vph, strokeSizeNDC = 2*this._strokeWidth/vpw, tlRadiusNDC = 2*tlRadius/vpw, yTLRadiusNDC = 2*tlRadius/vph, trRadiusNDC = 2*trRadius/vpw, yTRRadiusNDC = 2*trRadius/vph, blRadiusNDC = 2*blRadius/vpw, yBLRadiusNDC = 2*blRadius/vph, brRadiusNDC = 2*brRadius/vpw, yBRRadiusNDC = 2*brRadius/vph; 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 fill var xFill = -z*(r-l)/(2.0*zn)*xFillNDC, yFill = -z*(t-b)/(2.0*zn)*yFillNDC; // keep some variables giving the overall dimensions of the // rectangle. These values are used to calculate consistent // texture map coordinates across all pieces. this._rectWidth = xFill; this._rectHeight = yFill; // get the stroke size var strokeSize = -z*(r-l)/(2.0*zn)*strokeSizeNDC; // get the absolute corner radii tlRadius = -z*(r-l)/(2.0*zn)*tlRadiusNDC, trRadius = -z*(r-l)/(2.0*zn)*trRadiusNDC, blRadius = -z*(r-l)/(2.0*zn)*blRadiusNDC, brRadius = -z*(r-l)/(2.0*zn)*brRadiusNDC; // stroke var i; var strokeMaterial = this.makeStrokeMaterial(); var strokePrimArray = this.createStroke([x,y], 2*xFill, 2*yFill, strokeSize, tlRadius, blRadius, brRadius, trRadius, strokeMaterial); strokeMaterial.fitToPrimitiveArray( strokePrimArray ); for (i=0; i minDimen) tlRad = minDimen; if (blRad > minDimen) blRad = minDimen; if (brRad > minDimen) brRad = minDimen; if (trRad > minDimen) trRad = minDimen; var viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; var world = this.getWorld(); viewUtils.pushViewportObj( world.getCanvas() ); var cop = viewUtils.getCenterOfProjection(); viewUtils.popViewportObj(); var xCtr = cop[0] + this._xOffset, yCtr = cop[1] - this._yOffset; var xLeft = xCtr - 0.5*this.getWidth(), yTop = yCtr - 0.5*this.getHeight(); var xDist = cop[0] - xLeft, yDist = cop[1] - yTop; var xOff = 0.5*world.getViewportWidth() - xDist, yOff = 0.5*world.getViewportHeight() - yDist; if ((tlRad <= 0) && (blRad <= 0) && (brRad <= 0) && (trRad <= 0)) { ctx.rect(pt[0]+xOff, pt[1]+yOff, width - 2*inset, height - 2*inset); } else { // get the top left point rad = tlRad - inset; if (rad < 0) rad = 0; pt[1] += rad; if (MathUtils.fpSign(rad) == 0) pt[1] = inset; ctx.moveTo( pt[0]+xOff, pt[1]+yOff ); // get the bottom left point pt = [inset, height - inset]; rad = blRad - inset; if (rad < 0) rad = 0; pt[1] -= rad; ctx.lineTo( pt[0]+xOff, pt[1]+yOff ); // get the bottom left curve if (MathUtils.fpSign(rad) > 0) { ctx.quadraticCurveTo( inset+xOff, height-inset+yOff, inset+rad+xOff, height-inset+yOff ); } // do the bottom of the rectangle pt = [width - inset, height - inset]; rad = brRad - inset; if (rad < 0) rad = 0; pt[0] -= rad; ctx.lineTo( pt[0]+xOff, pt[1]+yOff ); // get the bottom right arc if (MathUtils.fpSign(rad) > 0) { ctx.quadraticCurveTo( width-inset+xOff, height-inset+yOff, width-inset+xOff, height-inset-rad+yOff ); } // get the right of the rectangle pt = [width - inset, inset]; rad = trRad - inset; if (rad < 0) rad = 0; pt[1] += rad; ctx.lineTo( pt[0]+xOff, pt[1]+yOff ); // do the top right corner if (MathUtils.fpSign(rad) > 0) { ctx.quadraticCurveTo( width-inset+xOff, inset+yOff, width-inset-rad+xOff, inset+yOff ); } // do the top of the rectangle pt = [inset, inset]; rad = tlRad - inset; if (rad < 0) rad = 0; pt[0] += rad; ctx.lineTo( pt[0]+xOff, pt[1]+yOff ); // do the top left corner if (MathUtils.fpSign(rad) > 0) { ctx.quadraticCurveTo( inset+xOff, inset+yOff, inset+xOff, inset+rad+yOff ); } else { ctx.lineTo( inset+xOff, 2*inset+yOff ); } } } }, render: { value: function() { // get the world var world = this.getWorld(); if (!world) throw( "null world in rectangle render" ); // get the context var ctx = world.get2DContext(); if (!ctx) return; // get some dimensions var lw = this._strokeWidth; var w = world.getViewportWidth(), h = world.getViewportHeight(); var c, inset, gradient, colors, len, n, position, cs; // render the fill ctx.beginPath(); if (this._fillColor) { inset = Math.ceil( lw ) - 0.5; if(this._fillColor.gradientMode) { if(this._fillColor.gradientMode === "radial") { var ww = w - 2*lw, hh = h - 2*lw; gradient = ctx.createRadialGradient(w/2, h/2, 0, w/2, h/2, Math.max(ww, hh)/2); } else { gradient = ctx.createLinearGradient(inset, h/2, w-inset, h/2); } colors = this._fillColor.color; len = colors.length; for(n=0; n (this._xOffset + this._width)) return false; if(y < this._yOffset) return false; if(y > (this._yOffset + this._height)) return false; return true; } }, containsPoint: { value: 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 center and dimensions of the rect in NDC var vpw = world.getViewportWidth(), vph = world.getViewportHeight(); var xNDC = 2*this._xOffset/vpw, yNDC = 2*this._yOffset/vph, hw = this._width/vpw, hh = this._height/vph; var x = planePtNDC[0], y = planePtNDC[1]; if (x < (xNDC - hw)) return false; if (x > (xNDC + hw)) return false; if (y < (yNDC - hh)) return false; if (y > (yNDC + hh)) return false; return true; } }, getNearVertex: { value: 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, hwNDC = this._width/vpw, hhNDC = 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 near point in NDC var x = planePtNDC[0], y = planePtNDC[1]; var xMin = xNDC - hwNDC, xMax = xNDC + hwNDC, yMin = yNDC - hhNDC, yMax = yNDC + hhNDC; // compare the point against the 4 corners var pt, dist; pt = [xMin, yMin, 0]; dist = VecUtils.vecDist(2, pt, planePtNDC); var minPt = pt, minDist = dist; pt = [xMin, yMax, 0]; dist = VecUtils.vecDist(2, pt, planePtNDC); if (dist < minDist) { minDist = dist; minPt = pt; } pt = [xMax, yMax, 0]; dist = VecUtils.vecDist(2, pt, planePtNDC); if (dist < minDist) { minDist = dist; minPt = pt; } pt = [xMax, yMin, 0]; dist = VecUtils.vecDist(2, pt, planePtNDC); if (dist < minDist) { minDist = dist; minPt = pt; } // convert to GL coordinates x = minPt[0]; y = minPt[1]; 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 objPt = [0,0,0]; objPt[0] = -z*(r-l)/(2.0*zn)*x; objPt[1] = -z*(t-b)/(2.0*zn)*y; // re-apply the transform objPt = MathUtils.transformPoint( objPt, mat ); return objPt; } }, getNearPoint: { value: 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 = 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, hwNDC = this._width/vpw, hhNDC = 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 near point in NDC var x = planePtNDC[0], y = planePtNDC[1]; var xMin = xNDC - hwNDC, xMax = xNDC + hwNDC, yMin = yNDC - hhNDC, yMax = yNDC + hhNDC; // compare the point against the near point on the 4 sides var pt, dist; pt = [xMin, y, 0]; if (pt[1] < yMin) pt[1] = yMin; else if (pt[1] > yMax) pt[1] = yMax; dist = VecUtils.vecDist(2, pt, planePtNDC); var minPt = pt, minDist = dist; pt = [x, yMax, 0]; if (pt[0] < xMin) pt[0] = xMin; else if (pt[0] > xMax) pt[0] = xMax; dist = VecUtils.vecDist(2, pt, planePtNDC); if (dist < minDist) { minDist = dist; minPt = pt; } pt = [xMax, y, 0]; if (pt[1] < yMin) pt[1] = yMin; else if (pt[1] > yMax) pt[1] = yMax; dist = VecUtils.vecDist(2, pt, planePtNDC); if (dist < minDist) { minDist = dist; minPt = pt; } pt = [x, yMin, 0]; if (pt[0] < xMin) pt[0] = xMin; else if (pt[0] > xMax) pt[0] = xMax; dist = VecUtils.vecDist(2, pt, planePtNDC); if (dist < minDist) { minDist = dist; minPt = pt; } // convert to GL coordinates x = minPt[0]; y = minPt[1]; 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 objPt = [0,0,0]; objPt[0] = -z*(r-l)/(2.0*zn)*x; objPt[1] = -z*(t-b)/(2.0*zn)*y; // re-apply the transform objPt = MathUtils.transformPoint( objPt, mat ); return objPt; } }, recalcTexMapCoords: { value: function(vrts, uvs) { var n = vrts.length/3; var ivrt = 0, iuv = 0; for (var i=0; i minDimen) tlRad = minDimen; if (blRad > minDimen) blRad = minDimen; if (brRad > minDimen) brRad = minDimen; if (trRad > minDimen) trRad = minDimen; // define some local variables this.vertices = []; this.normals = []; this.uvs = []; this.indices = []; // the center of the rectangle is the first vertex RectangleFill.pushVertex( x, y, z ); // traverse the perimiter of the rectangle // push the starting point RectangleFill.pushVertex( x-hw, y+hh-tlRad, z); // do the left side var ctr; if (blRad <= 0){ RectangleFill.pushVertex( x-hw, y-hh, z); } else { ctr = [x - hw + blRad, y - hh + blRad, z]; RectangleFill.getRoundedCorner( ctr, [x-hw, y-hh+blRad, z], this.vertices ); } // do the bottom if (brRad <= 0) { RectangleFill.pushVertex( x+hw, y-hh, z); } else { ctr = [x + hw - brRad, y - hh + brRad, z]; RectangleFill.getRoundedCorner( ctr, [x+hw-brRad, y-hh, z], this.vertices ); } // do the right if (trRad <= 0) { RectangleFill.pushVertex( x+hw, y+hh, z); } else { ctr = [x + hw - trRad, y + hh - trRad, z]; RectangleFill.getRoundedCorner( ctr, [x+hw, y+hh-trRad, z], this.vertices ); } // do the top if (tlRad <= 0) { RectangleFill.pushVertex( x-hw, y+hh, z); } else { ctr = [x - hw + tlRad, y + hh - tlRad, z]; RectangleFill.getRoundedCorner( ctr, [x-hw+tlRad, y+hh, z], this.vertices ); } // get the normals and uvs var vrt, uv; var xMin = x - hw, yMin = y - hh; var n = [0, 0, 1]; var nVertices = this.vertices.length / 3; for (var i=0; i minDimen) tlRad = minDimen; if (blRad > minDimen) blRad = minDimen; if (brRad > minDimen) brRad = minDimen; if (trRad > minDimen) trRad = minDimen; // define some local variables this.vertices = []; this.normals = []; this.uvs = []; this.indices = []; // get the starting points if (tlRad == 0) { RectangleStroke.pushVertex( x-hw+sw, y+hh-sw, z); RectangleStroke.pushVertex( x-hw, y+hh, z); } else { if (tlRad > sw) { RectangleStroke.pushVertex( x-hw+sw, y+hh-tlRad, z); RectangleStroke.pushVertex( x-hw, y+hh-tlRad, z); } else { RectangleStroke.pushVertex( x-hw+tlRad, y+hh-tlRad, z); RectangleStroke.pushVertex( x-hw, y+hh-tlRad, z); RectangleStroke.pushVertex( x-hw+sw, y+hh-sw, z); RectangleStroke.pushVertex( x-hw, y+hh-sw, z); } } // get the left side if (blRad == 0) { RectangleStroke.pushVertex( x-hw+sw, y-hh+sw, z); RectangleStroke.pushVertex( x-hw, y-hh, z); } else { if (blRad >= sw) { RectangleStroke.pushVertex( x-hw+sw, y-hh+blRad, z); RectangleStroke.pushVertex( x-hw, y-hh+blRad, z); var ctr = [x-hw+blRad, y-hh+blRad, z], insidePt = [x-hw+sw, y-hh+blRad, z], outsidePt = [x-hw, y-hh+blRad, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); } else { RectangleStroke.pushVertex( x-hw+sw, y-hh+sw, z); RectangleStroke.pushVertex( x-hw, y-hh+blRad, z); var ctr = [x-hw+blRad, y-hh+blRad, z], insidePt = [x-hw+blRad, y-hh+blRad, z], outsidePt = [x-hw, y-hh+blRad, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); RectangleStroke.pushVertex( x-hw+sw, y-hh+sw, z); RectangleStroke.pushVertex( x-hw+sw, y-hh, z); } } // get the bottom if (brRad == 0) { RectangleStroke.pushVertex( x+hw-sw, y-hh+sw, z); RectangleStroke.pushVertex( x+hw, y-hh, z); } else { RectangleStroke.pushVertex( x+hw-brRad, y-hh+sw, z); RectangleStroke.pushVertex( x+hw-brRad, y-hh, z); if (brRad >= sw) { var ctr = [x+hw-brRad, y-hh+brRad, z], insidePt = [x+hw-brRad, y-hh+sw, z], outsidePt = [x+hw-brRad, y-hh, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); } else { RectangleStroke.pushVertex( x+hw-sw, y-hh+sw, z); RectangleStroke.pushVertex( x+hw-brRad, y-hh, z); var ctr = [x+hw-brRad, y-hh+brRad, z], insidePt = [x+hw-brRad, y-hh+brRad, z], outsidePt = [x+hw-brRad, y-hh, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); RectangleStroke.pushVertex( x+hw-sw, y-hh+sw, z); RectangleStroke.pushVertex( x+hw, y-hh+sw, z); } } // get the right if (trRad == 0) { RectangleStroke.pushVertex( x+hw-sw, y+hh-sw, z); RectangleStroke.pushVertex( x+hw, y+hh, z); } else { if (trRad >= sw) { RectangleStroke.pushVertex( x+hw-sw, y+hh-trRad, z); RectangleStroke.pushVertex( x+hw, y+hh-trRad, z); var ctr = [x+hw-trRad, y+hh-trRad, z], insidePt = [x+hw-sw, y+hh-trRad, z], outsidePt = [x+hw, y+hh-trRad, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); } else { RectangleStroke.pushVertex( x+hw-sw, y+hh-sw, z); RectangleStroke.pushVertex( x+hw, y+hh-trRad, z); var ctr = [x+hw-trRad, y+hh-trRad, z], insidePt = [x+hw-trRad, y+hh-trRad, z], outsidePt = [x+hw, y+hh-trRad, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); RectangleStroke.pushVertex( x+hw-sw, y+hh-sw, z); RectangleStroke.pushVertex( x+hw-sw, y+hh, z); } } // get the top if (tlRad == 0) { RectangleStroke.pushVertex( x-hw+sw, y+hh-sw, z); RectangleStroke.pushVertex( x-hw, y+hh, z); } else { if (tlRad >= sw) { RectangleStroke.pushVertex( x-hw+tlRad, y+hh-sw, z); RectangleStroke.pushVertex( x-hw+tlRad, y+hh, z); var ctr = [x-hw+tlRad, y+hh-tlRad, z], insidePt = [x-hw+tlRad, y+hh-sw, z], outsidePt = [x-hw+tlRad, y+hh, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); } else { RectangleStroke.pushVertex( x-hw+sw, y+hh-sw, z); RectangleStroke.pushVertex( x-hw+tlRad, y+hh, z); var ctr = [x-hw+tlRad, y+hh-tlRad, z], insidePt = [x-hw+tlRad, y+hh-tlRad, z], outsidePt = [x-hw+tlRad, y+hh, z]; RectangleStroke.getRoundedCorner( ctr, insidePt, outsidePt, this.vertices ); } } // get the normals and uvs var vrt, uv; var xMin = x - hw, yMin = y - hh; var n = [0, 0, 1]; var nVertices = this.vertices.length / 3; for (var i=0; i