Files
GTASource/game/vfx/misc/MovieMeshManager.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1712 lines
44 KiB
C++

#include "MovieMeshManager.h"
VFX_MISC_OPTIMISATIONS()
// framework
#include "fwscene/stores/psostore.h"
#include "fwsys/timer.h"
#include "streaming/streamingengine.h"
#include "vfx/channel.h"
#include "vfx/vfxwidget.h"
// rage
#include "grcore/image.h"
#include "grcore/texture.h"
#include "system/memops.h"
#include "system/nelem.h"
// game
#include "Core/Game.h"
#include "System/FileMgr.h"
#include "renderer/RenderTargetMgr.h"
#include "vfx/misc/MovieManager.h"
#include "vfx/misc/Fire.h"
#include "script/commands_graphics.h"
#include "modelinfo/ModelInfo.h"
#include "Objects/object.h"
#include "scene/Entity.h"
#include "scene/RegdRefTypes.h"
#include "script/script.h"
#include "streaming/streaming.h"
#include "objects/objectpopulation.h"
#include "scene/world/GameWorld.h"
#include "animation/MoveObject.h"
#include "atl/atfixedstring.h"
#define MM_SCRIPTED_RT_PREFIX "script_rt_"
#define MM_DATA_PATH "common:/data/effects/bink/"
#define MOVIEMESH_MNGR_STRING "MovieMeshManager"
CMovieMeshManager g_movieMeshMgr;
u32 CMovieMeshManager::ms_globalRtHandle = atStringHash(MOVIEMESH_MNGR_STRING);
//////////////////////////////////////////////////////////////////////////
// MovieMeshHandle
//////////////////////////////////////////////////////////////////////////
void MovieMeshHandle::Release()
{
if (refCount > 0)
{
refCount--;
REPLAY_ONLY( if( !CReplayMgr::IsEditModeActive() ) )
{
g_movieMgr.Release(movieHandle);
}
}
}
//////////////////////////////////////////////////////////////////////////
// MovieMeshGlobalPool
//////////////////////////////////////////////////////////////////////////
MovieMeshGlobalPool::MovieMeshGlobalPool() {
for (int i = 0; i < MOVIE_MESH_MAX_HANDLES; i++)
{
m_uniqueHandles[i].movieHandle = INVALID_MOVIE_MESH_HANDLE;
m_uniqueHandles[i].rtHandle = INVALID_MOVIE_MESH_HANDLE;
}
}
bool MovieMeshGlobalPool::GetFreeHandle(MovieMeshHandle*& pHandle)
{
for (int i = 0; i < MOVIE_MESH_MAX_HANDLES; i++)
{
if (m_uniqueHandles[i].bInUse == false) {
Assertf(m_uniqueHandles[i].rtHandle == INVALID_MOVIE_MESH_HANDLE && m_uniqueHandles[i].refCount == 0 && m_uniqueHandles[i].bInUse == false, "MovieMeshGlobalPool::GetFreeHandle: entry is corrupted");
pHandle = &m_uniqueHandles[i];
return true;
}
}
// no free handles
pHandle = NULL;
return false;
}
bool MovieMeshGlobalPool::FindHandle(MovieMeshHandle*& pHandle, u32 movieHandle)
{
Assertf(movieHandle != INVALID_MOVIE_MESH_HANDLE, "MovieMeshGlobalPool::FindHandle: Trying to find an entry with invalid handles");
for (int i = 0; i < MOVIE_MESH_MAX_HANDLES; i++)
{
if (m_uniqueHandles[i].movieHandle == movieHandle) {
pHandle = &m_uniqueHandles[i];
return true;
}
}
pHandle = NULL;
return false;
}
bool MovieMeshGlobalPool::HandleExists(const MovieMeshHandle* const pHandle) const
{
for (int i = 0; i < MOVIE_MESH_MAX_HANDLES; i++)
{
const MovieMeshHandle* const pCmpHandle = &m_uniqueHandles[i];
if (pCmpHandle == pHandle)
{
return true;
}
}
return false;
}
bool MovieMeshGlobalPool::AddHandle(MovieMeshHandle*& pHandle, u32 movieHandle)
{
// if it's already in the pool, increment ref count
if (FindHandle(pHandle, movieHandle))
{
pHandle->IncRef();
return true;
}
// not in the pool, try to add it
else if (GetFreeHandle(pHandle))
{
Assertf(movieHandle != INVALID_MOVIE_MESH_HANDLE, "MovieMeshGlobalPool::AddHandle: Trying to add an entry with invalid handles");
// initialise handle
pHandle->movieHandle = movieHandle;
pHandle->bInUse = true;
pHandle->IncRef();
return true;
}
// something's gone wrong...
pHandle = NULL;
return false;
}
void MovieMeshGlobalPool::ModifyHandle(MovieMeshHandle* const pHandle, u32 movieHandle, u32 rtHandle, u32 rtNameHash)
{
if (HandleExists(pHandle))
{
Assertf(pHandle->bInUse != false, "MovieMeshGlobalPool::ModifyHandle: corrupted handle (not in use)");
Assertf(pHandle->movieHandle == movieHandle, "MovieMeshGlobalPool::ModifyHandle: corrupted handle (movie handle doesn't match)");
pHandle->rtHandle = rtHandle;
pHandle->movieHandle = movieHandle;
pHandle->rtNameHash = rtNameHash;
return;
}
Assertf(0, "MovieMeshGlobalPool::ModifyHandle: tried to modify a handle that doesn't exist");
}
void MovieMeshGlobalPool::Update()
{
for (int i = 0; i < MOVIE_MESH_MAX_HANDLES; i++)
{
MovieMeshHandle* pHandle = &m_uniqueHandles[i];
if (pHandle->bInUse && pHandle->refCount == 0)
{
// release bink movie
if (pHandle->movieHandle != INVALID_MOVIE_MESH_HANDLE)
{
g_movieMgr.Release(pHandle->movieHandle);
}
// release render target
if (pHandle->rtHandle != INVALID_MOVIE_MESH_HANDLE)
{
g_movieMeshMgr.GetRTManager().Release(pHandle->rtNameHash);
}
pHandle->Reset();
}
}
}
//////////////////////////////////////////////////////////////////////////
// CMovieMeshRenderTargetManager class
//////////////////////////////////////////////////////////////////////////
void CMovieMeshRenderTargetManager::Init()
{
sysMemSet(m_numDelayedReleaseRts, 0, sizeof(m_numDelayedReleaseRts));
m_delayedReleaseRtsFrame = 0;
}
void CMovieMeshRenderTargetManager::Shutdown()
{
for (int i = 0; i < m_renderTargets.GetCount(); i++)
{
MovieMeshRenderTarget* pTarget = &m_renderTargets[i];
pTarget->m_numRefs = 0;
pTarget->m_state = MovieMeshRenderTarget::kWaitingForRelease;
ProcessWaitingOnReleaseState(pTarget);
}
}
u32 CMovieMeshRenderTargetManager::Register(atFinalHashString name)
{
// Check if the render target exists
MovieMeshRenderTarget* pRt = Get(name);
if (pRt)
{
// Render target is good to reuse
if (pRt->m_state == MovieMeshRenderTarget::kLoading || pRt->m_state == MovieMeshRenderTarget::kReady)
{
pRt->m_numRefs++;
return pRt->m_name.GetHash();
}
// Render target exists, but in a state it cannot be used, try later
return 0U;
}
// Check whether we can create a new one
if (m_renderTargets.GetCount() == MAX_MOVIE_MESH_RT)
{
return 0U;
}
// It doesn't exist, create one
pRt = &(m_renderTargets.Append());
pRt->Reset();
pRt->m_name = name;
pRt->m_state = MovieMeshRenderTarget::kLoading;
pRt->m_numRefs++;
return pRt->m_name.GetHash();
}
bool CMovieMeshRenderTargetManager::Exists(atFinalHashString name) const
{
return (Get(name) != NULL);
}
void CMovieMeshRenderTargetManager::Release(atFinalHashString name)
{
// Remove a ref
MovieMeshRenderTarget* pRt = Get(name);
if (Verifyf(pRt != NULL, "target does not exists"))
{
if (pRt->m_numRefs <= 1)
{
// Don't release now, we'll do it during the update tick
pRt->m_numRefs = 0;
pRt->m_state = MovieMeshRenderTarget::kWaitingForRelease;
return;
}
pRt->m_numRefs--;
}
}
void CMovieMeshRenderTargetManager::Release(u32 rtHash)
{
// Remove a ref
MovieMeshRenderTarget* pRt = Get(rtHash);
if (Verifyf(pRt != NULL, "target does not exists"))
{
if (pRt->m_numRefs <= 1)
{
// Don't release now, we'll do it during the update tick
pRt->m_numRefs = 0;
pRt->m_state = MovieMeshRenderTarget::kWaitingForRelease;
return;
}
pRt->m_numRefs--;
}
}
void CMovieMeshRenderTargetManager::Update()
{
const unsigned delayedReleaseRtsFrame = (m_delayedReleaseRtsFrame + 1) % NELEM(m_delayedReleaseRts);
m_delayedReleaseRtsFrame = delayedReleaseRtsFrame;
const unsigned numDelayedReleaseRts = m_numDelayedReleaseRts[delayedReleaseRtsFrame];
for (int i = 0; i < numDelayedReleaseRts; i++)
{
grcRenderTarget *const rt = m_delayedReleaseRts[delayedReleaseRtsFrame][i];
m_delayedReleaseRts[delayedReleaseRtsFrame][i] = NULL;
rt->Release();
}
m_numDelayedReleaseRts[delayedReleaseRtsFrame] = 0;
for (int i = 0; i < m_renderTargets.GetCount(); i++)
{
MovieMeshRenderTarget* pRt = &m_renderTargets[i];
MovieMeshRenderTarget::eState rtState = pRt->m_state;
// Release target
if (rtState == MovieMeshRenderTarget::kWaitingForRelease)
{
Assert(pRt->m_numRefs == 0);
if (ProcessWaitingOnReleaseState(pRt))
{
m_renderTargets.DeleteFast(i);
i--;
}
}
// Check whether it's ready
else if (rtState == MovieMeshRenderTarget::kLoading)
{
ProcessLoadingState(pRt);
}
// Do stuff
else if (rtState == MovieMeshRenderTarget::kReady)
{
ProcessReadyState(pRt);
}
// Shouldn't happen...
else
{
Assertf(0, "Invalid state");
}
}
}
bool CMovieMeshRenderTargetManager::ProcessWaitingOnReleaseState(MovieMeshRenderTarget* pTarget)
{
// Release render target
grcRenderTarget *const rt = pTarget->m_pRenderTarget;
if (rt)
{
const unsigned delayedReleaseRtsFrame = m_delayedReleaseRtsFrame;
const unsigned numDelayedReleaseRts = m_numDelayedReleaseRts[delayedReleaseRtsFrame];
Assert(numDelayedReleaseRts < MAX_MOVIE_MESH_RT);
m_delayedReleaseRts[delayedReleaseRtsFrame][numDelayedReleaseRts] = rt;
m_numDelayedReleaseRts[delayedReleaseRtsFrame] = numDelayedReleaseRts+1;
pTarget->m_pRenderTarget = NULL;
}
// Remove ref from txd
bool bRefAdded = pTarget->m_bTxdRefAdded;
s32 txdIdx = pTarget->m_txdIdx;
if (bRefAdded && txdIdx != -1 && g_TxdStore.HasObjectLoaded(strLocalIndex(txdIdx)))
{
gDrawListMgr->AddRefCountedModuleIndex(txdIdx, &g_TxdStore);
}
pTarget->Reset();
return true;
}
void CMovieMeshRenderTargetManager::ReleaseOnFailure(MovieMeshRenderTarget* pTarget)
{
pTarget->m_numRefs = 0;
pTarget->m_state = MovieMeshRenderTarget::kWaitingForRelease;
ProcessWaitingOnReleaseState(pTarget);
}
static inline void EnsureTextureGpuWritable(grcTexture *texture)
{
#if RSG_DURANGO || RSG_ORBIS
static_cast<grcOrbisDurangoTextureBase*>(texture)->EnsureGpuWritable();
#else
(void)texture;
#endif
}
void CMovieMeshRenderTargetManager::ProcessLoadingState(MovieMeshRenderTarget* pTarget)
{
strLocalIndex txdIdx = strLocalIndex(pTarget->m_txdIdx);
// We still don't have a txd slot
if (txdIdx == -1)
{
atHashString txdName("vfx_reference");
txdIdx = g_TxdStore.FindSlotFromHashKey(txdName);
}
// If we do and it's loaded, prepare the render target
if (txdIdx != -1 && g_TxdStore.HasObjectLoaded(txdIdx))
{
bool bOk = true;
// Make sure the texture we're after exists
fwTxd* pTxd = g_TxdStore.Get(txdIdx);
grcTexture* pTex = pTxd->Lookup(pTarget->m_name);
EnsureTextureGpuWritable(pTex);
CStreaming::SetDoNotDefrag(txdIdx, g_TxdStore.GetStreamingModuleId());
grcRenderTarget* pRt = NULL;
if (pTex)
{
pRt = CreateRenderTarget(pTarget, pTex);
bOk = (pRt != NULL);
}
// All good to go
if (bOk)
{
// Add a ref to the TXD
g_TxdStore.AddRef(txdIdx, REF_OTHER);
pTarget->m_bTxdRefAdded = true;
pTarget->m_pTexture = pTex;
pTarget->m_pRenderTarget = pRt;
pTarget->m_state = MovieMeshRenderTarget::kReady;
}
// Something went wrong, release immediately
else
{
ReleaseOnFailure(pTarget);
}
}
}
void CMovieMeshRenderTargetManager::ProcessReadyState(MovieMeshRenderTarget* )
{
}
grcRenderTarget* CMovieMeshRenderTargetManager::CreateRenderTarget(MovieMeshRenderTarget* pTarget, grcTexture* pTexture)
{
grcRenderTarget* pRenderTarget = NULL;
EnsureTextureGpuWritable(pTexture);
u32 imgFormat = pTexture->GetImageFormat();
bool isSupported = imgFormat == grcImage::A8R8G8B8 ||
imgFormat == grcImage::A8B8G8R8 ||
imgFormat == grcImage::L8 ||
imgFormat == grcImage::A1R5G5B5 ||
imgFormat == grcImage::R5G6B5;
Assertf(isSupported == true, "Warning: RT is in an unsupported format");
if(isSupported)
{
pRenderTarget = grcTextureFactory::GetInstance().CreateRenderTarget(pTarget->m_name.GetCStr(), pTexture->GetTexturePtr());
}
return pRenderTarget;
}
MovieMeshRenderTarget* CMovieMeshRenderTargetManager::Get(atFinalHashString name)
{
for (int i = 0; i < m_renderTargets.GetCount(); i++)
{
if (m_renderTargets[i].m_name == name)
return &m_renderTargets[i];
}
return NULL;
}
const MovieMeshRenderTarget* CMovieMeshRenderTargetManager::Get(atFinalHashString name) const
{
for (int i = 0; i < m_renderTargets.GetCount(); i++)
{
if (m_renderTargets[i].m_name == name)
return &m_renderTargets[i];
}
return NULL;
}
MovieMeshRenderTarget* CMovieMeshRenderTargetManager::Get(u32 rtHash)
{
for (int i = 0; i < m_renderTargets.GetCount(); i++)
{
if (m_renderTargets[i].m_name.GetHash() == rtHash)
return &m_renderTargets[i];
}
return NULL;
}
void CMovieMeshRenderTargetManager::BufferDataForDrawList(MovieMeshRenderTargetBufferedData* pOut)
{
int count = m_renderTargets.GetCount();
for (int i = 0; i < count; i++)
{
MovieMeshRenderTarget& current = m_renderTargets[i];
grcRenderTarget* pRt = current.m_pRenderTarget;
grcTexture* pTexture = NULL;
if (pRt && current.m_state == MovieMeshRenderTarget::kReady)
{
pTexture = current.m_pTexture;
// Add a temporary ref to the resource the render target belongs to.
// Should be inside of a txd, a frag, etc.
if (pTexture)
{
const strIndex strIdx = strStreamingEngine::GetStrIndex(&*pTexture);
Assert(strIdx.IsValid());
strStreamingModule* const module = strStreamingEngine::GetInfo().GetModule(strIdx);
Assert(module);
const strLocalIndex objIdx = module->GetObjectIndex(strIdx);
module->AddRef(objIdx, REF_RENDER);
gDrawListMgr->AddRefCountedModuleIndex(objIdx.Get(), module);
}
else
{
// Clear out the render target pointer that is going to be
// stored.
pRt = NULL;
}
}
pOut->pRt = pRt;
pOut->tex = pTexture;
pOut->id = current.m_name.GetHash();
++pOut;
}
}
bool CMovieMeshRenderTargetManager::IsReady(u32 rtHash) const
{
for (int i = 0; i < m_renderTargets.GetCount(); i++)
{
if (m_renderTargets[i].m_name.GetHash() == rtHash && m_renderTargets[i].m_state == MovieMeshRenderTarget::kReady)
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
// CMovieMeshManager class
//////////////////////////////////////////////////////////////////////////
CMovieMeshManager::CMovieMeshManager()
{
Reset();
}
CMovieMeshManager::~CMovieMeshManager()
{
Reset();
}
void CMovieMeshManager::Init(unsigned initMode)
{
g_movieMeshMgr.InitInternal(initMode);
}
void CMovieMeshManager::Shutdown(unsigned shutdownMode)
{
g_movieMeshMgr.ShutdownInternal(shutdownMode);
}
void CMovieMeshManager::InitInternal(unsigned UNUSED_PARAM(initMode))
{
Reset();
m_renderTargetMgr.Init();
}
void CMovieMeshManager::ShutdownInternal(unsigned UNUSED_PARAM(shutdownMode))
{
Reset(true);
}
void CMovieMeshManager::Reset(bool bReleaseResources)
{
#if __BANK
m_bDebugIgnoreAnimData = false;
#endif
if (bReleaseResources)
{
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
MovieMeshSet* pCurSet = &m_setPool[i];
ReleaseSet(pCurSet);
}
m_renderTargetMgr.Shutdown();
}
m_loadRequestPending = false;
m_releaseRequestPending = false;
}
void CMovieMeshManager::Update()
{
// process deferred deletion requests
ProcessDeleteRequests();
// pool housekeeping
m_globalPool.Update();
// process deferred loading requests
ProcessLoadRequests();
m_renderTargetMgr.Update();
// update active sets
UpdateSets();
// draw any rt/bink pair
Render();
#if __BANK
// update debug widgets
CMovieMeshDebugTool::Update();
#endif
}
void CMovieMeshManager::UpdateSets()
{
// update individual sets
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
MovieMeshSet* pCurSet = &m_setPool[i];
UpdateSet(pCurSet);
}
}
void CMovieMeshManager::Render()
{
// draw binks
for (int i = 0; i < MOVIE_MESH_MAX_HANDLES; i++)
{
MovieMeshHandle& curHandle = m_globalPool.m_uniqueHandles[i];
if (curHandle.rtHandle == INVALID_MOVIE_MESH_HANDLE)
{
continue;
}
if (m_renderTargetMgr.IsReady(curHandle.rtHandle))
{
CScriptHud::scriptTextRenderID = curHandle.rtHandle;
gRenderTargetMgr.UseRenderTarget(CRenderTargetMgr::RTI_MovieMesh);
CScriptHud::CurrentScriptWidescreenFormat = WIDESCREEN_FORMAT_STRETCH;
graphics_commands::DrawSpriteTex(NULL, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 255, 255, 255, 255, curHandle.movieHandle, SCRIPT_GFX_SPRITE, Vector2(0.0f,0.0f), Vector2(1.0f, 1.0f));
}
}
}
#if __BANK
void CMovieMeshManager::RenderDebug3D()
{
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
const MovieMeshSet* pCurSet = &m_setPool[i];
if (pCurSet->m_state == MMS_LOADED)
{
CMovieMeshDebugTool::Render(pCurSet);
}
}
}
#endif //__BANK
void CMovieMeshManager::UpdateSet(MovieMeshSet* pCurSet)
{
// return if there's no active set
if (pCurSet == NULL)
{
return;
}
// update anim data that hasn't been already processed
if (pCurSet->m_state != MMS_FAILED)
UpdateAnimDataForSet(pCurSet);
// return if the whole set is not ready
if (pCurSet->m_state != MMS_LOADED)
{
return;
}
// if set is loaded, register fires
MovieMeshInfoList& meshInfo = pCurSet->m_info;
for (int i = 0; i < meshInfo.m_BoundingSpheres.GetCount(); i++)
{
Vec4V vSpherePosAndRadius = RC_VEC4V(meshInfo.m_BoundingSpheres[i]);
g_fireMan.RegisterPtFxFire(NULL, vSpherePosAndRadius.GetXYZ(), pCurSet, i, vSpherePosAndRadius.GetWf(), false, false);
}
}
void CMovieMeshManager::UpdateAnimDataForSet(MovieMeshSet* pCurSet)
{
for (int i = 0; i < pCurSet->m_pMeshes.GetCount(); i++)
{
// skip if object has already been processed and is ready
if (pCurSet->m_pMeshes[i].m_bIsReady)
{
continue;
}
CObject* pObject = static_cast<CObject*>(pCurSet->m_pMeshes[i].m_pObj.Get());
if (pObject == NULL)
{
continue;
}
u32 modelIndex = CModelInfo::GetModelIdFromName(pCurSet->m_info.m_Data[i].m_ModelName.c_str()).GetModelIndex();
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(modelIndex)));
// check clip dictionary index to determine whether the model has animation or not
s32 clipDictionaryIndex = pModelInfo->GetClipDictionaryIndex().Get();
// object has no animation
if (clipDictionaryIndex == -1 BANK_ONLY(|| m_bDebugIgnoreAnimData == true))
{
pCurSet->m_pMeshes[i].m_bIsReady = true;
continue;
}
// object has animation and needs to be initialised once a drawable is available
// drawable might not be available, don't keep the system from updating because of it
if (pObject->GetDrawable() != NULL)
{
pObject->InitAnimLazy();
if (pObject->GetAnimDirector())
{
const crClip* pClip = fwAnimManager::GetClipIfExistsByDictIndex(clipDictionaryIndex, pModelInfo->GetHashKey());
// there's no clip matching the model's name, no further processing needed
// but model should has probably been exported with hasAnim == false
if (pClip == NULL)
{
vfxDisplayf("CMovieMeshManager::UpdateAnimDataForSet: expected an animation clip for model \"%s\", please fix me", pCurSet->m_info.m_Data[i].m_ModelName.c_str());
pCurSet->m_pMeshes[i].m_bIsReady = true;
continue;
}
CMoveObject& moveObj = pObject->GetMoveObject();
moveObj.GetClipHelper().BlendInClipByClip( pObject, pClip, INSTANT_BLEND_IN_DELTA, INSTANT_BLEND_OUT_DELTA, true, false);
pCurSet->m_pMeshes[i].m_bIsReady = true;
}
}
}
// set state
pCurSet->m_state = MMS_LOADED;
}
MovieMeshSetHandle CMovieMeshManager::GetTemporaryHandle(const char* pFilename) const
{
if (m_loadRequestPending == false)
{
vfxDisplayf("CMovieMeshManager::GetTemporaryHandle: a handle has been requested but there are no pending load requests");
return INVALID_MOVIE_MESH_SET_HANDLE;
}
return atStringHash(pFilename);
}
MovieMeshSetHandle CMovieMeshManager::LoadSet(const char* pFilename)
{
// check whether the set is already loaded
MovieMeshSetHandle tmpHandle = atStringHash(pFilename);
MovieMeshSet* pCurSet = FindSet(tmpHandle);
if (pCurSet != NULL)
{
vfxAssertf(0, "CMovieMeshManager::LoadSet: the set \"%s\" is already loaded", pFilename);
return pCurSet->m_handle;
}
int scriptHandle;
pCurSet = GetFreeSet(scriptHandle);
if (pCurSet == NULL)
{
Assert(scriptHandle == INVALID_MOVIE_MESH_SCRIPT_ID);
return scriptHandle;
}
pCurSet->m_loadRequestName = atString(pFilename);
pCurSet->m_state = MMS_PENDING_LOAD;
pCurSet->m_scriptId = scriptHandle;
pCurSet->m_handle = atStringHash(pFilename);
m_loadRequestPending = true;
return pCurSet->m_handle;
}
void CMovieMeshManager::ProcessLoadRequests()
{
// release requests should have been processed first
vfxAssertf(m_releaseRequestPending == false, "CMovieMeshManager::ProcessLoadRequests: trying to process load requests before processing deletions");
// no pending load requests
if (m_loadRequestPending == false)
{
return;
}
// reset pending load requests flag
m_loadRequestPending = false;
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
MovieMeshSet* pCurSet = &m_setPool[i];
if (pCurSet->m_state == MMS_PENDING_LOAD)
{
ProcessLoadRequest(pCurSet);
}
}
}
void CMovieMeshManager::ProcessLoadRequest(MovieMeshSet* pCurSet)
{
Assertf(pCurSet->m_state == MMS_PENDING_LOAD, "CMovieMeshManager::ProcessLoadRequest: trying to load a set with state %d", pCurSet->m_state);
if (pCurSet == NULL)
{
vfxDisplayf("CMovieMeshManager::ProcessLoadRequests: Failed to find a free set");
return;
}
// try loading movie the mesh info data
bool bOk = LoadMovieMeshInfoData(pCurSet);
// try loading the models
bOk = bOk && LoadMovieMeshObjects(pCurSet);
// try loading bink movies
bOk = bOk && LoadMovies(pCurSet);
// try loading and linking named render targets
bOk = bOk && LoadNamedRenderTargets(pCurSet);
// if something went wrong, return set to pool
if (bOk)
{
SetupBoundingSpheres(pCurSet);
}
else
{
ReleaseSet(pCurSet);
}
// set state as loaded
pCurSet->m_state = MMS_LOADED;
}
void CMovieMeshManager::SetupBoundingSpheres(MovieMeshSet* pCurSet)
{
MovieMeshInfoList& setInfo = pCurSet->m_info;
// initialise default transform
Mat34V vTransform;
vTransform.SetIdentity3x3();
// check if interior is loaded and ready
CInteriorInst* pInteriorInst = GetInteriorAtCoordsOfType(setInfo.m_InteriorPosition, setInfo.m_InteriorName.c_str());
bool bIsInteriorLoaded = IsInteriorReady(pInteriorInst);
if (pInteriorInst == NULL || bIsInteriorLoaded == false)
{
vfxDisplayf("CMovieMeshManager::SetupBoundingSpheres: Interior \"%s\" is not available", setInfo.m_InteriorName.c_str());
}
else
{
pInteriorInst->GetTransform().GetMatrixCopy(vTransform);
}
for (int i=0; i < setInfo.m_BoundingSpheres.GetCount(); i++)
{
// the position stored in the xml data is relative to m_InteriorMaxPosition,
// so we need to take the offset into account to make the position local to the interior origin.
Vector3 origPos = setInfo.m_BoundingSpheres[i].GetVector3();
const float radius = setInfo.m_BoundingSpheres[i].GetW();
const Vector3 interiorPos = setInfo.m_InteriorMaxPosition;
// the position stored in the xml data is relative to m_InteriorMaxPosition,
// so we need to take the offset into account to make the position local to the interior origin.
Vector3 localTranslation = origPos-setInfo.m_InteriorMaxPosition;
Mat34V vLocalTransform;
vLocalTransform.SetIdentity3x3();
vLocalTransform.Setd(VECTOR3_TO_VEC3V(localTranslation));
Mat34V vFinalTransform;
Transform(vFinalTransform, vTransform, vLocalTransform);
setInfo.m_BoundingSpheres[i].SetVector3(VEC3V_TO_VECTOR3(vFinalTransform.d()));
setInfo.m_BoundingSpheres[i].w = radius;
}
}
void CMovieMeshManager::ProcessDeleteRequests()
{
if (m_releaseRequestPending == false)
{
return;
}
m_releaseRequestPending = false;
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
MovieMeshSet* pCurSet = &m_setPool[i];
if (pCurSet->m_state == MMS_PENDING_DELETE)
{
ReleaseSet(pCurSet);
}
}
}
CObject* CMovieMeshManager::CreateMovieMeshObject(u32 modelIndex, Mat34V_In vTransform, fwInteriorLocation intLoc)
{
fwModelId modelId((strLocalIndex(modelIndex)));
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
if(pModelInfo==NULL)
{
Displayf ("CMovieMeshManager::CreateMovieMeshObject: invalid model: %d", modelIndex);
return NULL;
}
RegdEnt pEnt(NULL);
if(pModelInfo->GetIsTypeObject())
{
pEnt = CObjectPopulation::CreateObject(modelId, ENTITY_OWNEDBY_VFX, true);
}
else
{
Displayf("CMovieMeshManager::CreateMovieMeshObject: model type not supported");
return NULL;
}
if (pEnt != NULL)
{
// fwMatrixTransform trans = fwMatrixTransform(vTransform);
pEnt->SetMatrix(MAT34V_TO_MATRIX34(vTransform));
fragInst* pFragInst = pEnt->GetFragInst();
if (pFragInst != NULL)
{
pFragInst->SetResetMatrix(MAT34V_TO_MATRIX34(vTransform));
}
CGameWorld::Add(pEnt, intLoc);
if(pEnt->GetIsTypeObject())
{
CObject* pDynamicEnt = static_cast<CObject*>(pEnt.Get());
pDynamicEnt->GetPortalTracker()->RequestRescanNextUpdate();
pDynamicEnt->GetPortalTracker()->Update(VEC3V_TO_VECTOR3(pEnt->GetTransform().GetPosition()));
pDynamicEnt->SetupMissionState();
}
}
if (pEnt && pEnt->GetIsTypeObject())
{
return static_cast<CObject*>(pEnt.Get());
}
return NULL;
}
MovieMeshSet* CMovieMeshManager::GetFreeSet(int& scriptIdx)
{
scriptIdx = INVALID_MOVIE_MESH_SCRIPT_ID;
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
if (m_setPool[i].m_handle == INVALID_MOVIE_MESH_SET_HANDLE)
{
scriptIdx = i+1;
return &m_setPool[i];
}
}
Assertf(0, "CMovieMeshManager::GetFreeSet: No free sets");
return NULL;
}
MovieMeshSet* CMovieMeshManager::FindSet(MovieMeshSetHandle handle)
{
if (handle == INVALID_MOVIE_MESH_SET_HANDLE)
{
return NULL;
}
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
if (m_setPool[i].m_handle == handle)
{
return &m_setPool[i];
}
}
return NULL;
}
const MovieMeshSet* CMovieMeshManager::FindSet(MovieMeshSetHandle handle) const
{
if (handle == INVALID_MOVIE_MESH_SET_HANDLE)
{
return NULL;
}
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
if (m_setPool[i].m_handle == handle)
{
return &m_setPool[i];
}
}
return NULL;
}
bool CMovieMeshManager::LoadMovieMeshObjects(MovieMeshSet* pCurSet)
{
const MovieMeshInfoList& setInfo = pCurSet->m_info;
bool bOk = true;
// initialise default transform
Mat34V vTransform;
vTransform.SetIdentity3x3();
// default interior location (outdoors) for sets that are not bound to an interior
fwInteriorLocation intLoc = CGameWorld::OUTSIDE;
bool bIsInterior = setInfo.m_UseInterior;
// check if the set belongs in an interior
if (bIsInterior)
{
CInteriorInst* pInteriorInst = GetInteriorAtCoordsOfType(setInfo.m_InteriorPosition, setInfo.m_InteriorName.c_str());
// check if interior is loaded and ready
bool bIsInteriorLoaded = IsInteriorReady(pInteriorInst);
if (pInteriorInst == NULL || bIsInteriorLoaded == false)
{
bOk = false;
vfxDisplayf("CMovieMeshManager::LoadMovieMeshObjects: Interior \"%s\" is not available", setInfo.m_InteriorName.c_str());
}
else
{
pInteriorInst->GetTransform().GetMatrixCopy(vTransform);
intLoc = CInteriorInst::CreateLocation(pInteriorInst, 0);
}
}
// iterate through meshes in the set
if (bOk)
{
for (int i = 0; i < setInfo.m_Data.GetCount(); i++)
{
// get a model index for the current mesh
u32 nModelIndex = CModelInfo::GetModelIdFromName(setInfo.m_Data[i].m_ModelName.c_str()).GetModelIndex();
// check model info is valid
if (CModelInfo::IsValidModelInfo(nModelIndex) == false)
{
vfxDisplayf("CMovieMeshManager::LoadMovieMeshObjects: Invalid model index for \"%s\"", setInfo.m_Data[i].m_ModelName.c_str());
bOk = false;
break;
}
Mat34V vLocalTransform;
vLocalTransform.Seta(VECTOR3_TO_VEC3V(setInfo.m_Data[i].m_TransformA));
vLocalTransform.Setb(VECTOR3_TO_VEC3V(setInfo.m_Data[i].m_TransformB));
vLocalTransform.Setc(VECTOR3_TO_VEC3V(setInfo.m_Data[i].m_TransformC));
// the position stored in the xml data is relative to m_InteriorMaxPosition,
// so we need to take the offset into account to make the position local to the interior origin.
Vector3 localTranslation = setInfo.m_Data[i].m_TransformD-setInfo.m_InteriorMaxPosition;
vLocalTransform.Setd(VECTOR3_TO_VEC3V(localTranslation));
Mat34V vFinalTransform;
Transform(vFinalTransform, vTransform, vLocalTransform);
ReOrthonormalize3x3(vFinalTransform, vFinalTransform);
//load the entered object
CObject* pObj = CreateMovieMeshObject(nModelIndex, vFinalTransform, intLoc);
// check object was created ok
if (pObj == NULL)
{
vfxDisplayf("CMovieMeshManager::LoadMovieMeshObjects: Failed to load model \"%s\"", setInfo.m_Data[i].m_ModelName.c_str());
bOk = false;
break;
}
MovieMeshSet::MeshObject mesh;
mesh.m_bIsReady = false;
mesh.m_pObj = RegdEnt(pObj);
// add object to active set
pCurSet->m_pMeshes.PushAndGrow(mesh);
}
}
// potentially need to release some objects from the current set
if (bOk == false)
{
ReleaseObjectsFromSet(pCurSet);
vfxDisplayf("CMovieMeshManager::LoadMovieMeshObjects: Failed to load set \"%s\"", pCurSet->m_loadRequestName.c_str());
return false;
}
return bOk;
}
bool CMovieMeshManager::LoadMovieMeshInfoData(MovieMeshSet* pCurSet)
{
MovieMeshInfoList& setInfo = pCurSet->m_info;
// compose full file name
atFixedString<1024> str = MM_DATA_PATH;
str.Append(pCurSet->m_loadRequestName);
bool bOk = fwPsoStoreLoader::LoadDataIntoObject(str, "", setInfo);
// check mesh info data was parsed successfully
if (bOk == false)
{
vfxDisplayf("CMovieMeshManager::LoadMovieMeshInfoData: Failed to load mesh info data for set \"%s\"", pCurSet->m_loadRequestName.c_str());
return bOk;
}
// assign a valid handle to active set
pCurSet->m_handle = atStringHash(pCurSet->m_loadRequestName);
return bOk;
}
bool CMovieMeshManager::LoadMovies(MovieMeshSet* pCurSet)
{
const MovieMeshInfoList& setInfo = pCurSet->m_info;
bool bOk = true;
for (int i = 0; i < setInfo.m_Data.GetCount(); i++)
{
const char* pMovieName = setInfo.m_Data[i].m_TextureName.c_str();
u32 movieHandle = 0;
#if GTA_REPLAY
if( CReplayMgr::IsEditModeActive() )
{
movieHandle = atStringHash(pMovieName);
}
else
#endif //GTA_REPLAY
{
movieHandle = g_movieMgr.PreloadMovie(pMovieName);
if (g_movieMgr.IsHandleValid(movieHandle) == false)
{
vfxDisplayf("CMovieMeshManager::LoadMovies: Failed to load bink movie \"%s\"", pMovieName);
bOk = false;
break;
}
// start playing movie
g_movieMgr.Play(movieHandle);
}
// add movie handle to set
if (AddMovieHandle(pCurSet, movieHandle) == false)
{
Displayf("CMovieMeshManager::LoadMovies: failed to allocate handle for movie \"%s\"", pMovieName);
bOk = false;
break;
}
}
// potentially need to release some movies and objects from the current set
if (bOk == false)
{
ReleaseMoviesFromSet(pCurSet);
ReleaseObjectsFromSet(pCurSet);
return false;
}
return bOk;
}
bool CMovieMeshManager::LoadNamedRenderTargets(MovieMeshSet* pCurSet)
{
const MovieMeshInfoList& setInfo = pCurSet->m_info;
bool bOk = true;
for (int i = 0; i < setInfo.m_Data.GetCount(); i++)
{
atFinalHashString rtName(setInfo.m_Data[i].m_TextureName.c_str());
if (rtName.IsNull())
{
bOk = false;
vfxDisplayf("CMovieMeshManager::LoadNamedRenderTargets: Failed to setup named render target for \"%s\"", setInfo.m_Data[i].m_TextureName.c_str());
break;
}
// try registering only if it hasn't been registered previously
u32 rtId = 0U;
if (m_renderTargetMgr.Exists(rtName))
{
rtId = rtName.GetHash();
}
else
{
rtId = m_renderTargetMgr.Register(rtName);
}
// invalid id
if (rtId == 0)
{
bOk = false;
break;
}
// add render target id to set
AddRenderTargetHandle(pCurSet->m_pHandles[i], rtId, rtName.GetHash());
}
// potentially need to release some movies and objects from the current set
if (bOk == false)
{
ReleaseMoviesFromSet(pCurSet);
ReleaseObjectsFromSet(pCurSet);
return false;
}
return bOk;
}
void CMovieMeshManager::AddRenderTargetHandle(MovieMeshHandle* pHandle, u32 rtId, u32 rtNameHash)
{
Assertf(pHandle->movieHandle != INVALID_MOVIE_MESH_HANDLE, "CMovieMeshManager::AddRenderTargetHandle: trying to set up a bink rt, but associated bink movie handle is invalid");
Assertf(rtId != INVALID_MOVIE_MESH_HANDLE && rtNameHash != INVALID_MOVIE_MESH_HANDLE, "CMovieMeshManager::AddRenderTargetHandle: trying to set up a bink rt with an invalid handle");
m_globalPool.ModifyHandle(pHandle, pHandle->movieHandle, rtId, rtNameHash);
}
bool CMovieMeshManager::AddMovieHandle(MovieMeshSet* pCurSet, u32 movieHandle)
{
Assertf(movieHandle != INVALID_MOVIE_MESH_HANDLE, "CMovieMeshManager::AddMovieHandle: trying to set up a bink movie, but handle is invalid");
MovieMeshHandle* pHandle = NULL;
bool bOk = m_globalPool.AddHandle(pHandle, movieHandle);
if (bOk)
{
Assertf(pHandle != NULL, "CMovieMeshManager::AddMovieHandle: null handle");
pCurSet->m_pHandles.PushAndGrow(pHandle);
}
return bOk;
}
void CMovieMeshManager::ReleaseSet(MovieMeshSet* pCurSet)
{
if (pCurSet == NULL)
{
return;
}
ReleaseMoviesFromSet(pCurSet);
ReleaseObjectsFromSet(pCurSet);
pCurSet->m_handle = INVALID_MOVIE_MESH_SET_HANDLE;
pCurSet->m_state = MMS_FAILED;
}
void CMovieMeshManager::ReleaseObjectsFromSet(MovieMeshSet* pCurSet)
{
vfxAssert(pCurSet != NULL);
// release all objects
for (int i = 0; i < pCurSet->m_pMeshes.GetCount(); i++)
{
CObject* pObject = static_cast<CObject*>(pCurSet->m_pMeshes[i].m_pObj.Get());
pCurSet->m_pMeshes[i].m_bIsReady = false;
if (pObject != NULL)
{
CObjectPopulation::DestroyObject(pObject);
}
}
// reset array
pCurSet->m_pMeshes.Reset();
}
void CMovieMeshManager::ReleaseMoviesFromSet(MovieMeshSet* pCurSet)
{
vfxAssert(pCurSet != NULL);
// release all objects
for (int i = 0; i < pCurSet->m_pHandles.GetCount(); i++)
{
pCurSet->m_pHandles[i]->Release();
}
pCurSet->m_pHandles.Reset();
}
bool CMovieMeshManager::HandleExists(MovieMeshSetHandle handle) const
{
return (IsHandleValid(handle) && FindSet(handle));
}
CInteriorInst* CMovieMeshManager::GetInteriorAtCoordsOfType(const Vector3& scrVecInCoors, const char* typeName)
{
u32 typeKey = atStringHash(typeName);
Vector3 vecPositionToCheck(scrVecInCoors);
// get a list of MLOs at desired position
fwIsSphereIntersecting intersection(spdSphere(RCC_VEC3V(vecPositionToCheck), ScalarV(V_FLT_SMALL_1)));
fwPtrListSingleLink scanList;
CInteriorInst::FindIntersectingMLOs(intersection, scanList);
// get the closest interior of the right type
fwPtrNode* pNode = scanList.GetHeadPtr();
CInteriorInst* pClosest = NULL;
float closestDist2 = 0.0f;
Vec3V vPositionToCheck = RCC_VEC3V(vecPositionToCheck);
while(pNode){
CInteriorInst* pIntInst = reinterpret_cast<CInteriorInst*>(pNode->GetPtr());
if (pIntInst){
CBaseModelInfo* pModelInfo = pIntInst->GetBaseModelInfo();
if (pModelInfo->GetHashKey() == typeKey){
float dist2 = DistSquared(pIntInst->GetTransform().GetPosition(), vPositionToCheck).Getf();
if (pClosest){
if (dist2 < closestDist2){
pClosest = pIntInst;
closestDist2 = dist2;
}
} else {
pClosest = pIntInst;
closestDist2 = dist2;
}
}
}
pNode = pNode->GetNextPtr();
}
return pClosest;
}
bool CMovieMeshManager::IsInteriorReady(CInteriorInst* pInteriorInst)
{
if (pInteriorInst == NULL)
{
return false;
}
// tbr: for some reason GetCurrentState is not const, so tough luck for our unprotected pInteriorInst...
CInteriorProxy* pIntProxy = pInteriorInst->GetProxy();
Assert(pIntProxy);
if (pIntProxy->GetCurrentState() >= CInteriorProxy::PS_FULL)
{
return true;
}
return false;
}
void CMovieMeshManager::ExtractRenderTargetName(const char* pInputName, const char*& pOutputName)
{
const char* scriptRT = strstr(pInputName,MM_SCRIPTED_RT_PREFIX);
pOutputName = NULL;
if(scriptRT)
{
pOutputName = scriptRT + strlen(MM_SCRIPTED_RT_PREFIX);
}
}
void CMovieMeshManager::ReleaseSet(MovieMeshSetHandle handle)
{
MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet == NULL)
{
return;
}
pCurSet->m_state = MMS_PENDING_DELETE;
m_releaseRequestPending = true;
}
eMovieMeshSetState CMovieMeshManager::QuerySetStatus(MovieMeshSetHandle handle) const
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet == NULL)
{
// set still hasn't been loaded
if (m_loadRequestPending == true)
{
return MMS_PENDING_LOAD;
}
// set doesn't exist
return MMS_FAILED;
}
return pCurSet->m_state;
}
int CMovieMeshManager::GetScriptIdFromHandle(MovieMeshSetHandle handle) const
{
if (handle == INVALID_MOVIE_MESH_SET_HANDLE)
{
return INVALID_MOVIE_MESH_SCRIPT_ID;
}
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet == NULL)
{
vfxDisplayf("CMovieMeshManager::GetScriptIdFromHandle: could not find set for valid handle");
return INVALID_MOVIE_MESH_SCRIPT_ID;
}
return pCurSet->m_scriptId;
}
MovieMeshSetHandle CMovieMeshManager::GetHandleFromScriptId(int idx) const
{
// script id is invalid
if (idx == INVALID_MOVIE_MESH_SCRIPT_ID || idx < 0 || idx >= MOVIE_MESH_MAX_SETS) {
Assertf(idx >= 0 && idx < MOVIE_MESH_MAX_SETS, "CMovieMeshManager::GetHandleFromScriptId: script id out of range");
return INVALID_MOVIE_MESH_SET_HANDLE;
}
const MovieMeshSet* pCurSet = &m_setPool[idx-1];
return pCurSet->m_handle;
}
#if __BANK
const char* CMovieMeshManager::GetSetName(MovieMeshSetHandle handle) const
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet != NULL)
{
return pCurSet->m_loadRequestName.c_str();
}
return NULL;
}
void CMovieMeshManager::SetMeshIsVisible(MovieMeshSetHandle handle, int i, bool isVisible)
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet != NULL && i < pCurSet->m_pMeshes.GetCount())
{
pCurSet->m_pMeshes[i].m_pObj->SetIsVisibleForModule(SETISVISIBLE_MODULE_VFX, isVisible);
}
}
bool CMovieMeshManager::GetMeshIsVisible(MovieMeshSetHandle handle, int i) const
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet != NULL && i < pCurSet->m_pMeshes.GetCount())
{
return pCurSet->m_pMeshes[i].m_pObj->GetIsVisible();
}
return false;
}
int CMovieMeshManager::GetNumMeshes(MovieMeshSetHandle handle) const
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet != NULL)
{
return pCurSet->m_info.m_Data.GetCount();
}
return 0;
}
void CMovieMeshManager::InitWidgets()
{
CMovieMeshDebugTool::InitWidgets();
}
#endif // __BANK
#if __SCRIPT_MEM_CALC
void CMovieMeshManager::CountMemoryUsageForMovies(MovieMeshSetHandle handle)
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet != NULL)
{
for (int i = 0; i < pCurSet->m_pHandles.GetCount(); i++)
{
u32 movieHandle = pCurSet->m_pHandles[i]->movieHandle;
CTheScripts::GetScriptHandlerMgr().AddToMoviesUsedByMovieMeshes(movieHandle);
}
}
}
void CMovieMeshManager::CountMemoryUsageForRenderTargets(MovieMeshSetHandle)
{
}
void CMovieMeshManager::CountMemoryUsageForObjects(MovieMeshSetHandle handle)
{
const MovieMeshSet* pCurSet = FindSet(handle);
if (pCurSet != NULL)
{
for (int i = 0; i < pCurSet->m_pMeshes.GetCount(); i++)
{
CObject* pObject = static_cast<CObject*>(pCurSet->m_pMeshes[i].m_pObj.Get());
if (pObject != NULL)
{
CTheScripts::GetScriptHandlerMgr().AddToModelsUsedByMovieMeshes(pObject->GetModelIndex());
}
}
}
}
#endif // __SCRIPT_MEM_CALC
//////////////////////////////////////////////////////////////////////////
// CMovieMeshDebugTool
//////////////////////////////////////////////////////////////////////////
#if __BANK
// widgets
bkGroup* CMovieMeshDebugTool::ms_pBankGroup = NULL;
bkCombo* CMovieMeshDebugTool::ms_pLoadedSetsCombo = NULL;
bkText* CMovieMeshDebugTool::ms_pLoadRequestBox = NULL;
bkButton* CMovieMeshDebugTool::ms_pCreateButton = NULL;
bkButton* CMovieMeshDebugTool::ms_pLoadSetButton = NULL;
bkButton* CMovieMeshDebugTool::ms_pReleaseSetButton = NULL;
const char* CMovieMeshDebugTool::ms_comboSetNames[MOVIE_MESH_MAX_SETS];
MovieMeshSetHandle CMovieMeshDebugTool::ms_setHandles[MOVIE_MESH_MAX_SETS];
char CMovieMeshDebugTool::ms_strSetName[128] = "\0";
bool CMovieMeshDebugTool::ms_bActiveSetInitialised = false;
int CMovieMeshDebugTool::ms_comboSelIndex = 0;
const char* CMovieMeshDebugTool::ms_comboEmptyMessage = "[empty slot]";
bool CMovieMeshDebugTool::ms_bIgnoreAnimData = false;
bool CMovieMeshDebugTool::ms_bShowFireBoundingSpheres= false;
void CMovieMeshDebugTool::InitWidgets()
{
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
ms_comboSetNames[i] = &ms_comboEmptyMessage[0];
ms_setHandles[i] = INVALID_MOVIE_MESH_HANDLE;
}
ms_pBankGroup = vfxWidget::GetBank()->PushGroup("Movie Mesh Manager");
ms_pCreateButton = vfxWidget::GetBank()->AddButton("Create Movie Mesh Debug Widgets", CFA1(CMovieMeshDebugTool::CreateWidgetsOnDemand));
vfxWidget::GetBank()->PopGroup();
}
void CMovieMeshDebugTool::CreateWidgetsOnDemand()
{
bkBank* pBank = vfxWidget::GetBank();
if(ms_pCreateButton)
{
pBank->Remove(*((bkWidget*)ms_pCreateButton));
ms_pCreateButton = NULL;
}
pBank->SetCurrentGroup(*ms_pBankGroup);
pBank->AddToggle("Show Fire Bounding Spheres", &ms_bShowFireBoundingSpheres);
ms_pLoadRequestBox = pBank->AddText("Enter set name:", &ms_strSetName[0], 128, false, NullCB);
ms_pLoadSetButton = pBank->AddButton("Load Movie Mesh Set", CFA1(CMovieMeshDebugTool::LoadSet));
pBank->AddToggle("Ignore Animation Data When Loading Set", &ms_bIgnoreAnimData, CFA1(CMovieMeshDebugTool::OnIgnoreAnimDataToggleChange));
pBank->AddSeparator();
ms_pReleaseSetButton = pBank->AddButton("Release Movie Mesh Set", CFA1(CMovieMeshDebugTool::ReleaseSet));
ms_pLoadedSetsCombo = pBank->AddCombo("Available Set Slots", &ms_comboSelIndex, MOVIE_MESH_MAX_SETS, &ms_comboSetNames[0], NullCB);
pBank->UnSetCurrentGroup(*ms_pBankGroup);
}
void CMovieMeshDebugTool::LoadSet()
{
if (IsInputStringValid())
{
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
if (ms_setHandles[i] == INVALID_MOVIE_MESH_HANDLE)
{
ms_setHandles[i] = g_movieMeshMgr.LoadSet(ms_strSetName);
ms_comboSetNames[i] = g_movieMeshMgr.GetSetName(ms_setHandles[i]);
RefreshSetCombo();
return;
}
}
}
}
void CMovieMeshDebugTool::ReleaseSet()
{
if (ms_comboSelIndex <0 || ms_comboSelIndex >= MOVIE_MESH_MAX_SETS)
{
Displayf("CMovieMeshDebugTool::ReleaseSet: trying to release an invalid set (index %d)", ms_comboSelIndex);
return;
}
MovieMeshSetHandle curHandle = ms_setHandles[ms_comboSelIndex];
if (g_movieMeshMgr.HandleExists(curHandle))
{
g_movieMeshMgr.ReleaseSet(curHandle);
ms_setHandles[ms_comboSelIndex] = INVALID_MOVIE_MESH_HANDLE;
ms_comboSetNames[ms_comboSelIndex] = &ms_comboEmptyMessage[0];
ms_comboSelIndex = 0;
RefreshSetCombo();
}
}
void CMovieMeshDebugTool::RefreshSetCombo()
{
// refresh combo
bkBank* pBank = vfxWidget::GetBank();
pBank->SetCurrentGroup(*ms_pBankGroup);
pBank->Remove(*((bkWidget*)ms_pLoadedSetsCombo));
ms_pLoadedSetsCombo = pBank->AddCombo("Available Set Slots", &ms_comboSelIndex, MOVIE_MESH_MAX_SETS, &ms_comboSetNames[0], NullCB);
pBank->UnSetCurrentGroup(*ms_pBankGroup);
}
void CMovieMeshDebugTool::Render(const MovieMeshSet* pCurSet)
{
// render bounding spheres
if (ms_bShowFireBoundingSpheres)
{
if (pCurSet)
{
const MovieMeshInfoList& setInfo = pCurSet->m_info;
for (int k=0; k < setInfo.m_BoundingSpheres.GetCount(); k++)
{
const Vector3 spherePos = Vector3(setInfo.m_BoundingSpheres[k].x, setInfo.m_BoundingSpheres[k].y, setInfo.m_BoundingSpheres[k].z);
const float radius = setInfo.m_BoundingSpheres[k].w;
grcDebugDraw::Sphere(spherePos, radius, Color32(255, 0, 0, 128));
}
}
}
}
void CMovieMeshDebugTool::Update()
{
for (int i = 0; i < MOVIE_MESH_MAX_SETS; i++)
{
if (ms_setHandles[i] == INVALID_MOVIE_MESH_HANDLE)
{
continue;
}
// if there's a set that failed to load or that is about to be deleted, remove it from the combo box
if (g_movieMeshMgr.QuerySetStatus(ms_setHandles[i]) == MMS_FAILED ||
g_movieMeshMgr.QuerySetStatus(ms_setHandles[i]) == MMS_PENDING_DELETE)
{
ms_setHandles[i] = INVALID_MOVIE_MESH_HANDLE;
ms_comboSetNames[ms_comboSelIndex] = &ms_comboEmptyMessage[0];
RefreshSetCombo();
}
}
}
bool CMovieMeshDebugTool::IsInputStringValid()
{
int strLength = istrlen(ms_strSetName);
return (strLength > 0);
}
void CMovieMeshDebugTool::OnComboSelectionChange()
{
}
void CMovieMeshDebugTool::OnIgnoreAnimDataToggleChange()
{
g_movieMeshMgr.SetIgnoreAnimDataOnLoad(ms_bIgnoreAnimData);
}
#endif // __BANK