tsShape.cpp
Public Defines
define
tsalloc()
Public Variables
gTempNodeTransforms (__FILE__, __LINE__)
Detailed Description
Public Defines
tsalloc()
Public Variables
Vector< MatrixF > gTempNodeTransforms (__FILE__, __LINE__)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "ts/tsShape.h" 26 27#include "ts/tsLastDetail.h" 28#include "ts/tsMaterialList.h" 29#include "core/stringTable.h" 30#include "console/console.h" 31#include "ts/tsShapeInstance.h" 32#include "collision/convex.h" 33#include "materials/matInstance.h" 34#include "materials/materialManager.h" 35#include "math/mathIO.h" 36#include "core/util/endian.h" 37#include "core/stream/fileStream.h" 38#include "console/compiler.h" 39#include "core/fileObject.h" 40 41#ifdef TORQUE_COLLADA 42extern TSShape* loadColladaShape(const Torque::Path &path); 43#endif 44 45#ifdef TORQUE_ASSIMP 46extern TSShape* assimpLoadShape(const Torque::Path &path); 47#endif 48 49/// most recent version -- this is the version we write 50S32 TSShape::smVersion = 28; 51/// the version currently being read...valid only during a read 52S32 TSShape::smReadVersion = -1; 53const U32 TSShape::smMostRecentExporterVersion = DTS_EXPORTER_CURRENT_VERSION; 54 55F32 TSShape::smAlphaOutLastDetail = -1.0f; 56F32 TSShape::smAlphaInBillboard = 0.15f; 57F32 TSShape::smAlphaOutBillboard = 0.15f; 58F32 TSShape::smAlphaInDefault = -1.0f; 59F32 TSShape::smAlphaOutDefault = -1.0f; 60 61// don't bother even loading this many of the highest detail levels (but 62// always load last renderable detail) 63S32 TSShape::smNumSkipLoadDetails = 0; 64 65bool TSShape::smInitOnRead = true; 66bool TSShape::smUseHardwareSkinning = true; 67U32 TSShape::smMaxSkinBones = 70; 68 69 70TSShape::TSShape() 71{ 72 mExporterVersion = 124; 73 mSmallestVisibleSize = 2; 74 mSmallestVisibleDL = 0; 75 mRadius = 0; 76 mFlags = 0; 77 tubeRadius = 0; 78 data = NULL; 79 materialList = NULL; 80 mReadVersion = -1; // -1 means constructed from scratch (e.g., in exporter or no read yet) 81 mSequencesConstructed = false; 82 mShapeData = NULL; 83 mShapeDataSize = 0; 84 mVertexSize = 0; 85 mUseDetailFromScreenError = false; 86 mNeedReinit = false; 87 88 mDetailLevelLookup.setSize( 1 ); 89 mDetailLevelLookup[0].set( -1, 0 ); 90 91 VECTOR_SET_ASSOCIATION(sequences); 92 VECTOR_SET_ASSOCIATION(nodeRotations); 93 VECTOR_SET_ASSOCIATION(nodeTranslations); 94 VECTOR_SET_ASSOCIATION(nodeUniformScales); 95 VECTOR_SET_ASSOCIATION(nodeAlignedScales); 96 VECTOR_SET_ASSOCIATION(nodeArbitraryScaleRots); 97 VECTOR_SET_ASSOCIATION(nodeArbitraryScaleFactors); 98 VECTOR_SET_ASSOCIATION(groundRotations); 99 VECTOR_SET_ASSOCIATION(groundTranslations); 100 VECTOR_SET_ASSOCIATION(triggers); 101 VECTOR_SET_ASSOCIATION(billboardDetails); 102 VECTOR_SET_ASSOCIATION(detailCollisionAccelerators); 103 VECTOR_SET_ASSOCIATION(names); 104 105 VECTOR_SET_ASSOCIATION( nodes ); 106 VECTOR_SET_ASSOCIATION( objects ); 107 VECTOR_SET_ASSOCIATION( objectStates ); 108 VECTOR_SET_ASSOCIATION( subShapeFirstNode ); 109 VECTOR_SET_ASSOCIATION( subShapeFirstObject ); 110 VECTOR_SET_ASSOCIATION( detailFirstSkin ); 111 VECTOR_SET_ASSOCIATION( subShapeNumNodes ); 112 VECTOR_SET_ASSOCIATION( subShapeNumObjects ); 113 VECTOR_SET_ASSOCIATION( details ); 114 VECTOR_SET_ASSOCIATION( defaultRotations ); 115 VECTOR_SET_ASSOCIATION( defaultTranslations ); 116 117 VECTOR_SET_ASSOCIATION( subShapeFirstTranslucentObject ); 118 VECTOR_SET_ASSOCIATION( meshes ); 119 120 VECTOR_SET_ASSOCIATION( alphaIn ); 121 VECTOR_SET_ASSOCIATION( alphaOut ); 122} 123 124TSShape::~TSShape() 125{ 126 delete materialList; 127 128 S32 i; 129 130 // everything left over here is a legit mesh 131 for (i=0; i<meshes.size(); i++) 132 { 133 if (!meshes[i]) 134 continue; 135 136 // Handle meshes that were either assembled with the shape or added later 137 if (((S8*)meshes[i] >= mShapeData) && ((S8*)meshes[i] < (mShapeData + mShapeDataSize))) 138 destructInPlace(meshes[i]); 139 else 140 delete meshes[i]; 141 } 142 143 for (i=0; i<billboardDetails.size(); i++) 144 { 145 delete billboardDetails[i]; 146 billboardDetails[i] = NULL; 147 } 148 billboardDetails.clear(); 149 150 // Delete any generated accelerators 151 S32 dca; 152 for (dca = 0; dca < detailCollisionAccelerators.size(); dca++) 153 { 154 ConvexHullAccelerator* accel = detailCollisionAccelerators[dca]; 155 if (accel != NULL) { 156 delete [] accel->vertexList; 157 delete [] accel->normalList; 158 for (S32 j = 0; j < accel->numVerts; j++) 159 delete [] accel->emitStrings[j]; 160 delete [] accel->emitStrings; 161 delete accel; 162 } 163 } 164 for (dca = 0; dca < detailCollisionAccelerators.size(); dca++) 165 detailCollisionAccelerators[dca] = NULL; 166 167 if( mShapeData ) 168 delete[] mShapeData; 169} 170 171const String& TSShape::getName( S32 nameIndex ) const 172{ 173 AssertFatal(nameIndex>=0 && nameIndex<names.size(),"TSShape::getName"); 174 return names[nameIndex]; 175} 176 177const String& TSShape::getMeshName( S32 meshIndex ) const 178{ 179 S32 nameIndex = objects[meshIndex].nameIndex; 180 if ( nameIndex < 0 ) 181 return String::EmptyString; 182 183 return names[nameIndex]; 184} 185 186const String& TSShape::getNodeName( S32 nodeIndex ) const 187{ 188 S32 nameIdx = nodes[nodeIndex].nameIndex; 189 if ( nameIdx < 0 ) 190 return String::EmptyString; 191 192 return names[nameIdx]; 193} 194 195const String& TSShape::getSequenceName( S32 seqIndex ) const 196{ 197 AssertFatal(seqIndex >= 0 && seqIndex<sequences.size(),"TSShape::getSequenceName index beyond range"); 198 199 S32 nameIdx = sequences[seqIndex].nameIndex; 200 if ( nameIdx < 0 ) 201 return String::EmptyString; 202 203 return names[nameIdx]; 204} 205 206S32 TSShape::findName(const String &name) const 207{ 208 for (S32 i=0; i<names.size(); i++) 209 { 210 if (names[i].equal( name, String::NoCase )) 211 return i; 212 } 213 214 return -1; 215} 216 217const String& TSShape::getTargetName( S32 mapToNameIndex ) const 218{ 219 S32 targetCount = materialList->getMaterialNameList().size(); 220 221 if(mapToNameIndex < 0 || mapToNameIndex >= targetCount) 222 return String::EmptyString; 223 224 return materialList->getMaterialNameList()[mapToNameIndex]; 225} 226 227S32 TSShape::getTargetCount() const 228{ 229 if(!this) 230 return -1; 231 232 return materialList->getMaterialNameList().size(); 233 234} 235 236S32 TSShape::findNode(S32 nameIndex) const 237{ 238 for (S32 i=0; i<nodes.size(); i++) 239 if (nodes[i].nameIndex==nameIndex) 240 return i; 241 return -1; 242} 243 244S32 TSShape::findObject(S32 nameIndex) const 245{ 246 for (S32 i=0; i<objects.size(); i++) 247 if (objects[i].nameIndex==nameIndex) 248 return i; 249 return -1; 250} 251 252S32 TSShape::findDetail(S32 nameIndex) const 253{ 254 for (S32 i=0; i<details.size(); i++) 255 if (details[i].nameIndex==nameIndex) 256 return i; 257 return -1; 258} 259 260S32 TSShape::findDetailBySize(S32 size) const 261{ 262 for (S32 i=0; i<details.size(); i++) 263 if (details[i].size==<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a>) 264 return i; 265 return -1; 266} 267 268S32 TSShape::findSequence(S32 nameIndex) const 269{ 270 for (S32 i=0; i<sequences.size(); i++) 271 if (sequences[i].nameIndex==nameIndex) 272 return i; 273 return -1; 274} 275 276bool TSShape::findMeshIndex(const String& meshName, S32& objIndex, S32& meshIndex) 277{ 278 // Determine the object name and detail size from the mesh name 279 S32 detailSize = 999; 280 objIndex = findObject(String::GetTrailingNumber(meshName, detailSize)); 281 if (objIndex < 0) 282 return false; 283 284 // Determine the subshape this object belongs to 285 S32 subShapeIndex = getSubShapeForObject(objIndex); 286 AssertFatal(subShapeIndex < subShapeFirstObject.size(), "Could not find subshape for object!"); 287 288 // Get the detail levels for the subshape 289 Vector<S32> validDetails; 290 getSubShapeDetails(subShapeIndex, validDetails); 291 292 // Find the detail with the correct size 293 for (meshIndex = 0; meshIndex < validDetails.size(); meshIndex++) 294 { 295 const TSShape::Detail& det = details[validDetails[meshIndex]]; 296 if (detailSize == det.size) 297 return true; 298 } 299 300 return false; 301} 302 303bool TSShape::needsBufferUpdate() 304{ 305 // No buffer? definitely need an update! 306 if (mVertexSize == 0 || mShapeVertexData.size == 0) 307 return true; 308 309 // Check if we have modified vertex data 310 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 311 { 312 TSMesh *mesh = *iter; 313 if (!mesh || 314 (mesh->getMeshType() != TSMesh::StandardMeshType && 315 mesh->getMeshType() != TSMesh::SkinMeshType)) 316 continue; 317 318 // NOTE: cant use mVertexData.isReady since that might not be init'd at this stage 319 if (mesh->mVertSize == 0) 320 return true; 321 } 322 323 return false; 324} 325 326TSMesh* TSShape::findMesh(const String& meshName) 327{ 328 S32 objIndex, meshIndex; 329 if (!findMeshIndex(meshName, objIndex, meshIndex)) 330 return 0; 331 return meshes[objects[objIndex].startMeshIndex + meshIndex]; 332} 333 334S32 TSShape::getSubShapeForNode(S32 nodeIndex) 335{ 336 for (S32 i = 0; i < subShapeFirstNode.size(); i++) 337 { 338 S32 start = subShapeFirstNode[i]; 339 S32 end = start + subShapeNumNodes[i]; 340 if ((nodeIndex >= start) && (nodeIndex < end)) 341 return i;; 342 } 343 return -1; 344} 345 346S32 TSShape::getSubShapeForObject(S32 objIndex) 347{ 348 for (S32 i = 0; i < subShapeFirstObject.size(); i++) 349 { 350 S32 start = subShapeFirstObject[i]; 351 S32 end = start + subShapeNumObjects[i]; 352 if ((objIndex >= start) && (objIndex < end)) 353 return i; 354 } 355 return -1; 356} 357 358void TSShape::getSubShapeDetails(S32 subShapeIndex, Vector<S32>& validDetails) 359{ 360 validDetails.clear(); 361 for (S32 i = 0; i < details.size(); i++) 362 { 363 if ((details[i].subShapeNum == subShapeIndex) || 364 (details[i].subShapeNum < 0)) 365 validDetails.push_back(i); 366 } 367} 368 369void TSShape::getNodeWorldTransform(S32 nodeIndex, MatrixF* mat) const 370{ 371 if ( nodeIndex == -1 ) 372 { 373 mat->identity(); 374 } 375 else 376 { 377 // Calculate the world transform of the given node 378 defaultRotations[nodeIndex].getQuatF().setMatrix(mat); 379 mat->setPosition(defaultTranslations[nodeIndex]); 380 381 S32 parentIndex = nodes[nodeIndex].parentIndex; 382 while (parentIndex != -1) 383 { 384 MatrixF mat2(*mat); 385 defaultRotations[parentIndex].getQuatF().setMatrix(mat); 386 mat->setPosition(defaultTranslations[parentIndex]); 387 mat->mul(mat2); 388 389 parentIndex = nodes[parentIndex].parentIndex; 390 } 391 } 392} 393 394void TSShape::getNodeObjects(S32 nodeIndex, Vector<S32>& nodeObjects) 395{ 396 for (S32 i = 0; i < objects.size(); i++) 397 { 398 if ((nodeIndex == -1) || (objects[i].nodeIndex == nodeIndex)) 399 nodeObjects.push_back(i); 400 } 401} 402 403void TSShape::getNodeChildren(S32 nodeIndex, Vector<S32>& nodeChildren) 404{ 405 for (S32 i = 0; i < nodes.size(); i++) 406 { 407 if (nodes[i].parentIndex == nodeIndex) 408 nodeChildren.push_back(i); 409 } 410} 411 412void TSShape::getObjectDetails(S32 objIndex, Vector<S32>& objDetails) 413{ 414 // Get the detail levels for this subshape 415 Vector<S32> validDetails; 416 getSubShapeDetails(getSubShapeForObject(objIndex), validDetails); 417 418 // Get the non-null details for this object 419 const TSShape::Object& obj = objects[objIndex]; 420 for (S32 i = 0; i < obj.numMeshes; i++) 421 { 422 if (meshes[obj.startMeshIndex + i]) 423 objDetails.push_back(validDetails[i]); 424 } 425} 426 427void TSShape::init() 428{ 429 initObjects(); 430 initVertexFeatures(); 431 initMaterialList(); 432 mNeedReinit = false; 433} 434 435void TSShape::initObjects() 436{ 437 S32 numSubShapes = subShapeFirstNode.size(); 438 AssertFatal(numSubShapes == subShapeFirstObject.size(), "TSShape::initObjects"); 439 440 S32 i, j; 441 442 // set up parent/child relationships on nodes and objects 443 for (i = 0; i<nodes.size(); i++) 444 nodes[i].firstObject = nodes[i].firstChild = nodes[i].nextSibling = -1; 445 for (i = 0; i<nodes.size(); i++) 446 { 447 S32 parentIndex = nodes[i].parentIndex; 448 if (parentIndex >= 0) 449 { 450 if (nodes[parentIndex].firstChild<0) 451 nodes[parentIndex].firstChild = i; 452 else 453 { 454 S32 child = nodes[parentIndex].firstChild; 455 while (nodes[child].nextSibling >= 0) 456 child = nodes[child].nextSibling; 457 nodes[child].nextSibling = i; 458 } 459 } 460 } 461 for (i = 0; i<objects.size(); i++) 462 { 463 objects[i].nextSibling = -1; 464 465 S32 nodeIndex = objects[i].nodeIndex; 466 if (nodeIndex >= 0) 467 { 468 if (nodes[nodeIndex].firstObject<0) 469 nodes[nodeIndex].firstObject = i; 470 else 471 { 472 S32 objectIndex = nodes[nodeIndex].firstObject; 473 while (objects[objectIndex].nextSibling >= 0) 474 objectIndex = objects[objectIndex].nextSibling; 475 objects[objectIndex].nextSibling = i; 476 } 477 } 478 } 479 480 mFlags = 0; 481 for (i = 0; i<sequences.size(); i++) 482 { 483 if (!sequences[i].animatesScale()) 484 continue; 485 486 U32 curVal = mFlags & AnyScale; 487 U32 newVal = sequences[i].flags & AnyScale; 488 mFlags &= ~(AnyScale); 489 mFlags |= getMax(curVal, newVal); // take the larger value (can only convert upwards) 490 } 491 492 // set up alphaIn and alphaOut vectors... 493 alphaIn.setSize(details.size()); 494 alphaOut.setSize(details.size()); 495 496 for (i = 0; i<details.size(); i++) 497 { 498 if (details[i].size<0) 499 { 500 // we don't care... 501 alphaIn[i] = 0.0f; 502 alphaOut[i] = 0.0f; 503 } 504 else if (i + 1 == details.size() || details[i + 1].size<0) 505 { 506 alphaIn[i] = 0.0f; 507 alphaOut[i] = smAlphaOutLastDetail; 508 } 509 else 510 { 511 if (details[i + 1].subShapeNum<0) 512 { 513 // following detail is a billboard detail...treat special... 514 alphaIn[i] = smAlphaInBillboard; 515 alphaOut[i] = smAlphaOutBillboard; 516 } 517 else 518 { 519 // next detail is normal detail 520 alphaIn[i] = smAlphaInDefault; 521 alphaOut[i] = smAlphaOutDefault; 522 } 523 } 524 } 525 526 for (i = mSmallestVisibleDL - 1; i >= 0; i--) 527 { 528 if (i<smNumSkipLoadDetails) 529 { 530 // this detail level renders when pixel size 531 // is larger than our cap...zap all the meshes and decals 532 // associated with it and use the next detail level 533 // instead... 534 S32 ss = details[i].subShapeNum; 535 S32 od = details[i].objectDetailNum; 536 537 if (ss == details[i + 1].subShapeNum && od == details[i + 1].objectDetailNum) 538 // doh! already done this one (init can be called multiple times on same shape due 539 // to sequence importing). 540 continue; 541 details[i].subShapeNum = details[i + 1].subShapeNum; 542 details[i].objectDetailNum = details[i + 1].objectDetailNum; 543 } 544 } 545 546 for (i = 0; i<details.size(); i++) 547 { 548 S32 count = 0; 549 S32 ss = details[i].subShapeNum; 550 S32 od = details[i].objectDetailNum; 551 if (ss<0) 552 { 553 // billboard detail... 554 details[i].polyCount = 2; 555 continue; 556 } 557 S32 start = subShapeFirstObject[ss]; 558 S32 end = start + subShapeNumObjects[ss]; 559 for (j = start; j<end; j++) 560 { 561 Object & obj = objects[j]; 562 if (od<obj.numMeshes) 563 { 564 TSMesh * mesh = meshes[obj.startMeshIndex + od]; 565 count += mesh ? mesh->getNumPolys() : 0; 566 } 567 } 568 details[i].polyCount = count; 569 } 570 571 // Init the collision accelerator array. Note that we don't compute the 572 // accelerators until the app requests them 573 { 574 S32 dca; 575 for (dca = 0; dca < detailCollisionAccelerators.size(); dca++) 576 { 577 ConvexHullAccelerator* accel = detailCollisionAccelerators[dca]; 578 if (accel != NULL) { 579 delete[] accel->vertexList; 580 delete[] accel->normalList; 581 for (S32 vertID = 0; vertID < accel->numVerts; vertID++) 582 delete[] accel->emitStrings[vertID]; 583 delete[] accel->emitStrings; 584 delete accel; 585 } 586 } 587 588 detailCollisionAccelerators.setSize(details.size()); 589 for (dca = 0; dca < detailCollisionAccelerators.size(); dca++) 590 detailCollisionAccelerators[dca] = NULL; 591 } 592 593 // Assign mesh parents & format 594 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 595 { 596 TSMesh *mesh = *iter; 597 if (!mesh) 598 continue; 599 600 if (mesh->mParentMesh >= meshes.size()) 601 { 602 Con::warnf("Mesh %i has a bad parentMeshObject (%i)", iter - meshes.begin(), mesh->mParentMesh); 603 } 604 605 if (mesh->mParentMesh >= 0 && mesh->mParentMesh < meshes.size()) 606 { 607 mesh->mParentMeshObject = meshes[mesh->mParentMesh]; 608 } 609 else 610 { 611 mesh->mParentMeshObject = NULL; 612 } 613 614 mesh->mVertexFormat = &mVertexFormat; 615 } 616} 617 618void TSShape::initVertexBuffers() 619{ 620 // Assumes mVertexData is valid 621 if (!mShapeVertexData.vertexDataReady) 622 { 623 AssertFatal(false, "WTF"); 624 } 625 626 U32 destIndices = 0; 627 U32 destPrims = 0; 628 629 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 630 { 631 TSMesh *mesh = *iter; 632 if (!mesh || 633 (mesh->getMeshType() != TSMesh::StandardMeshType && 634 mesh->getMeshType() != TSMesh::SkinMeshType)) 635 continue; 636 637 destIndices += mesh->mIndices.size(); 638 destPrims += mesh->mPrimitives.size(); 639 } 640 641 // For HW skinning we can just use the static buffer 642 if (TSShape::smUseHardwareSkinning) 643 { 644 getVertexBuffer(mShapeVertexBuffer, GFXBufferTypeStatic); 645 } 646 647 // Also the IBO 648 mShapeVertexIndices.set(GFX, destIndices, destPrims, GFXBufferTypeStatic); 649 U16 *indicesStart = NULL; 650 mShapeVertexIndices.lock(&indicesStart, NULL); 651 U16 *ibIndices = indicesStart; 652 GFXPrimitive *piInput = mShapeVertexIndices->mPrimitiveArray; 653 U32 vertStart = 0; 654 U32 primStart = 0; 655 U32 indStart = 0; 656 657 // Create VBO 658 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 659 { 660 TSMesh *mesh = *iter; 661 if (!mesh || 662 (mesh->getMeshType() != TSMesh::StandardMeshType && 663 mesh->getMeshType() != TSMesh::SkinMeshType)) 664 continue; 665 666 // Make the offset vbo 667 mesh->mPrimBufferOffset = primStart; 668 669 // Dump primitives to locked buffer 670 mesh->dumpPrimitives(vertStart, indStart, piInput, ibIndices); 671 672 AssertFatal(mesh->mVertOffset / mVertexSize == vertStart, "offset mismatch"); 673 674 vertStart += mesh->mNumVerts; 675 primStart += mesh->mPrimitives.size(); 676 indStart += mesh->mIndices.size(); 677 678 mesh->mVB = mShapeVertexBuffer; 679 mesh->mPB = mShapeVertexIndices; 680 681 // Advance 682 piInput += mesh->mPrimitives.size(); 683 ibIndices += mesh->mIndices.size(); 684 685 if (TSSkinMesh::smDebugSkinVerts && mesh->getMeshType() == TSMesh::SkinMeshType) 686 { 687 static_cast<TSSkinMesh*>(mesh)->printVerts(); 688 } 689 } 690 691#ifdef TORQUE_DEBUG 692 // Verify prims 693 if (TSSkinMesh::smDebugSkinVerts) 694 { 695 U32 vertsInBuffer = mShapeVertexData.size / mVertexSize; 696 U32 indsInBuffer = ibIndices - indicesStart; 697 698 for (U32 primID = 0; primID < primStart; primID++) 699 { 700 GFXPrimitive &prim = mShapeVertexIndices->mPrimitiveArray[primID]; 701 702 if (prim.type != GFXTriangleList && prim.type != GFXTriangleStrip) 703 { 704 AssertFatal(false, "Unexpected triangle list"); 705 } 706 707 if (prim.type == GFXTriangleStrip) 708 continue; 709 710 AssertFatal(prim.startVertex < vertsInBuffer, "wrong start vertex"); 711 AssertFatal((prim.startVertex + prim.numVertices) <= vertsInBuffer, "too many verts"); 712 AssertFatal(prim.startIndex + (prim.numPrimitives * 3) <= indsInBuffer, "too many inds"); 713 714 for (U32 i = prim.startIndex; i < prim.startIndex + (prim.numPrimitives * 3); i++) 715 { 716 if (indicesStart[i] >= vertsInBuffer) 717 { 718 AssertFatal(false, "vert not in buffer"); 719 } 720 U16 idx = indicesStart[i]; 721 if (idx < prim.minIndex) 722 { 723 AssertFatal(false, "index out of minIndex range"); 724 } 725 } 726 } 727 } 728#endif 729 730 mShapeVertexIndices.unlock(); 731} 732 733void TSShape::getVertexBuffer(TSVertexBufferHandle &vb, GFXBufferType bufferType) 734{ 735 vb.set(GFX, mVertexSize, &mVertexFormat, mShapeVertexData.size / mVertexSize, bufferType); 736 737 U8 *vertPtr = vb.lock(); 738 dMemcpy(vertPtr, mShapeVertexData.base, mShapeVertexData.size); 739 vb.unlock(); 740} 741 742void TSShape::initVertexBufferPointers() 743{ 744 if (mBasicVertexFormat.vertexSize == -1) 745 return; 746 AssertFatal(mVertexSize == mBasicVertexFormat.vertexSize, "vertex size mismatch"); 747 748 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 749 { 750 TSMesh *mesh = *iter; 751 if (mesh && 752 (mesh->getMeshType() == TSMesh::StandardMeshType || 753 mesh->getMeshType() == TSMesh::SkinMeshType)) 754 { 755 // Set buffer 756 AssertFatal(mesh->mNumVerts == 0 || mesh->mNumVerts >= mesh->vertsPerFrame, "invalid verts per frame"); 757 if (mesh->mVertSize > 0 && !mesh->mVertexData.isReady()) 758 { 759 U32 boneOffset = 0; 760 U32 texCoordOffset = 0; 761 AssertFatal(mesh->mVertSize == mVertexFormat.getSizeInBytes(), "mismatch in format size"); 762 763 if (mBasicVertexFormat.boneOffset >= 0) 764 { 765 boneOffset = mBasicVertexFormat.boneOffset; 766 } 767 768 if (mBasicVertexFormat.texCoordOffset >= 0) 769 { 770 texCoordOffset = mBasicVertexFormat.texCoordOffset; 771 } 772 773 // Initialize the vertex data 774 mesh->mVertexData.set(mShapeVertexData.base + mesh->mVertOffset, mesh->mVertSize, mesh->mNumVerts, texCoordOffset, boneOffset, false); 775 mesh->mVertexData.setReady(true); 776 } 777 } 778 } 779} 780 781void TSShape::initVertexFeatures() 782{ 783 784 if (!needsBufferUpdate()) 785 { 786 // Init format from basic format 787 mVertexFormat.clear(); 788 mBasicVertexFormat.getFormat(mVertexFormat); 789 mVertexSize = mVertexFormat.getSizeInBytes(); 790 791 initVertexBufferPointers(); 792 793 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 794 { 795 TSMesh *mesh = *iter; 796 if (mesh && 797 (mesh->getMeshType() == TSMesh::SkinMeshType)) 798 { 799 static_cast<TSSkinMesh*>(mesh)->createSkinBatchData(); 800 } 801 } 802 803 // Make sure VBO is init'd 804 initVertexBuffers(); 805 return; 806 } 807 808 // Cleanout VBO 809 mShapeVertexBuffer = NULL; 810 811 // Make sure mesh has verts stored in mesh data, we're recreating the buffer 812 TSBasicVertexFormat basicFormat; 813 814 initVertexBufferPointers(); 815 816 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 817 { 818 TSMesh *mesh = *iter; 819 if (mesh && 820 (mesh->getMeshType() == TSMesh::StandardMeshType || 821 mesh->getMeshType() == TSMesh::SkinMeshType)) 822 { 823 // Make sure we have everything in the vert lists 824 mesh->makeEditable(); 825 826 // We need the skin batching data here to determine bone counts 827 if (mesh->getMeshType() == TSMesh::SkinMeshType) 828 { 829 static_cast<TSSkinMesh*>(mesh)->createSkinBatchData(); 830 } 831 832 basicFormat.addMeshRequirements(mesh); 833 } 834 } 835 836 mVertexFormat.clear(); 837 mBasicVertexFormat = basicFormat; 838 mBasicVertexFormat.getFormat(mVertexFormat); 839 mBasicVertexFormat.vertexSize = mVertexFormat.getSizeInBytes(); 840 mVertexSize = mBasicVertexFormat.vertexSize; 841 842 U32 destVertex = 0; 843 U32 destIndices = 0; 844 845 // Go fix up meshes to include defaults for optional features 846 // and initialize them if they're not a skin mesh. 847 U32 count = 0; 848 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 849 { 850 TSMesh *mesh = *iter; 851 if (!mesh || 852 (mesh->getMeshType() != TSMesh::StandardMeshType && 853 mesh->getMeshType() != TSMesh::SkinMeshType)) 854 continue; 855 856 mesh->mVertSize = mVertexSize; 857 mesh->mVertOffset = destVertex; 858 859 destVertex += mesh->mVertSize * mesh->getNumVerts(); 860 destIndices += mesh->mIndices.size(); 861 862 count += 1; 863 } 864 865 // Don't set up if we have no meshes 866 if (count == 0) 867 { 868 mShapeVertexData.set(NULL, 0); 869 mShapeVertexData.vertexDataReady = false; 870 return; 871 } 872 873 // Now we can create the VBO 874 mShapeVertexData.set(NULL, 0); 875 U8 *vertexData = (U8*)dMalloc_aligned(destVertex, 16); 876 U8 *vertexDataPtr = vertexData; 877 mShapeVertexData.set(vertexData, destVertex); 878 879 // Create VBO 880 for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++) 881 { 882 TSMesh *mesh = *iter; 883 884 if (!mesh || 885 (mesh->getMeshType() != TSMesh::StandardMeshType && 886 mesh->getMeshType() != TSMesh::SkinMeshType)) 887 continue; 888 889 U32 boneOffset = 0; 890 U32 texCoordOffset = 0; 891 AssertFatal(mesh->mVertSize == mVertexFormat.getSizeInBytes(), "mismatch in format size"); 892 893 if (mBasicVertexFormat.boneOffset >= 0) 894 { 895 boneOffset = mBasicVertexFormat.boneOffset; 896 } 897 898 if (mBasicVertexFormat.texCoordOffset >= 0) 899 { 900 texCoordOffset = mBasicVertexFormat.texCoordOffset; 901 } 902 903 // Dump everything 904 mesh->mVertexData.setReady(false); 905 mesh->mVertSize = mVertexSize; 906 AssertFatal(mesh->mVertOffset == vertexDataPtr - vertexData, "vertex offset mismatch"); 907 mesh->mNumVerts = mesh->getNumVerts(); 908 909 // Correct bad meshes 910 if (mesh->mNumVerts != 0 && mesh->vertsPerFrame > mesh->mNumVerts) 911 { 912 Con::warnf("Shape mesh has bad vertsPerFrame (%i, should be <= %i)", mesh->vertsPerFrame, mesh->mNumVerts); 913 mesh->vertsPerFrame = mesh->mNumVerts; 914 } 915 916 mesh->mVertexData.set(mShapeVertexData.base + mesh->mVertOffset, mesh->mVertSize, mesh->mNumVerts, texCoordOffset, boneOffset, false); 917 mesh->convertToVertexData(); 918 mesh->mVertexData.setReady(true); 919 920#ifdef TORQUE_DEBUG 921 AssertFatal(mesh->mNumVerts == mesh->mVerts.size(), "vert mismatch"); 922 for (U32 i = 0; i < mesh->mNumVerts; i++) 923 { 924 Point3F v1 = mesh->mVerts[i]; 925 Point3F v2 = mesh->mVertexData.getBase(i).vert(); 926 AssertFatal(mesh->mVerts[i] == mesh->mVertexData.getBase(i).vert(), "vert data mismatch"); 927 } 928 929 if (mesh->getMeshType() == TSMesh::SkinMeshType) 930 { 931 AssertFatal(mesh->getMaxBonesPerVert() != 0, "Skin mesh has no bones used, very strange!"); 932 } 933#endif 934 935 // Advance 936 vertexDataPtr += mesh->mVertSize * mesh->mNumVerts; 937 938 AssertFatal(vertexDataPtr - vertexData <= destVertex, "Vertex data overflow"); 939 } 940 941 mShapeVertexData.vertexDataReady = true; 942 943 initVertexBuffers(); 944} 945 946void TSShape::setupBillboardDetails( const String &cachePath ) 947{ 948 // set up billboard details -- only do this once, meaning that 949 // if we add a sequence to the shape we don't redo the billboard 950 // details... 951 if ( !billboardDetails.empty() ) 952 return; 953 954 for ( U32 i=0; i < details.size(); i++ ) 955 { 956 const Detail &det = details[i]; 957 958 if ( det.subShapeNum >= 0 ) 959 continue; // not a billboard detail 960 961 while (billboardDetails.size() <= i ) 962 billboardDetails.push_back(NULL); 963 964 billboardDetails[i] = new TSLastDetail( this, 965 cachePath, 966 det.bbEquatorSteps, 967 det.bbPolarSteps, 968 det.bbPolarAngle, 969 det.bbIncludePoles, 970 det.bbDetailLevel, 971 det.bbDimension ); 972 973 billboardDetails[i]->update(); 974 } 975} 976 977void TSShape::initMaterialList() 978{ 979 S32 numSubShapes = subShapeFirstObject.size(); 980 #if defined(TORQUE_MAX_LIB) 981 subShapeFirstTranslucentObject.setSize(numSubShapes); 982 #endif 983 984 S32 i,j,k; 985 // for each subshape, find the first translucent object 986 // also, while we're at it, set mHasTranslucency 987 for (S32 ss = 0; ss<numSubShapes; ss++) 988 { 989 S32 start = subShapeFirstObject[ss]; 990 S32 end = subShapeNumObjects[ss]; 991 subShapeFirstTranslucentObject[ss] = end; 992 for (i=start; i<end; i++) 993 { 994 // check to see if this object has translucency 995 Object & obj = objects[i]; 996 for (j=0; j<obj.numMeshes; j++) 997 { 998 TSMesh * mesh = meshes[obj.startMeshIndex+j]; 999 if (!mesh) 1000 continue; 1001 1002 for (k=0; k<mesh->mPrimitives.size(); k++) 1003 { 1004 if (mesh->mPrimitives[k].matIndex & TSDrawPrimitive::NoMaterial) 1005 continue; 1006 S32 flags = materialList->getFlags(mesh->mPrimitives[k].matIndex & TSDrawPrimitive::MaterialMask); 1007 if (flags & TSMaterialList::AuxiliaryMap) 1008 continue; 1009 if (flags & TSMaterialList::Translucent) 1010 { 1011 mFlags |= HasTranslucency; 1012 subShapeFirstTranslucentObject[ss] = i; 1013 break; 1014 } 1015 } 1016 if (k!=mesh->mPrimitives.size()) 1017 break; 1018 } 1019 if (j!=obj.numMeshes) 1020 break; 1021 } 1022 if (i!=<a href="/coding/namespace/namespaceprimbuild/#namespaceprimbuild_1acf3edd784de91bee46e8a68ea08c9532">end</a>) 1023 break; 1024 } 1025 1026} 1027 1028bool TSShape::preloadMaterialList(const Torque::Path &path) 1029{ 1030 if (materialList) 1031 materialList->setTextureLookupPath(path.getPath()); 1032 return true; 1033} 1034 1035bool TSShape::buildConvexHull(S32 dl) const 1036{ 1037 AssertFatal(dl>=0 && dl<details.size(),"TSShape::buildConvexHull: detail out of range"); 1038 1039 bool ok = true; 1040 1041 const Detail & detail = details[dl]; 1042 S32 ss = detail.subShapeNum; 1043 S32 od = detail.objectDetailNum; 1044 1045 S32 start = subShapeFirstObject[ss]; 1046 S32 end = subShapeNumObjects[ss]; 1047 for (S32 i=start; i<end; i++) 1048 { 1049 TSMesh * mesh = meshes[objects[i].startMeshIndex+od]; 1050 if (!mesh) 1051 continue; 1052 ok &= mesh->buildConvexHull(); 1053 } 1054 return ok; 1055} 1056 1057Vector<MatrixF> gTempNodeTransforms(__FILE__, __LINE__); 1058 1059void TSShape::computeBounds(S32 dl, Box3F & bounds) const 1060{ 1061 // if dl==-1, nothing to do 1062 if (dl==-1) 1063 return; 1064 1065 AssertFatal(dl>=0 && dl<details.size(),"TSShapeInstance::computeBounds"); 1066 1067 // get subshape and object detail 1068 const TSDetail * detail = &details[dl]; 1069 S32 ss = detail->subShapeNum; 1070 S32 od = detail->objectDetailNum; 1071 1072 // If we have no subshapes then there is 1073 // no valid bounds for this detail level. 1074 if ( ss < 0 ) 1075 return; 1076 1077 // set up temporary storage for non-local transforms... 1078 S32 i; 1079 S32 start = subShapeFirstNode[ss]; 1080 S32 end = subShapeNumNodes[ss] + start; 1081 gTempNodeTransforms.setSize(end-start); 1082 for (i=start; i<end; i++) 1083 { 1084 MatrixF mat; 1085 QuatF q; 1086 TSTransform::setMatrix(defaultRotations[i].getQuatF(&q),defaultTranslations[i],&mat); 1087 if (nodes[i].parentIndex>=0) 1088 gTempNodeTransforms[i-start].mul(gTempNodeTransforms[nodes[i].parentIndex-start],mat); 1089 else 1090 gTempNodeTransforms[i-start] = mat; 1091 } 1092 1093 // run through objects and updating bounds as we go 1094 bounds.minExtents.set( 10E30f, 10E30f, 10E30f); 1095 bounds.maxExtents.set(-10E30f,-10E30f,-10E30f); 1096 Box3F box; 1097 start = subShapeFirstObject[ss]; 1098 end = subShapeNumObjects[ss] + start; 1099 for (i=start; i<end; i++) 1100 { 1101 const Object * object = &objects[i]; 1102 TSMesh * mesh = od<object->numMeshes ? meshes[object->startMeshIndex+od] : NULL; 1103 if (mesh) 1104 { 1105 static MatrixF idMat(true); 1106 if (object->nodeIndex<0) 1107 mesh->computeBounds(idMat,box); 1108 else 1109 mesh->computeBounds(gTempNodeTransforms[object->nodeIndex-start],box); 1110 bounds.minExtents.setMin(box.minExtents); 1111 bounds.maxExtents.setMax(box.maxExtents); 1112 } 1113 } 1114} 1115 1116TSShapeAlloc TSShape::smTSAlloc; 1117 1118#define tsalloc TSShape::smTSAlloc 1119 1120 1121// messy stuff: check to see if we should "skip" meshNum 1122// this assumes that meshes for a given object are in a row 1123// skipDL is the lowest detail number we keep (i.e., the # of details we skip) 1124bool TSShape::checkSkip(S32 meshNum, S32 & curObject, S32 skipDL) 1125{ 1126 if (skipDL==0) 1127 // easy out... 1128 return false; 1129 1130 // skip detail level exists on this subShape 1131 S32 skipSS = details[skipDL].subShapeNum; 1132 1133 if (curObject<objects.size()) 1134 { 1135 S32 start = objects[curObject].startMeshIndex; 1136 if (meshNum>=start) 1137 { 1138 // we are either from this object, the next object, or a decal 1139 if (meshNum < start + objects[curObject].numMeshes) 1140 { 1141 // this object... 1142 if (subShapeFirstObject[skipSS]>curObject) 1143 // haven't reached this subshape yet 1144 return true; 1145 if (skipSS+1==<a href="/coding/class/classtsshape/#classtsshape_1ab304b57ca121344cb6b5fb44612ebe94">subShapeFirstObject</a>.size() || curObject<subShapeFirstObject[skipSS+1]) 1146 // curObject is on subshape of skip detail...make sure it's after skipDL 1147 return (meshNum-start<details[skipDL].objectDetailNum); 1148 // if we get here, then curObject occurs on subShape after skip detail (so keep it) 1149 return false; 1150 } 1151 else 1152 // advance object, try again 1153 return checkSkip(meshNum,++curObject,skipDL); 1154 } 1155 } 1156 1157 AssertFatal(0,"TSShape::checkSkip: assertion failed"); 1158 return false; 1159} 1160 1161void TSShape::assembleShape() 1162{ 1163 S32 i,j; 1164 1165 // get counts... 1166 S32 numNodes = tsalloc.get32(); 1167 S32 numObjects = tsalloc.get32(); 1168 S32 numDecals = tsalloc.get32(); 1169 S32 numSubShapes = tsalloc.get32(); 1170 S32 numIflMaterials = tsalloc.get32(); 1171 S32 numNodeRots; 1172 S32 numNodeTrans; 1173 S32 numNodeUniformScales; 1174 S32 numNodeAlignedScales; 1175 S32 numNodeArbitraryScales; 1176 if (smReadVersion<22) 1177 { 1178 numNodeRots = numNodeTrans = tsalloc.get32() - numNodes; 1179 numNodeUniformScales = numNodeAlignedScales = numNodeArbitraryScales = 0; 1180 } 1181 else 1182 { 1183 numNodeRots = tsalloc.get32(); 1184 numNodeTrans = tsalloc.get32(); 1185 numNodeUniformScales = tsalloc.get32(); 1186 numNodeAlignedScales = tsalloc.get32(); 1187 numNodeArbitraryScales = tsalloc.get32(); 1188 } 1189 S32 numGroundFrames = 0; 1190 if (smReadVersion>23) 1191 numGroundFrames = tsalloc.get32(); 1192 S32 numObjectStates = tsalloc.get32(); 1193 S32 numDecalStates = tsalloc.get32(); 1194 S32 numTriggers = tsalloc.get32(); 1195 S32 numDetails = tsalloc.get32(); 1196 S32 numMeshes = tsalloc.get32(); 1197 S32 numSkins = 0; 1198 if (smReadVersion<23) 1199 // in later versions, skins are kept with other meshes 1200 numSkins = tsalloc.get32(); 1201 S32 numNames = tsalloc.get32(); 1202 1203 // Note that we are recalculating these values later on for safety. 1204 mSmallestVisibleSize = (F32)tsalloc.get32(); 1205 mSmallestVisibleDL = tsalloc.get32(); 1206 1207 tsalloc.checkGuard(); 1208 1209 // get bounds... 1210 tsalloc.get32((S32*)&mRadius,1); 1211 tsalloc.get32((S32*)&tubeRadius,1); 1212 tsalloc.get32((S32*)¢er,3); 1213 tsalloc.get32((S32*)&mBounds,6); 1214 1215 tsalloc.checkGuard(); 1216 1217 // copy various vectors... 1218 S32 * ptr32 = tsalloc.copyToShape32(numNodes*5); 1219 nodes.set(ptr32,numNodes); 1220 1221 tsalloc.checkGuard(); 1222 1223 ptr32 = tsalloc.copyToShape32(numObjects*6,true); 1224 if (!ptr32) 1225 ptr32 = tsalloc.allocShape32(numSkins*6); // pre v23 shapes store skins and meshes separately...no longer 1226 else 1227 tsalloc.allocShape32(numSkins*6); 1228 objects.set(ptr32,numObjects); 1229 1230 tsalloc.checkGuard(); 1231 1232 // DEPRECATED decals 1233 ptr32 = tsalloc.getPointer32(numDecals*5); 1234 1235 tsalloc.checkGuard(); 1236 1237 // DEPRECATED ifl materials 1238 ptr32 = tsalloc.copyToShape32(numIflMaterials*5); 1239 1240 tsalloc.checkGuard(); 1241 1242 ptr32 = tsalloc.copyToShape32(numSubShapes,true); 1243 subShapeFirstNode.set(ptr32,numSubShapes); 1244 ptr32 = tsalloc.copyToShape32(numSubShapes,true); 1245 subShapeFirstObject.set(ptr32,numSubShapes); 1246 // DEPRECATED subShapeFirstDecal 1247 ptr32 = tsalloc.getPointer32(numSubShapes); 1248 1249 tsalloc.checkGuard(); 1250 1251 ptr32 = tsalloc.copyToShape32(numSubShapes); 1252 subShapeNumNodes.set(ptr32,numSubShapes); 1253 ptr32 = tsalloc.copyToShape32(numSubShapes); 1254 subShapeNumObjects.set(ptr32,numSubShapes); 1255 // DEPRECATED subShapeNumDecals 1256 ptr32 = tsalloc.getPointer32(numSubShapes); 1257 1258 tsalloc.checkGuard(); 1259 1260 ptr32 = tsalloc.allocShape32(numSubShapes); 1261 subShapeFirstTranslucentObject.set(ptr32,numSubShapes); 1262 1263 // get default translation and rotation 1264 S16 * ptr16 = tsalloc.allocShape16(0); 1265 for (i=0;i<numNodes;i++) 1266 tsalloc.copyToShape16(4); 1267 defaultRotations.set(ptr16,numNodes); 1268 tsalloc.align32(); 1269 ptr32 = tsalloc.allocShape32(0); 1270 for (i=0;i<numNodes;i++) 1271 { 1272 tsalloc.copyToShape32(3); 1273 tsalloc.copyToShape32(sizeof(Point3F)-12); // handle alignment issues w/ point3f 1274 } 1275 defaultTranslations.set(ptr32,numNodes); 1276 1277 // get any node sequence data stored in shape 1278 nodeTranslations.setSize(numNodeTrans); 1279 for (i=0;i<numNodeTrans;i++) 1280 tsalloc.get32((S32*)&nodeTranslations[i],3); 1281 nodeRotations.setSize(numNodeRots); 1282 for (i=0;i<numNodeRots;i++) 1283 tsalloc.get16((S16*)&nodeRotations[i],4); 1284 tsalloc.align32(); 1285 1286 tsalloc.checkGuard(); 1287 1288 if (smReadVersion>21) 1289 { 1290 // more node sequence data...scale 1291 nodeUniformScales.setSize(numNodeUniformScales); 1292 for (i=0;i<numNodeUniformScales;i++) 1293 tsalloc.get32((S32*)&nodeUniformScales[i],1); 1294 nodeAlignedScales.setSize(numNodeAlignedScales); 1295 for (i=0;i<numNodeAlignedScales;i++) 1296 tsalloc.get32((S32*)&nodeAlignedScales[i],3); 1297 nodeArbitraryScaleFactors.setSize(numNodeArbitraryScales); 1298 for (i=0;i<numNodeArbitraryScales;i++) 1299 tsalloc.get32((S32*)&nodeArbitraryScaleFactors[i],3); 1300 nodeArbitraryScaleRots.setSize(numNodeArbitraryScales); 1301 for (i=0;i<numNodeArbitraryScales;i++) 1302 tsalloc.get16((S16*)&nodeArbitraryScaleRots[i],4); 1303 tsalloc.align32(); 1304 1305 tsalloc.checkGuard(); 1306 } 1307 1308 // old shapes need ground transforms moved to ground arrays...but only do it once 1309 if (smReadVersion<22 && tsalloc.allocShape32(0)) 1310 { 1311 for (i=0; i<sequences.size(); i++) 1312 { 1313 // move ground transform data to ground vectors 1314 Sequence & seq = sequences[i]; 1315 S32 oldSz = groundTranslations.size(); 1316 groundTranslations.setSize(oldSz+seq.numGroundFrames); 1317 groundRotations.setSize(oldSz+seq.numGroundFrames); 1318 for (S32 groundFrm =0; groundFrm<seq.numGroundFrames; groundFrm++) 1319 { 1320 groundTranslations[groundFrm +oldSz] = nodeTranslations[seq.firstGroundFrame+ groundFrm -numNodes]; 1321 groundRotations[groundFrm +oldSz] = nodeRotations[seq.firstGroundFrame+ groundFrm -numNodes]; 1322 } 1323 seq.firstGroundFrame = oldSz; 1324 seq.baseTranslation -= numNodes; 1325 seq.baseRotation -= numNodes; 1326 seq.baseScale = 0; // not used on older shapes...but keep it clean 1327 } 1328 } 1329 1330 // version 22 & 23 shapes accidentally had no ground transforms, and ground for 1331 // earlier shapes is handled just above, so... 1332 if (smReadVersion>23) 1333 { 1334 groundTranslations.setSize(numGroundFrames); 1335 for (i=0;i<numGroundFrames;i++) 1336 tsalloc.get32((S32*)&groundTranslations[i],3); 1337 groundRotations.setSize(numGroundFrames); 1338 for (i=0;i<numGroundFrames;i++) 1339 tsalloc.get16((S16*)&groundRotations[i],4); 1340 tsalloc.align32(); 1341 1342 tsalloc.checkGuard(); 1343 } 1344 1345 // object states 1346 ptr32 = tsalloc.copyToShape32(numObjectStates*3); 1347 objectStates.set(ptr32,numObjectStates); 1348 tsalloc.allocShape32(numSkins*3); // provide buffer after objectStates for older shapes 1349 1350 tsalloc.checkGuard(); 1351 1352 // DEPRECATED decal states 1353 ptr32 = tsalloc.getPointer32(numDecalStates); 1354 1355 tsalloc.checkGuard(); 1356 1357 // frame triggers 1358 ptr32 = tsalloc.getPointer32(numTriggers*2); 1359 triggers.setSize(numTriggers); 1360 dMemcpy(triggers.address(),ptr32,sizeof(S32)*numTriggers*2); 1361 1362 tsalloc.checkGuard(); 1363 1364 // details 1365 if ( smReadVersion >= 26 ) 1366 { 1367 U32 alignedSize32 = sizeof( Detail ) / 4; 1368 ptr32 = tsalloc.copyToShape32( numDetails * alignedSize32, true ); 1369 details.set( ptr32, numDetails ); 1370 } 1371 else 1372 { 1373 // Previous to version 26 the Detail structure 1374 // only contained the first 7 values... 1375 // 1376 // struct Detail 1377 // { 1378 // S32 nameIndex; 1379 // S32 subShapeNum; 1380 // S32 objectDetailNum; 1381 // F32 size; 1382 // F32 averageError; 1383 // F32 maxError; 1384 // S32 polyCount; 1385 // }; 1386 // 1387 // In the code below we're reading just these 7 values and 1388 // copying them to the new larger structure. 1389 1390 ptr32 = tsalloc.copyToShape32( numDetails * 7, true ); 1391 1392 details.setSize( numDetails ); 1393 for ( U32 detID = 0; detID < details.size(); detID++, ptr32 += 7 ) 1394 { 1395 Detail *det = &(details[detID]); 1396 1397 // Clear the struct... we don't want to leave 1398 // garbage in the parts that are unfilled. 1399 U32 alignedSize32 = sizeof( Detail ); 1400 dMemset( det, 0, alignedSize32 ); 1401 1402 // Copy the old struct values over. 1403 dMemcpy( det, ptr32, 7 * 4 ); 1404 1405 // If this is an autobillboard then we need to 1406 // fill in the new part of the struct. 1407 if ( det->subShapeNum >= 0 ) 1408 continue; 1409 1410 S32 lastDetailOpts = det->objectDetailNum; 1411 det->bbEquatorSteps = lastDetailOpts & 0x7F; // bits 0..6 1412 det->bbPolarSteps = (lastDetailOpts >> 7) & 0x3F; // bits 7..12 1413 det->bbPolarAngle = 0.5f * M_PI_F * (1.0f/64.0f) * (F32) (( lastDetailOpts >>13 ) & 0x3F); // bits 13..18 1414 det->bbDetailLevel = (lastDetailOpts >> 19) & 0x0F; // 19..22 1415 det->bbDimension = (lastDetailOpts >> 23) & 0xFF; // 23..30 1416 det->bbIncludePoles = (lastDetailOpts & 0x80000000)!=0; // bit 31 1417 } 1418 } 1419 1420 // Some DTS exporters (MAX - I'm looking at you!) write garbage into the 1421 // averageError and maxError values which stops LOD from working correctly. 1422 // Try to detect and fix it 1423 for ( U32 erID = 0; erID < details.size(); erID++ ) 1424 { 1425 if ( ( details[erID].averageError == 0 ) || ( details[erID].averageError > 10000 ) || 1426 ( details[erID].maxError == 0 ) || ( details[erID].maxError > 10000 ) ) 1427 { 1428 details[erID].averageError = details[erID].maxError = -1.0f; 1429 } 1430 } 1431 1432 // We don't trust the value of mSmallestVisibleDL loaded from the dts 1433 // since some legacy meshes seem to have the wrong value. Recalculate it 1434 // now that we have the details loaded. 1435 updateSmallestVisibleDL(); 1436 1437 S32 skipDL = getMin(mSmallestVisibleDL,smNumSkipLoadDetails); 1438 if (skipDL < 0) 1439 skipDL = 0; 1440 1441 1442 tsalloc.checkGuard(); 1443 1444 if (TSShape::smReadVersion >= 27) 1445 { 1446 // Vertex format is set here 1447 S8 *vboData = NULL; 1448 S32 vboSize = 0; 1449 1450 mBasicVertexFormat.readAlloc(&tsalloc); 1451 mVertexFormat.clear(); 1452 mBasicVertexFormat.getFormat(mVertexFormat); 1453 mVertexSize = mVertexFormat.getSizeInBytes(); 1454 1455 AssertFatal(mVertexSize == mBasicVertexFormat.vertexSize, "vertex size mismatch"); 1456 1457 vboSize = tsalloc.get32(); 1458 vboData = tsalloc.getPointer8(vboSize); 1459 1460 if (tsalloc.getBuffer() && vboSize > 0) 1461 { 1462 U8 *vertexData = (U8*)dMalloc_aligned(vboSize, 16); 1463 dMemcpy(vertexData, vboData, vboSize); 1464 mShapeVertexData.set(vertexData, vboSize); 1465 mShapeVertexData.vertexDataReady = true; 1466 } 1467 else 1468 { 1469 mShapeVertexData.set(NULL, 0); 1470 } 1471 } 1472 else 1473 { 1474 mShapeVertexData.set(NULL, 0); 1475 } 1476 1477 // about to read in the meshes...first must allocate some scratch space 1478 S32 scratchSize = getMax(numSkins,numMeshes); 1479 TSMesh::smVertsList.setSize(scratchSize); 1480 TSMesh::smTVertsList.setSize(scratchSize); 1481 1482 if ( smReadVersion >= 26 ) 1483 { 1484 TSMesh::smTVerts2List.setSize(scratchSize); 1485 TSMesh::smColorsList.setSize(scratchSize); 1486 } 1487 1488 TSMesh::smNormsList.setSize(scratchSize); 1489 TSMesh::smEncodedNormsList.setSize(scratchSize); 1490 TSMesh::smDataCopied.setSize(scratchSize); 1491 TSSkinMesh::smInitTransformList.setSize(scratchSize); 1492 TSSkinMesh::smVertexIndexList.setSize(scratchSize); 1493 TSSkinMesh::smBoneIndexList.setSize(scratchSize); 1494 TSSkinMesh::smWeightList.setSize(scratchSize); 1495 TSSkinMesh::smNodeIndexList.setSize(scratchSize); 1496 for (i=0; i<numMeshes; i++) 1497 { 1498 TSMesh::smVertsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1499 TSMesh::smTVertsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1500 1501 if ( smReadVersion >= 26 ) 1502 { 1503 TSMesh::smTVerts2List[i] = NULL; 1504 TSMesh::smColorsList[i] = NULL; 1505 } 1506 1507 TSMesh::smNormsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1508 TSMesh::smEncodedNormsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1509 TSMesh::smDataCopied[i]=false; 1510 TSSkinMesh::smInitTransformList[i] = NULL; 1511 TSSkinMesh::smVertexIndexList[i] = NULL; 1512 TSSkinMesh::smBoneIndexList[i] = NULL; 1513 TSSkinMesh::smWeightList[i] = NULL; 1514 TSSkinMesh::smNodeIndexList[i] = NULL; 1515 } 1516 1517 // read in the meshes (sans skins)...straightforward read one at a time 1518 TSMesh **ptrmesh = (TSMesh**)tsalloc.allocShape32((numMeshes + numSkins*numDetails) * (sizeof(TSMesh*) / 4)); 1519 S32 curObject = 0; // for tracking skipped meshes 1520 for (i=0; i<numMeshes; i++) 1521 { 1522 bool skip = checkSkip(i,curObject,skipDL); // skip this mesh? 1523 S32 meshType = tsalloc.get32(); 1524 if (meshType == TSMesh::DecalMeshType) 1525 // decal mesh deprecated 1526 skip = true; 1527 TSMesh * mesh = TSMesh::assembleMesh(meshType,skip); 1528 if (ptrmesh) 1529 { 1530 ptrmesh[i] = skip ? 0 : mesh; 1531 } 1532 1533 // fill in location of verts, tverts, and normals for detail levels 1534 if (mesh && meshType!=<a href="/coding/class/classtsmesh/#classtsmesh_1abecf9557a0f4b4a582f2cae15eff21bfa20c73022bcf281f02273d7d6d770e482">TSMesh::DecalMeshType</a>) 1535 { 1536 TSMesh::smVertsList[i] = mesh->mVerts.address(); 1537 TSMesh::smTVertsList[i] = mesh->mTverts.address(); 1538 if (smReadVersion >= 26) 1539 { 1540 TSMesh::smTVerts2List[i] = mesh->mTverts2.address(); 1541 TSMesh::smColorsList[i] = mesh->mColors.address(); 1542 } 1543 TSMesh::smNormsList[i] = mesh->mNorms.address(); 1544 TSMesh::smEncodedNormsList[i] = mesh->mEncodedNorms.address(); 1545 TSMesh::smDataCopied[i] = !skip; // as long as we didn't skip this mesh, the data should be in shape now 1546 if (meshType==<a href="/coding/class/classtsmesh/#classtsmesh_1abecf9557a0f4b4a582f2cae15eff21bfa4e7301620099d7cf3438bea494da25e4">TSMesh::SkinMeshType</a>) 1547 { 1548 TSSkinMesh * skin = (TSSkinMesh*)mesh; 1549 TSMesh::smVertsList[i] = skin->batchData.initialVerts.address(); 1550 TSMesh::smNormsList[i] = skin->batchData.initialNorms.address(); 1551 TSSkinMesh::smInitTransformList[i] = skin->batchData.initialTransforms.address(); 1552 TSSkinMesh::smVertexIndexList[i] = skin->vertexIndex.address(); 1553 TSSkinMesh::smBoneIndexList[i] = skin->boneIndex.address(); 1554 TSSkinMesh::smWeightList[i] = skin->weight.address(); 1555 TSSkinMesh::smNodeIndexList[i] = skin->batchData.nodeIndex.address(); 1556 } 1557 } 1558 } 1559 meshes.set(ptrmesh, numMeshes); 1560 1561 tsalloc.checkGuard(); 1562 1563 // names 1564 char * nameBufferStart = (char*)tsalloc.getPointer8(0); 1565 char * name = nameBufferStart; 1566 S32 nameBufferSize = 0; 1567 names.setSize(numNames); 1568 for (i=0; i<numNames; i++) 1569 { 1570 for (j=0; name[j]; j++) 1571 ; 1572 1573 names[i] = name; 1574 nameBufferSize += j + 1; 1575 name += j + 1; 1576 } 1577 1578 tsalloc.getPointer8(nameBufferSize); 1579 tsalloc.align32(); 1580 1581 tsalloc.checkGuard(); 1582 1583 if (smReadVersion<23) 1584 { 1585 // get detail information about skins... 1586 S32 * detFirstSkin = tsalloc.getPointer32(numDetails); 1587 S32 * detailNumSkins = tsalloc.getPointer32(numDetails); 1588 1589 tsalloc.checkGuard(); 1590 1591 // about to read in skins...clear out scratch space... 1592 if (numSkins) 1593 { 1594 TSSkinMesh::smInitTransformList.setSize(numSkins); 1595 TSSkinMesh::smVertexIndexList.setSize(numSkins); 1596 TSSkinMesh::smBoneIndexList.setSize(numSkins); 1597 TSSkinMesh::smWeightList.setSize(numSkins); 1598 TSSkinMesh::smNodeIndexList.setSize(numSkins); 1599 } 1600 for (i=0; i<numSkins; i++) 1601 { 1602 TSMesh::smVertsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1603 TSMesh::smTVertsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1604 TSMesh::smNormsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1605 TSMesh::smEncodedNormsList[i]=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 1606 TSMesh::smDataCopied[i]=false; 1607 TSSkinMesh::smInitTransformList[i] = NULL; 1608 TSSkinMesh::smVertexIndexList[i] = NULL; 1609 TSSkinMesh::smBoneIndexList[i] = NULL; 1610 TSSkinMesh::smWeightList[i] = NULL; 1611 TSSkinMesh::smNodeIndexList[i] = NULL; 1612 } 1613 1614 // skins 1615 ptr32 = tsalloc.allocShape32(numSkins); 1616 for (i=0; i<numSkins; i++) 1617 { 1618 bool skip = i<detFirstSkin[skipDL]; 1619 TSSkinMesh * skin = (TSSkinMesh*)TSMesh::assembleMesh(TSMesh::SkinMeshType,skip); 1620 if (meshes.address()) 1621 { 1622 // add pointer to skin in shapes list of meshes 1623 // we reserved room for this above... 1624 meshes.set(meshes.address(),meshes.size()+1); 1625 meshes[meshes.size()-1] = skip ? NULL : skin; 1626 } 1627 1628 // fill in location of verts, tverts, and normals for shared detail levels 1629 if (skin) 1630 { 1631 TSMesh::smVertsList[i] = skin->batchData.initialVerts.address(); 1632 TSMesh::smTVertsList[i] = skin->mTverts.address(); 1633 TSMesh::smNormsList[i] = skin->batchData.initialNorms.address(); 1634 TSMesh::smEncodedNormsList[i] = skin->mEncodedNorms.address(); 1635 TSMesh::smDataCopied[i] = !skip; // as long as we didn't skip this mesh, the data should be in shape now 1636 TSSkinMesh::smInitTransformList[i] = skin->batchData.initialTransforms.address(); 1637 TSSkinMesh::smVertexIndexList[i] = skin->vertexIndex.address(); 1638 TSSkinMesh::smBoneIndexList[i] = skin->boneIndex.address(); 1639 TSSkinMesh::smWeightList[i] = skin->weight.address(); 1640 TSSkinMesh::smNodeIndexList[i] = skin->batchData.nodeIndex.address(); 1641 } 1642 } 1643 1644 tsalloc.checkGuard(); 1645 1646 // we now have skins in mesh list...add skin objects to object list and patch things up 1647 fixupOldSkins(numMeshes,numSkins,numDetails,detFirstSkin,detailNumSkins); 1648 } 1649 1650 // allocate storage space for some arrays (filled in during Shape::init)... 1651 ptr32 = tsalloc.allocShape32(numDetails); 1652 alphaIn.set(ptr32,numDetails); 1653 ptr32 = tsalloc.allocShape32(numDetails); 1654 alphaOut.set(ptr32,numDetails); 1655} 1656 1657void TSShape::disassembleShape() 1658{ 1659 S32 i; 1660 1661 // set counts... 1662 S32 numNodes = tsalloc.set32(nodes.size()); 1663 S32 numObjects = tsalloc.set32(objects.size()); 1664 tsalloc.set32(0); // DEPRECATED decals 1665 S32 numSubShapes = tsalloc.set32(subShapeFirstNode.size()); 1666 tsalloc.set32(0); // DEPRECATED ifl materials 1667 S32 numNodeRotations = tsalloc.set32(nodeRotations.size()); 1668 S32 numNodeTranslations = tsalloc.set32(nodeTranslations.size()); 1669 S32 numNodeUniformScales = tsalloc.set32(nodeUniformScales.size()); 1670 S32 numNodeAlignedScales = tsalloc.set32(nodeAlignedScales.size()); 1671 S32 numNodeArbitraryScales = tsalloc.set32(nodeArbitraryScaleFactors.size()); 1672 S32 numGroundFrames = tsalloc.set32(groundTranslations.size()); 1673 S32 numObjectStates = tsalloc.set32(objectStates.size()); 1674 tsalloc.set32(0); // DEPRECATED decals 1675 S32 numTriggers = tsalloc.set32(triggers.size()); 1676 S32 numDetails = tsalloc.set32(details.size()); 1677 S32 numMeshes = tsalloc.set32(meshes.size()); 1678 S32 numNames = tsalloc.set32(names.size()); 1679 tsalloc.set32((S32)mSmallestVisibleSize); 1680 tsalloc.set32(mSmallestVisibleDL); 1681 1682 tsalloc.setGuard(); 1683 1684 // get bounds... 1685 tsalloc.copyToBuffer32((S32*)&mRadius,1); 1686 tsalloc.copyToBuffer32((S32*)&tubeRadius,1); 1687 tsalloc.copyToBuffer32((S32*)¢er,3); 1688 tsalloc.copyToBuffer32((S32*)&mBounds,6); 1689 1690 tsalloc.setGuard(); 1691 1692 // copy various vectors... 1693 tsalloc.copyToBuffer32((S32*)nodes.address(),numNodes*5); 1694 tsalloc.setGuard(); 1695 tsalloc.copyToBuffer32((S32*)objects.address(),numObjects*6); 1696 tsalloc.setGuard(); 1697 // DEPRECATED: no copy decals 1698 tsalloc.setGuard(); 1699 tsalloc.copyToBuffer32(0,0); // DEPRECATED: ifl materials! 1700 tsalloc.setGuard(); 1701 tsalloc.copyToBuffer32((S32*)subShapeFirstNode.address(),numSubShapes); 1702 tsalloc.copyToBuffer32((S32*)subShapeFirstObject.address(),numSubShapes); 1703 tsalloc.copyToBuffer32(0, numSubShapes); // DEPRECATED: no copy subShapeFirstDecal 1704 tsalloc.setGuard(); 1705 tsalloc.copyToBuffer32((S32*)subShapeNumNodes.address(),numSubShapes); 1706 tsalloc.copyToBuffer32((S32*)subShapeNumObjects.address(),numSubShapes); 1707 tsalloc.copyToBuffer32(0, numSubShapes); // DEPRECATED: no copy subShapeNumDecals 1708 tsalloc.setGuard(); 1709 1710 // default transforms... 1711 tsalloc.copyToBuffer16((S16*)defaultRotations.address(),numNodes*4); 1712 tsalloc.copyToBuffer32((S32*)defaultTranslations.address(),numNodes*3); 1713 1714 // animated transforms... 1715 tsalloc.copyToBuffer16((S16*)nodeRotations.address(),numNodeRotations*4); 1716 tsalloc.copyToBuffer32((S32*)nodeTranslations.address(),numNodeTranslations*3); 1717 1718 tsalloc.setGuard(); 1719 1720 // ...with scale 1721 tsalloc.copyToBuffer32((S32*)nodeUniformScales.address(),numNodeUniformScales); 1722 tsalloc.copyToBuffer32((S32*)nodeAlignedScales.address(),numNodeAlignedScales*3); 1723 tsalloc.copyToBuffer32((S32*)nodeArbitraryScaleFactors.address(),numNodeArbitraryScales*3); 1724 tsalloc.copyToBuffer16((S16*)nodeArbitraryScaleRots.address(),numNodeArbitraryScales*4); 1725 1726 tsalloc.setGuard(); 1727 1728 tsalloc.copyToBuffer32((S32*)groundTranslations.address(),3*numGroundFrames); 1729 tsalloc.copyToBuffer16((S16*)groundRotations.address(),4*numGroundFrames); 1730 1731 tsalloc.setGuard(); 1732 1733 // object states.. 1734 tsalloc.copyToBuffer32((S32*)objectStates.address(),numObjectStates*3); 1735 tsalloc.setGuard(); 1736 1737 // decal states... 1738 // DEPRECATED (numDecalStates = 0) 1739 tsalloc.setGuard(); 1740 1741 // frame triggers 1742 tsalloc.copyToBuffer32((S32*)triggers.address(),numTriggers*2); 1743 tsalloc.setGuard(); 1744 1745 // details 1746 if (TSShape::smVersion > 25) 1747 { 1748 U32 alignedSize32 = sizeof( Detail ) / 4; 1749 tsalloc.copyToBuffer32((S32*)details.address(),numDetails * alignedSize32 ); 1750 } 1751 else 1752 { 1753 // Legacy details => no explicit autobillboard parameters 1754 U32 legacyDetailSize32 = 7; // only store the first 7 4-byte values of each detail 1755 for ( S32 bbID = 0; bbID < details.size(); bbID++ ) 1756 tsalloc.copyToBuffer32( (S32*)&details[bbID], legacyDetailSize32 ); 1757 } 1758 tsalloc.setGuard(); 1759 1760 if (TSShape::smVersion >= 27) 1761 { 1762 // Vertex format now included with mesh data. Note this doesn't include index data which 1763 // is constructed directly in the buffer from the meshes 1764 1765 mBasicVertexFormat.writeAlloc(&tsalloc); 1766 1767 tsalloc.set32(mShapeVertexData.size); 1768 tsalloc.copyToBuffer8((S8*)mShapeVertexData.base, mShapeVertexData.size); 1769 } 1770 1771 // read in the meshes (sans skins)... 1772 bool * isMesh = new bool[numMeshes]; // funny business because decals are pretend meshes (legacy issue) 1773 for (i=0;i<numMeshes;i++) 1774 isMesh[i]=false; 1775 for (i=0; i<objects.size(); i++) 1776 { 1777 for (S32 j=0; j<objects[i].numMeshes; j++) 1778 // even if an empty mesh, it's a mesh... 1779 isMesh[objects[i].startMeshIndex+j]=true; 1780 } 1781 for (i=0; i<numMeshes; i++) 1782 { 1783 TSMesh * mesh = NULL; 1784 // decal mesh deprecated 1785 if (isMesh[i]) 1786 mesh = meshes[i]; 1787 tsalloc.set32( (mesh && mesh->getMeshType() != TSMesh::DecalMeshType) ? mesh->getMeshType() : TSMesh::NullMeshType); 1788 if (mesh) 1789 mesh->disassemble(); 1790 } 1791 delete [] isMesh; 1792 tsalloc.setGuard(); 1793 1794 // names 1795 for (i=0; i<numNames; i++) 1796 tsalloc.copyToBuffer8((S8 *)(names[i].c_str()),names[i].length()+1); 1797 1798 tsalloc.setGuard(); 1799} 1800 1801//------------------------------------------------- 1802// write whole shape 1803//------------------------------------------------- 1804/** Determine whether we can write this shape in TSTPRO compatible format */ 1805bool TSShape::canWriteOldFormat() const 1806{ 1807 // Cannot use old format if using autobillboard details 1808 for (S32 i = 0; i < details.size(); i++) 1809 { 1810 if (details[i].subShapeNum < 0) 1811 return false; 1812 } 1813 1814 for (S32 i = 0; i < meshes.size(); i++) 1815 { 1816 if (!meshes[i]) 1817 continue; 1818 1819 // Cannot use old format if using the new functionality (COLORs, 2nd UV set) 1820 if (meshes[i]->mTverts2.size() || meshes[i]->mColors.size()) 1821 return false; 1822 1823 // Cannot use old format if any primitive has too many triangles 1824 // (ie. cannot fit in a S16) 1825 for (S32 j = 0; j < meshes[i]->mPrimitives.size(); j++) 1826 { 1827 if ((meshes[i]->mPrimitives[j].start + 1828 meshes[i]->mPrimitives[j].numElements) >= (1 << 15)) 1829 { 1830 return false; 1831 } 1832 } 1833 } 1834 1835 return true; 1836} 1837 1838void TSShape::write(Stream * s, bool saveOldFormat) 1839{ 1840 S32 currentVersion = smVersion; 1841 if (saveOldFormat) 1842 smVersion = 24; 1843 1844 // write version 1845 s->write(smVersion | (mExporterVersion<<16)); 1846 1847 tsalloc.setWrite(); 1848 disassembleShape(); 1849 1850 S32 * buffer32 = tsalloc.getBuffer32(); 1851 S16 * buffer16 = tsalloc.getBuffer16(); 1852 S8 * buffer8 = tsalloc.getBuffer8(); 1853 1854 S32 size32 = tsalloc.getBufferSize32(); 1855 S32 size16 = tsalloc.getBufferSize16(); 1856 S32 size8 = tsalloc.getBufferSize8(); 1857 1858 // convert sizes to dwords... 1859 if (size16 & 1) 1860 size16 += 2; 1861 size16 >>= 1; 1862 if (size8 & 3) 1863 size8 += 4; 1864 size8 >>= 2; 1865 1866 S32 sizeMemBuffer, start16, start8; 1867 sizeMemBuffer = size32 + size16 + size8; 1868 start16 = size32; 1869 start8 = start16+size16; 1870 1871 // in dwords -- write will properly endian-flip. 1872 s->write(sizeMemBuffer); 1873 s->write(start16); 1874 s->write(start8); 1875 1876 // endian-flip the entire write buffers. 1877 fixEndian(buffer32,buffer16,buffer8,size32,size16,size8); 1878 1879 // now write buffers 1880 s->write(size32*4,buffer32); 1881 s->write(size16*4,buffer16); 1882 s->write(size8 *4,buffer8); 1883 1884 // write sequences - write will properly endian-flip. 1885 s->write(sequences.size()); 1886 for (S32 i=0; i<sequences.size(); i++) 1887 sequences[i].write(s); 1888 1889 // write material list - write will properly endian-flip. 1890 materialList->write(*s); 1891 1892 delete [] buffer32; 1893 delete [] buffer16; 1894 delete [] buffer8; 1895 1896 smVersion = currentVersion; 1897} 1898 1899//------------------------------------------------- 1900// read whole shape 1901//------------------------------------------------- 1902 1903bool TSShape::read(Stream * s) 1904{ 1905 // read version - read handles endian-flip 1906 s->read(&smReadVersion); 1907 mExporterVersion = smReadVersion >> 16; 1908 smReadVersion &= 0xFF; 1909 if (smReadVersion>smVersion) 1910 { 1911 // error -- don't support future versions yet :> 1912 Con::errorf(ConsoleLogEntry::General, 1913 "Error: attempt to load a version %i dts-shape, can currently only load version %i and before.", 1914 smReadVersion,smVersion); 1915 return false; 1916 } 1917 mReadVersion = smReadVersion; 1918 1919 S32 * memBuffer32; 1920 S16 * memBuffer16; 1921 S8 * memBuffer8; 1922 S32 count32, count16, count8; 1923 if (mReadVersion<19) 1924 { 1925 Con::errorf("... Shape with old version."); 1926 return false; 1927 } 1928 else 1929 { 1930 S32 i; 1931 U32 sizeMemBuffer, startU16, startU8; 1932 1933 // in dwords. - read handles endian-flip 1934 s->read(&sizeMemBuffer); 1935 s->read(&startU16); 1936 s->read(&startU8); 1937 1938 if (s->getStatus()!=<a href="/coding/class/classstream/#classstream_1ab4b87f75f121255ce4e2647941503dd3a7e7659659592dca84c4ff72af19dae16">Stream::Ok</a>) 1939 { 1940 Con::errorf(ConsoleLogEntry::General, "Error: bad shape file."); 1941 return false; 1942 } 1943 1944 S32 * tmp = new S32[sizeMemBuffer]; 1945 s->read(sizeof(S32)*sizeMemBuffer,(U8*)tmp); 1946 memBuffer32 = tmp; 1947 memBuffer16 = (S16*)(tmp+startU16); 1948 memBuffer8 = (S8*)(tmp+startU8); 1949 1950 count32 = startU16; 1951 count16 = startU8-startU16; 1952 count8 = sizeMemBuffer-startU8; 1953 1954 // read sequences 1955 S32 numSequences; 1956 s->read(&numSequences); 1957 sequences.setSize(numSequences); 1958 for (i=0; i<numSequences; i++) 1959 { 1960 sequences[i].read(s); 1961 1962 // Store initial (empty) source data 1963 sequences[i].sourceData.total = sequences[i].numKeyframes; 1964 sequences[i].sourceData.end = sequences[i].sourceData.total - 1; 1965 } 1966 1967 // read material list 1968 delete materialList; // just in case... 1969 materialList = new TSMaterialList; 1970 materialList->read(*s); 1971 } 1972 1973 // since we read in the buffers, we need to endian-flip their entire contents... 1974 fixEndian(memBuffer32,memBuffer16,memBuffer8,count32,count16,count8); 1975 1976 tsalloc.setRead(memBuffer32,memBuffer16,memBuffer8,true); 1977 assembleShape(); // determine size of buffer needed 1978 mShapeDataSize = tsalloc.getSize(); 1979 tsalloc.doAlloc(); 1980 mShapeData = tsalloc.getBuffer(); 1981 tsalloc.setRead(memBuffer32,memBuffer16,memBuffer8,false); 1982 assembleShape(); // copy to buffer 1983 AssertFatal(tsalloc.getSize()==<a href="/coding/class/classtsshape/#classtsshape_1aceeb988a62e9fcfbc4bde6bda7e2597e">mShapeDataSize</a>,"TSShape::read: shape data buffer size mis-calculated"); 1984 1985 delete [] memBuffer32; 1986 1987 if (smInitOnRead) 1988 { 1989 init(); 1990 } 1991 1992 return true; 1993} 1994 1995void TSShape::createEmptyShape() 1996{ 1997 nodes.set(dMalloc(1 * sizeof(Node)), 1); 1998 nodes[0].nameIndex = 1; 1999 nodes[0].parentIndex = -1; 2000 nodes[0].firstObject = 0; 2001 nodes[0].firstChild = -1; 2002 nodes[0].nextSibling = -1; 2003 2004 objects.set(dMalloc(1 * sizeof(Object)), 1); 2005 objects[0].nameIndex = 2; 2006 objects[0].numMeshes = 1; 2007 objects[0].startMeshIndex = 0; 2008 objects[0].nodeIndex = 0; 2009 objects[0].nextSibling = -1; 2010 objects[0].firstDecal = -1; 2011 2012 objectStates.set(dMalloc(1 * sizeof(ObjectState)), 1); 2013 objectStates[0].vis = 1; 2014 objectStates[0].frameIndex = 0; 2015 objectStates[0].matFrameIndex = 0; 2016 2017 subShapeFirstNode.set(dMalloc(1 * sizeof(S32)), 1); 2018 subShapeFirstNode[0] = 0; 2019 2020 subShapeFirstObject.set(dMalloc(1 * sizeof(S32)), 1); 2021 subShapeFirstObject[0] = 0; 2022 2023 detailFirstSkin.set(NULL, 0); 2024 2025 subShapeNumNodes.set(dMalloc(1 * sizeof(S32)), 1); 2026 subShapeNumNodes[0] = 1; 2027 2028 subShapeNumObjects.set(dMalloc(1 * sizeof(S32)), 1); 2029 subShapeNumObjects[0] = 1; 2030 2031 details.set(dMalloc(1 * sizeof(Detail)), 1); 2032 details[0].nameIndex = 0; 2033 details[0].subShapeNum = 0; 2034 details[0].objectDetailNum = 0; 2035 details[0].size = 2.0f; 2036 details[0].averageError = -1.0f; 2037 details[0].maxError = -1.0f; 2038 details[0].polyCount = 0; 2039 2040 defaultRotations.set(dMalloc(1 * sizeof(Quat16)), 1); 2041 defaultRotations[0].x = 0.0f; 2042 defaultRotations[0].y = 0.0f; 2043 defaultRotations[0].z = 0.0f; 2044 defaultRotations[0].w = 0.0f; 2045 2046 defaultTranslations.set(dMalloc(1 * sizeof(Point3F)), 1); 2047 defaultTranslations[0].set(0.0f, 0.0f, 0.0f); 2048 2049 subShapeFirstTranslucentObject.set(dMalloc(1 * sizeof(S32)), 1); 2050 subShapeFirstTranslucentObject[0] = 1; 2051 2052 alphaIn.set(dMalloc(1 * sizeof(F32)), 1); 2053 alphaIn[0] = 0; 2054 2055 alphaOut.set(dMalloc(1 * sizeof(F32)), 1); 2056 alphaOut[0] = -1; 2057 2058 sequences.set(NULL, 0); 2059 nodeRotations.set(NULL, 0); 2060 nodeTranslations.set(NULL, 0); 2061 nodeUniformScales.set(NULL, 0); 2062 nodeAlignedScales.set(NULL, 0); 2063 nodeArbitraryScaleRots.set(NULL, 0); 2064 nodeArbitraryScaleFactors.set(NULL, 0); 2065 groundRotations.set(NULL, 0); 2066 groundTranslations.set(NULL, 0); 2067 triggers.set(NULL, 0); 2068 billboardDetails.set(NULL, 0); 2069 2070 names.setSize(3); 2071 names[0] = StringTable->insert("Detail2"); 2072 names[1] = StringTable->insert("Mesh2"); 2073 names[2] = StringTable->insert("Mesh"); 2074 2075 mRadius = 0.866025f; 2076 tubeRadius = 0.707107f; 2077 center.set(0.0f, 0.5f, 0.0f); 2078 mBounds.minExtents.set(-0.5f, 0.0f, -0.5f); 2079 mBounds.maxExtents.set(0.5f, 1.0f, 0.5f); 2080 2081 mExporterVersion = 124; 2082 mSmallestVisibleSize = 2; 2083 mSmallestVisibleDL = 0; 2084 mReadVersion = 24; 2085 mFlags = 0; 2086 mSequencesConstructed = 0; 2087 2088 mUseDetailFromScreenError = false; 2089 2090 mDetailLevelLookup.setSize( 1 ); 2091 mDetailLevelLookup[0].set( -1, 0 ); 2092 2093 // Init the collision accelerator array. Note that we don't compute the 2094 // accelerators until the app requests them 2095 detailCollisionAccelerators.setSize(details.size()); 2096 for (U32 i = 0; i < detailCollisionAccelerators.size(); i++) 2097 detailCollisionAccelerators[i] = NULL; 2098} 2099 2100void TSShape::fixEndian(S32 * buff32, S16 * buff16, S8 *, S32 count32, S32 count16, S32) 2101{ 2102 // if endian-ness isn't the same, need to flip the buffer contents. 2103 if (0x12345678!=convertLEndianToHost(0x12345678)) 2104 { 2105 for (S32 i=0; i<count32; i++) 2106 buff32[i]=convertLEndianToHost(buff32[i]); 2107 for (S32 i=0; i<count16*2; i++) 2108 buff16[i]=convertLEndianToHost(buff16[i]); 2109 } 2110} 2111 2112template<> void *Resource<TSShape>::create(const Torque::Path &path) 2113{ 2114 // Execute the shape script if it exists 2115 Torque::Path scriptPath(path); 2116 scriptPath.setExtension(TORQUE_SCRIPT_EXTENSION); 2117 2118 // Don't execute the script if we're already doing so! 2119 StringTableEntry currentScript = Platform::stripBasePath(CodeBlock::getCurrentCodeBlockFullPath()); 2120 if (!scriptPath.getFullPath().equal(currentScript)) 2121 { 2122 Torque::Path scriptPathDSO(scriptPath); 2123 scriptPathDSO.setExtension(TORQUE_SCRIPT_EXTENSION ".dso"); 2124 2125 if (Torque::FS::IsFile(scriptPathDSO) || Torque::FS::IsFile(scriptPath)) 2126 { 2127 String evalCmd = "exec(\"" + scriptPath + "\");"; 2128 2129 String instantGroup = Con::getVariable("InstantGroup"); 2130 Con::setIntVariable("InstantGroup", RootGroupId); 2131 Con::evaluate((const char*)evalCmd.c_str(), false, scriptPath.getFullPath()); 2132 Con::setVariable("InstantGroup", instantGroup.c_str()); 2133 } 2134 } 2135 2136 // Attempt to load the shape 2137 TSShape * ret = 0; 2138 bool readSuccess = false; 2139 const String extension = path.getExtension(); 2140 2141 if ( extension.equal( "dts", String::NoCase ) ) 2142 { 2143 FileStream stream; 2144 stream.open( path.getFullPath(), Torque::FS::File::Read ); 2145 if ( stream.getStatus() != Stream::Ok ) 2146 { 2147 Con::errorf( "Resource<TSShape>::create - Could not open '%s'", path.getFullPath().c_str() ); 2148 return NULL; 2149 } 2150 2151 ret = new TSShape; 2152 readSuccess = ret->read(&stream); 2153 } 2154 else if ( extension.equal( "dae", String::NoCase ) || extension.equal( "kmz", String::NoCase ) ) 2155 { 2156#ifdef TORQUE_COLLADA 2157 // Attempt to load the DAE file 2158 ret = loadColladaShape(path); 2159 readSuccess = (ret != NULL); 2160#else 2161 // No COLLADA support => attempt to load the cached DTS file instead 2162 Torque::Path cachedPath = path; 2163 cachedPath.setExtension("cached.dts"); 2164 2165 FileStream stream; 2166 stream.open( cachedPath.getFullPath(), Torque::FS::File::Read ); 2167 if ( stream.getStatus() != Stream::Ok ) 2168 { 2169 Con::errorf( "Resource<TSShape>::create - Could not open '%s'", cachedPath.getFullPath().c_str() ); 2170 return NULL; 2171 } 2172 ret = new TSShape; 2173 readSuccess = ret->read(&stream); 2174#endif 2175 } 2176 else 2177 { 2178 //Con::errorf( "Resource<TSShape>::create - '%s' has an unknown file format", path.getFullPath().c_str() ); 2179 //delete ret; 2180 //return NULL; 2181 2182 // andrewmac: Open Asset Import Library 2183#ifdef TORQUE_ASSIMP 2184 ret = assimpLoadShape(path); 2185 readSuccess = (ret != NULL); 2186#endif 2187 2188 // andrewmac : I could have used another conditional macro but I think this is suffice: 2189 if (!readSuccess) 2190 { 2191 Con::errorf("Resource<TSShape>::create - '%s' has an unknown file format", path.getFullPath().c_str()); 2192 delete ret; 2193 return NULL; 2194 } 2195 } 2196 2197 if( !readSuccess ) 2198 { 2199 Con::errorf( "Resource<TSShape>::create - Error reading '%s'", path.getFullPath().c_str() ); 2200 delete ret; 2201 ret = NULL; 2202 } 2203 2204 return ret; 2205} 2206 2207template<> ResourceBase::Signature Resource<TSShape>::signature() 2208{ 2209 return MakeFourCC('t','s','s','h'); 2210} 2211 2212TSShape::ConvexHullAccelerator* TSShape::getAccelerator(S32 dl) 2213{ 2214 AssertFatal(dl < details.size(), "Error, bad detail level!"); 2215 if (dl == -1) 2216 return NULL; 2217 2218 AssertFatal( detailCollisionAccelerators.size() == details.size(), 2219 "TSShape::getAccelerator() - mismatched array sizes!" ); 2220 2221 if (detailCollisionAccelerators[dl] == NULL) 2222 computeAccelerator(dl); 2223 2224 AssertFatal(detailCollisionAccelerators[dl] != NULL, "This should be non-null after computing it!"); 2225 return detailCollisionAccelerators[dl]; 2226} 2227 2228 2229void TSShape::computeAccelerator(S32 dl) 2230{ 2231 AssertFatal(dl < details.size(), "Error, bad detail level!"); 2232 2233 // Have we already computed this? 2234 if (detailCollisionAccelerators[dl] != NULL) 2235 return; 2236 2237 // Create a bogus features list... 2238 ConvexFeature cf; 2239 MatrixF mat(true); 2240 Point3F n(0, 0, 1); 2241 2242 const TSDetail* detail = &details[dl]; 2243 S32 ss = detail->subShapeNum; 2244 S32 od = detail->objectDetailNum; 2245 2246 S32 start = subShapeFirstObject[ss]; 2247 S32 end = subShapeNumObjects[ss] + start; 2248 if (start < end) 2249 { 2250 // run through objects and collide 2251 // DMMNOTE: This assumes that the transform of the collision hulls is 2252 // identity... 2253 U32 surfaceKey = 0; 2254 for (S32 i = start; i < end; i++) 2255 { 2256 const TSObject* obj = &objects[i]; 2257 2258 if (obj->numMeshes && od < obj->numMeshes) { 2259 TSMesh* mesh = meshes[obj->startMeshIndex + od]; 2260 if (mesh) 2261 mesh->getFeatures(0, mat, n, &cf, surfaceKey); 2262 } 2263 } 2264 } 2265 2266 Vector<Point3F> fixedVerts; 2267 VECTOR_SET_ASSOCIATION(fixedVerts); 2268 S32 i; 2269 for (i = 0; i < cf.mVertexList.size(); i++) { 2270 S32 j; 2271 bool found = false; 2272 for (j = 0; j < cf.mFaceList.size(); j++) { 2273 if (cf.mFaceList[j].vertex[0] == i || 2274 cf.mFaceList[j].vertex[1] == i || 2275 cf.mFaceList[j].vertex[2] == i) { 2276 found = true; 2277 break; 2278 } 2279 } 2280 if (!found) 2281 continue; 2282 2283 found = false; 2284 for (j = 0; j < fixedVerts.size(); j++) { 2285 if (fixedVerts[j] == cf.mVertexList[i]) { 2286 found = true; 2287 break; 2288 } 2289 } 2290 if (found == true) { 2291 // Ok, need to replace any references to vertex i in the facelists with 2292 // a reference to vertex j in the fixed list 2293 for (S32 k = 0; k < cf.mFaceList.size(); k++) { 2294 for (S32 l = 0; l < 3; l++) { 2295 if (cf.mFaceList[k].vertex[l] == i) 2296 cf.mFaceList[k].vertex[l] = j; 2297 } 2298 } 2299 } else { 2300 for (S32 k = 0; k < cf.mFaceList.size(); k++) { 2301 for (S32 l = 0; l < 3; l++) { 2302 if (cf.mFaceList[k].vertex[l] == i) 2303 cf.mFaceList[k].vertex[l] = fixedVerts.size(); 2304 } 2305 } 2306 fixedVerts.push_back(cf.mVertexList[i]); 2307 } 2308 } 2309 cf.mVertexList.setSize(0); 2310 cf.mVertexList = fixedVerts; 2311 2312 // Ok, so now we have a vertex list. Lets copy that out... 2313 ConvexHullAccelerator* accel = new ConvexHullAccelerator; 2314 detailCollisionAccelerators[dl] = accel; 2315 accel->numVerts = cf.mVertexList.size(); 2316 accel->vertexList = new Point3F[accel->numVerts]; 2317 dMemcpy(accel->vertexList, cf.mVertexList.address(), sizeof(Point3F) * accel->numVerts); 2318 2319 accel->normalList = new Point3F[cf.mFaceList.size()]; 2320 for (i = 0; i < cf.mFaceList.size(); i++) 2321 accel->normalList[i] = cf.mFaceList[i].normal; 2322 2323 accel->emitStrings = new U8*[accel->numVerts]; 2324 dMemset(accel->emitStrings, 0, sizeof(U8*) * accel->numVerts); 2325 2326 for (i = 0; i < accel->numVerts; i++) { 2327 S32 j; 2328 2329 Vector<U32> faces; 2330 VECTOR_SET_ASSOCIATION(faces); 2331 for (j = 0; j < cf.mFaceList.size(); j++) { 2332 if (cf.mFaceList[j].vertex[0] == i || 2333 cf.mFaceList[j].vertex[1] == i || 2334 cf.mFaceList[j].vertex[2] == i) { 2335 faces.push_back(j); 2336 } 2337 } 2338 AssertFatal(faces.size() != 0, "Huh? Vertex unreferenced by any faces"); 2339 2340 // Insert all faces that didn't make the first cut, but share a plane with 2341 // a face that's on the short list. 2342 for (j = 0; j < cf.mFaceList.size(); j++) { 2343 bool found = false; 2344 S32 k; 2345 for (k = 0; k < faces.size(); k++) { 2346 if (faces[k] == j) 2347 found = true; 2348 } 2349 if (found) 2350 continue; 2351 2352 found = false; 2353 for (k = 0; k < faces.size(); k++) { 2354 if (mDot(accel->normalList[faces[k]], accel->normalList[j]) > 0.999) { 2355 found = true; 2356 break; 2357 } 2358 } 2359 if (found) 2360 faces.push_back(j); 2361 } 2362 2363 Vector<U32> vertRemaps; 2364 VECTOR_SET_ASSOCIATION(vertRemaps); 2365 for (j = 0; j < faces.size(); j++) { 2366 for (U32 k = 0; k < 3; k++) { 2367 U32 insert = cf.mFaceList[faces[j]].vertex[k]; 2368 bool found = false; 2369 for (S32 l = 0; l < vertRemaps.size(); l++) { 2370 if (insert == vertRemaps[l]) { 2371 found = true; 2372 break; 2373 } 2374 } 2375 if (!found) 2376 vertRemaps.push_back(insert); 2377 } 2378 } 2379 2380 Vector<Point2I> edges; 2381 VECTOR_SET_ASSOCIATION(edges); 2382 for (j = 0; j < faces.size(); j++) { 2383 for (U32 k = 0; k < 3; k++) { 2384 U32 edgeStart = cf.mFaceList[faces[j]].vertex[(k + 0) % 3]; 2385 U32 edgeEnd = cf.mFaceList[faces[j]].vertex[(k + 1) % 3]; 2386 2387 U32 e0 = getMin(edgeStart, edgeEnd); 2388 U32 e1 = getMax(edgeStart, edgeEnd); 2389 2390 bool found = false; 2391 for (S32 l = 0; l < edges.size(); l++) { 2392 if (edges[l].x == e0 && edges[l].y == e1) { 2393 found = true; 2394 break; 2395 } 2396 } 2397 if (!found) 2398 edges.push_back(Point2I(e0, e1)); 2399 } 2400 } 2401 2402 //AssertFatal(vertRemaps.size() < 256 && faces.size() < 256 && edges.size() < 256, 2403 // "Error, ran over the shapebase assumptions about convex hulls."); 2404 2405 U32 emitStringLen = 1 + vertRemaps.size() + 2406 1 + (edges.size() * 2) + 2407 1 + (faces.size() * 4); 2408 accel->emitStrings[i] = new U8[emitStringLen]; 2409 2410 U32 currPos = 0; 2411 2412 accel->emitStrings[i][currPos++] = vertRemaps.size(); 2413 for (j = 0; j < vertRemaps.size(); j++) 2414 accel->emitStrings[i][currPos++] = vertRemaps[j]; 2415 2416 accel->emitStrings[i][currPos++] = edges.size(); 2417 for (j = 0; j < edges.size(); j++) { 2418 S32 l; 2419 U32 old = edges[j].x; 2420 bool found = false; 2421 for (l = 0; l < vertRemaps.size(); l++) { 2422 if (vertRemaps[l] == old) { 2423 found = true; 2424 accel->emitStrings[i][currPos++] = l; 2425 break; 2426 } 2427 } 2428 AssertFatal(found, "Error, couldn't find the remap!"); 2429 2430 old = edges[j].y; 2431 found = false; 2432 for (l = 0; l < vertRemaps.size(); l++) { 2433 if (vertRemaps[l] == old) { 2434 found = true; 2435 accel->emitStrings[i][currPos++] = l; 2436 break; 2437 } 2438 } 2439 AssertFatal(found, "Error, couldn't find the remap!"); 2440 } 2441 2442 accel->emitStrings[i][currPos++] = faces.size(); 2443 for (j = 0; j < faces.size(); j++) { 2444 accel->emitStrings[i][currPos++] = faces[j]; 2445 for (U32 k = 0; k < 3; k++) { 2446 U32 old = cf.mFaceList[faces[j]].vertex[k]; 2447 bool found = false; 2448 for (S32 l = 0; l < vertRemaps.size(); l++) { 2449 if (vertRemaps[l] == old) { 2450 found = true; 2451 accel->emitStrings[i][currPos++] = l; 2452 break; 2453 } 2454 } 2455 AssertFatal(found, "Error, couldn't find the remap!"); 2456 } 2457 } 2458 AssertFatal(currPos == emitStringLen, "Error, over/underflowed the emission string!"); 2459 } 2460} 2461 2462void TSShape::finalizeEditable() 2463{ 2464 for (U32 i = 0; i < meshes.size(); i++) 2465 { 2466 if (meshes[i]) 2467 { 2468 meshes[i]->clearEditable(); 2469 } 2470 } 2471} 2472