2024-09-01 21:39:00 +00:00
# include "SubScene.h"
# include "gameMode.h"
2024-10-28 01:04:13 +00:00
# include "console/persistenceManager.h"
2024-09-01 21:39:00 +00:00
# include "console/script.h"
2025-02-06 04:51:43 +00:00
# include "environment/meshRoad.h"
# include "environment/river.h"
2024-09-01 21:39:00 +00:00
# include "scene/sceneRenderState.h"
# include "renderInstance/renderPassManager.h"
# include "gfx/gfxDrawUtil.h"
# include "gfx/gfxTransformSaver.h"
# include "gui/editor/inspector/group.h"
2025-05-25 12:40:10 +00:00
# include "gui/worldEditor/editor.h"
# include "math/mathIO.h"
2024-10-21 05:08:07 +00:00
# include "T3D/gameBase/gameBase.h"
2024-09-01 21:39:00 +00:00
2024-11-06 02:14:36 +00:00
bool SubScene : : smTransformChildren = false ;
2024-09-01 21:39:00 +00:00
IMPLEMENT_CO_NETOBJECT_V1 ( SubScene ) ;
S32 SubScene : : mUnloadTimeoutMs = 5000 ;
2024-10-21 05:08:07 +00:00
IMPLEMENT_CALLBACK ( SubScene , onLoaded , void , ( ) , ( ) ,
" @brief Called when a subScene has been loaded and has game mode implications. \n \n " ) ;
IMPLEMENT_CALLBACK ( SubScene , onUnloaded , void , ( ) , ( ) ,
" @brief Called when a subScene has been unloaded and has game mode implications. \n \n " ) ;
2024-09-01 21:39:00 +00:00
SubScene : : SubScene ( ) :
2025-03-30 21:36:15 +00:00
mSubSceneAssetId ( StringTable - > EmptyString ( ) ) ,
2024-09-01 21:39:00 +00:00
mGameModesNames ( StringTable - > EmptyString ( ) ) ,
mScopeDistance ( - 1 ) ,
mLoaded ( false ) ,
2024-10-21 05:08:07 +00:00
mFreezeLoading ( false ) ,
mTickPeriodMS ( 1000 ) ,
mCurrTick ( 0 ) ,
2025-02-06 04:51:43 +00:00
mGlobalLayer ( false ) ,
2025-05-25 12:40:10 +00:00
mSaving ( false ) ,
mUseSeparateLoadBounds ( false ) ,
mLoadBounds ( Point3F : : One )
2024-09-01 21:39:00 +00:00
{
mNetFlags . set ( Ghostable | ScopeAlways ) ;
mTypeMask | = StaticObjectType ;
}
SubScene : : ~ SubScene ( )
{
}
bool SubScene : : onAdd ( )
{
if ( ! Parent : : onAdd ( ) )
return false ;
2024-10-21 05:08:07 +00:00
setProcessTick ( true ) ;
2024-09-01 21:39:00 +00:00
return true ;
}
void SubScene : : onRemove ( )
{
if ( isClientObject ( ) )
removeFromScene ( ) ;
2024-10-21 05:08:07 +00:00
unload ( ) ;
2024-09-01 21:39:00 +00:00
Parent : : onRemove ( ) ;
}
void SubScene : : initPersistFields ( )
{
addGroup ( " SubScene " ) ;
addField ( " isGlobalLayer " , TypeBool , Offset ( mGlobalLayer , SubScene ) , " " ) ;
2025-03-30 21:36:15 +00:00
INITPERSISTFIELD_SUBSCENEASSET ( SubScene , SubScene , " The subscene asset to load. " ) ;
2025-02-06 04:51:43 +00:00
addField ( " tickPeriodMS " , TypeS32 , Offset ( mTickPeriodMS , SubScene ) , " evaluation rate (ms) " ) ;
2024-09-01 21:39:00 +00:00
addField ( " gameModes " , TypeGameModeList , Offset ( mGameModesNames , SubScene ) , " The game modes that this subscene is associated with. " ) ;
2025-05-25 12:40:10 +00:00
addField ( " UseSeparateLoadBounds " , TypeBool , Offset ( mUseSeparateLoadBounds , SubScene ) , " If true, this subscene will utilize a separate bounds for triggering loading/unloading than it's object bounds " ) ;
addField ( " LoadBounds " , TypePoint3F , Offset ( mLoadBounds , SubScene ) , " If UseSeparateLoadBounds is true, this subscene will use this value to set up the load/unload bounds " ) ;
2024-09-01 21:39:00 +00:00
endGroup ( " SubScene " ) ;
2024-10-21 05:08:07 +00:00
addGroup ( " LoadingManagement " ) ;
addField ( " freezeLoading " , TypeBool , Offset ( mFreezeLoading , SubScene ) , " If true, will prevent the zone from being changed from it's current loading state. " ) ;
addField ( " loadIf " , TypeCommand , Offset ( mLoadIf , SubScene ) , " evaluation condition (true/false) " ) ;
addField ( " tickPeriodMS " , TypeS32 , Offset ( mTickPeriodMS , SubScene ) , " evaluation rate (ms) " ) ;
addField ( " onLoadCommand " , TypeCommand , Offset ( mOnLoadCommand , SubScene ) , " The command to execute when the subscene is loaded. Maximum 1023 characters. " ) ;
addField ( " onUnloadCommand " , TypeCommand , Offset ( mOnUnloadCommand , SubScene ) , " The command to execute when subscene is unloaded. Maximum 1023 characters. " ) ;
endGroup ( " LoadingManagement " ) ;
2024-09-01 21:39:00 +00:00
Parent : : initPersistFields ( ) ;
}
void SubScene : : consoleInit ( )
{
Parent : : consoleInit ( ) ;
Con : : addVariable ( " $SubScene::UnloadTimeoutMS " , TypeBool , & SubScene : : mUnloadTimeoutMs , " The amount of time in milliseconds it takes for a SubScene to be unloaded if it's inactive. \n "
" @ingroup Editors \n " ) ;
2024-11-06 02:14:36 +00:00
Con : : addVariable ( " $SubScene::transformChildren " , TypeBool , & SubScene : : smTransformChildren ,
" @brief If true, then transform manipulations modify child objects. If false, only triggering bounds is manipulated \n \n "
" @ingroup Editors " ) ;
2024-09-01 21:39:00 +00:00
}
void SubScene : : addObject ( SimObject * object )
{
SceneObject : : addObject ( object ) ;
}
void SubScene : : removeObject ( SimObject * object )
{
SceneObject : : removeObject ( object ) ;
}
U32 SubScene : : packUpdate ( NetConnection * conn , U32 mask , BitStream * stream )
{
U32 retMask = Parent : : packUpdate ( conn , mask , stream ) ;
stream - > writeFlag ( mGlobalLayer ) ;
2025-05-25 12:40:10 +00:00
if ( stream - > writeFlag ( mUseSeparateLoadBounds ) )
{
mathWrite ( * stream , mLoadBounds ) ;
}
2024-09-01 21:39:00 +00:00
return retMask ;
}
void SubScene : : unpackUpdate ( NetConnection * conn , BitStream * stream )
{
Parent : : unpackUpdate ( conn , stream ) ;
mGlobalLayer = stream - > readFlag ( ) ;
2025-05-25 12:40:10 +00:00
mUseSeparateLoadBounds = stream - > readFlag ( ) ;
if ( mUseSeparateLoadBounds )
{
mathRead ( * stream , & mLoadBounds ) ;
}
2024-09-01 21:39:00 +00:00
}
void SubScene : : onInspect ( GuiInspector * inspector )
{
Parent : : onInspect ( inspector ) ;
2025-05-17 23:41:15 +00:00
# ifdef TORQUE_TOOLS
2024-09-01 21:39:00 +00:00
//Put the SubScene group before everything that'd be SubScene-effecting, for orginazational purposes
GuiInspectorGroup * subsceneGrp = inspector - > findExistentGroup ( StringTable - > insert ( " SubScene " ) ) ;
if ( ! subsceneGrp )
return ;
GuiControl * stack = dynamic_cast < GuiControl * > ( subsceneGrp - > findObjectByInternalName ( StringTable - > insert ( " Stack " ) ) ) ;
//Save button
GuiInspectorField * saveFieldGui = subsceneGrp - > createInspectorField ( ) ;
saveFieldGui - > init ( inspector , subsceneGrp ) ;
saveFieldGui - > setSpecialEditField ( true ) ;
saveFieldGui - > setTargetObject ( this ) ;
StringTableEntry fldnm = StringTable - > insert ( " SaveSubScene " ) ;
saveFieldGui - > setSpecialEditVariableName ( fldnm ) ;
saveFieldGui - > setInspectorField ( NULL , fldnm ) ;
saveFieldGui - > setDocs ( " " ) ;
stack - > addObject ( saveFieldGui ) ;
GuiButtonCtrl * saveButton = new GuiButtonCtrl ( ) ;
saveButton - > registerObject ( ) ;
saveButton - > setDataField ( StringTable - > insert ( " profile " ) , NULL , " ToolsGuiButtonProfile " ) ;
saveButton - > setText ( " Save SubScene " ) ;
saveButton - > resize ( Point2I : : Zero , saveFieldGui - > getExtent ( ) ) ;
saveButton - > setHorizSizing ( GuiControl : : horizResizeWidth ) ;
saveButton - > setVertSizing ( GuiControl : : vertResizeHeight ) ;
char szBuffer [ 512 ] ;
dSprintf ( szBuffer , 512 , " %d.save(); " , this - > getId ( ) ) ;
saveButton - > setConsoleCommand ( szBuffer ) ;
saveFieldGui - > addObject ( saveButton ) ;
2025-05-17 23:41:15 +00:00
# endif
2024-09-01 21:39:00 +00:00
}
void SubScene : : inspectPostApply ( )
{
Parent : : inspectPostApply ( ) ;
setMaskBits ( - 1 ) ;
}
2024-11-06 02:14:36 +00:00
void SubScene : : setTransform ( const MatrixF & mat )
{
if ( SubScene : : smTransformChildren )
{
Parent : : setTransform ( mat ) ;
}
else
{
SceneObject : : setTransform ( mat ) ;
}
}
void SubScene : : setRenderTransform ( const MatrixF & mat )
{
if ( SubScene : : smTransformChildren )
{
Parent : : setRenderTransform ( mat ) ;
}
else
{
SceneObject : : setRenderTransform ( mat ) ;
}
}
2024-10-21 05:08:07 +00:00
bool SubScene : : evaluateCondition ( )
2024-09-01 21:39:00 +00:00
{
2024-10-21 05:08:07 +00:00
if ( ! mLoadIf . isEmpty ( ) )
2024-10-04 05:10:26 +00:00
{
//test the mapper plugged in condition line
String resVar = getIdString ( ) + String ( " .result " ) ;
Con : : setBoolVariable ( resVar . c_str ( ) , false ) ;
String command = resVar + " = " + mLoadIf + " ; " ;
2024-10-21 05:08:07 +00:00
2024-10-04 05:10:26 +00:00
Con : : evaluatef ( command . c_str ( ) ) ;
2024-10-21 05:08:07 +00:00
return Con : : getBoolVariable ( resVar . c_str ( ) ) ;
2024-10-04 05:10:26 +00:00
}
2024-10-21 05:08:07 +00:00
return true ;
}
2024-10-04 05:10:26 +00:00
2024-10-21 05:08:07 +00:00
bool SubScene : : testBox ( const Box3F & testBox )
{
2025-02-13 20:32:23 +00:00
bool passes = mGlobalLayer ;
if ( ! passes )
2025-05-25 12:40:10 +00:00
{
if ( mUseSeparateLoadBounds )
{
Box3F loadBox = Box3F ( - mLoadBounds . x , - mLoadBounds . y , - mLoadBounds . z ,
mLoadBounds . x , mLoadBounds . y , mLoadBounds . z ) ;
loadBox . setCenter ( getPosition ( ) ) ;
passes = loadBox . isOverlapped ( testBox ) ;
}
else
{
passes = getWorldBox ( ) . isOverlapped ( testBox ) ;
}
}
2024-10-21 05:08:07 +00:00
if ( passes )
passes = evaluateCondition ( ) ;
2024-10-04 05:10:26 +00:00
return passes ;
2024-09-01 21:39:00 +00:00
}
void SubScene : : write ( Stream & stream , U32 tabStop , U32 flags )
{
MutexHandle handle ;
handle . lock ( mMutex ) ;
// export selected only?
if ( ( flags & SelectedOnly ) & & ! isSelected ( ) )
{
for ( U32 i = 0 ; i < size ( ) ; i + + )
( * this ) [ i ] - > write ( stream , tabStop , flags ) ;
return ;
}
stream . writeTabs ( tabStop ) ;
char buffer [ 2048 ] ;
const U32 bufferWriteLen = dSprintf ( buffer , sizeof ( buffer ) , " new %s(%s) { \r \n " , getClassName ( ) , getName ( ) & & ! ( flags & NoName ) ? getName ( ) : " " ) ;
stream . write ( bufferWriteLen , buffer ) ;
writeFields ( stream , tabStop + 1 ) ;
//The only meaningful difference between this and simSet for writing is we skip the children, since they're just the levelAsset contents
stream . writeTabs ( tabStop ) ;
stream . write ( 4 , " }; \r \n " ) ;
}
void SubScene : : processTick ( const Move * move )
{
2024-10-21 05:08:07 +00:00
mCurrTick + = TickMs ;
if ( mCurrTick > mTickPeriodMS )
{
mCurrTick = 0 ;
//re-evaluate
if ( ! evaluateCondition ( ) )
unload ( ) ;
}
2024-09-01 21:39:00 +00:00
}
void SubScene : : _onFileChanged ( const Torque : : Path & path )
{
2025-05-25 12:40:10 +00:00
if ( gEditingMission )
return ;
2025-03-30 21:36:15 +00:00
if ( mSubSceneAsset . isNull ( ) | | Torque : : Path ( mSubSceneAsset - > getLevelPath ( ) ) ! = path )
2024-09-01 21:39:00 +00:00
return ;
2025-02-06 04:51:43 +00:00
if ( mSaving )
return ;
2025-03-30 21:36:15 +00:00
AssertFatal ( path = = mSubSceneAsset - > getLevelPath ( ) , " SubScene::_onFileChanged - path does not match filename. " ) ;
2024-09-01 21:39:00 +00:00
_closeFile ( false ) ;
_loadFile ( false ) ;
setMaskBits ( U32_MAX ) ;
}
2024-10-21 05:08:07 +00:00
void SubScene : : _removeContents ( SimGroupIterator set )
2024-09-01 21:39:00 +00:00
{
2024-10-21 05:08:07 +00:00
for ( SimGroupIterator itr ( set ) ; * itr ; + + itr )
2024-09-01 21:39:00 +00:00
{
2024-10-21 05:08:07 +00:00
SimGroup * child = dynamic_cast < SimGroup * > ( * itr ) ;
2024-09-01 21:39:00 +00:00
if ( child )
2024-10-21 05:08:07 +00:00
{
_removeContents ( SimGroupIterator ( child ) ) ;
GameBase * asGameBase = dynamic_cast < GameBase * > ( child ) ;
if ( asGameBase )
{
asGameBase - > scriptOnRemove ( ) ;
}
Sim : : cancelPendingEvents ( child ) ;
2024-09-01 21:39:00 +00:00
child - > safeDeleteObject ( ) ;
2024-10-21 05:08:07 +00:00
}
2024-09-01 21:39:00 +00:00
}
2024-10-21 05:08:07 +00:00
}
void SubScene : : _closeFile ( bool removeFileNotify )
{
AssertFatal ( isServerObject ( ) , " Trying to close out a subscene file on the client is bad! " ) ;
_removeContents ( SimGroupIterator ( this ) ) ;
2024-09-01 21:39:00 +00:00
2025-03-30 21:36:15 +00:00
if ( removeFileNotify & & mSubSceneAsset . notNull ( ) & & mSubSceneAsset - > getLevelPath ( ) ! = StringTable - > EmptyString ( ) )
2024-09-01 21:39:00 +00:00
{
2025-03-30 21:36:15 +00:00
Torque : : FS : : RemoveChangeNotification ( mSubSceneAsset - > getLevelPath ( ) , this , & SubScene : : _onFileChanged ) ;
2024-09-01 21:39:00 +00:00
}
mGameModesList . clear ( ) ;
}
void SubScene : : _loadFile ( bool addFileNotify )
{
AssertFatal ( isServerObject ( ) , " Trying to load a SubScene file on the client is bad! " ) ;
2025-03-30 21:36:15 +00:00
if ( mSubSceneAsset . isNull ( ) | | mSubSceneAsset - > getLevelPath ( ) = = StringTable - > EmptyString ( ) )
2024-09-01 21:39:00 +00:00
return ;
2025-03-30 21:36:15 +00:00
String evalCmd = String : : ToString ( " exec( \" %s \" ); " , mSubSceneAsset - > getLevelPath ( ) ) ;
2024-09-01 21:39:00 +00:00
String instantGroup = Con : : getVariable ( " InstantGroup " ) ;
Con : : setIntVariable ( " InstantGroup " , this - > getId ( ) ) ;
2025-03-30 21:36:15 +00:00
Con : : evaluate ( ( const char * ) evalCmd . c_str ( ) , false , mSubSceneAsset - > getLevelPath ( ) ) ;
2024-09-01 21:39:00 +00:00
Con : : setVariable ( " InstantGroup " , instantGroup . c_str ( ) ) ;
if ( addFileNotify )
2025-03-30 21:36:15 +00:00
Torque : : FS : : AddChangeNotification ( mSubSceneAsset - > getLevelPath ( ) , this , & SubScene : : _onFileChanged ) ;
2024-09-01 21:39:00 +00:00
}
void SubScene : : load ( )
{
mStartUnloadTimerMS = - 1 ; //reset unload timers
//no need to load multiple times
if ( mLoaded )
return ;
2024-10-21 05:08:07 +00:00
if ( mFreezeLoading )
return ;
2025-02-06 04:51:43 +00:00
if ( mSaving )
return ;
2025-02-13 20:32:23 +00:00
GameMode : : findGameModes ( mGameModesNames , & mGameModesList ) ;
2025-02-26 01:17:43 +00:00
if ( ! isSelected ( ) & & ( String ( mGameModesNames ) . isNotEmpty ( ) & & mGameModesList . size ( ) = = 0 ) | | ! evaluateCondition ( ) )
2025-02-13 20:32:23 +00:00
{
mLoaded = false ;
return ;
}
2024-09-01 21:39:00 +00:00
_loadFile ( true ) ;
mLoaded = true ;
2024-10-21 05:08:07 +00:00
onLoaded_callback ( ) ;
2024-09-01 21:39:00 +00:00
for ( U32 i = 0 ; i < mGameModesList . size ( ) ; i + + )
{
2024-10-21 05:08:07 +00:00
mGameModesList [ i ] - > onSubsceneLoaded_callback ( this ) ;
}
2024-09-01 21:39:00 +00:00
}
void SubScene : : unload ( )
{
if ( ! mLoaded )
return ;
2024-10-21 05:08:07 +00:00
if ( mFreezeLoading )
return ;
2025-02-06 04:51:43 +00:00
if ( mSaving )
return ;
2024-09-01 21:39:00 +00:00
if ( isSelected ( ) )
{
mStartUnloadTimerMS = Sim : : getCurrentTime ( ) ;
return ; //if a child is selected, then we don't want to unload
}
//scan down through our child objects, see if any are marked as selected,
//if so, skip unloading and reset the timer
2024-10-21 05:08:07 +00:00
for ( SimGroupIterator itr ( this ) ; * itr ; + + itr )
2024-09-01 21:39:00 +00:00
{
SimGroup * childGrp = dynamic_cast < SimGroup * > ( * itr ) ;
2024-10-21 05:08:07 +00:00
if ( childGrp )
2024-09-01 21:39:00 +00:00
{
2024-10-21 05:08:07 +00:00
if ( childGrp - > isSelected ( ) )
2024-09-01 21:39:00 +00:00
{
mStartUnloadTimerMS = Sim : : getCurrentTime ( ) ;
return ; //if a child is selected, then we don't want to unload
}
2024-10-21 05:08:07 +00:00
for ( SimGroupIterator cldItr ( childGrp ) ; * cldItr ; + + cldItr )
{
SimObject * chldChld = dynamic_cast < SimObject * > ( * cldItr ) ;
if ( chldChld & & chldChld - > isSelected ( ) )
{
mStartUnloadTimerMS = Sim : : getCurrentTime ( ) ;
return ; //if a child is selected, then we don't want to unload
}
}
2024-09-01 21:39:00 +00:00
}
}
2024-10-21 05:08:07 +00:00
onUnloaded_callback ( ) ;
2024-09-01 21:39:00 +00:00
for ( U32 i = 0 ; i < mGameModesList . size ( ) ; i + + )
{
2024-10-21 05:08:07 +00:00
mGameModesList [ i ] - > onSubsceneUnloaded_callback ( this ) ;
2024-09-01 21:39:00 +00:00
}
2024-10-21 05:08:07 +00:00
if ( ! mOnUnloadCommand . isEmpty ( ) )
{
String command = " %this = " + String ( getIdString ( ) ) + " ; " + mOnUnloadCommand + " ; " ;
Con : : evaluatef ( command . c_str ( ) ) ;
}
_closeFile ( true ) ;
mLoaded = false ;
2024-09-01 21:39:00 +00:00
}
2025-05-25 12:40:10 +00:00
bool SubScene : : save ( const String & filename )
2024-09-01 21:39:00 +00:00
{
2024-12-07 19:20:30 +00:00
if ( ! isServerObject ( ) )
return false ;
2024-09-01 21:39:00 +00:00
//if there's nothing TO save, don't bother
if ( size ( ) = = 0 | | ! isLoaded ( ) )
return false ;
2025-03-30 21:36:15 +00:00
if ( mSubSceneAsset . isNull ( ) )
2024-09-01 21:39:00 +00:00
return false ;
2025-02-06 04:51:43 +00:00
if ( mSaving )
return false ;
2024-09-01 21:39:00 +00:00
//If we're flagged for unload, push back the unload timer so we can't accidentally trip be saving partway through an unload
if ( mStartUnloadTimerMS ! = - 1 )
mStartUnloadTimerMS = Sim : : getCurrentTime ( ) ;
2025-02-06 04:51:43 +00:00
mSaving = true ;
2024-10-28 01:04:13 +00:00
PersistenceManager prMger ;
2025-03-30 21:36:15 +00:00
StringTableEntry levelPath = mSubSceneAsset - > getLevelPath ( ) ;
2024-09-01 21:39:00 +00:00
2025-05-25 12:40:10 +00:00
if ( filename . isNotEmpty ( ) )
levelPath = StringTable - > insert ( filename . c_str ( ) ) ;
2024-10-28 01:04:13 +00:00
FileStream fs ;
fs . open ( levelPath , Torque : : FS : : File : : Write ) ;
fs . close ( ) ;
for ( SimGroupIterator itr ( this ) ; * itr ; + + itr )
2024-09-01 21:39:00 +00:00
{
2024-12-07 19:20:30 +00:00
SimObject * childObj = ( * itr ) ;
if ( ! prMger . isDirty ( childObj ) )
2024-09-01 21:39:00 +00:00
{
2024-12-07 19:20:30 +00:00
if ( ( * itr ) - > isMethod ( " onSaving " ) )
{
2025-03-30 21:36:15 +00:00
Con : : executef ( ( * itr ) , " onSaving " , mSubSceneAssetId ) ;
2024-12-07 19:20:30 +00:00
}
2024-09-01 21:39:00 +00:00
2024-12-07 19:20:30 +00:00
if ( childObj - > getGroup ( ) = = this )
{
prMger . setDirty ( ( * itr ) , levelPath ) ;
}
}
2025-02-06 04:51:43 +00:00
if ( dynamic_cast < MeshRoad * > ( childObj ) | | dynamic_cast < River * > ( childObj ) )
{
prMger . addRemoveField ( childObj , " position " ) ;
}
2024-09-01 21:39:00 +00:00
}
2024-10-28 01:04:13 +00:00
prMger . saveDirty ( ) ;
2024-09-01 21:39:00 +00:00
//process our gameModeList and write it out to the levelAsset for metadata stashing
bool saveSuccess = false ;
//Get the level asset
2025-03-30 21:36:15 +00:00
if ( mSubSceneAsset . isNull ( ) )
2024-09-01 21:39:00 +00:00
return saveSuccess ;
//update the gamemode list as well
2025-03-30 21:36:15 +00:00
mSubSceneAsset - > setDataField ( StringTable - > insert ( " gameModesNames " ) , NULL , StringTable - > insert ( mGameModesNames ) ) ;
2024-09-01 21:39:00 +00:00
//Finally, save
2025-03-30 21:36:15 +00:00
saveSuccess = mSubSceneAsset - > saveAsset ( ) ;
2024-09-01 21:39:00 +00:00
2025-02-06 04:51:43 +00:00
mSaving = false ;
2024-09-01 22:14:08 +00:00
return saveSuccess ;
2024-09-01 21:39:00 +00:00
}
void SubScene : : _onSelected ( )
{
if ( ! isLoaded ( ) & & isServerObject ( ) )
load ( ) ;
}
void SubScene : : _onUnselected ( )
{
}
void SubScene : : prepRenderImage ( SceneRenderState * state )
{
// only render if selected or render flag is set
if ( /*!smRenderTriggers && */ ! isSelected ( ) )
return ;
ObjectRenderInst * ri = state - > getRenderPass ( ) - > allocInst < ObjectRenderInst > ( ) ;
ri - > renderDelegate . bind ( this , & SubScene : : renderObject ) ;
ri - > type = RenderPassManager : : RIT_Editor ;
ri - > translucentSort = true ;
ri - > defaultKey = 1 ;
state - > getRenderPass ( ) - > addInst ( ri ) ;
}
void SubScene : : renderObject ( ObjectRenderInst * ri ,
SceneRenderState * state ,
BaseMatInstance * overrideMat )
{
if ( overrideMat )
return ;
GFXStateBlockDesc desc ;
desc . setZReadWrite ( true , false ) ;
desc . setBlend ( true ) ;
// Trigger polyhedrons are set up with outward facing normals and CCW ordering
// so can't enable backface culling.
desc . setCullMode ( GFXCullNone ) ;
GFXTransformSaver saver ;
MatrixF mat = getRenderTransform ( ) ;
GFX - > multWorld ( mat ) ;
GFXDrawUtil * drawer = GFX - > getDrawUtil ( ) ;
//Box3F scale = getScale()
//Box3F bounds = Box3F(-m)
2025-05-25 12:40:10 +00:00
if ( mUseSeparateLoadBounds & & ! mGlobalLayer )
{
Box3F loadBounds = Box3F ( - mLoadBounds . x , - mLoadBounds . y , - mLoadBounds . z ,
mLoadBounds . x , mLoadBounds . y , mLoadBounds . z ) ;
//bounds.setCenter(getPosition());
ColorI loadBoundsColor = ColorI ( 200 , 200 , 100 , 50 ) ;
drawer - > drawCube ( desc , loadBounds , loadBoundsColor ) ;
// Render wireframe.
desc . setFillModeWireframe ( ) ;
drawer - > drawCube ( desc , loadBounds , ColorI : : BLACK ) ;
desc . setFillModeSolid ( ) ;
}
2024-09-01 21:39:00 +00:00
Point3F scale = getScale ( ) ;
2025-05-25 12:40:10 +00:00
Box3F bounds = Box3F ( - scale / 2 , scale / 2 ) ;
2024-09-01 21:39:00 +00:00
ColorI boundsColor = ColorI ( 135 , 206 , 235 , 50 ) ;
if ( mGlobalLayer )
boundsColor = ColorI ( 200 , 100 , 100 , 25 ) ;
else if ( mLoaded )
boundsColor = ColorI ( 50 , 200 , 50 , 50 ) ;
drawer - > drawCube ( desc , bounds , boundsColor ) ;
// Render wireframe.
desc . setFillModeWireframe ( ) ;
drawer - > drawCube ( desc , bounds , ColorI : : BLACK ) ;
}
2025-05-25 12:40:10 +00:00
DefineEngineMethod ( SubScene , save , bool , ( const char * filename ) , ( " " ) ,
" Save out the subScene. \n "
" @param filename (optional) If empty, the subScene will save to it's regular asset path. If defined, it will save out to the filename provided " )
2024-09-01 21:39:00 +00:00
{
2025-05-25 12:40:10 +00:00
return object - > save ( filename ) ;
2024-09-01 21:39:00 +00:00
}
DefineEngineMethod ( SubScene , load , void , ( ) , ,
" Loads the SubScene's level file. \n " )
{
object - > load ( ) ;
}
DefineEngineMethod ( SubScene , unload , void , ( ) , ,
" Unloads the SubScene's level file. \n " )
{
object - > unload ( ) ;
}