1593 lines
48 KiB
C++
1593 lines
48 KiB
C++
//
|
|
// streaming/streamingrequestlist.cpp
|
|
//
|
|
// Copyright (C) 1999-2014 Rockstar Games. All Rights Reserved.
|
|
//
|
|
|
|
|
|
#include "streaming/streaming_channel.h"
|
|
|
|
STREAMING_OPTIMISATIONS()
|
|
|
|
|
|
#include "streamingrequestlist.h"
|
|
|
|
#include <set>
|
|
#include "bank/bank.h"
|
|
|
|
#include "atl/map.h"
|
|
#include "camera/camInterface.h"
|
|
#include "camera/viewports/ViewportManager.h"
|
|
#include "Cutscene/CutsceneManagerNew.h"
|
|
#include "ModelInfo/ModelInfo.h"
|
|
#include "ModelInfo/ModelInfo_Factories.h"
|
|
#include "parser/manager.h"
|
|
#include "parser/treenode.h"
|
|
#include "renderer/PostScan.h"
|
|
#include "streaming/zonedassetmanager.h"
|
|
#include "system/FileMgr.h"
|
|
#include "scene/texLod.h"
|
|
|
|
#include "entity/archetypemanager.h"
|
|
#include "fwscene/stores/boxstreamerassets.h"
|
|
#include "fwscene/stores/boxstreamersearch.h"
|
|
#include "fwscene/stores/mapdatastore.h"
|
|
#include "fwscene/stores/maptypesstore.h"
|
|
#include "fwscene/world/WorldLimits.h"
|
|
#include "fwsys/fileExts.h"
|
|
#include "fwsys/metadatastore.h"
|
|
#include "fwsys/timer.h"
|
|
#include "grcore/debugdraw.h"
|
|
#include "network/live/livemanager.h"
|
|
#include "renderer/PostScan.h"
|
|
#include "scene/FocusEntity.h"
|
|
#include "scene/ipl/IplCullBox.h"
|
|
#include "scene/LoadScene.h"
|
|
#include "scene/streamer/SceneStreamerList.h"
|
|
#include "scene/streamer/SceneStreamerMgr.h"
|
|
#include "scene/world/GameScan.h"
|
|
#include "streaming/packfilemanager.h"
|
|
#include "streaming/streaming.h"
|
|
#include "streaming/streaming_channel.h"
|
|
#include "streaming/streamingengine.h"
|
|
#include "streaming/streamingmodule.h"
|
|
#include "streaming/streamingrequestlisteditor.h"
|
|
#include "streaming/streamingvisualize.h"
|
|
#include "string/stringutil.h"
|
|
|
|
#include "streamingrequestlist_shared.h"
|
|
#include "streamingrequestlist_parser.h"
|
|
|
|
|
|
float g_lastWriteTime;
|
|
s32 g_requestListIndex;
|
|
s32 g_removeListIndex;
|
|
s32 g_retryNeeded;
|
|
s32 g_requestListIndexPrestream;
|
|
bool g_bHDTexLoadedThisFrame = false;
|
|
|
|
const s32 DEFAULT_STREAMING_AHEAD_TIME = 3;
|
|
const s32 DEFAULT_STREAMING_AHEAD_TIME_PRESTREAM = 3;
|
|
const s32 DEFAULT_LOADSCENE_AHEAD_TIME = 3;
|
|
const s32 DEFAULT_LOADSCENE_AHEAD_TIME_PRESTREAM = 3;
|
|
|
|
s32 g_streamingAheadTime = DEFAULT_STREAMING_AHEAD_TIME; //load ahead for objects
|
|
s32 g_streamingAheadTimePrestream = DEFAULT_STREAMING_AHEAD_TIME_PRESTREAM; //prestream load ahead for objects
|
|
s32 g_loadsceneAheadTime = DEFAULT_LOADSCENE_AHEAD_TIME; //load ahead for imaps
|
|
s32 g_loadsceneAheadTimePrestream = DEFAULT_LOADSCENE_AHEAD_TIME_PRESTREAM; //load ahead for imaps on first frame
|
|
|
|
extern bool g_HACK_GlobalSRLSkipGC;
|
|
bool g_disableForGTAO = false; //disables HD textures and zoned assets for the GTAO intro
|
|
|
|
CStreamingRequestList gStreamingRequestList;
|
|
static atMap<atHashString, s32> s_AddRefedMaps; // A list of objIndices of map datas for which we incremented the ref count.
|
|
// Key is the model hash, value is the objIndex of the map type
|
|
|
|
#if __BANK
|
|
// from streamingrequestlist_rec_dbg.h
|
|
extern char g_recordingFilename[128];
|
|
extern f32 g_BoxStreamerThreshold;
|
|
bool g_DisableHDTxdRequests = false;
|
|
#endif // __BANK
|
|
|
|
#if __ASSERT
|
|
static atMap<atHashString, bool> s_RequestedAssets;
|
|
#endif // __ASSERT
|
|
|
|
PARAM(nosrl, "disable SRLs");
|
|
PARAM(addsvframemarkers, "Add a SV marker for every time we switch to a new recorded frame");
|
|
|
|
CStreamingRequestFrame::~CStreamingRequestFrame()
|
|
{
|
|
}
|
|
|
|
void CStreamingRequestFrame::OnPostLoad()
|
|
{
|
|
}
|
|
|
|
void CStreamingRequestFrame::OnPostSave(parTreeNode* NOTFINAL_ONLY(pNode))
|
|
{
|
|
#if !__FINAL
|
|
pNode->GetElement().AddAttribute("frameIndex", pNode->GetParent()->FindNumChildren() - 1);
|
|
#endif // !__FINAL
|
|
}
|
|
|
|
bool CStreamingRequestFrame::AddMapDataRefCount(atHashString modelName, fwModelId modelId)
|
|
{
|
|
strLocalIndex mapTypeSlotIndex = modelId.GetMapTypeDefIndex();
|
|
if(mapTypeSlotIndex != fwModelId::TF_INVALID)
|
|
{
|
|
// Did we already do it?
|
|
if (s_AddRefedMaps.Access(modelName))
|
|
{
|
|
// Yeah, we're good.
|
|
return true;
|
|
}
|
|
|
|
// Is this thing resident?
|
|
if (strStreamingEngine::GetInfo().GetStreamingInfoRef(g_MapTypesStore.GetStreamingIndex(mapTypeSlotIndex)).GetStatus() != STRINFO_LOADED)
|
|
{
|
|
// Not yet - we can't add a ref!!
|
|
return false;
|
|
}
|
|
|
|
// It's resident - add the ref count and check it off.
|
|
g_MapTypesStore.AddRef(mapTypeSlotIndex, REF_SCRIPT);
|
|
s_AddRefedMaps.Insert(modelName, mapTypeSlotIndex.Get());
|
|
return true;
|
|
}
|
|
|
|
// Doesn't have a map type, so screw it.
|
|
return true;
|
|
}
|
|
|
|
void CStreamingRequestFrame::RemoveMapDataRefCount(atHashString modelName, fwModelId modelId)
|
|
{
|
|
strLocalIndex mapTypeSlotIndex = modelId.GetMapTypeDefIndex();
|
|
if(mapTypeSlotIndex != fwModelId::TF_INVALID)
|
|
{
|
|
// Only remove the ref if we added it earlier.
|
|
if (s_AddRefedMaps.Access(modelName))
|
|
{
|
|
Assert(*s_AddRefedMaps.Access(modelName) == mapTypeSlotIndex.Get());
|
|
g_MapTypesStore.RemoveRef(mapTypeSlotIndex, REF_SCRIPT); // If this fails, something is wrong - we added a ref earlier, so it must be resident.
|
|
s_AddRefedMaps.Delete(modelName);
|
|
}
|
|
}
|
|
}
|
|
|
|
CStreamingRequestFrame::AssetLoadState CStreamingRequestFrame::ProcessRequestList(const CStreamingRequestRecord &record)
|
|
{
|
|
bool canSkipToNext = true;
|
|
bool missingAssets = false;
|
|
|
|
atHashString tempStorage[MAX_REQUESTS_PER_FRAME];
|
|
atUserArray<atHashString> tempRequestList(tempStorage, MAX_REQUESTS_PER_FRAME);
|
|
CreateFullRequestList(record, tempRequestList);
|
|
|
|
for (int i = 0; i < tempRequestList.GetCount(); ++i) {
|
|
fwModelId modelId;
|
|
if (fwArchetypeManager::GetArchetypeFromHashKey(tempRequestList[i], modelId)) {
|
|
//s32 objIndex = modelId.ConvertToStreamingIndex();
|
|
bool isModelLoaded = CModelInfo::HaveAssetsLoaded(modelId);
|
|
AddMapDataRefCount(tempRequestList[i], modelId);
|
|
|
|
// Wait here until the models are all loaded.
|
|
if(!isModelLoaded) {
|
|
// Not loaded yet, okay. Is it at least requested?
|
|
if (!CModelInfo::AreAssetsRequested(modelId)) {
|
|
streamSRLDebugf1("SRL - %s needs to be requested", CModelInfo::GetBaseModelInfoName(modelId));
|
|
} else {
|
|
streamSRLDebugf2("SRL - still waiting for %s", CModelInfo::GetBaseModelInfoName(modelId));
|
|
}
|
|
|
|
isModelLoaded = !CModelInfo::RequestAssets(modelId, STRFLAG_CUTSCENE_REQUIRED);
|
|
|
|
if (!isModelLoaded)
|
|
{
|
|
#if __ASSERT
|
|
{
|
|
USE_DEBUG_MEMORY();
|
|
s_RequestedAssets[tempRequestList[i]] = true;
|
|
}
|
|
#endif // __ASSERT
|
|
}
|
|
else
|
|
{
|
|
missingAssets = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gStreamingRequestList.GetEnsureCutsceneRequired())
|
|
{
|
|
CModelInfo::SetAssetRequiredFlag(modelId, STRFLAG_CUTSCENE_REQUIRED);
|
|
|
|
#if __ASSERT
|
|
{
|
|
USE_DEBUG_MEMORY();
|
|
s_RequestedAssets[tempRequestList[i]] = true;
|
|
}
|
|
#endif // __ASSERT
|
|
}
|
|
}
|
|
canSkipToNext &= isModelLoaded;
|
|
}
|
|
}
|
|
|
|
BANK_ONLY(if (!g_DisableHDTxdRequests))
|
|
{
|
|
|
|
for (int i = 0; i < m_PromoteToHDList.GetCount(); ++i) {
|
|
fwModelId modelId;
|
|
fwArchetype *pArchetype = fwArchetypeManager::GetArchetypeFromHashKey(m_PromoteToHDList[i], modelId);
|
|
|
|
if ( pArchetype ) {
|
|
bool isModelLoaded = CModelInfo::HaveAssetsLoaded(modelId);
|
|
if(isModelLoaded) {
|
|
CBaseModelInfo *pMI = CModelInfo::GetBaseModelInfo(modelId);
|
|
if(pMI){
|
|
CTexLod::AddHDTxdRequest(pMI->GetAssetLocation(), pArchetype->GetStreamSlot().Get());
|
|
#if !RSG_PC
|
|
g_bHDTexLoadedThisFrame &= pMI->GetAssetLocation().GetIsBoundHD();
|
|
#if __BANK
|
|
if(!pMI->GetAssetLocation().GetIsBoundHD())
|
|
streamSRLDebugf1("SRL (HDTex) - %s has not Loaded", CModelInfo::GetBaseModelInfoName(modelId));
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return canSkipToNext ? (missingAssets ? ALL_REQUESTED_BUT_MISSING : ALL_RESIDENT) : NONRESIDENT_ASSETS;
|
|
}
|
|
|
|
void CStreamingRequestFrame::CreateFullRequestList(const CStreamingRequestRecord &record, atArray<atHashString> &outRequestList) const
|
|
{
|
|
// Get the full count.
|
|
int fullCount = m_AddList.GetCount();
|
|
int commonCount = m_CommonAddSets.GetCount();
|
|
|
|
for (int x=0; x<commonCount; x++)
|
|
{
|
|
fullCount += record.GetCommonSet(m_CommonAddSets[x]).GetCount();
|
|
}
|
|
|
|
outRequestList.Resize(fullCount);
|
|
|
|
if (fullCount)
|
|
{
|
|
sysMemCpy(&outRequestList[0], m_AddList.GetElements(), sizeof(atHashString) * m_AddList.GetCount());
|
|
|
|
int index = m_AddList.GetCount();
|
|
for (int x=0; x<commonCount; x++)
|
|
{
|
|
const atArray<atHashString> &commonSet = record.GetCommonSet(m_CommonAddSets[x]);
|
|
sysMemCpy(&outRequestList[index], commonSet.GetElements(), sizeof(atHashString) * commonSet.GetCount());
|
|
index += commonSet.GetCount();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestFrame::SetListDeleteable()
|
|
{
|
|
for (int i = 0; i < m_RemoveList.GetCount(); ++i) {
|
|
fwModelId modelId;
|
|
if (fwArchetypeManager::GetArchetypeFromHashKey(m_RemoveList[i], modelId)) {
|
|
CModelInfo::ClearAssetRequiredFlag(modelId, STRFLAG_CUTSCENE_REQUIRED);
|
|
RemoveMapDataRefCount(m_RemoveList[i], modelId);
|
|
|
|
#if __ASSERT
|
|
if (s_RequestedAssets.Access(m_RemoveList[i]))
|
|
{
|
|
s_RequestedAssets.Delete(m_RemoveList[i]);
|
|
}
|
|
#endif // __ASSERT
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestFrame::MakeRequestsDeleteable(CStreamingRequestRecord &record)
|
|
{
|
|
atHashString tempStorage[MAX_REQUESTS_PER_FRAME];
|
|
atUserArray<atHashString> tempRequestList(tempStorage, MAX_REQUESTS_PER_FRAME);
|
|
CreateFullRequestList(record, tempRequestList);
|
|
|
|
for (int i = 0; i < tempRequestList.GetCount(); ++i) {
|
|
fwModelId modelId;
|
|
if (fwArchetypeManager::GetArchetypeFromHashKey(tempRequestList[i], modelId)) {
|
|
CModelInfo::ClearAssetRequiredFlag(modelId, STRFLAG_CUTSCENE_REQUIRED);
|
|
RemoveMapDataRefCount(tempRequestList[i], modelId);
|
|
|
|
#if __ASSERT
|
|
if (s_RequestedAssets.Access(tempRequestList[i]))
|
|
{
|
|
s_RequestedAssets.Delete(tempRequestList[i]);
|
|
}
|
|
#endif // __ASSERT
|
|
}
|
|
else
|
|
{
|
|
Assertf(s_RequestedAssets.Access(tempRequestList[i]) == NULL, "Can't free up %s", tempRequestList[i].GetCStr());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CStreamingRequestFrame::AreAllLoadedOrUnrequested(const CStreamingRequestRecord &record) const
|
|
{
|
|
atHashString tempStorage[MAX_REQUESTS_PER_FRAME];
|
|
atUserArray<atHashString> tempRequestList(tempStorage, MAX_REQUESTS_PER_FRAME);
|
|
CreateFullRequestList(record, tempRequestList);
|
|
|
|
for (int i = 0; i < tempRequestList.GetCount(); ++i) {
|
|
fwModelId modelId;
|
|
|
|
if (CModelInfo::GetBaseModelInfoFromHashKey(tempRequestList[i], &modelId)){
|
|
if(!CModelInfo::HaveAssetsLoaded(modelId) &&
|
|
CModelInfo::AreAssetsRequested(modelId)){
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
CStreamingRequestRecord::CStreamingRequestRecord()
|
|
: m_NewStyle(false)
|
|
{
|
|
}
|
|
|
|
CStreamingRequestRecord::~CStreamingRequestRecord()
|
|
{
|
|
m_Frames.Reset();
|
|
}
|
|
|
|
void CStreamingRequestRecord::Clear()
|
|
{
|
|
m_Frames.Reset();
|
|
}
|
|
|
|
class SRLMounter : public CDataFileMountInterface
|
|
{
|
|
virtual bool LoadDataFile(const CDataFileMgr::DataFile & file)
|
|
{
|
|
switch(file.m_fileType)
|
|
{
|
|
case CDataFileMgr::STREAMING_REQUEST_LISTS_FILE:
|
|
CStreamingRequestList::RegisterFromFile(file.m_filename);
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
virtual void UnloadDataFile(const CDataFileMgr::DataFile &file)
|
|
{
|
|
switch(file.m_fileType)
|
|
{
|
|
case CDataFileMgr::STREAMING_REQUEST_LISTS_FILE:
|
|
CStreamingRequestList::UnregisterFromFile(file.m_filename);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
} g_SRLMounter;
|
|
|
|
//
|
|
// name: CStreamingRequestList::CStreamingRequestList
|
|
// description: Constructor
|
|
CStreamingRequestList::CStreamingRequestList()
|
|
{
|
|
m_AllAssetsLoaded = true;
|
|
m_stateFlags = 0;
|
|
m_IsRunFromScript = false;
|
|
m_IsLongJumpMode = false;
|
|
m_PrestreamMode = SRL_PRESTREAM_DEFAULT;
|
|
|
|
m_PostCutsceneCameraPos.ZeroComponents();
|
|
|
|
#if __BANK
|
|
m_ShowStatus = true;
|
|
m_SubstringSearch[0] = 0;
|
|
m_ShowRequestDetails = false;
|
|
m_ShowNonResidentOnly = true;
|
|
m_Modified = false;
|
|
m_DisableSRL = false;
|
|
m_KeepSceneStreamerOn = false;
|
|
m_SkipPrestream = false;
|
|
m_ShowCurrentFrameInfo = false;
|
|
m_ThoroughRecording = true;
|
|
m_AddSVFrameMarkers = false;
|
|
m_IsFramesOverride = false;
|
|
m_framesAhead = DEFAULT_STREAMING_AHEAD_TIME;
|
|
m_searchFramesAhead = DEFAULT_LOADSCENE_AHEAD_TIME;
|
|
m_SkipTimedEntities = false;
|
|
m_DisableHDTexRequests = false;
|
|
#endif // __BANK
|
|
|
|
#if USE_SRL_PROFILING_INFO
|
|
m_ProfileLists = false;
|
|
m_ShowProfileInfo = true;
|
|
m_ShowReportAtEnd = false;
|
|
#endif // USE_SRL_PROFILING_INFO
|
|
}
|
|
|
|
void CStreamingRequestList::RegisterFromFile(const char* fileName)
|
|
{
|
|
if (!CStreaming::ShouldLoadStaticData())
|
|
{
|
|
return;
|
|
}
|
|
CStreamingRequestMasterList masterList;
|
|
Displayf("Loading SRL file %s", fileName);
|
|
if (streamSRLVerifyf(PARSER.LoadObject(fileName, "meta", masterList), "Unable to load streaming request list file: %s",fileName))
|
|
{
|
|
// Get all those files and register them.
|
|
for (int x=0; x<masterList.m_Files.GetCount(); x++)
|
|
{
|
|
const char *name = masterList.m_Files[x].c_str();
|
|
|
|
streamSRLAssertf(strlen(name) > 4 && stricmp(&name[strlen(name)-4], "_srl") == 0,
|
|
"A streaming request list resource must end with '_srl' - check %s", name);
|
|
|
|
char rawFileName[RAGE_MAX_PATH];
|
|
char finalName[RAGE_MAX_PATH];
|
|
formatf(rawFileName, "%s.%s", name, META_FILE_EXT);
|
|
DATAFILEMGR.ExpandFilename(rawFileName,finalName,RAGE_MAX_PATH);
|
|
strPackfileManager::RegisterIndividualFile(finalName, true, ASSET.FileName(finalName), false,true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestList::UnregisterFromFile(const char* fileName)
|
|
{
|
|
if (!CStreaming::ShouldLoadStaticData())
|
|
{
|
|
return;
|
|
}
|
|
CStreamingRequestMasterList masterList;
|
|
if (streamVerifyf(PARSER.LoadObject(fileName, "meta", masterList), "Unable to load streaming request list file: %s",fileName))
|
|
{
|
|
// Get all those files and register them.
|
|
for (int x=0; x<masterList.m_Files.GetCount(); x++)
|
|
{
|
|
const char *name = masterList.m_Files[x].c_str();
|
|
|
|
streamSRLAssertf(strlen(name) > 4 && stricmp(&name[strlen(name)-4], "_srl") == 0,
|
|
"A streaming request list resource must end with '_srl' - check %s", name);
|
|
|
|
char rawFileName[RAGE_MAX_PATH] = {0};
|
|
char finalName[RAGE_MAX_PATH] = {0};
|
|
formatf(rawFileName, "%s.%s", name, META_FILE_EXT);
|
|
DATAFILEMGR.ExpandFilename(rawFileName,finalName,RAGE_MAX_PATH);
|
|
strPackfileManager::InvalidateIndividualFile(finalName);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestList::Init(unsigned initMode)
|
|
{
|
|
if (initMode == INIT_SESSION)
|
|
{
|
|
CDataFileMount::RegisterMountInterface(CDataFileMgr::STREAMING_REQUEST_LISTS_FILE, &g_SRLMounter,eDFMI_UnloadFirst);
|
|
if (CStreaming::ShouldLoadStaticData())
|
|
{
|
|
const CDataFileMgr::DataFile* pData = DATAFILEMGR.GetLastFile(CDataFileMgr::STREAMING_REQUEST_LISTS_FILE);
|
|
|
|
while(DATAFILEMGR.IsValid(pData))
|
|
{
|
|
if(!pData->m_disabled)
|
|
{
|
|
RegisterFromFile(pData->m_filename);
|
|
}
|
|
pData = DATAFILEMGR.GetNextFile(pData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestList::Shutdown(unsigned initMode)
|
|
{
|
|
if (initMode == INIT_CORE || (initMode == INIT_SESSION && CStreaming::GetReloadPackfilesOnRestart()))
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: CStreamingRequestList::EnableRecording
|
|
// description: Enable recording if we have started recording
|
|
void CStreamingRequestList::EnableRecording(bool BANK_ONLY(bRecord))
|
|
{
|
|
#if __BANK
|
|
if(bRecord)
|
|
m_stateFlags |= STRREQ_RECORDING_ENABLED;
|
|
else
|
|
m_stateFlags &= ~STRREQ_RECORDING_ENABLED;
|
|
#endif // __BANK
|
|
}
|
|
|
|
//
|
|
// name: CStreamingInfoManager::StartRecordingStreamingRequests
|
|
// description: Start recording streaming requests
|
|
#if SRL_ENABLED
|
|
void CStreamingRequestList::BeginPrestream(const char* cutsceneName, bool fromScript)
|
|
{
|
|
Assertf(!m_IsRunFromScript || !fromScript, "Calling PREFETCH_SRL on %s, but there's already a scripted SRL active. PREFETCH_SRL should only be called once per cutscene, and then released with END_SRL once the cutscene is over.", cutsceneName);
|
|
// There may be a left-over previous recording if we were currently showing the generated
|
|
// report of a profiled cutscene playback.
|
|
if(!(m_stateFlags & STRREQ_REPLAY_ENABLED))//if we are enabled for replay then we don't call this
|
|
DeleteRecording();
|
|
|
|
m_AllAssetsLoaded = false;
|
|
m_IsRunFromScript = fromScript;
|
|
|
|
m_stateFlags |= STRREQ_STARTED | STRREQ_PAUSED;
|
|
#if __BANK
|
|
if (m_DisableSRL)
|
|
{
|
|
m_stateFlags &= ~STRREQ_STARTED;
|
|
// Don't even load anything if SRLs are disabled.
|
|
return;
|
|
}
|
|
|
|
if(m_stateFlags & STRREQ_RECORD)
|
|
{
|
|
StartRecord(cutsceneName);
|
|
m_stateFlags |= STRREQ_RECORD_IN_PROGRESS;
|
|
CIplCullBox::SetEnabled(false);
|
|
|
|
CutSceneManager::GetInstance()->SetExternalTimeStep(1.0f / 30.0f);
|
|
CutSceneManager::GetInstance()->SetUseExternalTimeStep(true);
|
|
}
|
|
else
|
|
#endif // __BANK
|
|
{
|
|
StartPlayback(cutsceneName);
|
|
}
|
|
}
|
|
#else
|
|
void CStreamingRequestList::BeginPrestream(const char*){}
|
|
#endif //SRL_ENABLED
|
|
|
|
void CStreamingRequestList::Start()
|
|
{
|
|
m_stateFlags &= ~STRREQ_PAUSED;
|
|
}
|
|
|
|
void CStreamingRequestList::Pause()
|
|
{
|
|
m_stateFlags |= STRREQ_PAUSED;
|
|
}
|
|
|
|
|
|
#if SRL_ENABLED
|
|
|
|
//
|
|
// name: CStreamingInfoManager::FinishRecordingStreamingRequests
|
|
// description: Finish recording streaming requests
|
|
void CStreamingRequestList::Finish()
|
|
{
|
|
const bool bIsPlaybackActive = IsPlaybackActive();
|
|
|
|
m_PostCutsceneCameraPos.ZeroComponents();
|
|
|
|
if (m_CurrentRecord)
|
|
{
|
|
g_streamingAheadTime = DEFAULT_STREAMING_AHEAD_TIME;
|
|
g_streamingAheadTimePrestream = DEFAULT_STREAMING_AHEAD_TIME_PRESTREAM;
|
|
g_loadsceneAheadTime = DEFAULT_LOADSCENE_AHEAD_TIME;
|
|
g_loadsceneAheadTimePrestream = DEFAULT_LOADSCENE_AHEAD_TIME_PRESTREAM;
|
|
m_IsLongJumpMode = false;
|
|
m_PrestreamMode = SRL_PRESTREAM_DEFAULT;
|
|
}
|
|
|
|
g_HACK_GlobalSRLSkipGC = false;
|
|
m_stateFlags &= ~STRREQ_STARTED;
|
|
|
|
if(m_stateFlags & STRREQ_RECORD_IN_PROGRESS)
|
|
{
|
|
FinishRecord();
|
|
}
|
|
else
|
|
{
|
|
FinishPlayback(bIsPlaybackActive);
|
|
}
|
|
|
|
m_IsRunFromScript = false;
|
|
}
|
|
|
|
#else
|
|
void CStreamingRequestList::Finish(){}
|
|
#endif //SRL_ENABLED
|
|
|
|
//
|
|
// name: CStreamingRequestList::Update
|
|
// description: Update streaming request list if active
|
|
void CStreamingRequestList::Update()
|
|
{
|
|
#if __BANK
|
|
UpdateRecordAll();
|
|
#endif // __BANK
|
|
|
|
if(IsActive())
|
|
{
|
|
// If we're run from a script, we have to keep track of time ourselves.
|
|
if (m_IsRunFromScript)
|
|
{
|
|
|
|
if (m_stateFlags & STRREQ_PAUSED && !(m_stateFlags & STRREQ_REPLAY_ENABLED))
|
|
{
|
|
m_time = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
// In case the script doesn't update it for us (which it should), we'll update ourselves. We just assume that each tick is 1/30 of a second,
|
|
// which is good enough as a general guideline. The script needs to sychronize via SET_SRL_TIME, or else it will never work. This tick here will
|
|
// just keep us afloat if the script forgets to tick for a frame or two.
|
|
m_time += TIME.GetSeconds();
|
|
}
|
|
}
|
|
|
|
if(m_stateFlags & STRREQ_RECORD_IN_PROGRESS)
|
|
{
|
|
UpdateRecord(m_time);
|
|
}
|
|
else
|
|
{
|
|
UpdatePlayback(m_time);
|
|
}
|
|
}
|
|
|
|
#if __BANK
|
|
DebugDraw();
|
|
#endif // __BANK
|
|
|
|
#if USE_SRL_PROFILING_INFO
|
|
if (m_CurrentRecord && m_ShowReportAtEnd && m_ProfilingInfo)
|
|
{
|
|
m_CurrentRecord->DisplayReport(*m_ProfilingInfo);
|
|
}
|
|
#endif // USE_SRL_PROFILING_INFO
|
|
}
|
|
|
|
|
|
//
|
|
// name: CStreamingRequestList::StartPlayback
|
|
// description: Start playback of streaming request list
|
|
void CStreamingRequestList::StartPlayback(const char* cutsceneName)
|
|
{
|
|
if(cutsceneName)
|
|
{
|
|
if(!LoadRecording(cutsceneName))
|
|
{
|
|
m_stateFlags &= ~STRREQ_STARTED;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_stateFlags &= ~STRREQ_STREAMING; //we are not streaming the srl. it should already be resident in memory
|
|
}
|
|
g_lastWriteTime = 0.0f;
|
|
g_requestListIndex = 0;
|
|
g_removeListIndex = 0;
|
|
g_requestListIndexPrestream = 0;
|
|
g_retryNeeded = -1;
|
|
}
|
|
|
|
//
|
|
// name: CStreamingRequestList::FinishPlayback
|
|
// description: Finish playback of streaming request list
|
|
void CStreamingRequestList::FinishPlayback(bool bResetFocus)
|
|
{
|
|
streamSRLDisplayf("Finish playback of SRL");
|
|
|
|
#if STREAMING_VISUALIZE
|
|
STRVIS_ADD_MARKER(strStreamingVisualize::MARKER);
|
|
STRVIS_SET_MARKER_TEXT("End SRL playback");
|
|
#endif // STREAMING_VISUALIZE
|
|
|
|
//during replay playback don't touch the scene streamer
|
|
if((m_stateFlags & STRREQ_REPLAY_ENABLED) == 0)
|
|
g_SceneStreamerMgr.GetStreamer()->SetEnableIssueRequests(true);
|
|
|
|
if (bResetFocus)
|
|
{
|
|
CFocusEntityMgr::GetMgr().SetDefault();
|
|
}
|
|
|
|
#if __PS3 || __XENON
|
|
CZonedAssetManager::SetEnabled(true);
|
|
#else
|
|
if (g_disableForGTAO){
|
|
CZonedAssetManager::SetEnabled(true);
|
|
}
|
|
#endif //__PS3 || __XENON
|
|
|
|
if (g_disableForGTAO == true)
|
|
{
|
|
CTexLod::EnableStateSwapper(true);
|
|
g_disableForGTAO = false;
|
|
}
|
|
|
|
|
|
CIplCullBox::SetEnabled(true);
|
|
|
|
// Be sure to unpin all interiors.
|
|
atMap<CInteriorProxy *, int>::Iterator it = m_PinnedInteriors.CreateIterator();
|
|
|
|
for (it.Start(); !it.AtEnd(); it.Next())
|
|
{
|
|
it.GetKey()->SetRequestedState(CInteriorProxy::RM_CUTSCENE, CInteriorProxy::PS_NONE);
|
|
}
|
|
|
|
m_PinnedInteriors.Reset();
|
|
|
|
|
|
if (m_CurrentRecord)
|
|
{
|
|
int frameCount = m_CurrentRecord->GetFrameCount();
|
|
|
|
streamSRLDisplayf("Freeing up all SRL requests");
|
|
|
|
m_CurrentRecord->GetFrame(frameCount - 1).SetListDeleteable();
|
|
|
|
#if USE_SRL_PROFILING_INFO
|
|
// If we want a report at the end, don't delete this object yet! We'll need it for the report!
|
|
if (m_ShowReportAtEnd && m_ShowProfileInfo && m_ProfilingInfo)
|
|
{
|
|
m_CurrentRecord->GenerateProfileReport(*m_ProfilingInfo);
|
|
}
|
|
else
|
|
#endif // USE_SRL_PROFILING_INFO
|
|
{
|
|
DeleteRecording();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
streamSRLDisplayf("No active SRL");
|
|
|
|
// The recording might still be in the process of being streamed.
|
|
if (m_Index.IsValid())
|
|
{
|
|
streamSRLDisplayf("SRL presumed in flight - removing now");
|
|
strStreamingEngine::GetInfo().ClearRequiredFlag(m_Index, STRFLAG_CUTSCENE_REQUIRED);
|
|
strStreamingEngine::GetInfo().RemoveObject(m_Index);
|
|
m_Index = strIndex();
|
|
}
|
|
}
|
|
|
|
#if __ASSERT
|
|
if (s_RequestedAssets.GetNumUsed())
|
|
{
|
|
streamSRLErrorf("First leak: %s", s_RequestedAssets.CreateIterator().GetKey().GetCStr());
|
|
}
|
|
|
|
streamSRLAssertf(s_RequestedAssets.GetNumUsed() == 0, "SRL is leaking %d asset(s). This is a memory leak.", s_RequestedAssets.GetNumUsed());
|
|
#endif // __ASSERT
|
|
|
|
// Remove all remaining references to maps. There shouldn't be any, the final list deletion should have cleared them all
|
|
// out, but I'd rather be safe than have a memory leak.
|
|
if (s_AddRefedMaps.GetNumUsed() > 0)
|
|
{
|
|
atMap<atHashString, s32>::Iterator entry = s_AddRefedMaps.CreateIterator();
|
|
for (entry.Start(); !entry.AtEnd(); entry.Next())
|
|
{
|
|
streamSRLErrorf("Left-over reference to %s (map type %d)", entry.GetKey().TryGetCStr(), entry.GetData());
|
|
g_MapTypesStore.RemoveRef(strLocalIndex(entry.GetData()), REF_SCRIPT);
|
|
}
|
|
|
|
streamSRLAssertf(false, "There are %d map(s) with SRL-based ref counts. There shouldn't be any, but that's okay, we can clean them up.",s_AddRefedMaps.GetNumUsed());
|
|
|
|
s_AddRefedMaps.Reset();
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestList::SetSrlReadAheadTimes(int prestreamMap, int /*prestreamAssets*/, int playbackMap, int playbackAssets)
|
|
{
|
|
g_streamingAheadTime = (playbackAssets == -1) ? DEFAULT_STREAMING_AHEAD_TIME : playbackAssets;
|
|
g_loadsceneAheadTime = (playbackMap == -1) ? DEFAULT_LOADSCENE_AHEAD_TIME : playbackMap;
|
|
g_loadsceneAheadTimePrestream = (prestreamMap == -1) ? DEFAULT_LOADSCENE_AHEAD_TIME_PRESTREAM : prestreamMap;
|
|
if(g_loadsceneAheadTimePrestream < DEFAULT_LOADSCENE_AHEAD_TIME_PRESTREAM)
|
|
{
|
|
g_streamingAheadTimePrestream = g_loadsceneAheadTimePrestream;
|
|
}
|
|
else{
|
|
g_streamingAheadTimePrestream = DEFAULT_STREAMING_AHEAD_TIME_PRESTREAM;
|
|
}
|
|
|
|
}
|
|
|
|
void CStreamingRequestList::SetPostCutsceneCamera(Vec3V_In camPos, Vec3V_In camDir)
|
|
{
|
|
m_PostCutsceneCameraPos = camPos;
|
|
m_PostCutsceneCameraDir = camDir;
|
|
|
|
STRVIS_SET_MARKER_TEXT("** POST CUTSCENE INFO SET ** %.2f %.2f .%2f", camPos.GetXf(), camPos.GetYf(), camPos.GetZf());
|
|
}
|
|
|
|
void CStreamingRequestList::DeleteRecording()
|
|
{
|
|
if (m_CurrentRecord && (m_stateFlags & STRREQ_STARTED))
|
|
{
|
|
// Be sure to clean it up. Note that this will call DeleteRecording() again,
|
|
// but that time with the stateFlags not set to STRREQ_STARTED, so that's cool.
|
|
Finish();
|
|
}
|
|
|
|
// Did we stream it in?
|
|
if (m_Index.IsValid())
|
|
{
|
|
streamSRLDisplayf("Removing SRL resource");
|
|
|
|
if (m_CurrentRecord)
|
|
{
|
|
streamSRLDisplayf("SRL unref");
|
|
g_fwMetaDataStore.RemoveRef(g_fwMetaDataStore.GetObjectIndex(m_Index), REF_SCRIPT);
|
|
g_fwMetaDataStore.RemoveRef(g_fwMetaDataStore.GetObjectIndex(m_Index), REF_SCRIPT);
|
|
}
|
|
strStreamingEngine::GetInfo().ClearRequiredFlag(m_Index, STRFLAG_CUTSCENE_REQUIRED);
|
|
strStreamingEngine::GetInfo().RemoveObject(m_Index);
|
|
m_Index = strIndex();
|
|
}
|
|
else
|
|
{
|
|
//if we are recording for replay then we should infact be being old style SRLS
|
|
//so ignore the assert below
|
|
if(!(m_stateFlags & STRREQ_REPLAY_ENABLED))
|
|
{
|
|
streamSRLAssertf(!m_CurrentRecord || (m_stateFlags & STRREQ_RECORD), "We shouldn't have old-school SRLs anymore");
|
|
}
|
|
// Or did we create it ourselves?
|
|
delete m_CurrentRecord;
|
|
}
|
|
|
|
m_CurrentRecord = NULL;
|
|
|
|
#if USE_SRL_PROFILING_INFO
|
|
USE_DEBUG_MEMORY();
|
|
delete m_ProfilingInfo;
|
|
m_ProfilingInfo = NULL;
|
|
#endif // USE_SRL_PROFILING_INFO
|
|
}
|
|
|
|
//
|
|
// name: CStreamingRequestList::UpdatePlayback
|
|
// description: Update playback of streaming request list
|
|
void CStreamingRequestList::UpdatePlayback(float time)
|
|
{
|
|
// Have we finished streaming yet?
|
|
if (m_stateFlags & STRREQ_STREAMING)
|
|
{
|
|
strStreamingInfo &info = strStreamingEngine::GetInfo().GetStreamingInfoRef(m_Index);
|
|
|
|
streamSRLAssertf(info.GetStatus() != STRINFO_NOTLOADED,
|
|
"SRL %s is trying to play, but not streaming", strStreamingEngine::GetObjectName(m_Index));
|
|
|
|
if (info.GetStatus() != STRINFO_LOADED)
|
|
{
|
|
#if __BANK
|
|
if (gStreamingRequestList.IsShowStatus())
|
|
{
|
|
grcDebugDraw::AddDebugOutput("Waiting for Streaming Request List to stream...");
|
|
}
|
|
#endif // __BANK
|
|
|
|
// Still waiting...
|
|
return;
|
|
}
|
|
|
|
#if STREAMING_VISUALIZE
|
|
STRVIS_ADD_MARKER(strStreamingVisualize::MARKER);
|
|
STRVIS_SET_MARKER_TEXT("Begin SRL playback");
|
|
#endif // STREAMING_VISUALIZE
|
|
|
|
// We finished streaming - let's grab the data.
|
|
strLocalIndex objIndex = g_fwMetaDataStore.GetObjectIndex(m_Index);
|
|
m_CurrentRecord = g_fwMetaDataStore.Get(objIndex)->GetObject<CStreamingRequestRecord>();
|
|
streamSRLAssert(m_CurrentRecord);
|
|
|
|
g_fwMetaDataStore.AddRef(objIndex, REF_SCRIPT);
|
|
g_fwMetaDataStore.AddRef(objIndex, REF_SCRIPT);
|
|
|
|
streamSRLDisplayf("Got SRL asset, ref'd");
|
|
|
|
m_stateFlags &= ~STRREQ_STREAMING;
|
|
|
|
Assertf(m_CurrentRecord->IsNewStyle(), "Old-style SRLs are no longer supported");
|
|
|
|
int frameCount = m_CurrentRecord->GetFrameCount();
|
|
|
|
if (frameCount == 0)
|
|
{
|
|
streamSRLWarningf("SRL is empty");
|
|
// Actually empty - let's ignore it then.
|
|
m_stateFlags &= ~STRREQ_STARTED;
|
|
DeleteRecording();
|
|
return;
|
|
}
|
|
|
|
#if !__FINAL
|
|
for (int x=0; x<frameCount; x++)
|
|
{
|
|
if (m_CurrentRecord->GetFrame(x).GetRequestList().GetCount() > 10000)
|
|
{
|
|
streamSRLAssertf(false, "Streaming request list %s seems to contain garbage data. I'll disable it so it won't crash. The PSO reading probably went wrong.",
|
|
g_fwMetaDataStore.GetName(objIndex));
|
|
|
|
m_stateFlags &= ~STRREQ_STARTED;
|
|
DeleteRecording();
|
|
return;
|
|
}
|
|
}
|
|
#endif // !__FINAL
|
|
|
|
#if USE_SRL_PROFILING_INFO
|
|
Assert(!m_ProfilingInfo);
|
|
{
|
|
USE_DEBUG_MEMORY();
|
|
m_ProfilingInfo = rage_new CStreamingRequestListProfilingInfo();
|
|
m_ProfilingInfo->m_PerFrameProfileInfo.Resize(m_CurrentRecord->GetFrameCount());
|
|
}
|
|
#endif // USE_SRL_PROFILING_INFO
|
|
|
|
STRVIS_ADD_MARKER(strStreamingVisualize::MARKER);
|
|
STRVIS_SET_MARKER_TEXT("SRL prestreamed");
|
|
}
|
|
|
|
STRVIS_SET_CONTEXT(strStreamingVisualize::SRL);
|
|
|
|
streamSRLAssert(m_CurrentRecord);
|
|
// If this is a new-style SRL, use the new-style playback.
|
|
//if (m_CurrentRecord->IsNewStyle())
|
|
{
|
|
UpdateNewStylePlayback(time);
|
|
}
|
|
|
|
STRVIS_SET_CONTEXT(strStreamingVisualize::NONE);
|
|
}
|
|
|
|
bool CStreamingRequestList::IsCamPosValid(Vec3V_In camPos) const
|
|
{
|
|
if (MagSquared(camPos).Getf() < 1.0f)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return g_WorldLimits_AABB.ContainsPoint(camPos);
|
|
}
|
|
|
|
|
|
atFixedArray<fwBoxStreamerSearch, 10> s_BoxSearches;
|
|
|
|
void CStreamingRequestList::ComputeSearchesAndFocus()
|
|
{
|
|
s_BoxSearches.Resize(0);
|
|
|
|
if (m_CurrentRecord)
|
|
{
|
|
atFixedArray<fwBoxStreamerSearch, 10>& searchList = s_BoxSearches;
|
|
|
|
#if __BANK
|
|
const float thresholdSquared = (m_stateFlags & STRREQ_PAUSED) ? LONG_CAMERA_CUT_THRESHOLD_PRESTREAM * LONG_CAMERA_CUT_THRESHOLD_PRESTREAM : g_BoxStreamerThreshold * g_BoxStreamerThreshold;
|
|
#else
|
|
const float thresholdSquared = (m_stateFlags & STRREQ_PAUSED) ? LONG_CAMERA_CUT_THRESHOLD_PRESTREAM * LONG_CAMERA_CUT_THRESHOLD_PRESTREAM : LONG_CAMERA_CUT_THRESHOLD * LONG_CAMERA_CUT_THRESHOLD;
|
|
#endif
|
|
int frameCounter = TIME.GetFrameCount();
|
|
|
|
// The first frame is used for pre-streaming, so let's use that. Otherwise, during playback we'll want the subsequent ones.
|
|
int firstFrame = (g_removeListIndex == 0) ? 0 : g_removeListIndex + 1;
|
|
|
|
int readAhead = firstFrame ? g_loadsceneAheadTimePrestream : g_loadsceneAheadTime;
|
|
#if __BANK
|
|
if(m_IsFramesOverride)
|
|
{
|
|
readAhead = m_searchFramesAhead;
|
|
}
|
|
#endif
|
|
|
|
int maxLoadScene = Min(firstFrame + readAhead, m_CurrentRecord->GetFrameCount());
|
|
Vec3V focusPos = VECTOR3_TO_VEC3V(CFocusEntityMgr::GetMgr().GetPos());
|
|
int minFrameForBoxSearch = 0;
|
|
int maxFrameForBoxSearch = 0x7fffffff;
|
|
bool focusOverride = false;
|
|
|
|
fwInteriorLocation loc = CPortalVisTracker::GetInteriorLocation();
|
|
bool isInside = (loc.IsValid());
|
|
|
|
m_bValidInteriorHint = false;
|
|
|
|
// Are we currently inside an interior?
|
|
if (IsPlaybackActive())
|
|
{
|
|
Vec3V curCamPos = VECTOR3_TO_VEC3V(camInterface::GetPos());
|
|
|
|
|
|
if (isInside)
|
|
{
|
|
#if STREAMING_VISUALIZE
|
|
// CInteriorProxy* pIntProxy = reinterpret_cast<CInteriorProxy*>(pNode->GetPtr());
|
|
// STRVIS_SET_MARKER_TEXT("Start Frame %d at %.2f: Inside interior (%s) at %.2f %.2f", g_removeListIndex, m_time / 1000.f, pIntProxy->GetName().GetCStr(), curCamPos.GetXf(), curCamPos.GetYf());
|
|
// STRVIS_SET_MARKER_TEXT("Start Frame %d at %.2f: Inside interior (%d) at %.2f %.2f %.2f", g_removeListIndex, m_time / 1000.f, loc.GetRoomIndex(), curCamPos.GetXf(), curCamPos.GetYf(), curCamPos.GetZf());
|
|
#endif // STREAMING_VISUALIZE
|
|
|
|
// We're currently inside an interior.
|
|
// Being inside is a special case, IF we're also about to make a long camera cut.
|
|
// Let's look at the upcoming cuts and see if there's a long cut.
|
|
for (int x=firstFrame; x<maxLoadScene; x++)
|
|
{
|
|
Vec3V nextPos = m_CurrentRecord->GetFrame(x).GetCamPos();
|
|
|
|
if (IsCamPosValid(nextPos) && DistSquared(curCamPos, nextPos).Getf() >= thresholdSquared)
|
|
{
|
|
bool nextIsInside = m_CurrentRecord->GetFrame(x).IsInside();
|
|
|
|
if (!m_CurrentRecord->GetFrame(x).HasExtraInfo())
|
|
{
|
|
// Now, special case - what if we're cutting into another interior?
|
|
// In that case, pretend it didn't happen. Interior-to-interior can happen when the camera sneaks into an interior.
|
|
fwIsSphereIntersecting nextIntersection(spdSphere(nextPos, ScalarV(V_FLT_SMALL_1)));
|
|
fwPtrListSingleLink nextScanList;
|
|
CInteriorProxy::FindActiveIntersecting(nextIntersection, nextScanList);
|
|
|
|
fwPtrNode* nextNode = nextScanList.GetHeadPtr();
|
|
nextIsInside = nextNode != NULL && nextNode->GetPtr() != NULL;
|
|
}
|
|
|
|
if (!nextIsInside)
|
|
{
|
|
// Yes, there's a long camera cut coming up.
|
|
// First off, we need to make sure the current focus is set to the next shot and we pin the current interior.
|
|
// Don't add any more searches until the focus has been set.
|
|
Vec3V currentFocus = VECTOR3_TO_VEC3V(CFocusEntityMgr::GetMgr().GetPos());
|
|
focusOverride = true;
|
|
|
|
const bool bLeadOut = !( g_requestListIndex < m_CurrentRecord->GetFrameCount()-1 ) ;
|
|
if ( !bLeadOut && (DistSquared(currentFocus, nextPos).Getf() > 0.0001f))
|
|
{
|
|
// Let's set the focus position first before adding more searches.
|
|
CFocusEntityMgr::GetMgr().SetPosAndVel(RCC_VECTOR3(nextPos), ORIGIN);
|
|
maxFrameForBoxSearch = x - 1;
|
|
break;
|
|
}
|
|
|
|
// We can add more box searches, but only after the camera cut.
|
|
minFrameForBoxSearch = x;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int loadSceneFrame = firstFrame; loadSceneFrame < maxLoadScene-1; loadSceneFrame++)
|
|
{
|
|
CStreamingRequestFrame &frame = m_CurrentRecord->GetFrame(loadSceneFrame);
|
|
Vec3V futureCamPos = frame.GetCamPos();
|
|
if (IsCamPosValid(futureCamPos))
|
|
{
|
|
bool nextIsInside = m_CurrentRecord->GetFrame(loadSceneFrame).IsInside();
|
|
|
|
// Find all the interiors there.
|
|
fwIsSphereIntersecting intersection(spdSphere(futureCamPos, ScalarV(V_FLT_SMALL_1)));
|
|
fwPtrListSingleLink scanList;
|
|
CInteriorProxy::FindActiveIntersecting(intersection, scanList);
|
|
|
|
fwPtrNode* pNode = scanList.GetHeadPtr();
|
|
|
|
if (!m_CurrentRecord->GetFrame(loadSceneFrame).HasExtraInfo())
|
|
{
|
|
nextIsInside = pNode != NULL;
|
|
}
|
|
|
|
// Are we about to go into an interior?
|
|
if (IsPlaybackActive() && maxFrameForBoxSearch == 0x7fffffff && minFrameForBoxSearch == 0 && loadSceneFrame > 0)
|
|
{
|
|
// Is this position in an interior?
|
|
if (nextIsInside)
|
|
{
|
|
//CInteriorProxy* pIntProxy = reinterpret_cast<CInteriorProxy*>(pNode->GetPtr());
|
|
//STRVIS_SET_MARKER_TEXT("Frame %d: Inside interior (%s) at %.2f %.2f %.2f", loadSceneFrame, pIntProxy->GetName().GetCStr(), futureCamPos.GetXf(), futureCamPos.GetYf(), futureCamPos.GetZf());
|
|
|
|
// Is this going to be a camera cut? If so, just pin the interior, don't do a full box search there.
|
|
Vec3V prevPos = m_CurrentRecord->GetFrame(loadSceneFrame-1).GetCamPos();
|
|
|
|
if (DistSquared(futureCamPos, prevPos).Getf() >= thresholdSquared)
|
|
{
|
|
// We did. That means we need to stop adding box searches, or else the pools might blow over.
|
|
// We'll continue to pin the interior, so that's fine.
|
|
maxFrameForBoxSearch = loadSceneFrame - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// try to pin all these interiors
|
|
bool bPinnedInteriors = false;
|
|
while(pNode != NULL)
|
|
{
|
|
// for each found proxy, pull in the .imap file and collisions
|
|
CInteriorProxy* pIntProxy = reinterpret_cast<CInteriorProxy*>(pNode->GetPtr());
|
|
if (pIntProxy )
|
|
{
|
|
pIntProxy->SetRequestedState(CInteriorProxy::RM_CUTSCENE, CInteriorProxy::PS_FULL);
|
|
m_PinnedInteriors[pIntProxy] = frameCounter;
|
|
bPinnedInteriors = true;
|
|
}
|
|
|
|
pNode = pNode->GetNextPtr();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// generate hint for interior we're about to cut to - for drawable creation
|
|
if (!m_bValidInteriorHint && bPinnedInteriors)
|
|
{
|
|
CInteriorProxy* targetInteriorProxy = NULL;
|
|
s32 probedRoomIdx = -1;
|
|
|
|
bool bProbeRet = CPortalTracker::ProbeForInteriorProxy(VEC3V_TO_VECTOR3(futureCamPos), targetInteriorProxy, probedRoomIdx, NULL, CPortalTracker::FAR_PROBE_DIST);
|
|
|
|
if (bProbeRet && targetInteriorProxy)
|
|
{
|
|
m_posInteriorHint = futureCamPos;
|
|
m_bValidInteriorHint = true;
|
|
m_locInteriorHint = CInteriorProxy::CreateLocation(targetInteriorProxy, probedRoomIdx);
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// How far are we from the focus position?
|
|
|
|
// Request the mapdata, UNLESS for long camera cuts. We can't fit two scenes in memory at the same time.
|
|
if (IsPlaybackActive() || (GetPrestreamMode() != SRL_PRESTREAM_FORCE_OFF && GetPrestreamMode() != SRL_PRESTREAM_FORCE_COMPLETELY_OFF && (GetPrestreamMode() == SRL_PRESTREAM_FORCE_ON || DistSquared(focusPos, futureCamPos).Getf() < thresholdSquared)))
|
|
{
|
|
//STRVIS_SET_MARKER_TEXT("Add frame %d (%d-%d): %.2f %.2f", loadSceneFrame, minFrameForBoxSearch, maxFrameForBoxSearch, frame.GetCamPos().GetXf(), frame.GetCamPos().GetYf());
|
|
if (loadSceneFrame >= minFrameForBoxSearch && loadSceneFrame <= maxFrameForBoxSearch)
|
|
{
|
|
fwBoxStreamerSearch search(
|
|
frame.GetCamPos(),
|
|
fwBoxStreamerSearch::TYPE_SRL,
|
|
fwBoxStreamerAsset::MASK_MAPDATA,
|
|
true
|
|
);
|
|
|
|
if (m_IsLongJumpMode)
|
|
{
|
|
search.SetCamPosAndDir(frame.GetCamPos(), frame.GetCamDir());
|
|
search.SetIgnoreCulling(true);
|
|
}
|
|
|
|
searchList.Append() = search;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now unpin every interior that wasn't needed this frame.
|
|
atMap<CInteriorProxy *, int>::Iterator it = m_PinnedInteriors.CreateIterator();
|
|
atFixedArray<CInteriorProxy *, 1024> staleInteriors;
|
|
|
|
for (it.Start(); !it.AtEnd(); it.Next())
|
|
{
|
|
if (it.GetData() != frameCounter)
|
|
{
|
|
// Stale interior.
|
|
it.GetKey()->SetRequestedState(CInteriorProxy::RM_CUTSCENE, CInteriorProxy::PS_NONE);
|
|
staleInteriors.Append() = it.GetKey();
|
|
}
|
|
}
|
|
|
|
// Finally, remove the entries from the map.
|
|
int count = staleInteriors.GetCount();
|
|
|
|
for (int x=0; x<count; x++)
|
|
{
|
|
m_PinnedInteriors.Delete(staleInteriors[x]);
|
|
}
|
|
|
|
if (!focusOverride && IsPlaybackActive())
|
|
{
|
|
if(g_requestListIndex < m_CurrentRecord->GetFrameCount() - 1)
|
|
{
|
|
CFocusEntityMgr::GetMgr().SetPosAndVel(camInterface::GetPos(), camInterface::GetVelocity());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStreamingRequestList::AddSearches(atArray<fwBoxStreamerSearch>& searchList, fwBoxStreamerAssetFlags supportedAssetFlags)
|
|
{
|
|
if (supportedAssetFlags & fwBoxStreamerAsset::MASK_MAPDATA)
|
|
{
|
|
if(!(m_stateFlags & STRREQ_RECORD))
|
|
{
|
|
for (int x=0; x<s_BoxSearches.GetCount(); x++)
|
|
{
|
|
searchList.Grow() = s_BoxSearches[x];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CStreamingRequestList::IsAboutToFinish() const
|
|
{
|
|
return g_requestListIndex >= m_CurrentRecord->GetFrameCount() - 1;
|
|
}
|
|
|
|
|
|
void CStreamingRequestList::UpdateNewStylePlayback(float time)
|
|
{
|
|
if(!m_CurrentRecord){
|
|
return;
|
|
}
|
|
int frameCount = m_CurrentRecord->GetFrameCount();
|
|
g_bHDTexLoadedThisFrame = true;
|
|
BANK_ONLY(g_DisableHDTxdRequests = m_DisableHDTexRequests);
|
|
|
|
// During prestreaming, we only request stuff in the current frame, we don't unrequest anything
|
|
// or advance time.
|
|
if (m_stateFlags & STRREQ_PAUSED)
|
|
{
|
|
// Handle branching cutscenes!
|
|
g_lastWriteTime = time;
|
|
g_removeListIndex = g_requestListIndex = (s32)(time / (float) STREAMING_REQUEST_UPDATE);
|
|
g_retryNeeded = -1;
|
|
|
|
if (g_requestListIndex < frameCount)
|
|
{
|
|
if (GetPrestreamMode() != SRL_PRESTREAM_FORCE_COMPLETELY_OFF)
|
|
{
|
|
//preload the first few frames of data if required
|
|
g_requestListIndexPrestream = Max(g_requestListIndex, g_requestListIndexPrestream);
|
|
if (g_requestListIndexPrestream >= frameCount){
|
|
g_requestListIndexPrestream = frameCount-1;
|
|
}
|
|
CStreamingRequestFrame::AssetLoadState loadState = m_CurrentRecord->GetFrame(g_requestListIndexPrestream).ProcessRequestList(*m_CurrentRecord);
|
|
m_AllAssetsLoaded = (loadState != CStreamingRequestFrame::NONRESIDENT_ASSETS) && g_bHDTexLoadedThisFrame;
|
|
//the box streamer won't advance if GetPrestreamMode() == SRL_PRESTREAM_FORCE_OFF or SRL_PRESTREAM_FORCE_COMPLETELY_OFF
|
|
//so don't advance under those conditions
|
|
if(m_AllAssetsLoaded && g_requestListIndexPrestream-g_requestListIndex < g_streamingAheadTimePrestream)// && GetPrestreamMode() != SRL_PRESTREAM_FORCE_OFF)
|
|
{
|
|
g_requestListIndexPrestream++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_AllAssetsLoaded = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
streamErrorf("Cutscene begins at %.2f seconds - that's outside the recorded SRL (length=%d)", m_time, frameCount);
|
|
m_AllAssetsLoaded = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if __BANK
|
|
bool changed = false;
|
|
|
|
// Support rewinding.
|
|
while (g_removeListIndex > 0 && time < g_lastWriteTime)
|
|
{
|
|
g_removeListIndex--;
|
|
g_requestListIndex = g_removeListIndex;
|
|
g_retryNeeded = -1;
|
|
g_lastWriteTime -= (float)STREAMING_REQUEST_UPDATE;
|
|
changed = true;
|
|
}
|
|
|
|
bool keepSceneStreamerOn = m_KeepSceneStreamerOn;
|
|
#else // __BANK
|
|
bool keepSceneStreamerOn = false;
|
|
#endif // __BANK
|
|
|
|
|
|
if(g_disableForGTAO)
|
|
{
|
|
CTexLod::EnableStateSwapper(false);
|
|
}
|
|
|
|
while(g_removeListIndex < frameCount - 1 && time - g_lastWriteTime > (float)STREAMING_REQUEST_UPDATE)
|
|
{
|
|
m_CurrentRecord->GetFrame(g_removeListIndex).SetListDeleteable();
|
|
|
|
g_removeListIndex++;
|
|
g_lastWriteTime += (float)STREAMING_REQUEST_UPDATE;
|
|
BANK_ONLY(changed = true;)
|
|
}
|
|
|
|
// We can't let the requests fall behind.
|
|
if (g_requestListIndex < g_removeListIndex)
|
|
{
|
|
STRVIS_SET_MARKER_TEXT("SRL is lagging");
|
|
}
|
|
|
|
g_requestListIndex = Max(g_requestListIndex, g_removeListIndex);
|
|
|
|
// Do we need to move onto the next request list
|
|
{
|
|
if(g_requestListIndex < frameCount - 1)
|
|
{
|
|
//during replay playback don't touch the scene streamer
|
|
if((m_stateFlags & STRREQ_REPLAY_ENABLED) == 0)
|
|
g_SceneStreamerMgr.GetStreamer()->SetEnableIssueRequests(keepSceneStreamerOn);
|
|
|
|
if (m_IsLongJumpMode)
|
|
{
|
|
CIplCullBox::SetEnabled(false);
|
|
}
|
|
|
|
// Are all the requests in memory?
|
|
CStreamingRequestFrame &frame = m_CurrentRecord->GetFrame(g_requestListIndex);
|
|
CStreamingRequestFrame::AssetLoadState loadState = frame.ProcessRequestList(*m_CurrentRecord);
|
|
m_AllAssetsLoaded = loadState != CStreamingRequestFrame::NONRESIDENT_ASSETS;
|
|
|
|
// Where should we be at this point? Consider branches.
|
|
float maxOffset = (float) g_streamingAheadTime;
|
|
#if __BANK
|
|
if(m_IsFramesOverride)
|
|
{
|
|
maxOffset = (float) m_framesAhead;
|
|
}
|
|
#endif
|
|
|
|
if (!m_IsRunFromScript)
|
|
{
|
|
maxOffset = CutSceneManager::GetInstance()->CalculateStreamingOffset(maxOffset, (float) g_removeListIndex);
|
|
}
|
|
|
|
// Try this frame again later if some things couldn't be loaded (possibly do to non-resident .ctyp files)
|
|
if (loadState == CStreamingRequestFrame::ALL_REQUESTED_BUT_MISSING && g_retryNeeded != -1)
|
|
{
|
|
g_retryNeeded = g_requestListIndex;
|
|
}
|
|
|
|
//Displayf("At %.2f (%.2f), offset=%.2f", (float) g_removeListIndex, time, maxOffset);
|
|
|
|
if (m_AllAssetsLoaded && g_requestListIndex < g_removeListIndex + (int) maxOffset)
|
|
{
|
|
g_requestListIndex++;
|
|
BANK_ONLY(changed = true;)
|
|
|
|
// Remind the zoned asset manager not to create any requests.
|
|
if (g_requestListIndex < frameCount - 1)
|
|
{
|
|
|
|
#if __PS3 || __XENON
|
|
CZonedAssetManager::ClearRequests();
|
|
CZonedAssetManager::SetEnabled(false);
|
|
#else
|
|
if(g_disableForGTAO)
|
|
{
|
|
CZonedAssetManager::ClearRequests();
|
|
CZonedAssetManager::SetEnabled(false);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// If we're stuck, try the older assets again that didn't load the first time.
|
|
if (g_retryNeeded != -1)
|
|
{
|
|
g_requestListIndex = g_retryNeeded;
|
|
g_retryNeeded = -1;
|
|
}
|
|
}
|
|
|
|
if (g_requestListIndex == g_removeListIndex)
|
|
{
|
|
STRVIS_SET_MARKER_TEXT("SRL is not ahead");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CIplCullBox::SetEnabled(true);
|
|
bool hasPostCutsceneInfo = MagSquared(m_PostCutsceneCameraPos).Getf() > 0.0f;
|
|
|
|
#if STREAMING_VISUALIZE
|
|
if (!g_SceneStreamerMgr.GetStreamer()->GetEnableIssueRequests())
|
|
{
|
|
STRVIS_ADD_MARKER(strStreamingVisualize::MARKER);
|
|
|
|
if (hasPostCutsceneInfo)
|
|
{
|
|
STRVIS_SET_MARKER_TEXT("Re-enabling scene streamer, CS almost over - has post-cutscene camera");
|
|
}
|
|
else
|
|
{
|
|
STRVIS_SET_MARKER_TEXT("Re-enabling scene streamer, CS almost over - no post-cutscene info");
|
|
}
|
|
}
|
|
#endif // STREAMING_VISUALIZE
|
|
|
|
// If we're done with our requests, we can turn the scene streamer back on to make the transition into
|
|
// gameplay easier.
|
|
if((m_stateFlags & STRREQ_REPLAY_ENABLED) == 0) //during replay playback don't touch the scene streamer
|
|
g_SceneStreamerMgr.GetStreamer()->SetEnableIssueRequests(true);
|
|
|
|
#if __PS3 || __XENON
|
|
CZonedAssetManager::SetEnabled(true);
|
|
#else
|
|
if(g_disableForGTAO)
|
|
{
|
|
CZonedAssetManager::SetEnabled(true);
|
|
}
|
|
#endif
|
|
|
|
// Override the focus position if we know where to.
|
|
if (hasPostCutsceneInfo)
|
|
{
|
|
// If this is really far away, then something must be wrong - maybe this is a stale position, or
|
|
// the designer made a mistake.
|
|
#if __ASSERT
|
|
if (g_removeListIndex < m_CurrentRecord->GetFrameCount())
|
|
{
|
|
CStreamingRequestFrame &frame = m_CurrentRecord->GetFrame(g_removeListIndex);
|
|
Vec3V futureCamPos = frame.GetCamPos();
|
|
|
|
if (IsCamPosValid(futureCamPos) && DistSquared(m_PostCutsceneCameraPos, futureCamPos).Getf() > 100.0f * 100.0f)
|
|
{
|
|
streamSRLWarningf("The SRL post cutscene position and current camera position are quite far away (%.2f, %.2f, %.2f) "
|
|
"and (%.2f, %.2f, %.2f).",
|
|
m_PostCutsceneCameraPos.GetXf(), m_PostCutsceneCameraPos.GetYf(), m_PostCutsceneCameraPos.GetZf(),
|
|
futureCamPos.GetXf(), futureCamPos.GetYf(), futureCamPos.GetZf());
|
|
}
|
|
|
|
Assertf(!IsCamPosValid(futureCamPos) || DistSquared(m_PostCutsceneCameraPos, futureCamPos).Getf() < 350.0f * 350.0f,
|
|
"The SRL post cutscene position and current camera position are very far away (%.2f, %.2f, %.2f) "
|
|
"and (%.2f, %.2f, %.2f). Is the post cutscene position correct?!",
|
|
m_PostCutsceneCameraPos.GetXf(), m_PostCutsceneCameraPos.GetYf(), m_PostCutsceneCameraPos.GetZf(),
|
|
futureCamPos.GetXf(), futureCamPos.GetYf(), futureCamPos.GetZf());
|
|
}
|
|
#endif // __ASSERT
|
|
|
|
CFocusEntityMgr::GetMgr().SetPosAndVel(RCC_VECTOR3(m_PostCutsceneCameraPos), ORIGIN);
|
|
}
|
|
else
|
|
{
|
|
CFocusEntityMgr::GetMgr().SetDefault();
|
|
}
|
|
}
|
|
}
|
|
|
|
// STRVIS_SET_MARKER_TEXT("SRL: time: %.2f, rem=%d, req=%d, retry=%d", m_time, g_removeListIndex, g_requestListIndex, g_retryNeeded);
|
|
|
|
#if __BANK
|
|
if (changed && ( m_AddSVFrameMarkers || PARAM_addsvframemarkers.Get()))
|
|
{
|
|
char markerText[128];
|
|
formatf(markerText, "SRL: Unreq=%d, Req=%d", g_removeListIndex, g_requestListIndex);
|
|
STRVIS_ADD_MARKER(strStreamingVisualize::MARKER);
|
|
STRVIS_SET_MARKER_TEXT(markerText);
|
|
}
|
|
#endif // __BANK
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: ReadArray/WriteArray
|
|
// description: Helper functions for writing arrays in the load and save routines
|
|
template<class _T> void ReadArray(FileHandle fid, atArray<_T>& array)
|
|
{
|
|
s32 value;
|
|
CFileMgr::Read(fid, (char*)&value, 4);
|
|
array.Reset();
|
|
array.Resize(value);
|
|
CFileMgr::Read(fid, (char*)array.GetElements(), sizeof(_T)*array.GetCount());
|
|
}
|
|
|
|
template<class _T> void WriteArray(FileHandle fid, atArray<_T>& array)
|
|
{
|
|
s32 value = array.GetCount();
|
|
CFileMgr::Write(fid, (char*)&value, 4);
|
|
CFileMgr::Write(fid, (char*)array.GetElements(), sizeof(_T)*array.GetCount());
|
|
}
|
|
|
|
//
|
|
// name: ReadModelInfoArray/WriteModelInfoArray
|
|
// description: Helper functions for writing arrays in the load and save routines
|
|
template<class _T> void ReadModelInfoArray(FileHandle fid, atArray<_T>& array)
|
|
{
|
|
s32 value;
|
|
CFileMgr::Read(fid, (char*)&value, 4);
|
|
array.Reset();
|
|
array.Resize(value);
|
|
for(s32 i=0; i<array.GetCount(); i++)
|
|
{
|
|
u32 hashKey;
|
|
CFileMgr::Read(fid, (char*)&hashKey, 4);
|
|
|
|
fwModelId modelId;
|
|
CModelInfo::GetBaseModelInfoFromHashKey(hashKey, &modelId);
|
|
array[i] = modelId.GetModelIndex();
|
|
}
|
|
}
|
|
|
|
template<class _T> void WriteModelInfoArray(FileHandle fid, atArray<_T>& array)
|
|
{
|
|
s32 value = array.GetCount();
|
|
CFileMgr::Write(fid, (char*)&value, 4);
|
|
for(s32 i=0; i<array.GetCount(); i++)
|
|
{
|
|
u32 hashKey = CModelInfo::GetBaseModelInfo(fwModelId(array[i]))->GetHashKey();
|
|
CFileMgr::Write(fid, (char*)&hashKey, 4);
|
|
}
|
|
}
|
|
|
|
|
|
void CStreamingRequestList::CreateSrlFilename(const char* srcFilename, char *outBuffer, size_t bufferSize)
|
|
{
|
|
formatf(outBuffer, bufferSize, "%s_srl", srcFilename);
|
|
}
|
|
|
|
//
|
|
// name: CStreamingRequestList::LoadRecording
|
|
// description: Load recording
|
|
bool CStreamingRequestList::LoadRecording(const char* cutsceneName)
|
|
{
|
|
#if __BANK
|
|
// Remember the name of the last list we loaded so we can save it again
|
|
// through the editor.
|
|
safecpy(g_recordingFilename, cutsceneName);
|
|
#endif // __BANK
|
|
|
|
streamSRLAssert(!m_CurrentRecord);
|
|
|
|
char srlName[RAGE_MAX_PATH];
|
|
CStreamingRequestList::CreateSrlFilename(cutsceneName, srlName, sizeof(srlName));
|
|
|
|
// Find the streaming index.
|
|
strLocalIndex objIndex = g_fwMetaDataStore.FindSlotFromHashKey(atStringHash(srlName));
|
|
|
|
// if (!(streamVerifyf(objIndex != -1, "Unable to find streaming request list %s - make sure it's mentioned in the .meta file", srlName)))
|
|
if (objIndex == -1 || PARAM_nosrl.Get())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
streamSRLDisplayf("Loading SRL %s", cutsceneName);
|
|
|
|
// HACK: Only enable the "force cutscene required" mode in cutscenes that need it. We /should/ always be doing it though.
|
|
m_EnsureCutsceneRequired = strstr(cutsceneName, "armenian_1_int") != NULL;
|
|
|
|
if (strnicmp(cutsceneName, "gtao_intro", 10) == 0)
|
|
{
|
|
g_HACK_GlobalSRLSkipGC = true;
|
|
g_disableForGTAO = true;
|
|
}
|
|
|
|
m_Index = g_fwMetaDataStore.GetStreamingIndex(objIndex);
|
|
|
|
strStreamingEngine::GetInfo().RequestObject(m_Index, STRFLAG_FORCE_LOAD | STRFLAG_CUTSCENE_REQUIRED);
|
|
m_stateFlags |= STRREQ_STREAMING;
|
|
|
|
#if STREAMING_VISUALIZE
|
|
STRVIS_ADD_MARKER(strStreamingVisualize::MARKER);
|
|
char markerText[128];
|
|
formatf(markerText, "Loading SRL %s", cutsceneName);
|
|
STRVIS_SET_MARKER_TEXT(markerText);
|
|
#endif // STREAMING_VISUALIZE
|
|
|
|
return true;
|
|
}
|
|
|
|
// Get frame index of the request list currently being processed
|
|
int CStreamingRequestList::GetRequestListIndex() const
|
|
{
|
|
return g_requestListIndex;
|
|
}
|
|
|
|
// Get frame index of the unrequest list currently being processed
|
|
int CStreamingRequestList::GetUnrequestListIndex() const
|
|
{
|
|
return g_removeListIndex;
|
|
} |