prefab.cpp
Public Variables
bool
For frame signal.
Public Functions
ConsoleDocClass(Prefab , "@brief A collection of arbitrary objects which can be allocated and manipulated as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n\n</a>" "%<a href="/coding/class/classprefab/">Prefab</a> always points <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> (.prefab) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> which defines its objects. In " "fact more than one %<a href="/coding/class/classprefab/">Prefab</a> can reference this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and both will update " "<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">modified.\n\n</a>" "%<a href="/coding/class/classprefab/">Prefab</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> very simple object and only exists on the server. When it is " "created it allocates children objects by reading the (.prefab) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> like " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> list of instructions. It then sets their transform relative <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the %<a href="/coding/class/classprefab/">Prefab</a> " "and Torque networking handles the rest by ghosting the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> objects <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> clients. " "%<a href="/coding/class/classprefab/">Prefab</a> itself is not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ghosted.\n\n</a>" "@ingroup enviroMisc" )
IMPLEMENT_CALLBACK(Prefab , onLoad , void , (SimGroup *children) , (children) , "Called when the prefab <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> is loaded and children objects are <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">created.\n</a>" "@param children <a href="/coding/class/classsimgroup/">SimGroup</a> containing all children <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" )
Detailed Description
Public Variables
bool gEditingMission
For frame signal.
Vector< String > sPrefabFileStack
Public Functions
ConsoleDocClass(Prefab , "@brief A collection of arbitrary objects which can be allocated and manipulated as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n\n</a>" "%<a href="/coding/class/classprefab/">Prefab</a> always points <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> (.prefab) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> which defines its objects. In " "fact more than one %<a href="/coding/class/classprefab/">Prefab</a> can reference this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and both will update " "<a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">modified.\n\n</a>" "%<a href="/coding/class/classprefab/">Prefab</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> very simple object and only exists on the server. When it is " "created it allocates children objects by reading the (.prefab) <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> like " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> list of instructions. It then sets their transform relative <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the %<a href="/coding/class/classprefab/">Prefab</a> " "and Torque networking handles the rest by ghosting the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> objects <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> clients. " "%<a href="/coding/class/classprefab/">Prefab</a> itself is not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ghosted.\n\n</a>" "@ingroup enviroMisc" )
IMPLEMENT_CALLBACK(Prefab , onLoad , void , (SimGroup *children) , (children) , "Called when the prefab <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> is loaded and children objects are <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">created.\n</a>" "@param children <a href="/coding/class/classsimgroup/">SimGroup</a> containing all children <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" )
IMPLEMENT_CO_NETOBJECT_V1(Prefab )
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 "T3D/prefab.h" 26 27#include "math/mathIO.h" 28#include "core/stream/bitStream.h" 29#include "scene/sceneRenderState.h" 30#include "gfx/gfxTransformSaver.h" 31#include "renderInstance/renderPassManager.h" 32#include "console/consoleTypes.h" 33#include "core/volume.h" 34#include "console/engineAPI.h" 35#include "T3D/physics/physicsShape.h" 36#include "core/util/path.h" 37 38#include "T3D/Scene.h" 39 40// We use this locally ( within this file ) to prevent infinite recursion 41// while loading prefab files that contain other prefabs. 42static Vector<String> sPrefabFileStack; 43 44Map<SimObjectId,SimObjectId> Prefab::smChildToPrefabMap; 45 46IMPLEMENT_CO_NETOBJECT_V1(Prefab); 47 48ConsoleDocClass( Prefab, 49 "@brief A collection of arbitrary objects which can be allocated and manipulated as a group.\n\n" 50 51 "%Prefab always points to a (.prefab) file which defines its objects. In " 52 "fact more than one %Prefab can reference this file and both will update " 53 "if the file is modified.\n\n" 54 55 "%Prefab is a very simple object and only exists on the server. When it is " 56 "created it allocates children objects by reading the (.prefab) file like " 57 "a list of instructions. It then sets their transform relative to the %Prefab " 58 "and Torque networking handles the rest by ghosting the new objects to clients. " 59 "%Prefab itself is not ghosted.\n\n" 60 61 "@ingroup enviroMisc" 62); 63 64IMPLEMENT_CALLBACK( Prefab, onLoad, void, ( SimGroup *children ), ( children ), 65 "Called when the prefab file is loaded and children objects are created.\n" 66 "@param children SimGroup containing all children objects.\n" 67); 68 69Prefab::Prefab() 70{ 71 // Not ghosted unless we're editing 72 mNetFlags.clear(Ghostable); 73 74 mTypeMask |= StaticObjectType; 75} 76 77Prefab::~Prefab() 78{ 79} 80 81void Prefab::initPersistFields() 82{ 83 addGroup( "Prefab" ); 84 85 addProtectedField( "filename", TypePrefabFilename, Offset( mFilename, Prefab ), 86 &protectedSetFile, &defaultProtectedGetFn, 87 "(.prefab) File describing objects within this prefab." ); 88 89 endGroup( "Prefab" ); 90 91 Parent::initPersistFields(); 92} 93 94extern bool gEditingMission; 95 96bool Prefab::onAdd() 97{ 98 if ( !Parent::onAdd() ) 99 return false; 100 101 mObjBox.set( Point3F( -0.5f, -0.5f, -0.5f ), 102 Point3F( 0.5f, 0.5f, 0.5f ) ); 103 104 resetWorldBox(); 105 106 // Not added to the scene unless we are editing. 107 if ( gEditingMission ) 108 onEditorEnable(); 109 110 // Only the server-side prefab needs to create/update child objects. 111 // We rely on regular Torque ghosting of the individual child objects 112 // to take care of the rest. 113 if ( isServerObject() ) 114 { 115 _loadFile( true ); 116 _updateChildren(); 117 } 118 119 return true; 120} 121 122void Prefab::onRemove() 123{ 124 if ( isServerObject() ) 125 _closeFile( true ); 126 127 removeFromScene(); 128 Parent::onRemove(); 129} 130 131void Prefab::onEditorEnable() 132{ 133 if ( isClientObject() ) 134 return; 135 136 // Just in case we are already in the scene, lets not cause an assert. 137 if ( mContainer != NULL ) 138 return; 139 140 // Enable ghosting so we can see this on the client. 141 mNetFlags.set(Ghostable); 142 setScopeAlways(); 143 addToScene(); 144 145 Parent::onEditorEnable(); 146} 147 148void Prefab::onEditorDisable() 149{ 150 if ( isClientObject() ) 151 return; 152 153 // Just in case we are not in the scene, lets not cause an assert. 154 if ( mContainer == NULL ) 155 return; 156 157 // Do not need this on the client if we are not editing. 158 removeFromScene(); 159 mNetFlags.clear(Ghostable); 160 clearScopeAlways(); 161 162 Parent::onEditorDisable(); 163} 164 165void Prefab::inspectPostApply() 166{ 167 Parent::inspectPostApply(); 168} 169 170void Prefab::setTransform(const MatrixF & mat) 171{ 172 Parent::setTransform( mat ); 173 174 if ( isServerObject() ) 175 { 176 setMaskBits( TransformMask ); 177 _updateChildren(); 178 } 179} 180 181void Prefab::setScale(const VectorF & scale) 182{ 183 Parent::setScale( scale ); 184 185 if ( isServerObject() ) 186 { 187 setMaskBits( TransformMask ); 188 _updateChildren(); 189 } 190} 191 192U32 Prefab::packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) 193{ 194 U32 retMask = Parent::packUpdate( conn, mask, stream ); 195 196 mathWrite(*stream,mObjBox); 197 198 if ( stream->writeFlag( mask & FileMask ) ) 199 { 200 stream->write( mFilename ); 201 } 202 203 if ( stream->writeFlag( mask & TransformMask ) ) 204 { 205 mathWrite(*stream, getTransform()); 206 mathWrite(*stream, getScale()); 207 } 208 209 return retMask; 210} 211 212void Prefab::unpackUpdate(NetConnection *conn, BitStream *stream) 213{ 214 Parent::unpackUpdate(conn, stream); 215 216 mathRead(*stream, &mObjBox); 217 resetWorldBox(); 218 219 // FileMask 220 if ( stream->readFlag() ) 221 { 222 stream->read( &mFilename ); 223 } 224 225 // TransformMask 226 if ( stream->readFlag() ) 227 { 228 mathRead(*stream, &mObjToWorld); 229 mathRead(*stream, &mObjScale); 230 231 setTransform( mObjToWorld ); 232 } 233} 234 235bool Prefab::protectedSetFile( void *object, const char *index, const char *data ) 236{ 237 Prefab *prefab = static_cast<Prefab*>(object); 238 239 String file = String( Platform::makeRelativePathName(data, Platform::getMainDotCsDir()) ); 240 241 prefab->setFile( file ); 242 243 return false; 244} 245 246void Prefab::setFile( String file ) 247{ 248 AssertFatal( isServerObject(), "Prefab-bad" ); 249 250 if ( !isProperlyAdded() ) 251 { 252 mFilename = file; 253 return; 254 } 255 256 // Client-side Prefab(s) do not create/update/reference children, everything 257 // is handled on the server-side. In normal usage this will never actually 258 // be called for the client-side prefab but maybe the user did so accidentally. 259 if ( isClientObject() ) 260 { 261 Con::errorf( "Prefab::setFile( %s ) - Should not be called on a client-side Prefab.", file.c_str() ); 262 return; 263 } 264 265 _closeFile( true ); 266 267 mFilename = file; 268 269 if ( isProperlyAdded() ) 270 _loadFile( true ); 271} 272 273SimGroup* Prefab::explode() 274{ 275 Scene* scene = Scene::getRootScene(); 276 277 if ( !scene) 278 { 279 Con::errorf( "Prefab::explode, Scene was not found." ); 280 return NULL; 281 } 282 283 if ( !mChildGroup ) 284 return NULL; 285 286 SimGroup *group = mChildGroup; 287 Vector<SceneObject*> foundObjects; 288 289 group->findObjectByType( foundObjects ); 290 291 if ( foundObjects.empty() ) 292 return NULL; 293 294 for ( S32 i = 0; i < foundObjects.size(); i++ ) 295 { 296 SceneObject *child = foundObjects[i]; 297 _updateChildTransform( child ); 298 smChildToPrefabMap.erase( child->getId() ); 299 } 300 301 scene->addObject(group); 302 mChildGroup = NULL; 303 mChildMap.clear(); 304 305 return group; 306} 307 308void Prefab::_closeFile( bool removeFileNotify ) 309{ 310 AssertFatal( isServerObject(), "Prefab-bad" ); 311 312 mChildMap.clear(); 313 314 if ( mChildGroup ) 315 { 316 // Get a flat vector of all our children. 317 Vector<SceneObject*> foundObjects; 318 mChildGroup->findObjectByType( foundObjects ); 319 320 // Remove them all from the ChildToPrefabMap. 321 for ( S32 i = 0; i < foundObjects.size(); i++ ) 322 smChildToPrefabMap.erase( foundObjects[i]->getId() ); 323 324 mChildGroup->deleteObject(); 325 mChildGroup = NULL; 326 } 327 328 if ( removeFileNotify ) 329 Torque::FS::RemoveChangeNotification( mFilename, this, &Prefab::_onFileChanged ); 330 331 // Back to a default bounding box size. 332 mObjBox.set( Point3F( -0.5f, -0.5f, -0.5f ), Point3F( 0.5f, 0.5f, 0.5f ) ); 333 resetWorldBox(); 334} 335 336void Prefab::_loadFile( bool addFileNotify ) 337{ 338 AssertFatal( isServerObject(), "Prefab-bad" ); 339 340 if ( mFilename.isEmpty() ) 341 return; 342 343 if ( !Platform::isFile( mFilename ) ) 344 { 345 Con::errorf( "Prefab::_loadFile() - file %s was not found.", mFilename.c_str() ); 346 return; 347 } 348 349 if ( sPrefabFileStack.contains(mFilename) ) 350 { 351 Con::errorf( 352 "Prefab::_loadFile - failed loading prefab file (%s). \n" 353 "File was referenced recursively by both a Parent and Child prefab.", mFilename.c_str() ); 354 return; 355 } 356 357 sPrefabFileStack.push_back(mFilename); 358 359 String command = String::ToString( "exec( \"%s\" );", mFilename.c_str() ); 360 Con::evaluate( command ); 361 362 SimGroup *group; 363 if ( !Sim::findObject( Con::getVariable( "$ThisPrefab" ), group ) ) 364 { 365 Con::errorf( "Prefab::_loadFile() - file %s did not create $ThisPrefab.", mFilename.c_str() ); 366 return; 367 } 368 369 if ( addFileNotify ) 370 Torque::FS::AddChangeNotification( mFilename, this, &Prefab::_onFileChanged ); 371 372 mChildGroup = group; 373 374 Vector<SceneObject*> foundObjects; 375 mChildGroup->findObjectByType( foundObjects ); 376 377 if ( !foundObjects.empty() ) 378 { 379 mWorldBox = Box3F::Invalid; 380 381 for ( S32 i = 0; i < foundObjects.size(); i++ ) 382 { 383 SceneObject *child = foundObjects[i]; 384 mChildMap.insert( child->getId(), Transform( child->getTransform(), child->getScale() ) ); 385 smChildToPrefabMap.insert( child->getId(), getId() ); 386 387 _updateChildTransform( child ); 388 389 mWorldBox.intersect( child->getWorldBox() ); 390 } 391 392 resetObjectBox(); 393 } 394 395 sPrefabFileStack.pop_back(); 396 397 onLoad_callback( mChildGroup ); 398} 399 400void Prefab::_updateChildTransform( SceneObject* child ) 401{ 402 ChildToMatMap::Iterator itr = mChildMap.find(child->getId()); 403 AssertFatal( itr != mChildMap.end(), "Prefab, mChildMap out of synch with mChildGroup." ); 404 405 MatrixF mat( itr->value.mat ); 406 Point3F pos = mat.getPosition(); 407 pos.convolve( mObjScale ); 408 mat.setPosition( pos ); 409 mat.mulL( mObjToWorld ); 410 411 child->setTransform( mat ); 412 child->setScale( itr->value.scale * mObjScale ); 413 414 // Hack for PhysicsShape... need to store the "editor" position to return to 415 // when a physics reset event occurs. Normally this would be where it is 416 // during onAdd, but in this case it is not because the prefab stores its 417 // child objects in object space... 418 419 PhysicsShape *childPS = dynamic_cast<PhysicsShape*>( child ); 420 if ( childPS ) 421 childPS->storeRestorePos(); 422 423} 424 425void Prefab::_updateChildren() 426{ 427 if ( !mChildGroup ) 428 return; 429 430 Vector<SceneObject*> foundObjects; 431 mChildGroup->findObjectByType( foundObjects ); 432 433 for ( S32 i = 0; i < foundObjects.size(); i++ ) 434 { 435 SceneObject *child = foundObjects[i]; 436 437 _updateChildTransform( child ); 438 439 if ( child->getClientObject() ) 440 { 441 ((SceneObject*)child->getClientObject())->setTransform( child->getTransform() ); 442 ((SceneObject*)child->getClientObject())->setScale( child->getScale() ); 443 } 444 } 445} 446 447void Prefab::_onFileChanged( const Torque::Path &path ) 448{ 449 AssertFatal( path == mFilename, "Prefab::_onFileChanged - path does not match filename." ); 450 451 _closeFile(false); 452 _loadFile(false); 453 setMaskBits(U32_MAX); 454} 455 456Prefab* Prefab::getPrefabByChild( SimObject *child ) 457{ 458 ChildToPrefabMap::Iterator itr = smChildToPrefabMap.find( child->getId() ); 459 if ( itr == smChildToPrefabMap.end() ) 460 return NULL; 461 462 Prefab *prefab; 463 if ( !Sim::findObject( itr->value, prefab ) ) 464 { 465 Con::errorf( "Prefab::getPrefabByChild - child object mapped to a prefab that no longer exists." ); 466 return NULL; 467 } 468 469 return prefab; 470} 471 472bool Prefab::isValidChild( SimObject *simobj, bool logWarnings ) 473{ 474 if ( simobj->getName() && simobj == Scene::getRootScene() ) 475 { 476 if ( logWarnings ) 477 Con::warnf( "root Scene is not valid within a Prefab." ); 478 return false; 479 } 480 481 if ( simobj->getClassRep()->isClass( AbstractClassRep::findClassRep("LevelInfo") ) ) 482 { 483 if ( logWarnings ) 484 Con::warnf( "LevelInfo objects are not valid within a Prefab" ); 485 return false; 486 } 487 488 if ( simobj->getClassRep()->isClass( AbstractClassRep::findClassRep("TimeOfDay") ) ) 489 { 490 if ( logWarnings ) 491 Con::warnf( "TimeOfDay objects are not valid within a Prefab" ); 492 return false; 493 } 494 495 SceneObject *sceneobj = dynamic_cast<SceneObject*>(simobj); 496 497 if ( !sceneobj ) 498 return false; 499 500 if ( sceneobj->isGlobalBounds() ) 501 { 502 if ( logWarnings ) 503 Con::warnf( "SceneObject's with global bounds are not valid within a Prefab." ); 504 return false; 505 } 506 507 if ( sceneobj->getClassRep()->isClass( AbstractClassRep::findClassRep("TerrainBlock") ) ) 508 { 509 if ( logWarnings ) 510 Con::warnf( "TerrainBlock objects are not valid within a Prefab" ); 511 return false; 512 } 513 514 if ( sceneobj->getClassRep()->isClass( AbstractClassRep::findClassRep("Player") ) ) 515 { 516 if ( logWarnings ) 517 Con::warnf( "Player objects are not valid within a Prefab" ); 518 return false; 519 } 520 521 if ( sceneobj->getClassRep()->isClass( AbstractClassRep::findClassRep("DecalRoad") ) ) 522 { 523 if ( logWarnings ) 524 Con::warnf( "DecalRoad objects are not valid within a Prefab" ); 525 return false; 526 } 527 528 return true; 529} 530 531bool Prefab::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF& sphere) 532{ 533 Vector<SceneObject*> foundObjects; 534 if (mChildGroup.isNull() || mChildGroup->empty()) 535 { 536 Con::warnf("Bad Prefab Config! %s has no valid entries!", getName()); 537 return false; 538 } 539 mChildGroup->findObjectByType(foundObjects); 540 541 for (S32 i = 0; i < foundObjects.size(); i++) 542 { 543 foundObjects[i]->buildPolyList(context, polyList, box, sphere); 544 } 545 546 return true; 547} 548 549bool Prefab::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F &box, const SphereF &sphere) 550{ 551 Vector<SceneObject*> foundObjects; 552 mChildGroup->findObjectByType(foundObjects); 553 554 for (S32 i = 0; i < foundObjects.size(); i++) 555 { 556 foundObjects[i]->buildExportPolyList(exportData, box, sphere); 557 } 558 559 return true; 560} 561 562void Prefab::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList) 563{ 564 Vector<SceneObject*> foundObjects; 565 mChildGroup->findObjectByType(foundObjects); 566 567 for (S32 i = 0; i < foundObjects.size(); i++) 568 { 569 SceneObject* child = foundObjects[i]; 570 571 child->getUtilizedAssets(usedAssetsList); 572 } 573} 574 575ExplodePrefabUndoAction::ExplodePrefabUndoAction( Prefab *prefab ) 576: UndoAction( "Explode Prefab" ) 577{ 578 mPrefabId = prefab->getId(); 579 mGroup = NULL; 580 581 // Do the action. 582 redo(); 583} 584 585void ExplodePrefabUndoAction::undo() 586{ 587 if ( !mGroup ) 588 { 589 Con::errorf( "ExplodePrefabUndoAction::undo - NULL Group" ); 590 return; 591 } 592 593 mGroup->deleteObject(); 594 mGroup = NULL; 595} 596 597void ExplodePrefabUndoAction::redo() 598{ 599 Prefab *prefab; 600 if ( !Sim::findObject( mPrefabId, prefab ) ) 601 { 602 Con::errorf( "ExplodePrefabUndoAction::redo - Prefab (%i) not found.", mPrefabId ); 603 return; 604 } 605 606 mGroup = prefab->explode(); 607 608 String name; 609 610 if ( prefab->getName() && prefab->getName()[0] != '\0' ) 611 name = prefab->getName(); 612 else 613 name = "prefab"; 614 615 name += "_exploded"; 616 name = Sim::getUniqueName( name ); 617 mGroup->assignName( name ); 618} 619