1 /* 2 Copyright (c) 2008 Seneca College 3 Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/) 4 */ 5 6 /** 7 @class c3dl.Geometry is a container for the primitiveSets of a 8 geometric object. 9 */ 10 c3dl.Geometry = function() 11 { 12 // a geometry is composed of different collation elements (sets of primitives) 13 // collation elements are <triangles>, <polylist>, <polygon>, etc. 14 this.primitiveSets = []; 15 this.effect = null; 16 17 // the first time geometries are rendered, their VBO's need to 18 // be setup. Can't do this when Collada objects are created 19 // because we don't yet have a graphics context. 20 this.firstTimeRender = true; 21 22 /** 23 @private 24 25 Used by the collada loader 26 */ 27 this.addPrimitiveSet = function(primitiveSet) 28 { 29 this.primitiveSets.push(primitiveSet); 30 } 31 32 /** 33 @private 34 35 Used by the ColladaManager 36 */ 37 this.clone = function(other) 38 { 39 // 40 for(var i = 0; i < other.primitiveSets.length; i++) 41 { 42 this.primitiveSets.push( other.primitiveSets[i].getCopy()); 43 } 44 } 45 46 47 /** 48 @private 49 50 Used by the ColladaManager 51 */ 52 this.getCopy = function() 53 { 54 var geometry = new c3dl.Geometry(); 55 geometry.clone(this); 56 return geometry; 57 } 58 59 60 /** 61 @private 62 Get the effect of this geometry. 63 64 @param {c3dl.Effect} The effect of this geometry. 65 */ 66 this.getEffect = function() 67 { 68 return this.effect; 69 } 70 71 /** 72 Get the array of primitive sets for this geometry. 73 74 @returns {Array} The primitive sets for this geometry. 75 */ 76 this.getPrimitiveSets = function() 77 { 78 return this.primitiveSets; 79 } 80 81 82 /** 83 @private 84 85 Does the given ray intersect with any of the geometry's primitive set's 86 bounding spheres? 87 88 @param {Array} rayOrigin 89 @param {Array} rayDir 90 */ 91 this.rayIntersectsEnclosures = function(rayOrigin, rayDir) 92 { 93 var mat = c3dl.peekMatrix(); 94 95 for(var i = 0; i < this.primitiveSets.length; i++) 96 { 97 var bs = this.primitiveSets[i].getBoundingSphere(); 98 var longestVec; 99 100 var leftLen = c3dl.vectorLength([mat[0], mat[1], mat[2]]); 101 var upLen = c3dl.vectorLength([mat[4], mat[5], mat[6]]); 102 var dirLen = c3dl.vectorLength([mat[8], mat[9], mat[10]]); 103 104 longestVec = leftLen > upLen ? leftLen : upLen; 105 longestVec = longestVec > dirLen? longestVec : dirLen; 106 107 bs.setPosition([mat[12], mat[13], mat[14]]) 108 bs.scale([longestVec,longestVec,longestVec]); 109 110 if(c3dl.rayIntersectsSphere(rayOrigin, rayDir, bs.getPosition(), bs.getRadius())) 111 { 112 return true; 113 } 114 } 115 return false; 116 } 117 118 119 /** 120 @private 121 122 Does the mesh in this geometry node intersect with the ray? 123 124 @param {Array} rayOrigin 125 @param {Array} rayDir 126 */ 127 this.rayIntersectsTriangles = function(rayOrigin, rayDir) 128 { 129 var mat = c3dl.inverseMatrix(c3dl.peekMatrix()); 130 var rayorigin = c3dl.multiplyMatrixByVector(mat, rayOrigin); 131 var raydir = c3dl.normalizeVector(c3dl.multiplyMatrixByDirection(mat, rayDir)); 132 133 // allocate and resuse these vertices to prevent allocation and deletion every face. 134 var vert1 = new Array(3); 135 var vert2 = new Array(3); 136 var vert3 = new Array(3); 137 138 for(var i = 0; i < this.primitiveSets.length; i++) 139 { 140 var vertices = this.primitiveSets[i].getVertices(); 141 142 // Iterate over each face of the object and test it against the ray. 143 for (var j = 0; j < vertices.length; j += 9) 144 { 145 // 3 points of a triangle with the object's position offset 146 vert1[0] = vertices[j]; 147 vert1[1] = vertices[j+1] 148 vert1[2] = vertices[j+2]; 149 150 vert2[0] = vertices[j+3]; 151 vert2[1] = vertices[j+4]; 152 vert2[2] = vertices[j+5]; 153 154 vert3[0] = vertices[j+6]; 155 vert3[1] = vertices[j+7]; 156 vert3[2] = vertices[j+8]; 157 158 if (c3dl.rayIntersectsTriangle(rayorigin, raydir, vert1, vert2, vert3)) 159 { 160 return true; 161 } 162 } 163 } 164 return false; 165 } 166 167 168 169 /** 170 @private 171 172 Called automatically 173 */ 174 this.render = function(glCanvas3D, scene) 175 { 176 if (glCanvas3D == null) 177 { 178 c3dl.debug.logWarning('Geometry::render() called with a null glCanvas3D'); 179 return false; 180 } 181 182 // The first time this is rendered, setup VBOs. 183 if(this.firstTimeRender == true) 184 { 185 // iterate over the primitive sets and setup their VBOs 186 for(var i = 0; i < this.primitiveSets.length; i++) 187 { 188 this.primitiveSets[i].setupVBO(glCanvas3D); 189 } 190 this.firstTimeRender = false; 191 } 192 193 scene.getRenderer().renderGeometry(this); 194 195 if( scene.getBoundingVolumeVisibility() ) 196 { 197 // tell all the collation elements/ primitive sets to render their bounding spheres. 198 for(var i = 0; i < this.primitiveSets.length; i++) 199 { 200 var bs = this.primitiveSets[i].getBoundingSphere(); 201 if(bs) 202 { 203 bs.render(scene); 204 } 205 } 206 } 207 } 208 209 210 /** 211 @private 212 213 Set the effect of this geometry. The geometry has primitive sets, 214 but those cannot be set directly. All primitive sets under this 215 geometric object will be rendered the same. 216 217 @param {c3dl.Effect} effect 218 */ 219 this.setEffect = function(effect) 220 { 221 this.effect = effect; 222 } 223 224 225 /** 226 @private 227 228 @param {c3dl.Material} material 229 */ 230 this.setMaterial = function(material) 231 { 232 for(var i=0; i < this.primitiveSets.length; i++) 233 { 234 this.primitiveSets[i].setMaterial(material); 235 } 236 } 237 238 239 /** 240 @private 241 242 @param {} texture 243 */ 244 this.setTexture = function(texture) 245 { 246 for(var i=0; i < this.primitiveSets.length; i++) 247 { 248 this.primitiveSets[i].setTexture(texture); 249 } 250 } 251 252 253 /** 254 @private 255 256 Called automatically 257 */ 258 this.update = function(timeStep) 259 { 260 // 261 for(var i = 0; i < this.primitiveSets.length; i++) 262 { 263 var bs = this.primitiveSets[i].getBoundingSphere(); 264 if(bs) 265 { 266 //bs.setPosition(this.pos); 267 bs.setPosition([0,0,0]); 268 } 269 } 270 } 271 } 272