/*
Copyright (c) 2012, Motorola Mobility, Inc
All Rights Reserved.
BSD License.
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 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 OWNER 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();
} else {
this._strokeMaterial = MaterialsModel.getMaterial( MaterialsModel.getDefaultMaterialName() ).dup();
}
if (strokeColor && this._strokeMaterial.hasProperty( "color" )) this._strokeMaterial.setProperty( "color", this._strokeColor );
if(fillMaterial) {
this._fillMaterial = fillMaterial.dup();
} else {
this._fillMaterial = MaterialsModel.getMaterial( MaterialsModel.getDefaultMaterialName() ).dup();
}
if (fillColor && this._fillMaterial.hasProperty( "color" )) this._fillMaterial.setProperty( "color", this._fillColor );
}
},
///////////////////////////////////////////////////////////////////////
// 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() : MaterialsModel.getDefaultMaterialName(),
'fillMat' : this._fillMaterial ? this._fillMaterial.getName() : MaterialsModel.getDefaultMaterialName(),
'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;
var strokeMaterialName = jObj.strokeMat;
var fillMaterialName = jObj.fillMat;
var strokeMat = MaterialsModel.getMaterial( strokeMaterialName ).dup();
if (!strokeMat) {
console.log( "object material not found in library: " + strokeMaterialName );
strokeMat = MaterialsModel.getMaterial( MaterialsModel.getDefaultMaterialName() ).dup();
}
this._strokeMaterial = strokeMat;
if (this._strokeMaterial.hasProperty( 'color' ))
this._strokeMaterial.setProperty( 'color', this._strokeColor );
var fillMat = MaterialsModel.getMaterial( fillMaterialName ).dup();
if (!fillMat) {
console.log( "object material not found in library: " + fillMaterialName );
fillMat = MaterialsModel.getMaterial( MaterialsModel.getDefaultMaterialName() ).dup();
}
this._fillMaterial = fillMat;
if (this._fillMaterial.hasProperty( 'color' ))
this._fillMaterial.setProperty( 'color', this._fillColor );
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 strokeMaterial = this.makeStrokeMaterial();
var strokePrim = this.createStroke([x,y], 2*xFill, 2*yFill, strokeSize, tlRadius, blRadius, brRadius, trRadius, strokeMaterial);
strokeMaterial.fitToPrimitive( strokePrim );
this._primArray.push( strokePrim );
this._materialNodeArray.push( strokeMaterial.getMaterialNode() );
// fill
tlRadius -= strokeSize; if (tlRadius < 0) tlRadius = 0.0;
blRadius -= strokeSize; if (blRadius < 0) blRadius = 0.0;
brRadius -= strokeSize; if (brRadius < 0) brRadius = 0.0;
trRadius -= strokeSize; if (trRadius < 0) trRadius = 0.0;
xFill -= strokeSize;
yFill -= strokeSize;
var fillMaterial = this.makeFillMaterial();
//console.log( "fillMaterial: " + fillMaterial.getName() );
var fillPrim = this.createFill([x,y], 2*xFill, 2*yFill, tlRadius, blRadius, brRadius, trRadius, fillMaterial);
fillMaterial.fitToPrimitive( fillPrim );
this._primArray.push( fillPrim );
this._materialNodeArray.push( fillMaterial.getMaterialNode() );
world.updateObject(this);
}
},
renderQuadraticBezier: {
value: function(bPts, ctx) {
if (!bPts) return;
var nSegs = (bPts.length - 1)/2.0;
if (nSegs <= 0) return;
var index = 1;
for (var 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