tsShapeEdit.cpp
Engine/source/ts/tsShapeEdit.cpp
Public Functions
adjustForNameRemoval(Vector< T > & group, S32 nameIndex)
Adjust the nameIndex for elements in the group.
eraseStates(Vector< T > & vec, const TSIntegerSet & matters, S32 base, S32 numKeyframes, S32 index)
Erase animation keyframes (translation, rotation etc)
findByName(Vector< T > & group, S32 nameIndex)
Get the index of the element in the group with a given name.
Detailed Description
Public Functions
_PadMoveAndTrim(Vector< T * > & vec, S32 offset, S32 count, S32 padLength, S32 oldIndex, S32 newIndex)
adjustForNameRemoval(Vector< T > & group, S32 nameIndex)
Adjust the nameIndex for elements in the group.
doRename(TSShape * shape, Vector< T > & group, const String & oldName, const String & newName)
eraseStates(Vector< T > & vec, const TSIntegerSet & matters, S32 base, S32 numKeyframes, S32 index)
Erase animation keyframes (translation, rotation etc)
findByName(Vector< T > & group, S32 nameIndex)
Get the index of the element in the group with a given name.
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 26#include "console/consoleTypes.h" 27#include "core/resourceManager.h" 28#include "ts/tsShape.h" 29#include "ts/tsShapeInstance.h" 30#include "ts/tsLastDetail.h" 31#include "ts/tsMaterialList.h" 32#include "core/stream/fileStream.h" 33#include "core/volume.h" 34 35 36//----------------------------------------------------------------------------- 37 38S32 TSShape::addName(const String& name) 39{ 40 // Check for empty names 41 if (name.isEmpty()) 42 return -1; 43 44 // Return the index of the new name (add if it is unique) 45 S32 index = findName(name); 46 if (index >= 0) 47 return index; 48 49 names.push_back(StringTable->insert(name)); 50 return names.size()-1; 51} 52 53void TSShape::updateSmallestVisibleDL() 54{ 55 // Update smallest visible detail 56 mSmallestVisibleDL = -1; 57 mSmallestVisibleSize = F32_MAX; 58 F32 maxSize = 0.0f; 59 for (S32 i = 0; i < details.size(); i++) 60 { 61 maxSize = getMax( maxSize, details[i].size ); 62 63 if ((details[i].size >= 0) && (details[i].size < mSmallestVisibleSize)) 64 { 65 mSmallestVisibleDL = i; 66 mSmallestVisibleSize = details[i].size; 67 } 68 } 69 70 // Initialize the detail level lod lookup table. 71 mDetailLevelLookup.setSize( (U32)( maxSize * 2.0f ) + 2 ); 72 for ( U32 l=0; l < mDetailLevelLookup.size(); l++ ) 73 { 74 F32 pixelSize = (F32)l; 75 S32 dl = -1; 76 77 for ( U32 d=0; d < details.size(); d++ ) 78 { 79 // Break when we get to hidden detail 80 // levels like collision shapes. 81 if ( details[d].size < 0 ) 82 break; 83 84 if ( pixelSize > details[d].size ) 85 { 86 dl = d; 87 break; 88 } 89 90 if ( d + 1 >= details.size() || details[d+1].size < 0 ) 91 { 92 // We've run out of details and haven't found anything? 93 // Let's just grab this one. 94 dl = d; 95 break; 96 } 97 } 98 99 // Calculate the intra detail level. 100 F32 intraDL = 0; 101 if ( dl > -1 ) 102 { 103 F32 curSize = details[dl].size; 104 F32 nextSize = dl == 0 ? 2.0f * curSize : details[dl - 1].size; 105 intraDL = mClampF( nextSize - curSize > 0.01f ? (pixelSize - curSize) / (nextSize - curSize) : 1.0f, 0, 1 ); 106 } 107 108 mDetailLevelLookup[l].set( dl, intraDL ); 109 } 110 111 // Test for using the legacy screen error 112 // lod method here instead of runtime. 113 // 114 // See setDetailFromDistance(). 115 // 116 mUseDetailFromScreenError = mSmallestVisibleDL >= 0 && 117 details.first().maxError >= 0; 118} 119 120S32 TSShape::addDetail(const String& dname, S32 size, S32 subShapeNum) 121{ 122 S32 nameIndex = addName(avar("%s%d", dname.c_str(), size)); 123 124 // Check if this detail size has already been added 125 S32 index; 126 for (index = 0; index < details.size(); index++) 127 { 128 if ((details[index].size == size) && 129 (details[index].subShapeNum == subShapeNum) && 130 (details[index].nameIndex == nameIndex)) 131 return index; 132 if (details[index].size < size) 133 break; 134 } 135 136 // Create a new detail level at the right index, so array 137 // remains sorted by detail size (from largest to smallest) 138 details.insert(index); 139 TSShape::Detail &detail = details[index]; 140 141 // Clear the detail to ensure no garbage values 142 // are left in any vars we don't set. 143 dMemset( &detail, 0, sizeof( Detail ) ); 144 145 // Setup the detail. 146 detail.nameIndex = nameIndex; 147 detail.size = size; 148 detail.subShapeNum = subShapeNum; 149 detail.objectDetailNum = 0; 150 detail.averageError = -1; 151 detail.maxError = -1; 152 detail.polyCount = 0; 153 154 // Resize alpha vectors 155 alphaIn.increment(); 156 alphaOut.increment(); 157 158 // Fixup objectDetailNum in other detail levels 159 for (S32 i = index+1; i < details.size(); i++) 160 { 161 if ((details[i].subShapeNum >= 0) && 162 ((subShapeNum == -1) || (details[i].subShapeNum == subShapeNum))) 163 details[i].objectDetailNum++; 164 } 165 166 // Update smallest visible detail 167 updateSmallestVisibleDL(); 168 169 return index; 170} 171 172S32 TSShape::addImposter(const String& cachePath, S32 size, S32 numEquatorSteps, 173 S32 numPolarSteps, S32 dl, S32 dim, bool includePoles, F32 polarAngle) 174{ 175 // Check if the desired size is already in use 176 bool isNewDetail = false; 177 S32 detIndex = findDetailBySize( size ); 178 179 if ( detIndex >= 0 ) 180 { 181 // Size is in use. If the detail is already an imposter, we can just change 182 // the settings, otherwise quit 183 if ( details[detIndex].subShapeNum >= 0 ) 184 { 185 Con::errorf( "TSShape::addImposter: A non-billboard detail already " 186 "exists at size %d", size ); 187 return -1; 188 } 189 } 190 else 191 { 192 // Size is not in use. If an imposter already exists, change its size, otherwise 193 // create a new detail 194 for ( detIndex = 0; detIndex < details.size(); ++detIndex ) 195 { 196 if ( details[detIndex].subShapeNum < 0 ) 197 { 198 // Change the imposter detail size 199 setDetailSize( details[detIndex].size, size ); 200 break; 201 } 202 } 203 if ( detIndex == details.size() ) 204 { 205 isNewDetail = true; 206 detIndex = addDetail( "bbDetail", size, -1 ); 207 } 208 } 209 210 // Now set the billboard properties. 211 Detail &detail = details[detIndex]; 212 213 // In prior to DTS version 26 we would pack the autobillboard 214 // into this single 32bit value. This was prone to overflows 215 // of parameters caused random bugs. 216 // 217 // Set the old autobillboard properties var to zero. 218 detail.objectDetailNum = 0; 219 220 // We now use the new vars. 221 detail.bbEquatorSteps = numEquatorSteps; 222 detail.bbPolarSteps = numPolarSteps; 223 detail.bbPolarAngle = polarAngle; 224 detail.bbDetailLevel = dl; 225 detail.bbDimension = dim; 226 detail.bbIncludePoles = includePoles; 227 228 // Rebuild billboard details or force an update of the modified detail 229 if ( isNewDetail ) 230 { 231 // Add NULL meshes for this detail 232 for ( S32 iObj = 0; iObj < objects.size(); ++iObj ) 233 { 234 if ( detIndex < objects[iObj].numMeshes ) 235 { 236 objects[iObj].numMeshes++; 237 meshes.insert( objects[iObj].startMeshIndex + detIndex, NULL ); 238 for (S32 j = iObj + 1; j < objects.size(); ++j ) 239 objects[j].startMeshIndex++; 240 } 241 } 242 243 // Could be dedicated server. 244 if ( GFXDevice::devicePresent() ) 245 setupBillboardDetails( cachePath ); 246 247 while ( detailCollisionAccelerators.size() < details.size() ) 248 detailCollisionAccelerators.push_back( NULL ); 249 } 250 else 251 { 252 if ( billboardDetails.size() && GFXDevice::devicePresent() ) 253 { 254 delete billboardDetails[detIndex]; 255 billboardDetails[detIndex] = new TSLastDetail( 256 this, 257 cachePath, 258 detail.bbEquatorSteps, 259 detail.bbPolarSteps, 260 detail.bbPolarAngle, 261 detail.bbIncludePoles, 262 detail.bbDetailLevel, 263 detail.bbDimension ); 264 265 billboardDetails[detIndex]->update( true ); 266 } 267 } 268 269 return detIndex; 270} 271 272bool TSShape::removeImposter() 273{ 274 // Find the imposter detail level 275 S32 detIndex; 276 for ( detIndex = 0; detIndex < details.size(); ++detIndex ) 277 { 278 if ( details[detIndex].subShapeNum < 0 ) 279 break; 280 } 281 282 if ( detIndex == details.size() ) 283 { 284 Con::errorf( "TSShape::removeImposter: No imposter detail level found in shape" ); 285 return false; 286 } 287 288 // Remove the detail level 289 details.erase( detIndex ); 290 291 if ( detIndex < billboardDetails.size() ) 292 { 293 // Delete old textures 294 TSLastDetail* bb = billboardDetails[detIndex]; 295 bb->deleteImposterCacheTextures(); 296 delete billboardDetails[detIndex]; 297 } 298 billboardDetails.clear(); 299 300 detailCollisionAccelerators.erase( detIndex ); 301 302 // Remove the (NULL) meshes from each object 303 for ( S32 iObj = 0; iObj < objects.size(); ++iObj ) 304 { 305 if ( detIndex < objects[iObj].numMeshes ) 306 { 307 objects[iObj].numMeshes--; 308 meshes.erase( objects[iObj].startMeshIndex + detIndex ); 309 for (S32 j = iObj + 1; j < objects.size(); ++j ) 310 objects[j].startMeshIndex--; 311 } 312 } 313 314 // Update smallest visible size 315 updateSmallestVisibleDL(); 316 317 return true; 318} 319 320//----------------------------------------------------------------------------- 321 322/// Get the index of the element in the group with a given name 323template<class T> S32 findByName(Vector<T>& group, S32 nameIndex) 324{ 325 for (S32 i = 0; i < group.size(); i++) 326 if (group[i].nameIndex == nameIndex) 327 return i; 328 return -1; 329} 330 331/// Adjust the nameIndex for elements in the group 332template<class T> void adjustForNameRemoval(Vector<T>& group, S32 nameIndex) 333{ 334 for (S32 i = 0; i < group.size(); i++) 335 if (group[i].nameIndex > nameIndex) 336 group[i].nameIndex--; 337} 338 339bool TSShape::removeName(const String& name) 340{ 341 // Check if the name is still in use 342 S32 nameIndex = findName(name); 343 if ((findByName(nodes, nameIndex) >= 0) || 344 (findByName(objects, nameIndex) >= 0) || 345 (findByName(sequences, nameIndex) >= 0) || 346 (findByName(details, nameIndex) >= 0)) 347 return false; 348 349 // Remove the name, then update nameIndex for affected elements 350 names.erase(nameIndex); 351 352 adjustForNameRemoval(nodes, nameIndex); 353 adjustForNameRemoval(objects, nameIndex); 354 adjustForNameRemoval(sequences, nameIndex); 355 adjustForNameRemoval(details, nameIndex); 356 357 return true; 358} 359 360//----------------------------------------------------------------------------- 361 362template<class T> bool doRename(TSShape* shape, Vector<T>& group, const String& oldName, const String& newName) 363{ 364 // Find the element in the group with the oldName 365 S32 index = findByName(group, shape->findName(oldName)); 366 if (index < 0) 367 { 368 Con::errorf("TSShape::rename: Could not find '%s'", oldName.c_str()); 369 return false; 370 } 371 372 // Ignore trivial renames 373 if (oldName.equal(newName, String::NoCase)) 374 return true; 375 376 // Check that this name is not already in use 377 if (findByName(group, shape->findName(newName)) >= 0) 378 { 379 Con::errorf("TSShape::rename: '%s' is already in use", newName.c_str()); 380 return false; 381 } 382 383 // Do the rename (the old name will be removed if it is no longer in use) 384 group[index].nameIndex = shape->addName(newName); 385 shape->removeName(oldName); 386 return true; 387} 388 389bool TSShape::renameNode(const String& oldName, const String& newName) 390{ 391 return doRename(this, nodes, oldName, newName); 392} 393 394bool TSShape::renameObject(const String& oldName, const String& newName) 395{ 396 return doRename(this, objects, oldName, newName); 397} 398 399bool TSShape::renameDetail(const String& oldName, const String& newName) 400{ 401 return doRename(this, details, oldName, newName); 402} 403 404bool TSShape::renameSequence(const String& oldName, const String& newName) 405{ 406 return doRename(this, sequences, oldName, newName); 407} 408 409//----------------------------------------------------------------------------- 410 411bool TSShape::addNode(const String& name, const String& parentName, const Point3F& pos, const QuatF& rot) 412{ 413 // Check that adding this node would not exceed the maximum count 414 if (nodes.size() >= MAX_TS_SET_SIZE) 415 { 416 Con::errorf("TSShape::addNode: Cannot add node, shape already has maximum (%d) nodes", MAX_TS_SET_SIZE); 417 return false; 418 } 419 420 // Check that there is not already a node with this name 421 if (findNode(name) >= 0) 422 { 423 Con::errorf("TSShape::addNode: %s already exists!", name.c_str()); 424 return false; 425 } 426 427 // Find the parent node (OK for name to be empty => node is at root level) 428 S32 parentIndex = -1; 429 if (String::compare(parentName, "")) 430 { 431 parentIndex = findNode(parentName); 432 if (parentIndex < 0) 433 { 434 Con::errorf("TSShape::addNode: Could not find parent node '%s'", parentName.c_str()); 435 return false; 436 } 437 } 438 439 // Need to make everything editable since node indexes etc will change 440 makeEditable(); 441 442 // Insert node at the end of the subshape 443 S32 subShapeIndex = (parentIndex >= 0) ? getSubShapeForNode(parentIndex) : 0; 444 S32 nodeIndex = subShapeNumNodes[subShapeIndex]; 445 446 // Adjust subshape node indices 447 subShapeNumNodes[subShapeIndex]++; 448 for (S32 i = subShapeIndex + 1; i < subShapeFirstNode.size(); i++) 449 subShapeFirstNode[i]++; 450 451 // Update animation sequences 452 for (S32 iSeq = 0; iSeq < sequences.size(); iSeq++) 453 { 454 // Update animation matters arrays (new node is not animated) 455 TSShape::Sequence& seq = sequences[iSeq]; 456 seq.translationMatters.insert(nodeIndex, false); 457 seq.rotationMatters.insert(nodeIndex, false); 458 seq.scaleMatters.insert(nodeIndex, false); 459 } 460 461 // Insert the new node 462 TSShape::Node node; 463 node.nameIndex = addName(name); 464 node.parentIndex = parentIndex; 465 node.firstChild = -1; 466 node.firstObject = -1; 467 node.nextSibling = -1; 468 nodes.insert(nodeIndex, node); 469 470 // Insert node default translation and rotation 471 Quat16 rot16; 472 rot16.set(rot); 473 defaultTranslations.insert(nodeIndex, pos); 474 defaultRotations.insert(nodeIndex, rot16); 475 476 // Fixup node indices 477 for (S32 i = 0; i < nodes.size(); i++) 478 { 479 if (nodes[i].parentIndex >= nodeIndex) 480 nodes[i].parentIndex++; 481 } 482 for (S32 i = 0; i < objects.size(); i++) 483 { 484 if (objects[i].nodeIndex >= nodeIndex) 485 objects[i].nodeIndex++; 486 } 487 for (S32 i = 0; i < meshes.size(); i++) 488 { 489 if (meshes[i] && (meshes[i]->getMeshType() == TSMesh::SkinMeshType)) 490 { 491 TSSkinMesh* skin = dynamic_cast<TSSkinMesh*>(meshes[i]); 492 for (S32 j = 0; j < skin->batchData.nodeIndex.size(); j++) 493 { 494 if (skin->batchData.nodeIndex[j] >= nodeIndex) 495 skin->batchData.nodeIndex[j]++; 496 } 497 } 498 } 499 500 initObjects(); 501 502 return true; 503} 504 505/// Erase animation keyframes (translation, rotation etc) 506template<class T> S32 eraseStates(Vector<T>& vec, const TSIntegerSet& matters, S32 base, S32 numKeyframes, S32 index=-1) 507{ 508 S32 dest, count; 509 if (index == -1) 510 { 511 // Erase for all nodes/objects 512 dest = base; 513 count = numKeyframes * matters.count(); 514 } 515 else 516 { 517 // Erase for the indexed node/object only 518 dest = base + matters.count(index)*numKeyframes; 519 count = numKeyframes; 520 } 521 522 // Erase the values 523 if (count) 524 { 525 if ((dest + count) < vec.size()) 526 dCopyArray(&vec[dest], &vec[dest + count], vec.size() - (dest + count)); 527 vec.decrement(count); 528 } 529 return count; 530} 531 532bool TSShape::removeNode(const String& name) 533{ 534 // Find the node to be removed 535 S32 nodeIndex = findNode(name); 536 if (nodeIndex < 0) 537 { 538 Con::errorf("TSShape::removeNode: Could not find node '%s'", name.c_str()); 539 return false; 540 } 541 542 S32 nodeParentIndex = nodes[nodeIndex].parentIndex; 543 544 // Warn if there are objects attached to this node 545 Vector<S32> nodeObjects; 546 getNodeObjects(nodeIndex, nodeObjects); 547 if (nodeObjects.size()) 548 { 549 Con::warnf("TSShape::removeNode: Node '%s' has %d objects attached, these " 550 "will be reassigned to the node's parent ('%s')", name.c_str(), nodeObjects.size(), 551 ((nodeParentIndex >= 0) ? getName(nodes[nodeParentIndex].nameIndex).c_str() : "null")); 552 } 553 554 // Need to make everything editable since node indexes etc will change 555 makeEditable(); 556 557 // Update animation sequences 558 for (S32 iSeq = 0; iSeq < sequences.size(); iSeq++) 559 { 560 TSShape::Sequence& seq = sequences[iSeq]; 561 562 // Remove animated node transforms 563 if (seq.translationMatters.test(nodeIndex)) 564 eraseStates(nodeTranslations, seq.translationMatters, seq.baseTranslation, seq.numKeyframes, nodeIndex); 565 if (seq.rotationMatters.test(nodeIndex)) 566 eraseStates(nodeRotations, seq.rotationMatters, seq.baseRotation, seq.numKeyframes, nodeIndex); 567 if (seq.scaleMatters.test(nodeIndex)) 568 { 569 if (seq.flags & TSShape::ArbitraryScale) 570 { 571 eraseStates(nodeArbitraryScaleRots, seq.scaleMatters, seq.baseScale, seq.numKeyframes, nodeIndex); 572 eraseStates(nodeArbitraryScaleFactors, seq.scaleMatters, seq.baseScale, seq.numKeyframes, nodeIndex); 573 } 574 else if (seq.flags & TSShape::AlignedScale) 575 eraseStates(nodeAlignedScales, seq.scaleMatters, seq.baseScale, seq.numKeyframes, nodeIndex); 576 else 577 eraseStates(nodeUniformScales, seq.scaleMatters, seq.baseScale, seq.numKeyframes, nodeIndex); 578 } 579 580 seq.translationMatters.erase(nodeIndex); 581 seq.rotationMatters.erase(nodeIndex); 582 seq.scaleMatters.erase(nodeIndex); 583 } 584 585 // Remove the node 586 nodes.erase(nodeIndex); 587 defaultTranslations.erase(nodeIndex); 588 defaultRotations.erase(nodeIndex); 589 590 // Adjust subshape node indices 591 S32 subShapeIndex = getSubShapeForNode(nodeIndex); 592 subShapeNumNodes[subShapeIndex]--; 593 for (S32 i = subShapeIndex + 1; i < subShapeFirstNode.size(); i++) 594 subShapeFirstNode[i]--; 595 596 // Fixup node parent indices 597 for (S32 i = 0; i < nodes.size(); i++) 598 { 599 if (nodes[i].parentIndex == nodeIndex) 600 nodes[i].parentIndex = -1; 601 else if (nodes[i].parentIndex > nodeIndex) 602 nodes[i].parentIndex--; 603 } 604 if (nodeParentIndex > nodeIndex) 605 nodeParentIndex--; 606 607 // Fixup object node indices, and re-assign attached objects to node's parent 608 for (S32 i = 0; i < objects.size(); i++) 609 { 610 if (objects[i].nodeIndex == nodeIndex) 611 objects[i].nodeIndex = nodeParentIndex; 612 if (objects[i].nodeIndex > nodeIndex) 613 objects[i].nodeIndex--; 614 } 615 616 // Fixup skin weight node indices, and re-assign weights for deleted node to its parent 617 for (S32 i = 0; i < meshes.size(); i++) 618 { 619 if (meshes[i] && (meshes[i]->getMeshType() == TSMesh::SkinMeshType)) 620 { 621 TSSkinMesh* skin = dynamic_cast<TSSkinMesh*>(meshes[i]); 622 for (S32 j = 0; j < skin->batchData.nodeIndex.size(); j++) 623 { 624 if (skin->batchData.nodeIndex[j] == nodeIndex) 625 skin->batchData.nodeIndex[j] = nodeParentIndex; 626 if (skin->batchData.nodeIndex[j] > nodeIndex) 627 skin->batchData.nodeIndex[j]--; 628 } 629 } 630 } 631 632 // Remove the sequence name if it is no longer in use 633 removeName(name); 634 635 initObjects(); 636 637 return true; 638} 639 640//----------------------------------------------------------------------------- 641 642bool TSShape::setNodeTransform(const String& name, const Point3F& pos, const QuatF& rot) 643{ 644 // Find the node to be transformed 645 S32 nodeIndex = findNode(name); 646 if (nodeIndex < 0) 647 { 648 Con::errorf("TSShape::setNodeTransform: Could not find node '%s'", name.c_str()); 649 return false; 650 } 651 652 // Update initial node position and rotation 653 defaultTranslations[nodeIndex] = pos; 654 defaultRotations[nodeIndex].set(rot); 655 656 return true; 657} 658 659//----------------------------------------------------------------------------- 660 661S32 TSShape::addObject(const String& objName, S32 subShapeIndex) 662{ 663 S32 objIndex = subShapeNumObjects[subShapeIndex]; 664 665 // Add object to subshape 666 subShapeNumObjects[subShapeIndex]++; 667 for (S32 i = subShapeIndex + 1; i < subShapeFirstObject.size(); i++) 668 subShapeFirstObject[i]++; 669 670 TSShape::Object obj; 671 obj.nameIndex = addName(objName); 672 obj.nodeIndex = 0; 673 obj.numMeshes = 0; 674 obj.startMeshIndex = (objIndex == 0) ? 0 : objects[objIndex-1].startMeshIndex + objects[objIndex-1].numMeshes; 675 obj.firstDecal = 0; 676 obj.nextSibling = 0; 677 objects.insert(objIndex, obj); 678 679 // Add default object state 680 TSShape::ObjectState state; 681 state.frameIndex = 0; 682 state.matFrameIndex = 0; 683 state.vis = 1.0f; 684 objectStates.insert(objIndex, state); 685 686 // Fixup sequences 687 for (S32 i = 0; i < sequences.size(); i++) 688 sequences[i].baseObjectState++; 689 690 return objIndex; 691} 692 693void TSShape::addMeshToObject(S32 objIndex, S32 meshIndex, TSMesh* mesh) 694{ 695 TSShape::Object& obj = objects[objIndex]; 696 697 // Pad with NULLs if required 698 S32 oldNumMeshes = obj.numMeshes; 699 if (mesh) 700 { 701 for (S32 i = obj.numMeshes; i < meshIndex; i++) 702 { 703 meshes.insert(obj.startMeshIndex + i, NULL); 704 obj.numMeshes++; 705 } 706 } 707 708 // Insert the new mesh 709 meshes.insert(obj.startMeshIndex + meshIndex, mesh); 710 obj.numMeshes++; 711 712 // Skinned meshes are not attached to any node 713 if (mesh && (mesh->getMeshType() == TSMesh::SkinMeshType)) 714 obj.nodeIndex = -1; 715 716 // Fixup mesh indices for other objects 717 for (S32 i = 0; i < objects.size(); i++) 718 { 719 if ((i != objIndex) && (objects[i].startMeshIndex >= obj.startMeshIndex)) 720 objects[i].startMeshIndex += (obj.numMeshes - oldNumMeshes); 721 } 722} 723 724void TSShape::removeMeshFromObject(S32 objIndex, S32 meshIndex) 725{ 726 TSShape::Object& obj = objects[objIndex]; 727 728 // Remove the mesh, but do not destroy it (this must be done by the caller) 729 meshes[obj.startMeshIndex + meshIndex] = NULL; 730 731 // Check if there are any objects remaining that have a valid mesh at this 732 // detail size 733 bool removeDetail = true; 734 for (S32 i = 0; i < objects.size(); i++) 735 { 736 if ((meshIndex < objects[i].numMeshes) && meshes[objects[i].startMeshIndex + meshIndex]) 737 { 738 removeDetail = false; 739 break; 740 } 741 } 742 743 // Remove detail level if possible 744 if (removeDetail) 745 { 746 for (S32 i = 0; i < objects.size(); i++) 747 { 748 if (meshIndex < objects[i].numMeshes) 749 { 750 U32 idxToRemove = objects[i].startMeshIndex + meshIndex; 751 meshes.erase(idxToRemove); 752 objects[i].numMeshes--; 753 754 // Clear invalid parent 755 for (U32 k = 0; k < meshes.size(); k++) 756 { 757 if (meshes[k] == NULL) 758 continue; 759 760 if (meshes[k]->mParentMesh == idxToRemove) 761 { 762 meshes[k]->mParentMesh = -1; 763 } 764 else if (meshes[k]->mParentMesh > idxToRemove) 765 { 766 meshes[k]->mParentMesh--; 767 } 768 } 769 770 for (S32 j = 0; j < objects.size(); j++) 771 { 772 if (objects[j].startMeshIndex > objects[i].startMeshIndex) 773 objects[j].startMeshIndex--; 774 } 775 } 776 } 777 778 Vector<S32> validDetails; 779 getSubShapeDetails(getSubShapeForObject(objIndex), validDetails); 780 781 for (S32 i = 0; i < validDetails.size(); i++) 782 { 783 TSShape::Detail& detail = details[validDetails[i]]; 784 if (detail.objectDetailNum > meshIndex) 785 detail.objectDetailNum--; 786 } 787 788 details.erase(validDetails[meshIndex]); 789 } 790 791 // Remove trailing NULL meshes from the object 792 S32 oldNumMeshes = obj.numMeshes; 793 while (obj.numMeshes && !meshes[obj.startMeshIndex + obj.numMeshes - 1]) 794 { 795 U32 idxToRemove = obj.startMeshIndex + obj.numMeshes - 1; 796 meshes.erase(idxToRemove); 797 798 // Clear invalid parent 799 for (U32 k = 0; k < meshes.size(); k++) 800 { 801 if (meshes[k] == NULL) 802 continue; 803 804 if (meshes[k]->mParentMesh == idxToRemove) 805 { 806 meshes[k]->mParentMesh = -1; 807 } 808 else if (meshes[k]->mParentMesh > idxToRemove) 809 { 810 meshes[k]->mParentMesh--; 811 } 812 } 813 814 obj.numMeshes--; 815 } 816 817 // Fixup mesh indices for other objects 818 for (S32 i = 0; i < objects.size(); i++) 819 { 820 if (objects[i].startMeshIndex > obj.startMeshIndex) 821 objects[i].startMeshIndex -= (oldNumMeshes - obj.numMeshes); 822 } 823} 824 825bool TSShape::setObjectNode(const String& objName, const String& nodeName) 826{ 827 // Find the object and node 828 S32 objIndex = findObject(objName); 829 if (objIndex < 0) 830 { 831 Con::errorf("TSShape::setObjectNode: Could not find object '%s'", objName.c_str()); 832 return false; 833 } 834 835 S32 nodeIndex; 836 if (nodeName.isEmpty()) 837 nodeIndex = -1; 838 else 839 { 840 nodeIndex = findNode(nodeName); 841 if (nodeIndex < 0) 842 { 843 Con::errorf("TSShape::setObjectNode: Could not find node '%s'", nodeName.c_str()); 844 return false; 845 } 846 } 847 848 objects[objIndex].nodeIndex = nodeIndex; 849 850 return true; 851} 852 853bool TSShape::removeObject(const String& name) 854{ 855 // Find the object 856 S32 objIndex = findObject(name); 857 if (objIndex < 0) 858 { 859 Con::errorf("TSShape::removeObject: Could not find object '%s'", name.c_str()); 860 return false; 861 } 862 863 // Need to make everything editable since node indexes etc will change 864 makeEditable(); 865 866 // Destroy all meshes in the object 867 TSShape::Object& obj = objects[objIndex]; 868 while ( obj.numMeshes ) 869 { 870 destructInPlace(meshes[obj.startMeshIndex + obj.numMeshes - 1]); 871 removeMeshFromObject(objIndex, obj.numMeshes - 1); 872 } 873 874 // Remove the object from the shape 875 objects.erase(objIndex); 876 S32 subShapeIndex = getSubShapeForObject(objIndex); 877 subShapeNumObjects[subShapeIndex]--; 878 for (S32 i = subShapeIndex + 1; i < subShapeFirstObject.size(); i++) 879 subShapeFirstObject[i]--; 880 881 // Remove the object from all sequences 882 for (S32 i = 0; i < sequences.size(); i++) 883 { 884 TSShape::Sequence& seq = sequences[i]; 885 886 TSIntegerSet objMatters(seq.frameMatters); 887 objMatters.overlap(seq.matFrameMatters); 888 objMatters.overlap(seq.visMatters); 889 890 if (objMatters.test(objIndex)) 891 eraseStates(objectStates, objMatters, seq.baseObjectState, seq.numKeyframes, objIndex); 892 893 seq.frameMatters.erase(objIndex); 894 seq.matFrameMatters.erase(objIndex); 895 seq.visMatters.erase(objIndex); 896 } 897 898 // Remove the object name if it is no longer in use 899 removeName(name); 900 901 // Update smallest visible detail 902 updateSmallestVisibleDL(); 903 904 initObjects(); 905 906 return true; 907} 908 909//----------------------------------------------------------------------------- 910 911// Helper to copy a TSMesh ready for adding to this TSShape (with the right vertex format etc) 912TSMesh* TSShape::copyMesh( const TSMesh* srcMesh ) const 913{ 914 TSMesh * mesh = 0; 915 if ( srcMesh && ( srcMesh->getMeshType() == TSMesh::SkinMeshType ) ) 916 { 917 TSSkinMesh* skin = new TSSkinMesh; 918 919 // Copy skin elements 920 const TSSkinMesh *srcSkin = dynamic_cast<const TSSkinMesh*>(srcMesh); 921 skin->weight = srcSkin->weight; 922 skin->vertexIndex = srcSkin->vertexIndex; 923 skin->boneIndex = srcSkin->boneIndex; 924 925 skin->batchData.nodeIndex = srcSkin->batchData.nodeIndex; 926 skin->batchData.initialTransforms = srcSkin->batchData.initialTransforms; 927 skin->batchData.initialVerts = srcSkin->batchData.initialVerts; 928 skin->batchData.initialNorms = srcSkin->batchData.initialNorms; 929 930 mesh = static_cast<TSMesh*>(skin); 931 } 932 else 933 { 934 mesh = new TSMesh; 935 } 936 937 if ( !srcMesh ) 938 return mesh; // return an empty mesh 939 940 // Copy mesh elements 941 mesh->mIndices = srcMesh->mIndices; 942 mesh->mPrimitives = srcMesh->mPrimitives; 943 mesh->numFrames = srcMesh->numFrames; 944 mesh->numMatFrames = srcMesh->numMatFrames; 945 mesh->vertsPerFrame = srcMesh->vertsPerFrame; 946 mesh->setFlags(srcMesh->getFlags()); 947 mesh->mNumVerts = srcMesh->mNumVerts; 948 949 // Copy vertex data in an *unpacked* form 950 mesh->copySourceVertexDataFrom(srcMesh); 951 952 mesh->createTangents(mesh->mVerts, mesh->mNorms); 953 mesh->mEncodedNorms.set(NULL, 0); 954 955 mesh->computeBounds(); 956 957 return mesh; 958} 959 960bool TSShape::addMesh(TSMesh* mesh, const String& meshName) 961{ 962 // Ensure mesh is in editable state 963 mesh->makeEditable(); 964 965 // Need to make everything editable since node indexes etc will change 966 makeEditable(); 967 968 // Determine the object name and detail size from the mesh name 969 S32 detailSize = 999; 970 String objName(String::GetTrailingNumber(meshName, detailSize)); 971 972 // Find the destination object (create one if it does not exist) 973 S32 objIndex = findObject(objName); 974 if (objIndex < 0) 975 objIndex = addObject(objName, 0); 976 AssertFatal(objIndex >= 0 && objIndex < objects.size(), "Invalid object index!"); 977 978 // Determine the subshape this object belongs to 979 S32 subShapeIndex = getSubShapeForObject(objIndex); 980 AssertFatal(subShapeIndex < subShapeFirstObject.size(), "Could not find subshape for object!"); 981 982 // Get the existing detail levels for the subshape 983 Vector<S32> validDetails; 984 getSubShapeDetails(subShapeIndex, validDetails); 985 986 // Determine where to add the new mesh, and whether this is a new detail 987 S32 detIndex; 988 bool newDetail = true; 989 for (detIndex = 0; detIndex < validDetails.size(); detIndex++) 990 { 991 const TSShape::Detail& det = details[validDetails[detIndex]]; 992 if (detailSize >= det.size) 993 { 994 newDetail = (det.size != detailSize); 995 break; 996 } 997 } 998 999 // Insert the new detail level if required 1000 if (newDetail) 1001 { 1002 // Determine a name for the detail level 1003 const char* detailName; 1004 if (dStrStartsWith(objName, "Col")) 1005 detailName = "collision"; 1006 else if (dStrStartsWith(objName, "loscol")) 1007 detailName = "los"; 1008 else 1009 detailName = "detail"; 1010 1011 S32 index = addDetail(detailName, detailSize, subShapeIndex); 1012 details[index].objectDetailNum = detIndex; 1013 } 1014 1015 // Adding a new mesh or detail level is a bit tricky, since each 1016 // object potentially stores a different number of meshes, including 1017 // NULL meshes for higher detail levels where required. 1018 // For example, the following table shows 3 objects. Note how NULLs 1019 // must be inserted for detail levels higher than the first valid 1020 // mesh, but details after the the last valid mesh are left empty. 1021 // 1022 // Detail | Object1 | Object2 | Object3 1023 // ---------+-----------+-----------+--------- 1024 // 128 | 128 | NULL | NULL 1025 // 64 | | NULL | 64 1026 // 32 | | 32 | NULL 1027 // 2 | | | 2 1028 1029 // Add meshes as required for each object 1030 for (S32 i = 0; i < subShapeNumObjects[subShapeIndex]; i++) 1031 { 1032 S32 index = subShapeFirstObject[subShapeIndex] + i; 1033 const TSShape::Object& obj = objects[index]; 1034 1035 if (index == objIndex) 1036 { 1037 // The target object: replace the existing mesh (if any) or add a new one 1038 // if required. 1039 if (!newDetail && (detIndex < obj.numMeshes)) 1040 { 1041 if ( meshes[obj.startMeshIndex + detIndex] ) 1042 destructInPlace(meshes[obj.startMeshIndex + detIndex]); 1043 meshes[obj.startMeshIndex + detIndex] = mesh; 1044 } 1045 else 1046 addMeshToObject(index, detIndex, mesh); 1047 } 1048 else 1049 { 1050 // Other objects: add a NULL mesh only if inserting before a valid mesh 1051 if (newDetail && (detIndex < obj.numMeshes)) 1052 addMeshToObject(index, detIndex, NULL); 1053 } 1054 } 1055 1056 initObjects(); 1057 1058 return true; 1059} 1060 1061bool TSShape::addMesh(TSShape* srcShape, const String& srcMeshName, const String& meshName) 1062{ 1063 // Find the mesh in the source shape 1064 TSMesh* srcMesh = srcShape->findMesh(srcMeshName); 1065 if (!srcMesh) 1066 { 1067 Con::errorf("TSShape::addMesh: Could not find mesh '%s' in shape", srcMeshName.c_str()); 1068 return false; 1069 } 1070 1071 // Copy the source mesh 1072 TSMesh *mesh = copyMesh( srcMesh ); 1073 if (srcMesh->getMeshType() == TSMesh::SkinMeshType) 1074 { 1075 TSSkinMesh *srcSkin = dynamic_cast<TSSkinMesh*>(srcMesh); 1076 1077 // Check that the source skin is compatible with our skeleton 1078 Vector<S32> nodeMap(srcShape->nodes.size()); 1079 for (S32 i = 0; i < srcShape->nodes.size(); i++) 1080 nodeMap.push_back( findNode( srcShape->getName(srcShape->nodes[i].nameIndex) ) ); 1081 1082 for (S32 i = 0; i < srcSkin->boneIndex.size(); i++) 1083 { 1084 S32 srcNode = srcSkin->boneIndex[i]; 1085 if (nodeMap[srcNode] == -1) 1086 { 1087 const char* name = srcShape->getName(srcShape->nodes[srcNode].nameIndex).c_str(); 1088 Con::errorf("TSShape::addMesh: Skin is weighted to node (%s) that " 1089 "does not exist in this shape", name); 1090 return false; 1091 } 1092 } 1093 1094 TSSkinMesh *skin = dynamic_cast<TSSkinMesh*>(mesh); 1095 1096 // Remap node indices 1097 skin->batchData.nodeIndex = srcSkin->batchData.nodeIndex; 1098 for (S32 i = 0; i < skin->batchData.nodeIndex.size(); i++) 1099 skin->batchData.nodeIndex[i] = nodeMap[skin->batchData.nodeIndex[i]]; 1100 } 1101 1102 // Add the copied mesh to the shape 1103 if (!addMesh(mesh, meshName)) 1104 { 1105 delete mesh; 1106 return false; 1107 } 1108 1109 // Copy materials used by the source mesh (only if from a different shape) 1110 if (srcShape != this) 1111 { 1112 for (S32 i = 0; i < mesh->mPrimitives.size(); i++) 1113 { 1114 if (!(mesh->mPrimitives[i].matIndex & TSDrawPrimitive::NoMaterial)) 1115 { 1116 S32 drawType = (mesh->mPrimitives[i].matIndex & (~<a href="/coding/class/structtsdrawprimitive/">TSDrawPrimitive</a>::MaterialMask)); 1117 S32 srcMatIndex = mesh->mPrimitives[i].matIndex & TSDrawPrimitive::MaterialMask; 1118 const String& matName = srcShape->materialList->getMaterialName(srcMatIndex); 1119 1120 // Add the material if it does not already exist 1121 S32 destMatIndex = materialList->getMaterialNameList().find_next(matName); 1122 if (destMatIndex < 0) 1123 { 1124 destMatIndex = materialList->size(); 1125 materialList->push_back(matName, srcShape->materialList->getFlags(srcMatIndex)); 1126 } 1127 1128 mesh->mPrimitives[i].matIndex = drawType | destMatIndex; 1129 } 1130 } 1131 } 1132 1133 return true; 1134} 1135 1136bool TSShape::setMeshSize(const String& meshName, S32 size) 1137{ 1138 S32 objIndex, meshIndex; 1139 if (!findMeshIndex(meshName, objIndex, meshIndex) || 1140 !meshes[objects[objIndex].startMeshIndex + meshIndex]) 1141 { 1142 Con::errorf("TSShape::setMeshSize: Could not find mesh '%s'", meshName.c_str()); 1143 return false; 1144 } 1145 1146 // Need to make everything editable since node indexes etc will change 1147 makeEditable(); 1148 1149 // Remove the mesh from the object, but don't destroy it 1150 TSShape::Object& obj = objects[objIndex]; 1151 TSMesh* mesh = meshes[obj.startMeshIndex + meshIndex]; 1152 removeMeshFromObject(objIndex, meshIndex); 1153 1154 // Add the mesh back at the new position 1155 addMesh(mesh, avar("%s %d", getName(obj.nameIndex).c_str(), size)); 1156 1157 // Update smallest visible detail 1158 updateSmallestVisibleDL(); 1159 1160 initObjects(); 1161 1162 return true; 1163} 1164 1165bool TSShape::removeMesh(const String& meshName) 1166{ 1167 S32 objIndex, meshIndex; 1168 if (!findMeshIndex(meshName, objIndex, meshIndex) || 1169 !meshes[objects[objIndex].startMeshIndex + meshIndex]) 1170 { 1171 Con::errorf("TSShape::removeMesh: Could not find mesh '%s'", meshName.c_str()); 1172 return false; 1173 } 1174 1175 // Need to make everything editable since node indexes etc will change 1176 makeEditable(); 1177 1178 // Destroy and remove the mesh 1179 TSShape::Object& obj = objects[objIndex]; 1180 destructInPlace(meshes[obj.startMeshIndex + meshIndex]); 1181 removeMeshFromObject(objIndex, meshIndex); 1182 1183 // Remove the object if there are no meshes left 1184 if (!obj.numMeshes) 1185 removeObject(getName(obj.nameIndex)); 1186 1187 // Update smallest visible detail 1188 updateSmallestVisibleDL(); 1189 1190 initObjects(); 1191 1192 return true; 1193} 1194 1195//----------------------------------------------------------------------------- 1196 1197// Helper function for dealing with some of the Vectors used in a TSShape. 'meshes' 1198// for example contains a TSMesh* per-object, per-detail-level, with NULLs for 1199// undefined details for each object. Trailing NULLs are not added to the Vector, 1200// so you end up with a different number of pointers for each object, depending 1201// on which detail levels it defines. This makes it tricky to move meshes around 1202// since you have to know how many elements belong to each object. 1203// To simplify things, this function pads the Vector up to a certain length (so 1204// all objects can appear to have the same number of meshes), the moves a single 1205// element to a new index, then trims trailing NULLs again. 1206template<class T> 1207static void _PadMoveAndTrim(Vector<T*>& vec, S32 offset, S32 count, 1208 S32 padLength, S32 oldIndex, S32 newIndex) 1209{ 1210 // Pad the array with NULLs 1211 for ( S32 i = count; i < padLength; ++i ) 1212 vec.insert( offset + count, NULL ); 1213 1214 // Move the element from the old to the new index 1215 T* tmp = vec[offset + oldIndex]; 1216 vec.erase( offset + oldIndex ); 1217 vec.insert( offset + newIndex, tmp ); 1218 1219 // Trim trailing NULLs from the vector 1220 for ( S32 i = padLength - 1; i >= 0; --i ) 1221 { 1222 if ( vec[offset + i] ) 1223 break; 1224 else 1225 vec.erase( offset + i ); 1226 } 1227} 1228 1229S32 TSShape::setDetailSize(S32 oldSize, S32 newSize) 1230{ 1231 S32 oldIndex = findDetailBySize( oldSize ); 1232 if ( oldIndex < 0 ) 1233 { 1234 Con::errorf( "TSShape::setDetailSize: Cannot find detail with size %d", oldSize ); 1235 return -1; 1236 } 1237 1238 // Remove this detail from the list 1239 TSShape::Detail tmpDetail = details[oldIndex]; 1240 tmpDetail.size = newSize; 1241 details.erase(oldIndex); 1242 1243 // Determine the new position for the detail (details are sorted by size) 1244 S32 newIndex = 0; 1245 for ( newIndex = 0; newIndex < details.size(); ++newIndex ) 1246 { 1247 if ( newSize > details[newIndex].size ) 1248 break; 1249 } 1250 1251 // Add the detail at its new position 1252 details.insert( newIndex, tmpDetail ); 1253 1254 // Rename the detail so its trailing size value is correct 1255 { 1256 S32 tmp; 1257 String oldName( getName( tmpDetail.nameIndex ) ); 1258 String newName( String::GetTrailingNumber( oldName, tmp ) ); 1259 newName += String::ToString( "%d", newSize ); 1260 renameDetail(oldName, newName); 1261 } 1262 1263 if ( newIndex != oldIndex ) 1264 { 1265 // Fixup details 1266 for ( S32 iDet = 0; iDet < details.size(); iDet++ ) 1267 { 1268 if ( details[iDet].subShapeNum < 0 ) 1269 { 1270 if ( details[iDet].bbDetailLevel == oldIndex ) 1271 details[iDet].bbDetailLevel = newIndex; 1272 } 1273 else 1274 { 1275 details[iDet].objectDetailNum = iDet; 1276 } 1277 } 1278 1279 // Fixup Billboard details 1280 _PadMoveAndTrim( billboardDetails, 0, billboardDetails.size(), 1281 details.size(), oldIndex, newIndex ); 1282 1283 // Now move the mesh for each object in the subshape (adding and removing 1284 // NULLs as appropriate) 1285 for ( S32 iObj = 0; iObj < objects.size(); ++iObj ) 1286 { 1287 TSShape::Object& obj = objects[iObj]; 1288 S32 oldMeshCount = meshes.size(); 1289 1290 _PadMoveAndTrim( meshes, obj.startMeshIndex, obj.numMeshes, 1291 details.size(), oldIndex, newIndex ); 1292 1293 obj.numMeshes += ( meshes.size() - oldMeshCount ); 1294 1295 // Fixup startMeshIndex for remaining objects 1296 for ( S32 j = iObj + 1; j < objects.size(); ++j ) 1297 objects[j].startMeshIndex += ( meshes.size() - oldMeshCount ); 1298 } 1299 } 1300 1301 // Update smallest visible detail 1302 updateSmallestVisibleDL(); 1303 1304 // Nothing major, just reint object lists 1305 initObjects(); 1306 1307 return newIndex; 1308} 1309 1310bool TSShape::removeDetail( S32 size ) 1311{ 1312 S32 dl = findDetailBySize( size ); 1313 1314 if ( ( dl < 0 ) || ( dl >= details.size() ) ) 1315 { 1316 Con::errorf( "TSShape::removeDetail: Invalid detail index (%d)", dl ); 1317 return false; 1318 } 1319 1320 // Need to make everything editable since node indexes etc will change 1321 makeEditable(); 1322 1323 // Destroy and remove each mesh in the detail level 1324 for ( S32 objIndex = objects.size()-1; objIndex >= 0; objIndex-- ) 1325 { 1326 TSShape::Object& obj = objects[objIndex]; 1327 if ( dl < obj.numMeshes ) 1328 { 1329 if ( meshes[obj.startMeshIndex + dl] ) 1330 destructInPlace( meshes[obj.startMeshIndex + dl] ); 1331 removeMeshFromObject(objIndex, dl); 1332 1333 // Remove the object if there are no meshes left 1334 if (!obj.numMeshes) 1335 removeObject( getName( obj.nameIndex ) ); 1336 } 1337 } 1338 1339 // Destroy billboard detail level 1340 if ( dl < billboardDetails.size() ) 1341 { 1342 if ( billboardDetails[dl] ) 1343 { 1344 // Delete old textures 1345 billboardDetails[dl]->deleteImposterCacheTextures(); 1346 delete billboardDetails[dl]; 1347 } 1348 1349 billboardDetails.erase( dl ); 1350 } 1351 1352 // Update smallest visible detail 1353 updateSmallestVisibleDL(); 1354 1355 initObjects(); 1356 1357 return true; 1358} 1359 1360//----------------------------------------------------------------------------- 1361bool TSShape::addSequence(const Torque::Path& path, const String& fromSeq, 1362 const String& name, S32 startFrame, S32 endFrame, 1363 bool padRotKeys, bool padTransKeys) 1364{ 1365 String oldName(fromSeq); 1366 1367 if (path.getExtension().equal("dsq", String::NoCase)) 1368 { 1369 S32 oldSeqCount = sequences.size(); 1370 1371 // DSQ source file 1372 char filenameBuf[1024]; 1373 Con::expandScriptFilename(filenameBuf, sizeof(filenameBuf), path.getFullPath().c_str()); 1374 1375 FileStream *f; 1376 if((f = FileStream::createAndOpen( filenameBuf, Torque::FS::File::Read )) == NULL) 1377 { 1378 Con::errorf("TSShape::addSequence: Could not load DSQ file '%s'", filenameBuf); 1379 return false; 1380 } 1381 if (!importSequences(f, filenameBuf) || (f->getStatus() != Stream::Ok)) 1382 { 1383 delete f; 1384 Con::errorf("TSShape::addSequence: Load sequence file '%s' failed", filenameBuf); 1385 return false; 1386 } 1387 delete f; 1388 1389 // Rename the new sequence if required (avoid rename if name is not 1390 // unique (this will be fixed up later, and we don't need 2 errors about it!) 1391 if (oldName.isEmpty()) 1392 oldName = getName(sequences.last().nameIndex); 1393 if (!oldName.equal(name)) 1394 { 1395 if (findSequence(name) == -1) 1396 { 1397 // Use a dummy intermediate name since we might be renaming from an 1398 // existing name (and we want to rename the right sequence!) 1399 sequences.last().nameIndex = addName("__dummy__"); 1400 renameSequence("__dummy__", name); 1401 } 1402 } 1403 1404 // Check that sequences have unique names 1405 bool lastSequenceRejected = false; 1406 for (S32 i = sequences.size()-1; i >= oldSeqCount; i--) 1407 { 1408 S32 nameIndex = (i == sequences.size()-1) ? findName(name) : sequences[i].nameIndex; 1409 S32 seqIndex = findSequence(nameIndex); 1410 if ((seqIndex != -1) && (seqIndex != i)) 1411 { 1412 Con::errorf("TSShape::addSequence: Failed to add sequence '%s' " 1413 "(name already exists)", getName(nameIndex).c_str()); 1414 sequences[i].nameIndex = addName("__dummy__"); 1415 removeSequence("__dummy__"); 1416 if (i == sequences.size()) 1417 lastSequenceRejected = true; 1418 } 1419 } 1420 1421 // @todo:Need to remove keyframes if start!=0 and end!=-1 1422 TSShape::Sequence& seq = sequences.last(); 1423 1424 // Store information about how this sequence was created 1425 seq.sourceData.from = String::ToString("%s\t%s", filenameBuf, name.c_str()); 1426 seq.sourceData.total = seq.numKeyframes; 1427 seq.sourceData.start = ((startFrame < 0) || (startFrame >= seq.numKeyframes)) ? 0 : startFrame; 1428 seq.sourceData.end = ((endFrame < 0) || (endFrame >= seq.numKeyframes)) ? seq.numKeyframes-1 : endFrame; 1429 1430 return (sequences.size() != oldSeqCount); 1431 } 1432 1433 /* Check that sequence to be added does not already exist */ 1434 if (findSequence(name) != -1) 1435 { 1436 Con::errorf("TSShape::addSequence: Cannot add sequence '%s' (name already exists)", name.c_str()); 1437 return false; 1438 } 1439 1440 Resource<TSShape> hSrcShape; 1441 TSShape* srcShape = this; // Assume we are copying an existing sequence 1442 1443 if (path.getExtension().equal("dts", String::NoCase) || 1444 path.getExtension().equal("dae", String::NoCase)) 1445 { 1446 // DTS or DAE source file 1447 char filenameBuf[1024]; 1448 Con::expandScriptFilename(filenameBuf, sizeof(filenameBuf), path.getFullPath().c_str()); 1449 1450 hSrcShape = ResourceManager::get().load(filenameBuf); 1451 if (!bool(hSrcShape)) 1452 { 1453 Con::errorf("TSShape::addSequence: Could not load source shape '%s'", path.getFullPath().c_str()); 1454 return false; 1455 } 1456 srcShape = const_cast<TSShape*>((const TSShape*)hSrcShape); 1457 if (!srcShape->sequences.size()) 1458 { 1459 Con::errorf("TSShape::addSequence: Source shape '%s' does not contain any sequences", path.getFullPath().c_str()); 1460 return false; 1461 } 1462 1463 // If no sequence name is specified, just use the first one 1464 if (oldName.isEmpty()) 1465 oldName = srcShape->getName(srcShape->sequences[0].nameIndex); 1466 } 1467 else 1468 { 1469 // Source is an existing sequence 1470 oldName = path.getFullPath(); 1471 } 1472 1473 // Find the sequence 1474 S32 seqIndex = srcShape->findSequence(oldName); 1475 if (seqIndex < 0) 1476 { 1477 Con::errorf("TSShape::addSequence (%s): Could not find sequence named '%s'", path.getFullPath().c_str(), oldName.c_str()); 1478 return false; 1479 } 1480 1481 // Check keyframe range 1482 const TSShape::Sequence* srcSeq = &srcShape->sequences[seqIndex]; 1483 if ((startFrame < 0) || (startFrame >= srcSeq->numKeyframes)) 1484 { 1485 Con::warnf("TSShape::addSequence (%s): Start keyframe (%d) out of range (0-%d) for sequence '%s'", 1486 path.getFullPath().c_str(), startFrame, srcSeq->numKeyframes-1, oldName.c_str()); 1487 startFrame = 0; 1488 } 1489 if (endFrame < 0) 1490 endFrame = srcSeq->numKeyframes - 1; 1491 else if (endFrame >= srcSeq->numKeyframes) 1492 { 1493 Con::warnf("TSShape::addSequence (%s): End keyframe (%d) out of range (0-%d) for sequence '%s'", 1494 path.getFullPath().c_str(), endFrame, srcSeq->numKeyframes-1, oldName.c_str()); 1495 endFrame = srcSeq->numKeyframes - 1; 1496 } 1497 1498 // Create array to map source nodes to our nodes 1499 Vector<S32> nodeMap(srcShape->nodes.size()); 1500 for (S32 i = 0; i < srcShape->nodes.size(); i++) 1501 nodeMap.push_back(findNode(srcShape->getName(srcShape->nodes[i].nameIndex))); 1502 1503 // Create array to map source objects to our objects 1504 Vector<S32> objectMap(srcShape->objects.size()); 1505 for (S32 i = 0; i < srcShape->objects.size(); i++) 1506 objectMap.push_back(findObject(srcShape->getName(srcShape->objects[i].nameIndex))); 1507 1508 // Copy the source sequence (need to do it this ugly way instead of just 1509 // using push_back since srcSeq pointer may change if copying a sequence 1510 // from inside the shape itself 1511 sequences.increment(); 1512 TSShape::Sequence& seq = sequences.last(); 1513 srcSeq = &srcShape->sequences[seqIndex]; // update pointer as it may have changed! 1514 seq = *srcSeq; 1515 1516 seq.nameIndex = addName(name); 1517 seq.numKeyframes = endFrame - startFrame + 1; 1518 if (seq.duration > 0) 1519 seq.duration *= ((F32)seq.numKeyframes / srcSeq->numKeyframes); 1520 1521 // Add object states 1522 // Note: only visibility animation is supported 1523 seq.frameMatters.clearAll(); 1524 seq.matFrameMatters.clearAll(); 1525 seq.visMatters.clearAll(); 1526 for (S32 i = 0; i < objectMap.size(); i++) 1527 { 1528 if (objectMap[i] < 0) 1529 continue; 1530 1531 if (srcSeq->visMatters.test(i)) 1532 { 1533 // Check if visibility is animated within the frames to be copied 1534 const F32 defaultVis = srcShape->objectStates[i].vis; 1535 S32 objNum = srcSeq->visMatters.count(i); 1536 for (S32 iFrame = startFrame; iFrame <= endFrame; iFrame++) 1537 { 1538 if (srcShape->getObjectState(*srcSeq, iFrame, objNum).vis != defaultVis) 1539 { 1540 seq.visMatters.set(objectMap[i]); 1541 break; 1542 } 1543 } 1544 } 1545 } 1546 1547 TSIntegerSet srcObjectStateSet(srcSeq->frameMatters); 1548 srcObjectStateSet.overlap(srcSeq->matFrameMatters); 1549 srcObjectStateSet.overlap(srcSeq->visMatters); 1550 1551 TSIntegerSet objectStateSet(seq.frameMatters); 1552 objectStateSet.overlap(seq.matFrameMatters); 1553 objectStateSet.overlap(seq.visMatters); 1554 1555 seq.baseObjectState = objectStates.size(); 1556 objectStates.increment(objectStateSet.count()*seq.numKeyframes); 1557 for (S32 i = 0; i < objectMap.size(); i++) 1558 { 1559 if (objectMap[i] < 0) 1560 continue; 1561 1562 // Note: only visibility animation is supported 1563 if (objectStateSet.test(objectMap[i])) 1564 { 1565 S32 src = srcSeq->baseObjectState + srcSeq->numKeyframes * srcObjectStateSet.count(i) + startFrame; 1566 S32 dest = seq.baseObjectState + seq.numKeyframes * objectStateSet.count(objectMap[i]); 1567 dCopyArray(&objectStates[dest], &srcShape->objectStates[src], seq.numKeyframes); 1568 } 1569 } 1570 1571 // Add ground frames 1572 F32 ratio = (F32)seq.numKeyframes / srcSeq->numKeyframes; 1573 S32 groundBase = srcSeq->firstGroundFrame + startFrame*ratio; 1574 1575 seq.numGroundFrames *= ratio; 1576 seq.firstGroundFrame = groundTranslations.size(); 1577 groundTranslations.reserve(mMin(groundTranslations.size() + seq.numGroundFrames, srcShape->groundTranslations.size())); 1578 groundRotations.reserve(mMin(groundRotations.size() + seq.numGroundFrames, srcShape->groundRotations.size())); 1579 for (S32 i = 0; i < seq.numGroundFrames; i++) 1580 { 1581 S32 offset = groundBase + i; 1582 if (offset >= srcShape->groundTranslations.size()) 1583 { 1584 Con::errorf("%s groundTranslations out of bounds! [%i/%i] ", path.getFullPath().c_str(), groundBase + i, srcShape->groundTranslations.size()); 1585 offset = srcShape->groundTranslations.size() - 1; 1586 } 1587 1588 groundTranslations.push_back(srcShape->groundTranslations[offset]); 1589 1590 S32 offset2 = groundBase + i; 1591 if (offset2 >= srcShape->groundRotations.size()) 1592 { 1593 Con::errorf("%s groundRotations out of bounds! [%i/%i] ", path.getFullPath().c_str(), groundBase + i, srcShape->groundRotations.size()); 1594 offset2 = srcShape->groundRotations.size() - 1; 1595 } 1596 1597 groundRotations.push_back(srcShape->groundRotations[offset2]); 1598 } 1599 1600 // Add triggers 1601 seq.numTriggers = 0; 1602 seq.firstTrigger = triggers.size(); 1603 F32 seqStartPos = (F32)startFrame / seq.numKeyframes; 1604 F32 seqEndPos = (F32)endFrame / seq.numKeyframes; 1605 for (S32 i = 0; i < srcSeq->numTriggers; i++) 1606 { 1607 const TSShape::Trigger& srcTrig = srcShape->triggers[srcSeq->firstTrigger + i]; 1608 if ((srcTrig.pos >= seqStartPos) && (srcTrig.pos <= seqEndPos)) 1609 { 1610 triggers.push_back(srcTrig); 1611 triggers.last().pos -= seqStartPos; 1612 seq.numTriggers++; 1613 } 1614 } 1615 1616 // Fixup node matters arrays 1617 seq.translationMatters.clearAll(); 1618 seq.rotationMatters.clearAll(); 1619 seq.scaleMatters.clearAll(); 1620 for (S32 i = 0; i < nodeMap.size(); i++) 1621 { 1622 if (nodeMap[i] < 0) 1623 continue; 1624 1625 if (srcSeq->translationMatters.test(i)) 1626 { 1627 // Check if node position is animated within the frames to be copied 1628 const Point3F& defaultTrans = srcShape->defaultTranslations[i]; 1629 S32 tranNum = srcSeq->translationMatters.count(i); 1630 for (S32 iFrame = startFrame; iFrame <= endFrame; iFrame++) 1631 { 1632 if (srcShape->getTranslation(*srcSeq, iFrame, tranNum) != defaultTrans) 1633 { 1634 seq.translationMatters.set(nodeMap[i]); 1635 break; 1636 } 1637 } 1638 } 1639 1640 if (srcSeq->rotationMatters.test(i)) 1641 { 1642 // Check if node rotation is animated within the frames to be copied 1643 const QuatF defaultRot = srcShape->defaultRotations[i].getQuatF(); 1644 S32 rotNum = srcSeq->rotationMatters.count(i); 1645 for (S32 iFrame = startFrame; iFrame <= endFrame; iFrame++) 1646 { 1647 QuatF temp; 1648 if (srcShape->getRotation(*srcSeq, iFrame, rotNum, &temp) != defaultRot) 1649 { 1650 seq.rotationMatters.set(nodeMap[i]); 1651 break; 1652 } 1653 } 1654 } 1655 if (srcSeq->scaleMatters.test(i)) 1656 { 1657 S32 scaleNum = srcSeq->scaleMatters.count(i); 1658 1659 // Check if node scale is animated within the frames to be copied 1660 if (srcSeq->animatesArbitraryScale()) 1661 { 1662 TSScale defaultScale; 1663 defaultScale.identity(); 1664 for (S32 iFrame = startFrame; iFrame <= endFrame; iFrame++) 1665 { 1666 TSScale temp; 1667 if (!(srcShape->getArbitraryScale(*srcSeq, iFrame, scaleNum, &temp) == defaultScale)) 1668 { 1669 seq.scaleMatters.set(nodeMap[i]); 1670 break; 1671 } 1672 } 1673 } 1674 else if (srcSeq->animatesAlignedScale()) 1675 { 1676 const Point3F defaultScale(Point3F::One); 1677 for (S32 iFrame = startFrame; iFrame <= endFrame; iFrame++) 1678 { 1679 if (srcShape->getAlignedScale(*srcSeq, iFrame, scaleNum) != defaultScale) 1680 { 1681 seq.scaleMatters.set(nodeMap[i]); 1682 break; 1683 } 1684 } 1685 } 1686 else if (srcSeq->animatesUniformScale()) 1687 { 1688 const F32 defaultScale = 1.0f; 1689 for (S32 iFrame = startFrame; iFrame <= endFrame; iFrame++) 1690 { 1691 if (srcShape->getUniformScale(*srcSeq, iFrame, scaleNum) != defaultScale) 1692 { 1693 seq.scaleMatters.set(nodeMap[i]); 1694 break; 1695 } 1696 } 1697 } 1698 } 1699 } 1700 1701 // Resize the node transform arrays 1702 seq.baseTranslation = nodeTranslations.size(); 1703 nodeTranslations.increment(seq.translationMatters.count()*seq.numKeyframes); 1704 seq.baseRotation = nodeRotations.size(); 1705 nodeRotations.increment(seq.rotationMatters.count()*seq.numKeyframes); 1706 if (seq.flags & TSShape::ArbitraryScale) 1707 { 1708 S32 scaleCount = seq.scaleMatters.count(); 1709 seq.baseScale = nodeArbitraryScaleRots.size(); 1710 nodeArbitraryScaleRots.increment(scaleCount*seq.numKeyframes); 1711 nodeArbitraryScaleFactors.increment(scaleCount*seq.numKeyframes); 1712 } 1713 else if (seq.flags & TSShape::AlignedScale) 1714 { 1715 seq.baseScale = nodeAlignedScales.size(); 1716 nodeAlignedScales.increment(seq.scaleMatters.count()*seq.numKeyframes); 1717 } 1718 else 1719 { 1720 seq.baseScale = nodeUniformScales.size(); 1721 nodeUniformScales.increment(seq.scaleMatters.count()*seq.numKeyframes); 1722 } 1723 1724 // Add node transforms (remap from source node indices to our node indices). As 1725 // well as copying animated node translations and rotations, also handle when the 1726 // default translation and rotation are different between the source and 1727 // destination shapes. 1728 for (S32 i = 0; i < nodeMap.size(); i++) 1729 { 1730 if (nodeMap[i] < 0) 1731 continue; 1732 1733 if (seq.translationMatters.test(nodeMap[i])) 1734 { 1735 S32 src = srcSeq->baseTranslation + srcSeq->numKeyframes * srcSeq->translationMatters.count(i) + startFrame; 1736 S32 dest = seq.baseTranslation + seq.numKeyframes * seq.translationMatters.count(nodeMap[i]); 1737 dCopyArray(&nodeTranslations[dest], &srcShape->nodeTranslations[src], seq.numKeyframes); 1738 } 1739 else if (padTransKeys && (defaultTranslations[nodeMap[i]] != srcShape->defaultTranslations[i])) 1740 { 1741 seq.translationMatters.set(nodeMap[i]); 1742 S32 dest = seq.baseTranslation + seq.numKeyframes * seq.translationMatters.count(nodeMap[i]); 1743 for (S32 j = 0; j < seq.numKeyframes; j++) 1744 nodeTranslations.insert(dest, srcShape->defaultTranslations[i]); 1745 } 1746 1747 if (seq.rotationMatters.test(nodeMap[i])) 1748 { 1749 S32 src = srcSeq->baseRotation + srcSeq->numKeyframes * srcSeq->rotationMatters.count(i) + startFrame; 1750 S32 dest = seq.baseRotation + seq.numKeyframes * seq.rotationMatters.count(nodeMap[i]); 1751 dCopyArray(&nodeRotations[dest], &srcShape->nodeRotations[src], seq.numKeyframes); 1752 } 1753 else if (padRotKeys && (defaultRotations[nodeMap[i]] != srcShape->defaultRotations[i])) 1754 { 1755 seq.rotationMatters.set(nodeMap[i]); 1756 S32 dest = seq.baseRotation + seq.numKeyframes * seq.rotationMatters.count(nodeMap[i]); 1757 for (S32 j = 0; j < seq.numKeyframes; j++) 1758 nodeRotations.insert(dest, srcShape->defaultRotations[i]); 1759 } 1760 1761 if (seq.scaleMatters.test(nodeMap[i])) 1762 { 1763 S32 src = srcSeq->baseScale + srcSeq->numKeyframes * srcSeq->scaleMatters.count(i)+ startFrame; 1764 S32 dest = seq.baseScale + seq.numKeyframes * seq.scaleMatters.count(nodeMap[i]); 1765 if (seq.flags & TSShape::ArbitraryScale) 1766 { 1767 dCopyArray(&nodeArbitraryScaleRots[dest], &srcShape->nodeArbitraryScaleRots[src], seq.numKeyframes); 1768 dCopyArray(&nodeArbitraryScaleFactors[dest], &srcShape->nodeArbitraryScaleFactors[src], seq.numKeyframes); 1769 } 1770 else if (seq.flags & TSShape::AlignedScale) 1771 dCopyArray(&nodeAlignedScales[dest], &srcShape->nodeAlignedScales[src], seq.numKeyframes); 1772 else 1773 dCopyArray(&nodeUniformScales[dest], &srcShape->nodeUniformScales[src], seq.numKeyframes); 1774 } 1775 } 1776 1777 // Set shape flags (only the most significant scale type) 1778 U32 curVal = mFlags & AnyScale; 1779 mFlags &= ~(AnyScale); 1780 mFlags |= getMax(curVal, seq.flags & AnyScale); // take the larger value (can only convert upwards) 1781 1782 // Set sequence flags 1783 seq.dirtyFlags = 0; 1784 if (seq.rotationMatters.testAll() || seq.translationMatters.testAll() || seq.scaleMatters.testAll()) 1785 seq.dirtyFlags |= TSShapeInstance::TransformDirty; 1786 if (seq.visMatters.testAll()) 1787 seq.dirtyFlags |= TSShapeInstance::VisDirty; 1788 if (seq.frameMatters.testAll()) 1789 seq.dirtyFlags |= TSShapeInstance::FrameDirty; 1790 if (seq.matFrameMatters.testAll()) 1791 seq.dirtyFlags |= TSShapeInstance::MatFrameDirty; 1792 1793 // Store information about how this sequence was created 1794 seq.sourceData.from = String::ToString("%s\t%s", path.getFullPath().c_str(), oldName.c_str()); 1795 seq.sourceData.total = srcSeq->numKeyframes; 1796 seq.sourceData.start = startFrame; 1797 seq.sourceData.end = endFrame; 1798 1799 return true; 1800} 1801 1802bool TSShape::removeSequence(const String& name) 1803{ 1804 // Find the sequence to be removed 1805 S32 seqIndex = findSequence(name); 1806 if (seqIndex < 0) 1807 { 1808 Con::errorf("TSShape::removeSequence: Could not find sequence '%s'", name.c_str()); 1809 return false; 1810 } 1811 1812 TSShape::Sequence& seq = sequences[seqIndex]; 1813 1814 // Remove the node transforms for this sequence 1815 S32 transCount = eraseStates(nodeTranslations, seq.translationMatters, seq.baseTranslation, seq.numKeyframes); 1816 S32 rotCount = eraseStates(nodeRotations, seq.rotationMatters, seq.baseRotation, seq.numKeyframes); 1817 S32 scaleCount = 0; 1818 if (seq.flags & TSShape::ArbitraryScale) 1819 { 1820 scaleCount = eraseStates(nodeArbitraryScaleRots, seq.scaleMatters, seq.baseScale, seq.numKeyframes); 1821 eraseStates(nodeArbitraryScaleFactors, seq.scaleMatters, seq.baseScale, seq.numKeyframes); 1822 } 1823 else if (seq.flags & TSShape::AlignedScale) 1824 scaleCount = eraseStates(nodeAlignedScales, seq.scaleMatters, seq.baseScale, seq.numKeyframes); 1825 else 1826 scaleCount = eraseStates(nodeUniformScales, seq.scaleMatters, seq.baseScale, seq.numKeyframes); 1827 1828 // Remove the object states for this sequence 1829 TSIntegerSet objMatters(seq.frameMatters); 1830 objMatters.overlap(seq.matFrameMatters); 1831 objMatters.overlap(seq.visMatters); 1832 S32 objCount = eraseStates(objectStates, objMatters, seq.baseObjectState, seq.numKeyframes); 1833 1834 // Remove groundframes and triggers 1835 TSIntegerSet dummy; 1836 eraseStates(groundTranslations, dummy, seq.firstGroundFrame, seq.numGroundFrames, 0); 1837 eraseStates(groundRotations, dummy, seq.firstGroundFrame, seq.numGroundFrames, 0); 1838 eraseStates(triggers, dummy, seq.firstTrigger, seq.numTriggers, 0); 1839 1840 // Fixup the base indices of the other sequences 1841 for (S32 i = seqIndex + 1; i < sequences.size(); i++) 1842 { 1843 sequences[i].baseTranslation -= transCount; 1844 sequences[i].baseRotation -= rotCount; 1845 sequences[i].baseScale -= scaleCount; 1846 sequences[i].baseObjectState -= objCount; 1847 sequences[i].firstGroundFrame -= seq.numGroundFrames; 1848 sequences[i].firstTrigger -= seq.numTriggers; 1849 } 1850 1851 // Remove the sequence itself 1852 sequences.erase(seqIndex); 1853 1854 // Remove the sequence name if it is no longer in use 1855 removeName(name); 1856 1857 return true; 1858} 1859 1860//----------------------------------------------------------------------------- 1861 1862bool TSShape::addTrigger(const String& seqName, S32 keyframe, S32 state) 1863{ 1864 // Find the sequence 1865 S32 seqIndex = findSequence(seqName); 1866 if (seqIndex < 0) 1867 { 1868 Con::errorf("TSShape::addTrigger: Could not find sequence '%s'", seqName.c_str()); 1869 return false; 1870 } 1871 1872 TSShape::Sequence& seq = sequences[seqIndex]; 1873 if (keyframe >= seq.numKeyframes) 1874 { 1875 Con::errorf("TSShape::addTrigger: Keyframe out of range (0-%d for sequence '%s')", 1876 seq.numKeyframes-1, seqName.c_str()); 1877 return false; 1878 } 1879 1880 // Encode the trigger state 1881 if (state < 0) 1882 state = 1 << (-state-1); 1883 else if (state > 0) 1884 state = (1 << (state-1)) | TSShape::Trigger::StateOn; 1885 1886 // Fixup seq.firstTrigger if this sequence does not have any triggers yet 1887 if (seq.numTriggers == 0) 1888 { 1889 seq.firstTrigger = 0; 1890 for (S32 i = 0; i < seqIndex; i++) 1891 seq.firstTrigger += sequences[i].numTriggers; 1892 } 1893 1894 // Find where to insert the trigger (sorted by keyframe) 1895 S32 trigIndex; 1896 for (trigIndex = seq.firstTrigger; trigIndex < (seq.firstTrigger + seq.numTriggers); trigIndex++) 1897 { 1898 const TSShape::Trigger& trig = triggers[trigIndex]; 1899 if ((S32)(trig.pos * seq.numKeyframes) > keyframe) 1900 break; 1901 } 1902 1903 // Create the new trigger 1904 TSShape::Trigger trig; 1905 trig.pos = (F32)keyframe / getMax(1, seq.numKeyframes-1); 1906 trig.state = state; 1907 triggers.insert(trigIndex, trig); 1908 seq.numTriggers++; 1909 1910 // set invert for other triggers if needed 1911 if ((trig.state & TSShape::Trigger::StateOn) == 0) 1912 { 1913 U32 offTrigger = (trig.state & TSShape::Trigger::StateMask); 1914 for (S32 i = 0; i < seq.numTriggers; i++) 1915 { 1916 if (triggers[seq.firstTrigger + i].state & offTrigger) 1917 triggers[seq.firstTrigger + i].state |= TSShape::Trigger::InvertOnReverse; 1918 } 1919 } 1920 1921 // fixup firstTrigger index for other sequences 1922 for (S32 i = seqIndex + 1; i < sequences.size(); i++) 1923 { 1924 if (sequences[i].numTriggers > 0) 1925 sequences[i].firstTrigger++; 1926 } 1927 1928 // set MakePath flag so triggers will be animated 1929 seq.flags |= TSShape::MakePath; 1930 1931 return true; 1932} 1933 1934bool TSShape::removeTrigger(const String& seqName, S32 keyframe, S32 state) 1935{ 1936 // Find the sequence 1937 S32 seqIndex = findSequence(seqName); 1938 if (seqIndex < 0) 1939 { 1940 Con::errorf("TSShape::removeTrigger: Could not find sequence '%s'", seqName.c_str()); 1941 return false; 1942 } 1943 1944 TSShape::Sequence& seq = sequences[seqIndex]; 1945 if (keyframe >= seq.numKeyframes) 1946 { 1947 Con::errorf("TSShape::removeTrigger: Keyframe out of range (0-%d for sequence '%s')", 1948 seq.numKeyframes-1, seqName.c_str()); 1949 return false; 1950 } 1951 1952 // Encode the trigger state 1953 if (state < 0) 1954 state = 1 << (-state-1); 1955 else if (state > 0) 1956 state = (1 << (state-1)) | TSShape::Trigger::StateOn; 1957 1958 // Find and remove the trigger 1959 for (S32 trigIndex = seq.firstTrigger; trigIndex < (seq.firstTrigger + seq.numTriggers); trigIndex++) 1960 { 1961 TSShape::Trigger& trig = triggers[trigIndex]; 1962 S32 cmpFrame = (S32)(trig.pos * (seq.numKeyframes-1) + 0.5f); 1963 S32 cmpState = trig.state & (~TSShape::Trigger::InvertOnReverse); 1964 1965 if ((cmpFrame == keyframe) && (cmpState == state)) 1966 { 1967 triggers.erase(trigIndex); 1968 seq.numTriggers--; 1969 1970 // Fix up firstTrigger for other sequences 1971 for (S32 i = seqIndex + 1; i < sequences.size(); i++) 1972 { 1973 if (sequences[i].numTriggers > 0) 1974 sequences[i].firstTrigger--; 1975 } 1976 1977 // Clear MakePath flag if no more triggers 1978 if ( seq.numTriggers == 0 ) 1979 seq.flags &= (~TSShape::MakePath); 1980 1981 return true; 1982 } 1983 } 1984 1985 Con::errorf("TSShape::removeTrigger: Could not find trigger (%d, %d) for sequence '%s'", 1986 keyframe, state, seqName.c_str()); 1987 1988 return false; 1989} 1990 1991void TSShape::getNodeKeyframe(S32 nodeIndex, const TSShape::Sequence& seq, S32 keyframe, MatrixF* mat) const 1992{ 1993 // Get the node rotation and translation 1994 QuatF rot; 1995 if (seq.rotationMatters.test(nodeIndex)) 1996 { 1997 S32 index = seq.rotationMatters.count(nodeIndex) * seq.numKeyframes + keyframe; 1998 nodeRotations[seq.baseRotation + index].getQuatF(&rot); 1999 } 2000 else 2001 defaultRotations[nodeIndex].getQuatF(&rot); 2002 2003 Point3F trans; 2004 if (seq.translationMatters.test(nodeIndex)) 2005 { 2006 S32 index = seq.translationMatters.count(nodeIndex) * seq.numKeyframes + keyframe; 2007 trans = nodeTranslations[seq.baseTranslation + index]; 2008 } 2009 else 2010 trans = defaultTranslations[nodeIndex]; 2011 2012 // Set the keyframe matrix 2013 rot.setMatrix(mat); 2014 mat->setPosition(trans); 2015} 2016 2017bool TSShape::setSequenceBlend(const String& seqName, bool blend, const String& blendRefSeqName, S32 blendRefFrame) 2018{ 2019 // Find the target sequence 2020 S32 seqIndex = findSequence(seqName); 2021 if (seqIndex < 0) 2022 { 2023 Con::errorf("TSShape::setSequenceBlend: Could not find sequence named '%s'", seqName.c_str()); 2024 return false; 2025 } 2026 TSShape::Sequence& seq = sequences[seqIndex]; 2027 2028 // Ignore if blend flag is already correct 2029 if (seq.isBlend() == blend) 2030 return true; 2031 2032 // Find the sequence containing the reference frame 2033 S32 blendRefSeqIndex = findSequence(blendRefSeqName); 2034 if (blendRefSeqIndex < 0) 2035 { 2036 Con::errorf("TSShape::setSequenceBlend: Could not find reference sequence named '%s'", blendRefSeqName.c_str()); 2037 return false; 2038 } 2039 TSShape::Sequence& blendRefSeq = sequences[blendRefSeqIndex]; 2040 2041 if ((blendRefFrame < 0) || (blendRefFrame >= blendRefSeq.numKeyframes)) 2042 { 2043 Con::errorf("TSShape::setSequenceBlend: Reference frame out of range (0-%d)", blendRefSeq.numKeyframes-1); 2044 return false; 2045 } 2046 2047 // Set the new flag 2048 if (blend) 2049 seq.flags |= TSShape::Blend; 2050 else 2051 seq.flags &= (~TSShape::Blend); 2052 2053 // For each animated node in the target sequence, need to add or subtract the 2054 // reference keyframe from each frame 2055 TSIntegerSet nodeMatters(seq.rotationMatters); 2056 nodeMatters.overlap(seq.translationMatters); 2057 2058 S32 end = nodeMatters.end(); 2059 for (S32 nodeIndex = nodeMatters.start(); nodeIndex < end; nodeMatters.next(nodeIndex)) 2060 { 2061 MatrixF refMat; 2062 getNodeKeyframe(nodeIndex, blendRefSeq, blendRefFrame, &refMat); 2063 2064 // Add or subtract the reference? 2065 if (blend) 2066 refMat.inverse(); 2067 2068 bool updateRot(false), updateTrans(false); 2069 S32 rotOffset(0), transOffset(0); 2070 if (seq.rotationMatters.test(nodeIndex)) 2071 { 2072 updateRot = true; 2073 rotOffset = seq.baseRotation + seq.rotationMatters.count(nodeIndex) * seq.numKeyframes; 2074 } 2075 if (seq.translationMatters.test(nodeIndex)) 2076 { 2077 updateTrans = true; 2078 transOffset = seq.baseTranslation + seq.translationMatters.count(nodeIndex) * seq.numKeyframes; 2079 } 2080 2081 for (S32 frame = 0; frame < seq.numKeyframes; frame++) 2082 { 2083 MatrixF oldMat; 2084 getNodeKeyframe(nodeIndex, seq, frame, &oldMat); 2085 2086 MatrixF newMat; 2087 newMat.mul(refMat, oldMat); 2088 2089 if (updateRot) 2090 nodeRotations[rotOffset + frame].set(QuatF(newMat)); 2091 if (updateTrans) 2092 nodeTranslations[transOffset + frame] = newMat.getPosition(); 2093 } 2094 } 2095 2096 // Update sequence blend information 2097 seq.sourceData.blendSeq = blendRefSeqName; 2098 seq.sourceData.blendFrame = blendRefFrame; 2099 2100 return true; 2101} 2102 2103bool TSShape::setSequenceGroundSpeed(const String& seqName, const Point3F& trans, const Point3F& rot) 2104{ 2105 // Find the sequence 2106 S32 seqIndex = findSequence(seqName); 2107 if (seqIndex < 0) 2108 { 2109 Con::errorf("setSequenceGroundSpeed: Could not find sequence named '%s'", seqName.c_str()); 2110 return false; 2111 } 2112 TSShape::Sequence& seq = sequences[seqIndex]; 2113 2114 // Determine how many ground-frames to generate (FPS=10, at least 1 frame) 2115 const F32 groundFrameRate = 10.0f; 2116 S32 numFrames = getMax(1, (S32)(seq.duration * groundFrameRate)); 2117 2118 // Allocate space for the frames (add/delete frames as required) 2119 S32 frameAdjust = numFrames - seq.numGroundFrames; 2120 for (S32 i = 0; i < mAbs(frameAdjust); i++) 2121 { 2122 if (frameAdjust > 0) 2123 { 2124 groundTranslations.insert(seq.firstGroundFrame); 2125 groundRotations.insert(seq.firstGroundFrame); 2126 } 2127 else 2128 { 2129 groundTranslations.erase(seq.firstGroundFrame); 2130 groundRotations.erase(seq.firstGroundFrame); 2131 } 2132 } 2133 2134 // Fixup ground frame indices 2135 seq.numGroundFrames += frameAdjust; 2136 for (S32 i = seqIndex + 1; i < sequences.size(); i++) 2137 sequences[i].firstGroundFrame += frameAdjust; 2138 2139 // Generate the ground-frames 2140 Point3F adjTrans = trans; 2141 Point3F adjRot = rot; 2142 if (seq.numGroundFrames > 0) 2143 { 2144 adjTrans /= seq.numGroundFrames; 2145 adjRot /= seq.numGroundFrames; 2146 } 2147 QuatF rotSpeed(adjRot); 2148 QuatF groundRot(rotSpeed); 2149 for (S32 i = 0; i < seq.numGroundFrames; i++) 2150 { 2151 groundTranslations[seq.firstGroundFrame + i] = adjTrans * (i + 1); 2152 groundRotations[seq.firstGroundFrame + i].set(groundRot); 2153 groundRot *= rotSpeed; 2154 } 2155 2156 // set MakePath flag so ground frames will be animated 2157 seq.flags |= TSShape::MakePath; 2158 2159 return true; 2160} 2161 2162void TSShape::makeEditable() 2163{ 2164 mNeedReinit = true; 2165 if (mShapeVertexData.base == NULL) 2166 return; 2167 2168 for (U32 i = 0; i < meshes.size(); i++) 2169 { 2170 if (meshes[i]) 2171 { 2172 meshes[i]->makeEditable(); 2173 } 2174 } 2175 2176 mShapeVertexData.set(NULL, 0); 2177} 2178 2179bool TSShape::needsReinit() 2180{ 2181 return mVertexSize == 0 || mShapeVertexData.base == NULL || mNeedReinit; 2182} 2183