API Documentation
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 375 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 375 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 608 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 608 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 639 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 639 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 656 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 656 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 690 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 690 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 690 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_geometry_glge_mesh.js.html, line: 690 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
1 /* 2 GLGE WebGL Graphics Engine 3 Copyright (c) 2010, Paul Brunt 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of GLGE nor the 14 names of its contributors may be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY 21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @fileOverview 31 * @name glge_mesh.js 32 * @author me@paulbrunt.co.uk 33 */ 34 35 36 (function(GLGE){ 37 38 39 40 41 42 /** 43 * @class Creates a new mesh 44 * @see GLGE.Object 45 * @augments GLGE.QuickNotation 46 * @augments GLGE.JSONLoader 47 * @augments GLGE.Events 48 */ 49 GLGE.Mesh=function(uid,windingOrder){ 50 this.GLbuffers=[]; 51 this.buffers=[]; 52 this.framePositions=[]; 53 this.frameNormals=[]; 54 this.frameTangents=[]; 55 this.UV=[]; 56 this.boneWeights=[]; 57 this.setBuffers=[]; 58 this.faces={}; 59 if (windingOrder!==undefined) 60 this.windingOrder=windingOrder; 61 else 62 this.windingOrder=GLGE.Mesh.WINDING_ORDER_UNKNOWN; 63 64 GLGE.Assets.registerAsset(this,uid); 65 }; 66 67 GLGE.Mesh.WINDING_ORDER_UNKNOWN=2; 68 GLGE.Mesh.WINDING_ORDER_CLOCKWISE=1; 69 GLGE.Mesh.WINDING_ORDER_COUNTER=0; 70 71 GLGE.augment(GLGE.QuickNotation,GLGE.Mesh); 72 GLGE.augment(GLGE.JSONLoader,GLGE.Mesh); 73 GLGE.augment(GLGE.Events,GLGE.Mesh); 74 GLGE.Mesh.prototype.gl=null; 75 GLGE.Mesh.prototype.className="Mesh"; 76 GLGE.Mesh.prototype.GLbuffers=null; 77 GLGE.Mesh.prototype.buffers=null; 78 GLGE.Mesh.prototype.setBuffers=null; 79 GLGE.Mesh.prototype.GLfaces=null; 80 GLGE.Mesh.prototype.faces=null; 81 GLGE.Mesh.prototype.UV=null; 82 GLGE.Mesh.prototype.joints=null; 83 GLGE.Mesh.prototype.invBind=null; 84 GLGE.Mesh.prototype.loaded=false; 85 /** 86 * @name GLGE.Mesh#shaderupdate 87 * @event fired when the shader needs updating 88 * @param {object} data 89 */ 90 91 /** 92 * Gets the bounding volume for the mesh 93 * @returns {GLGE.BoundingVolume} 94 */ 95 GLGE.Mesh.prototype.getBoundingVolume=function(){ 96 if(!this.positions) return new GLGE.BoundingVolume(0,0,0,0,0,0); 97 if(!this.boundingVolume){ 98 var minX,maxX,minY,maxY,minZ,maxZ; 99 var positions=this.positions; 100 for(var i=0;i<positions.length;i=i+3){ 101 if(i==0){ 102 minX=maxX=positions[i]; 103 minY=maxY=positions[i+1]; 104 minZ=maxZ=positions[i+2]; 105 }else{ 106 minX=Math.min(minX,positions[i]); 107 maxX=Math.max(maxX,positions[i]); 108 minY=Math.min(minY,positions[i+1]); 109 maxY=Math.max(maxY,positions[i+1]); 110 minZ=Math.min(minZ,positions[i+2]); 111 maxZ=Math.max(maxZ,positions[i+2]); 112 } 113 } 114 this.boundingVolume=new GLGE.BoundingVolume(minX,maxX,minY,maxY,minZ,maxZ); 115 } 116 return this.boundingVolume; 117 } 118 /** 119 * Sets the joints 120 * @param {string[]} jsArray set joint objects 121 */ 122 GLGE.Mesh.prototype.setJoints=function(jsArray){ 123 this.joints=jsArray; 124 this.fireEvent("shaderupdate",{}); 125 return this; 126 } 127 /** 128 * Sets the inverse bind matrix for each joint 129 * @param {GLGE.Matrix[]} jsArray set joint names 130 */ 131 GLGE.Mesh.prototype.setInvBindMatrix=function(jsArray){ 132 this.invBind=jsArray; 133 this.fireEvent("shaderupdate",{}); 134 return this; 135 } 136 /** 137 * Sets the joint channels for each vertex 138 * @param {Number[]} jsArray The 1 dimentional array of bones 139 * @param {Number} num the number of chanels in this mesh 140 */ 141 GLGE.Mesh.prototype.setVertexJoints=function(jsArray,num){ 142 if(!num){ 143 num=jsArray.length*3/this.positions.length; 144 } 145 if(num<5){ 146 this.setBuffer("joints1",jsArray,num); 147 }else{ 148 var jsArray1=[]; 149 var jsArray2=[]; 150 for(var i=0;i<jsArray.length;i++){ 151 if(i%num<4){ 152 jsArray1.push(jsArray[i]); 153 }else{ 154 jsArray2.push(jsArray[i]); 155 } 156 157 } 158 this.setBuffer("joints1",jsArray1,4); 159 this.setBuffer("joints2",jsArray2,num-4); 160 } 161 this.fireEvent("shaderupdate",{}); 162 return this; 163 } 164 /** 165 * Sets the joint weights on each vertex 166 * @param {Number[]} jsArray The 1 dimentional array of weights 167 * @param {Number} num the number of chanels in this mesh 168 */ 169 GLGE.Mesh.prototype.setVertexWeights=function(jsArray,num){ 170 if(!num){ 171 num=jsArray.length*3/this.positions.length; 172 } 173 //normalize the weights! 174 for(var i=0;i<jsArray.length;i=i+parseInt(num)){ 175 var total=0; 176 for(var n=0;n<num;n++){ 177 total+=parseFloat(jsArray[i+n]); 178 } 179 if(total==0) total=1; 180 for(var n=0;n<num;n++){ 181 jsArray[i+n]=jsArray[i+n]/total; 182 } 183 } 184 185 186 if(num<4){ 187 this.setBuffer("weights1",jsArray,num); 188 }else{ 189 var jsArray1=[]; 190 var jsArray2=[]; 191 for(var i=0;i<jsArray.length;i++){ 192 if(i%num<4){ 193 jsArray1.push(jsArray[i]); 194 }else{ 195 jsArray2.push(jsArray[i]); 196 } 197 } 198 this.setBuffer("weights1",jsArray1,4); 199 this.setBuffer("weights2",jsArray2,num-4); 200 } 201 this.fireEvent("shaderupdate",{}); 202 return this; 203 } 204 /** 205 * clears any buffers currently set 206 * @param {Number[]} jsArray the UV coords in a 1 dimentional array 207 */ 208 GLGE.Mesh.prototype.clearBuffers=function(){ 209 //if(this.GLfaces) this.gl.deleteBuffer(this.GLfaces); 210 this.GLFaces=null; 211 delete(this.GLFaces); 212 for(var i in this.buffers){ 213 //if(this.buffers[i].GL) this.gl.deleteBuffer(this.buffers[i].GL); 214 this.buffers[i]=null; 215 delete(this.buffers[i]); 216 } 217 this.buffers=[]; 218 this.loaded=false; 219 } 220 /** 221 * Set the UV coord for the first UV layer 222 * @param {Number[]} jsArray the UV coords in a 1 dimentional array 223 */ 224 GLGE.Mesh.prototype.setUV=function(jsArray){ 225 this.uv1set=jsArray; 226 var idx=0; 227 for(var i=0; i<jsArray.length;i=i+2){ 228 this.UV[idx]=jsArray[i]; 229 this.UV[idx+1]=jsArray[i+1]; 230 if(!this.UV[idx+2]) this.UV[idx+2]=jsArray[i];//<-- hack in case the collada file only specified UV1 but accesses UV2 and expects the UV1 coordinates to be properly reflected there 231 if(!this.UV[idx+3]) this.UV[idx+3]=jsArray[i+1]; 232 idx=idx+4; 233 } 234 this.setBuffer("UV",this.UV,4); 235 return this; 236 } 237 /** 238 * Set the UV coord for the second UV layer 239 * @param {Number[]} jsArray the UV coords in a 1 dimentional array 240 */ 241 GLGE.Mesh.prototype.setUV2=function(jsArray){ 242 this.uv2set=jsArray; 243 var idx=0; 244 for(var i=0; i<jsArray.length;i=i+2){ 245 if(!this.UV[idx]) this.UV[idx]=jsArray[i]; 246 if(!this.UV[idx+1]) this.UV[idx+1]=jsArray[i+1]; 247 this.UV[idx+2]=jsArray[i]; 248 this.UV[idx+3]=jsArray[i+1]; 249 idx=idx+4; 250 } 251 this.setBuffer("UV",this.UV,4); 252 return this; 253 } 254 /** 255 * Sets the positions of the verticies 256 * @param {Number[]} jsArray The 1 dimentional array of positions 257 * @param {number} frame optional mesh frame number 258 */ 259 GLGE.Mesh.prototype.setPositions=function(jsArray,frame){ 260 if(!frame) frame=0; 261 this.loaded=true; 262 if(frame==0) this.positions=jsArray; 263 this.framePositions[frame]=jsArray; 264 this.setBuffer("position"+frame,jsArray,3,true); 265 this.boundingVolume=null; 266 this.fireEvent("updatebound"); 267 return this; 268 } 269 /** 270 * Sets the colors of the verticies 271 * @param {Number[]} jsArray The vertex colors 272 */ 273 GLGE.Mesh.prototype.setVertexColors=function(jsArray){ 274 this.colors=jsArray; 275 this.setBuffer("color",jsArray,4); 276 return this; 277 } 278 /** 279 * Sets the normals of the verticies 280 * @param {Number[]} jsArray The 1 dimentional array of normals 281 * @param {number} frame optional mesh frame number 282 */ 283 GLGE.Mesh.prototype.setNormals=function(jsArray,frame){ 284 if(!frame) frame=0; 285 if(frame==0) this.normals=jsArray; 286 this.frameNormals[frame]=jsArray; 287 this.setBuffer("normal"+frame,jsArray,3,true); 288 return this; 289 290 } 291 /** 292 * Sets the tangents of the verticies 293 * @param {Number[]} jsArray The 1 dimentional array of tangents 294 * @param {number} frame optional mesh frame number 295 */ 296 GLGE.Mesh.prototype.setTangents=function(jsArray,frame){ 297 if(!frame) frame=0; 298 if(frame==0) this.tangents=jsArray; 299 this.frameTangents[frame]=jsArray; 300 this.setBuffer("tangent"+frame,jsArray,3,true); 301 return this; 302 } 303 304 305 /** 306 * Sets a buffer for the 307 * @param {String} boneName The name of the bone 308 * @param {Number[]} jsArray The 1 dimentional array of weights 309 * @private 310 */ 311 GLGE.Mesh.prototype.setBuffer=function(bufferName,jsArray,size,exclude){ 312 //make sure all jsarray items are floats 313 if(typeof jsArray[0] !="number") for(var i=0;i<jsArray.length;i++) jsArray[i]=parseFloat(jsArray[i]); 314 315 var buffer; 316 for(var i=0;i<this.buffers.length;i++){ 317 if(this.buffers[i].name==bufferName) buffer=i; 318 } 319 if(!buffer){ 320 this.buffers.push({name:bufferName,data:jsArray,size:size,GL:false,exclude:exclude}); 321 } 322 else 323 { 324 this.buffers[buffer]={name:bufferName,data:jsArray,size:size,GL:false,exclude:exclude}; 325 } 326 return this; 327 } 328 329 /** 330 * gets a vert tangent 331 * @private 332 */ 333 GLGE.Mesh.prototype.tangentFromUV=function(p1,p2,p3,uv1,uv2,uv3,n){ 334 var toUnitVec3=GLGE.toUnitVec3; 335 var subVec3=GLGE.subVec3; 336 var scaleVec3=GLGE.scaleVec3; 337 var dotVec3=GLGE.dotVec3; 338 var crossVec3=GLGE.crossVec3; 339 340 uv21=[uv2[0]-uv1[0],uv2[1]-uv1[1]]; 341 uv31=[uv3[0]-uv1[0],uv3[1]-uv1[1]]; 342 343 p21=GLGE.subVec3(p2,p1); 344 p31=GLGE.subVec3(p3,p1); 345 var s=(uv21[0]*uv31[1]-uv31[0]*uv21[1]); 346 347 if(s!=0){ 348 s=1/s; 349 var t=subVec3(scaleVec3(p21,uv31[1]*s),scaleVec3(p31,uv21[1]*s)); 350 var b=subVec3(scaleVec3(p31,uv21[0]*s),scaleVec3(p21,uv31[0]*s)); 351 }else{ 352 t=[0,0,0]; 353 b=[0,0,0]; 354 } 355 if(GLGE.dotVec3(GLGE.crossVec3(p21,p31),n)>0){ 356 t=scaleVec3(t,-1); 357 b=scaleVec3(b,-1); 358 } 359 return [t,b]; 360 } 361 362 /** 363 * Sets the faces for this mesh 364 * @param {Number[]} jsArray The 1 dimentional array of normals 365 */ 366 GLGE.Mesh.prototype.setFaces=function(jsArray){ 367 this.faces={data:jsArray,GL:false}; 368 //if at this point calculate normals if we haven't got them yet 369 if(!this.normals) this.calcNormals(); 370 if(!this.tangents && this.UV.length>0) this.calcTangents(); 371 372 return this; 373 } 374 375 376 /** 377 * Calculates the tangents for this mesh - this is messy FIX ME! 378 * @private 379 */ 380 GLGE.Mesh.prototype.calcTangents=function(){ 381 382 for(var j=0;j<this.framePositions.length;j++){ 383 var position=this.framePositions[j]; 384 var normal=this.frameNormals[j]; 385 var uv=this.UV; 386 var tangentArray=[]; 387 var data={}; 388 var ref; 389 for(var i=0;i<position.length;i++){ 390 tangentArray[i]=0; 391 } 392 for(var i=0;i<this.faces.data.length;i=i+3){ 393 var p1=[position[(parseInt(this.faces.data[i]))*3],position[(parseInt(this.faces.data[i]))*3+1],position[(parseInt(this.faces.data[i]))*3+2]]; 394 var p2=[position[(parseInt(this.faces.data[i+1]))*3],position[(parseInt(this.faces.data[i+1]))*3+1],position[(parseInt(this.faces.data[i+1]))*3+2]]; 395 var p3=[position[(parseInt(this.faces.data[i+2]))*3],position[(parseInt(this.faces.data[i+2]))*3+1],position[(parseInt(this.faces.data[i+2]))*3+2]]; 396 397 var n1=[normal[(parseInt(this.faces.data[i]))*3],normal[(parseInt(this.faces.data[i]))*3+1],normal[(parseInt(this.faces.data[i]))*3+2]]; 398 var n2=[normal[(parseInt(this.faces.data[i+1]))*3],normal[(parseInt(this.faces.data[i+1]))*3+1],normal[(parseInt(this.faces.data[i+1]))*3+2]]; 399 var n3=[normal[(parseInt(this.faces.data[i+2]))*3],normal[(parseInt(this.faces.data[i+2]))*3+1],normal[(parseInt(this.faces.data[i+2]))*3+2]]; 400 401 var uv1=[uv[(parseInt(this.faces.data[i]))*4],uv[(parseInt(this.faces.data[i]))*4+1]]; 402 var uv2=[uv[(parseInt(this.faces.data[i+1]))*4],uv[(parseInt(this.faces.data[i+1]))*4+1]]; 403 var uv3=[uv[(parseInt(this.faces.data[i+2]))*4],uv[(parseInt(this.faces.data[i+2]))*4+1]]; 404 405 var tb=this.tangentFromUV(p2,p1,p3,uv2,uv1,uv3,n2); 406 407 if(!data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")]){ 408 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")]=tb; 409 }else{ 410 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][0][0]+=tb[0][0]; 411 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][0][1]+=tb[0][1]; 412 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][0][2]+=tb[0][2]; 413 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][1][0]+=tb[1][0]; 414 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][1][1]+=tb[1][1]; 415 data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][1][2]+=tb[1][2]; 416 } 417 if(!data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")]){ 418 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")]=tb; 419 }else{ 420 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")][0][0]+=tb[0][0]; 421 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")][0][1]+=tb[0][1]; 422 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")][0][2]+=tb[0][2]; 423 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")][1][0]+=tb[1][0]; 424 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")][1][1]+=tb[1][1]; 425 data[[p2[0],p2[1],p2[2],uv2[0],uv2[1],n2[0],n2[1],n2[2]].join(",")][1][2]+=tb[1][2]; 426 } 427 if(!data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")]){ 428 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")]=tb; 429 }else{ 430 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")][0][0]+=tb[0][0]; 431 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")][0][1]+=tb[0][1]; 432 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")][0][2]+=tb[0][2]; 433 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")][1][0]+=tb[1][0]; 434 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")][1][1]+=tb[1][1]; 435 data[[p3[0],p3[1],p3[2],uv3[0],uv3[1],n3[0],n3[1],n3[2]].join(",")][1][2]+=tb[1][2]; 436 } 437 438 } 439 for(var i=0;i<position.length/3;i++){ 440 var p1=[position[i*3],position[i*3+1],position[i*3+2]]; 441 var n1=[normal[i*3],normal[i*3+1],normal[i*3+2]]; 442 var uv1=[uv[i*4],uv[i*4+1]]; 443 try{ 444 var t=GLGE.toUnitVec3(data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][0]); 445 var b=GLGE.toUnitVec3(data[[p1[0],p1[1],p1[2],uv1[0],uv1[1],n1[0],n1[1],n1[2]].join(",")][1]); 446 }catch(e){ 447 //if we fail probably a exporter bug carry on anyway 448 } 449 if(t){ 450 tangentArray[i*3]=t[0]; 451 tangentArray[i*3+1]=t[1]; 452 tangentArray[i*3+2]=t[2]; 453 } 454 } 455 this.setTangents(tangentArray,j); 456 } 457 458 } 459 460 /** 461 * Sets the faces for this mesh 462 * @param {Number[]} jsArray The 1 dimentional array of normals 463 * @private 464 */ 465 GLGE.Mesh.prototype.GLSetFaceBuffer=function(gl){ 466 if(!this.GLfaces) this.GLfaces = gl.createBuffer(); 467 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces); 468 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.faces.data), gl.STATIC_DRAW); 469 this.GLfaces.itemSize = 1; 470 this.GLfaces.numItems = this.faces.data.length; 471 } 472 /** 473 * Sets up a GL Buffer 474 * @param {WebGLContext} gl The context being drawn on 475 * @param {String} bufferName The name of the buffer to create 476 * @param {Number[]} jsArray The data to add to the buffer 477 * @param {Number} size Size of a single element within the array 478 * @private 479 */ 480 GLGE.Mesh.prototype.GLSetBuffer=function(gl,bufferName,jsArray,size){ 481 if(!this.GLbuffers[bufferName]) this.GLbuffers[bufferName] = gl.createBuffer(); 482 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers[bufferName]); 483 if(!jsArray.byteLength) jsArray=new Float32Array(jsArray); 484 gl.bufferData(gl.ARRAY_BUFFER, jsArray, gl.STATIC_DRAW); 485 this.GLbuffers[bufferName].itemSize = size; 486 this.GLbuffers[bufferName].numItems = jsArray.length/size; 487 }; 488 /** 489 * Calculates the normals for this mesh 490 * @private 491 */ 492 GLGE.Mesh.prototype.calcNormals=function(){ 493 for(var n=0;n<this.framePositions.length;n++){ 494 var normals=[]; 495 var positions=this.framePositions[n]; 496 var faces=this.faces.data; 497 if(!faces){ 498 faces=[]; 499 for(var i=0;i<positions.length/3;i++) faces[i]=i; 500 } 501 for(var i=0;i<faces.length;i=i+3){ 502 var v1=[positions[faces[i]*3],positions[faces[i]*3+1],positions[faces[i]*3+2]]; 503 var v2=[positions[faces[i+1]*3],positions[faces[i+1]*3+1],positions[faces[i+1]*3+2]]; 504 var v3=[positions[faces[i+2]*3],positions[faces[i+2]*3+1],positions[faces[i+2]*3+2]]; 505 var vec1=GLGE.subVec3(v2,v1); 506 var vec2=GLGE.subVec3(v3,v1); 507 var norm=GLGE.toUnitVec3(GLGE.crossVec3(vec1,vec2)); 508 if(normals[faces[i]]==undefined) normals[faces[i]]=[]; 509 normals[faces[i]].push(norm); 510 if(normals[faces[i+1]]==undefined) normals[faces[i+1]]=[]; 511 normals[faces[i+1]].push(norm); 512 if(normals[faces[i+2]]==undefined) normals[faces[i+2]]=[]; 513 normals[faces[i+2]].push(norm); 514 } 515 var norms=[]; 516 for(i=0;i<normals.length;i++){ 517 var x=0,y=0,z=0; 518 if(normals[i]!=undefined){ 519 for(var j=0;j<normals[i].length;j++){ 520 x+=normals[i][j][0]; 521 y+=normals[i][j][1]; 522 z+=normals[i][j][2]; 523 } 524 x/=normals[i].length; 525 y/=normals[i].length; 526 z/=normals[i].length; 527 norms[i*3]=x; 528 norms[i*3+1]=y; 529 norms[i*3+2]=z; 530 } 531 } 532 this.setNormals(norms,n); 533 } 534 } 535 /** 536 * Calculates a ambient occlution effect and sets the vertex color with AO level 537 */ 538 GLGE.Mesh.prototype.calcFauxAO=function(){ 539 this.optimize(); 540 541 //calculate ambient color based on vertex angles 542 var verts=this.positions; 543 var faces=this.faces.data; 544 var normals=this.normals; 545 546 var idx=[]; 547 var len=verts.length/3 548 for(var i=0;i<len;i++){ 549 idx.push([]); 550 } 551 for(var i=0;i<faces.length;i=i+3){ 552 idx[faces[i]].push(faces[i+1]); 553 idx[faces[i]].push(faces[i+2]); 554 idx[faces[i+1]].push(faces[i]); 555 idx[faces[i+1]].push(faces[i+2]); 556 idx[faces[i+2]].push(faces[i]); 557 idx[faces[i+2]].push(faces[i+1]); 558 } 559 var ao=[]; 560 for(var i=0;i<len;i++){ 561 var AOfactor=0; 562 var normal=[normals[i*3],normals[i*3+1],normals[i*3+2]]; 563 for(var j=0;j<idx[i].length;j++){ 564 var f=idx[i][j]; 565 var v=[verts[f*3]-verts[i*3],verts[f*3+1]-verts[i*3+1],verts[f*3+2]-verts[i*3+2]]; 566 v=GLGE.toUnitVec3(v); 567 AOfactor+=v[0]*normal[0]+v[1]*normal[1]+v[2]*normal[2]; 568 } 569 AOfactor/=idx[i].length; 570 AOfactor=1.0-(AOfactor+1)*0.5; 571 ao.push(AOfactor); 572 ao.push(AOfactor); 573 ao.push(AOfactor); 574 ao.push(1); 575 } 576 this.setVertexColors(ao); 577 } 578 /** 579 * optimize geometry 580 * @private 581 */ 582 GLGE.Mesh.prototype.optimize=function(){ 583 var verts=this.positions; 584 var normals=this.normals; 585 var faces=this.faces.data; 586 var tangents=this.tangents; 587 var uv1=this.uv1set; 588 var uv2=this.uv2set; 589 //expand out the faces 590 var vertsTemp=[]; 591 var normalsTemp=[]; 592 var uv1Temp=[]; 593 var uv2Temp=[]; 594 var tangentsTemp=[]; 595 if(faces){ 596 for(var i=0;i<faces.length;i++){ 597 vertsTemp.push(verts[faces[i]*3]); 598 vertsTemp.push(verts[faces[i]*3+1]); 599 vertsTemp.push(verts[faces[i]*3+2]); 600 normalsTemp.push(normals[faces[i]*3]); 601 normalsTemp.push(normals[faces[i]*3+1]); 602 normalsTemp.push(normals[faces[i]*3+2]); 603 if(tangents && tangents.length>0){ 604 tangentsTemp.push(tangents[faces[i]*3]); 605 tangentsTemp.push(tangents[faces[i]*3+1]); 606 tangentsTemp.push(tangents[faces[i]*3+2]); 607 } 608 if(uv1){ 609 uv1Temp.push(uv1[faces[i]*2]); 610 uv1Temp.push(uv1[faces[i]*2+1]); 611 } 612 if(uv2){ 613 uv2Temp.push(uv2[faces[i]*2]); 614 uv2Temp.push(uv2[faces[i]*2+1]); 615 } 616 } 617 }else{ 618 vertsTemp=verts; 619 normalsTemp=normals; 620 tangentsTemp=tangents; 621 uv1Temp=uv1; 622 uv2Temp=uv2; 623 } 624 625 var newVerts=[]; 626 var newNormals=[]; 627 var newFaces=[]; 628 var newUV1s=[]; 629 var newUV2s=[]; 630 var newTangents=[]; 631 var stack=[]; 632 633 for(var i=0;i<vertsTemp.length;i=i+3){ 634 if(uv1 && uv2){ 635 var idx=[vertsTemp[i],vertsTemp[i+1],vertsTemp[i+2],normalsTemp[i],normalsTemp[i+1],normalsTemp[i+2],uv1Temp[i/3*2],uv1Temp[i/3*2+1]].join(" "); 636 }else if(uv1){ 637 var idx=[vertsTemp[i],vertsTemp[i+1],vertsTemp[i+2],normalsTemp[i],normalsTemp[i+1],normalsTemp[i+2],uv1Temp[i/3*2],uv1Temp[i/3*2+1]].join(" "); 638 }else{ 639 var idx=[vertsTemp[i],vertsTemp[i+1],vertsTemp[i+2],normalsTemp[i],normalsTemp[i+1],normalsTemp[i+2]].join(" "); 640 } 641 var vertIdx=stack.indexOf(idx); 642 if(vertIdx<0){ 643 stack.push(idx); 644 vertIdx=stack.length-1; 645 newVerts.push(vertsTemp[i]); 646 newVerts.push(vertsTemp[i+1]); 647 newVerts.push(vertsTemp[i+2]); 648 newNormals.push(normalsTemp[i]); 649 newNormals.push(normalsTemp[i+1]); 650 newNormals.push(normalsTemp[i+2]); 651 if(tangents && tangents.length>0){ 652 newTangents.push(tangentsTemp[i]); 653 newTangents.push(tangentsTemp[i+1]); 654 newTangents.push(tangentsTemp[i+2]); 655 } 656 if(uv1){ 657 newUV1s.push(uv1Temp[i/3*2]); 658 newUV1s.push(uv1Temp[i/3*2+1]); 659 } 660 if(uv2){ 661 newUV2s.push(uv2Temp[i/3*2]); 662 newUV2s.push(uv2Temp[i/3*2+1]); 663 } 664 } 665 newFaces.push(vertIdx); 666 } 667 this.setPositions(newVerts).setNormals(newNormals).setFaces(newFaces).setUV(newUV1s).setUV2(newUV2s).setTangents(newTangents); 668 } 669 670 671 672 /** 673 * Sets the Attributes for this mesh 674 * @param {WebGLContext} gl The context being drawn on 675 * @private 676 */ 677 GLGE.Mesh.prototype.GLAttributes=function(gl,shaderProgram,frame1, frame2){ 678 this.gl=gl; 679 if(!frame1) frame1=0; 680 //if at this point we have no normals set then calculate them 681 if(!this.normals) this.calcNormals(); 682 //disable all the attribute initially arrays - do I really need this? 683 for(var i=0; i<8; i++) gl.disableVertexAttribArray(i); 684 //check if the faces have been updated 685 if(!this.faces.GL && this.faces.data && this.faces.data.length>0){ 686 this.GLSetFaceBuffer(gl); 687 this.faces.GL=true; 688 } 689 //loop though the buffers 690 for(i=0; i<this.buffers.length;i++){ 691 if(!this.buffers[i].GL){ 692 this.GLSetBuffer(gl,this.buffers[i].name,this.buffers[i].data,this.buffers[i].size); 693 this.buffers[i].GL=true; 694 } 695 attribslot=GLGE.getAttribLocation(gl,shaderProgram, this.buffers[i].name); 696 if(attribslot>-1){ 697 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers[this.buffers[i].name]); 698 gl.enableVertexAttribArray(attribslot); 699 gl.vertexAttribPointer(attribslot, this.GLbuffers[this.buffers[i].name].itemSize, gl.FLOAT, false, 0, 0); 700 } 701 } 702 703 //do the position normal and if we have tangent then tangent 704 var positionSlot=GLGE.getAttribLocation(gl,shaderProgram, "position"); 705 if(positionSlot>-1){ 706 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["position"+frame1]); 707 gl.enableVertexAttribArray(positionSlot); 708 gl.vertexAttribPointer(positionSlot, this.GLbuffers["position"+frame1].itemSize, gl.FLOAT, false, 0, 0); 709 } 710 var normalSlot=GLGE.getAttribLocation(gl,shaderProgram, "normal"); 711 if(normalSlot>-1){ 712 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["normal"+frame1]); 713 gl.enableVertexAttribArray(normalSlot); 714 gl.vertexAttribPointer(normalSlot, this.GLbuffers["normal"+frame1].itemSize, gl.FLOAT, false, 0, 0); 715 } 716 var tangentSlot=GLGE.getAttribLocation(gl,shaderProgram, "tangent"); 717 if(tangentSlot>-1){ 718 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["tangent"+frame1]); 719 gl.enableVertexAttribArray(tangentSlot); 720 gl.vertexAttribPointer(tangentSlot, this.GLbuffers["tangent"+frame1].itemSize, gl.FLOAT, false, 0, 0); 721 } 722 if(frame2!=undefined){ 723 var positionSlot2=GLGE.getAttribLocation(gl,shaderProgram, "position2"); 724 if(positionSlot2>-1){ 725 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["position"+frame2]); 726 gl.enableVertexAttribArray(positionSlot2); 727 gl.vertexAttribPointer(positionSlot2, this.GLbuffers["position"+frame2].itemSize, gl.FLOAT, false, 0, 0); 728 } 729 var normalSlot2=GLGE.getAttribLocation(gl,shaderProgram, "normal2"); 730 if(normalSlot2>-1){ 731 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["normal"+frame2]); 732 gl.enableVertexAttribArray(normalSlot2); 733 gl.vertexAttribPointer(normalSlot2, this.GLbuffers["normal"+frame2].itemSize, gl.FLOAT, false, 0, 0); 734 } 735 var tangentSlot2=GLGE.getAttribLocation(gl,shaderProgram, "tangent2"); 736 if(tangentSlot2>-1){ 737 gl.bindBuffer(gl.ARRAY_BUFFER, this.GLbuffers["tangent"+frame2]); 738 gl.enableVertexAttribArray(tangentSlot2); 739 gl.vertexAttribPointer(tangentSlot2, this.GLbuffers["tangent"+frame2].itemSize, gl.FLOAT, false, 0, 0); 740 } 741 } 742 } 743 744 745 })(GLGE);