836 lines
26 KiB
C++
836 lines
26 KiB
C++
// =============================================================================================== //
|
|
// INCLUDES
|
|
// =============================================================================================== //
|
|
|
|
// rage headers
|
|
#include "grcore/debugdraw.h"
|
|
#include "spatialdata/transposedplaneset.h"
|
|
|
|
// framework headers
|
|
#include "fwmaths/Vector.h"
|
|
#include "fwscene/scan/Scan.h"
|
|
#include "fwscene/stores/mapdatastore.h"
|
|
|
|
// game headers
|
|
#include "ai/navmesh/navmeshextents.h"
|
|
#include "camera/viewports/ViewportManager.h"
|
|
#include "debug/Rendering/DebugLights.h"
|
|
#include "debug/Rendering/DebugLighting.h"
|
|
#include "entity/entity.h"
|
|
#include "renderer/Lights/LightEntity.h"
|
|
#include "renderer/Lights/Lights.h"
|
|
#include "renderer/Lights/LODLights.h"
|
|
#include "Renderer/RenderPhases/RenderPhaseWaterReflection.h"
|
|
#include "system/System.h"
|
|
#include "timecycle/TimeCycle.h"
|
|
#include "timecycle/TimeCycleConfig.h"
|
|
#include "objects/DummyObject.h"
|
|
#include "Objects/Object.h"
|
|
#include "vector/color32.h"
|
|
#include "vfx/channel.h"
|
|
#include "vfx/misc/Coronas.h"
|
|
#include "vfx/misc/DistantLights.h"
|
|
#include "vfx/misc/DistantLightsVertexBuffer.h"
|
|
#include "vfx/misc/LODLightManager.h"
|
|
#include "vfx/vfxutil.h"
|
|
|
|
// =============================================================================================== //
|
|
// DEFINES
|
|
// =============================================================================================== //
|
|
|
|
VFX_MISC_OPTIMISATIONS();
|
|
|
|
bool CLODLightManager::m_LODLightsCanLoad = true;
|
|
bool CLODLightManager::m_requireRenderthreadFrameInfoClear = false;
|
|
|
|
fwLinkList<CLODLightBucket> CLODLightManager::m_LODLightBuckets;
|
|
fwLinkList<CDistantLODLightBucket> CLODLightManager::m_DistantLODLightBuckets;
|
|
|
|
atArray<u16> CLODLightManager::m_LODLightImapIDXs;
|
|
|
|
LODLightData CLODLightManager::m_LODLightData;
|
|
LODLightData* CLODLightManager::m_currentFrameInfo = NULL;
|
|
|
|
// =============================================================================================== //
|
|
// HELPER CLASSES
|
|
// =============================================================================================== //
|
|
|
|
class dlCmdSetupLODLightsFrameInfo : public dlCmdBase {
|
|
public:
|
|
enum {
|
|
INSTRUCTION_ID = DC_SetupLODLightsFrameInfo,
|
|
};
|
|
|
|
dlCmdSetupLODLightsFrameInfo();
|
|
s32 GetCommandSize() { return(sizeof(*this)); }
|
|
static void ExecuteStatic(dlCmdBase &cmd) { ((dlCmdSetupLODLightsFrameInfo &) cmd).Execute(); }
|
|
void Execute();
|
|
|
|
private:
|
|
|
|
LODLightData* newFrameInfo;
|
|
};
|
|
|
|
class dlCmdClearLODLightsFrameInfo : public dlCmdBase {
|
|
public:
|
|
enum {
|
|
INSTRUCTION_ID = DC_ClearLODLightsFrameInfo,
|
|
};
|
|
|
|
s32 GetCommandSize() { return(sizeof(*this)); }
|
|
static void ExecuteStatic(dlCmdBase &cmd) { ((dlCmdClearLODLightsFrameInfo &) cmd).Execute(); }
|
|
void Execute();
|
|
};
|
|
|
|
dlCmdSetupLODLightsFrameInfo::dlCmdSetupLODLightsFrameInfo()
|
|
{
|
|
newFrameInfo = gDCBuffer->AllocateObjectFromPagedMemory<LODLightData>(DPT_LIFETIME_RENDER_THREAD, sizeof(LODLightData));
|
|
sysMemCpy(newFrameInfo, CLODLightManager::GetLODLightData(), sizeof(LODLightData));
|
|
|
|
CLODLightManager::ResetUpdateLODLightsDisabledThisFrame();
|
|
}
|
|
|
|
void dlCmdSetupLODLightsFrameInfo::Execute()
|
|
{
|
|
CLODLightManager::m_currentFrameInfo = newFrameInfo;
|
|
}
|
|
|
|
|
|
void dlCmdClearLODLightsFrameInfo::Execute()
|
|
{
|
|
CLODLightManager::m_currentFrameInfo = NULL;
|
|
}
|
|
|
|
// =============================================================================================== //
|
|
// FUNCTIONS
|
|
// =============================================================================================== //
|
|
|
|
CLODLightManager::CLODLightManager()
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
static rage::ServiceDelegate ms_serviceDelegate;
|
|
|
|
static void OnServiceEvent( rage::sysServiceEvent* evnt )
|
|
{
|
|
if(evnt != NULL)
|
|
{
|
|
switch(evnt->GetType())
|
|
{
|
|
case sysServiceEvent::RESUME_IMMEDIATE:
|
|
{
|
|
CLODLightManager::Shutdown(SHUTDOWN_SESSION);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CLODLightManager::Init(unsigned initMode)
|
|
{
|
|
if(initMode == INIT_CORE)
|
|
{
|
|
m_LODLightBuckets.Init(MAX_NUM_LOD_LIGHT_BUCKETS);
|
|
m_DistantLODLightBuckets.Init(MAX_NUM_LOD_LIGHT_BUCKETS);
|
|
|
|
ms_serviceDelegate.Bind(OnServiceEvent);
|
|
g_SysService.AddDelegate(&ms_serviceDelegate);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::Shutdown(unsigned shutdownMode)
|
|
{
|
|
if (shutdownMode == SHUTDOWN_SESSION || shutdownMode == SHUTDOWN_CORE)
|
|
{
|
|
m_requireRenderthreadFrameInfoClear = true;
|
|
|
|
m_LODLightData.m_LODLightsToRender.Reset();
|
|
m_LODLightData.m_DistLODLightsToRender[LODLIGHT_CATEGORY_SMALL].Reset();
|
|
m_LODLightData.m_DistLODLightsToRender[LODLIGHT_CATEGORY_MEDIUM].Reset();
|
|
m_LODLightData.m_DistLODLightsToRender[LODLIGHT_CATEGORY_LARGE].Reset();
|
|
}
|
|
|
|
if(shutdownMode == SHUTDOWN_CORE)
|
|
{
|
|
g_SysService.RemoveDelegate(&ms_serviceDelegate);
|
|
ms_serviceDelegate.Reset();
|
|
|
|
m_LODLightBuckets.Shutdown();
|
|
m_DistantLODLightBuckets.Shutdown();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::Update()
|
|
{
|
|
SetIfCanLoad();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::AddLODLight(CLODLight &LODLights, s32 mapDataSlotIndex, s32 parentMapDataSlotIndex)
|
|
{
|
|
// Assert to catch if mapDataSlotIndex goes beyond the 16 bits of storage I've allowed for it.
|
|
Assertf(mapDataSlotIndex < 65536, "mapDataSlotIndex above 16 bits");
|
|
|
|
// Don't add more than we can store!
|
|
if(Verifyf(m_LODLightBuckets.GetNumFree() > 0, "LODLightManager: ERROR - Ran out of buckets!"))
|
|
{
|
|
CLODLightBucketNode* pNode = m_LODLightBuckets.Insert();
|
|
CLODLightBucket* pBucket = &(pNode->item);
|
|
pBucket->mapDataSlotIndex = (u16)mapDataSlotIndex;
|
|
pBucket->parentMapDataSlotIndex = (u16)parentMapDataSlotIndex;
|
|
|
|
pBucket->lightCount = (u16)LODLights.m_direction.GetCount();
|
|
pBucket->pLights = &LODLights;
|
|
|
|
// Find the parent for this LODLight
|
|
CDistantLODLightBucket *pParent = FindDistantLODLightBucket(parentMapDataSlotIndex);
|
|
Assertf(pParent != NULL, "LODLightManager: Cannot find DistantLODLight for LODLight");
|
|
pBucket->pDistLights = pParent->pLights;
|
|
|
|
BANK_ONLY(DebugLighting::UpdateStatsLODLights(m_LODLightBuckets.GetNumUsed(), pBucket->lightCount, LODLIGHT_STANDARD));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::RemoveLODLight(s32 mapDataSlotIndex)
|
|
{
|
|
CLODLightBucketNode* pNode = m_LODLightBuckets.GetFirst()->GetNext();
|
|
// Delete all LODLights with matching map indices.
|
|
while(pNode != m_LODLightBuckets.GetLast())
|
|
{
|
|
CLODLightBucket* pCurEntry = &(pNode->item);
|
|
CLODLightBucketNode* pLastNode = pNode;
|
|
pNode = pNode->GetNext();
|
|
|
|
if (pCurEntry->mapDataSlotIndex == mapDataSlotIndex)
|
|
{
|
|
// Delete this entry.
|
|
BANK_ONLY(DebugLighting::UpdateStatsLODLights(m_LODLightBuckets.GetNumUsed() - 1, -pCurEntry->lightCount, LODLIGHT_STANDARD));
|
|
m_LODLightBuckets.Remove(pLastNode);
|
|
|
|
// B*3371677: Crash - CLODLights::RenderLODLights():
|
|
// ... and remove from m_LODLightsToRender list (if still there):
|
|
atFixedArray<CLODLightBucket*, MAX_NUM_LOD_LIGHT_BUCKETS>& LODLightsToRender = GetLODLightsToRenderUpdateBuffer();
|
|
const u32 count = LODLightsToRender.GetCount();
|
|
for(int i=0; i<count; i++)
|
|
{
|
|
if(LODLightsToRender[i] == pCurEntry)
|
|
{
|
|
LODLightsToRender[i] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
CDistantLODLightBucket *CLODLightManager::FindDistantLODLightBucket(s32 mapDataSlotIndex)
|
|
{
|
|
|
|
CDistantLODLightBucketNode* pNode = m_DistantLODLightBuckets.GetFirst()->GetNext();
|
|
while(pNode != m_DistantLODLightBuckets.GetLast())
|
|
{
|
|
CDistantLODLightBucket* pCurEntry = &(pNode->item);
|
|
pNode = pNode->GetNext();
|
|
|
|
if (pCurEntry->mapDataSlotIndex == mapDataSlotIndex)
|
|
{
|
|
return pCurEntry;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::AddDistantLODLight(CDistantLODLight &distLODLights, s32 mapDataSlotIndex)
|
|
{
|
|
// Assert to catch if mapDataSlotIndex goes beyond the 16 bits of storage I've allowed for it.
|
|
Assertf(mapDataSlotIndex < 65536, "mapDataSlotIndex above 16 bits");
|
|
|
|
// Don't add more than we can store!
|
|
if(Verifyf(m_DistantLODLightBuckets.GetNumFree() > 0, "LODLightManager: ERROR - Ran out of Distantlight buckets!"))
|
|
{
|
|
CDistantLODLightBucketNode* pNode = m_DistantLODLightBuckets.Insert();
|
|
CDistantLODLightBucket* pBucket = &(pNode->item);
|
|
pBucket->mapDataSlotIndex = (u16)mapDataSlotIndex;
|
|
pBucket->lightCount = (u16)distLODLights.m_position.GetCount();
|
|
pBucket->pLights = &distLODLights;
|
|
BANK_ONLY(DebugLighting::UpdateStatsLODLights(m_DistantLODLightBuckets.GetNumUsed(), pBucket->lightCount, LODLIGHT_DISTANT));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::RemoveDistantLODLight(s32 mapDataSlotIndex)
|
|
{
|
|
CDistantLODLightBucketNode* pNode = m_DistantLODLightBuckets.GetFirst()->GetNext();
|
|
// Delete all LODLights with matching map indices.
|
|
while(pNode != m_DistantLODLightBuckets.GetLast())
|
|
{
|
|
CDistantLODLightBucket* pCurEntry = &(pNode->item);
|
|
CDistantLODLightBucketNode* pLastNode = pNode;
|
|
pNode = pNode->GetNext();
|
|
|
|
if (pCurEntry->mapDataSlotIndex == mapDataSlotIndex)
|
|
{
|
|
BANK_ONLY(DebugLighting::UpdateStatsLODLights(m_DistantLODLightBuckets.GetNumUsed() - 1, -pCurEntry->lightCount, LODLIGHT_DISTANT));
|
|
m_DistantLODLightBuckets.Remove(pLastNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::ResetLODLightsBucketVisibility()
|
|
{
|
|
atFixedArray<CLODLightBucket*, MAX_NUM_LOD_LIGHT_BUCKETS> &LODLightsToRender = GetLODLightsToRenderUpdateBuffer();
|
|
LODLightsToRender.Reset();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::BuildLODLightsBucketVisibility(CViewport *pViewport)
|
|
{
|
|
atFixedArray<CLODLightBucket*, MAX_NUM_LOD_LIGHT_BUCKETS> &LODLightsToRender = GetLODLightsToRenderUpdateBuffer();
|
|
LODLightsToRender.Reset();
|
|
|
|
if(!m_LODLightsCanLoad)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Setup cull planes (use exterior quad if in an interior or just the frustum)
|
|
const grcViewport& grcVP = pViewport->GetGrcViewport();
|
|
const Vec3V vCameraPos = grcVP.GetCameraPosition();
|
|
|
|
spdTransposedPlaneSet8 cullPlanes;
|
|
spdTransposedPlaneSet8 waterReflectioncullPlanes;
|
|
if(g_SceneToGBufferPhaseNew &&
|
|
g_SceneToGBufferPhaseNew->GetPortalVisTracker() &&
|
|
g_SceneToGBufferPhaseNew->GetPortalVisTracker()->GetInteriorLocation().IsValid())
|
|
{
|
|
const bool bInteriorCullAll = !fwScan::GetScanResults().GetIsExteriorVisibleInGbuf();
|
|
|
|
if(bInteriorCullAll == false)
|
|
{
|
|
fwScreenQuad quad = fwScan::GetScanResults().GetExteriorGbufScreenQuad();
|
|
quad.GenerateFrustum(grcVP.GetCompositeMtx(), cullPlanes);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cullPlanes.Set(grcVP, true, true);
|
|
}
|
|
Vec3V vWaterReflectionCameraPos;
|
|
bool bCheckReflectionPhase = BANK_ONLY(DebugLighting::m_LODLightCoronaEnableWaterReflectionCheck && ) (Water::UseHQWaterRendering());
|
|
const grcViewport* grcWaterReflectionVP = CRenderPhaseWaterReflectionInterface::GetViewport();
|
|
if(grcWaterReflectionVP)
|
|
{
|
|
vWaterReflectionCameraPos = grcWaterReflectionVP->GetCameraPosition();
|
|
waterReflectioncullPlanes.Set(*grcWaterReflectionVP, true, true);
|
|
}
|
|
else
|
|
{
|
|
bCheckReflectionPhase = false;
|
|
}
|
|
|
|
|
|
fwMapDataStore& mapStore = fwMapDataStore::GetStore();
|
|
|
|
u32 startIndex = 0;
|
|
u32 endIndex = m_LODLightBuckets.GetNumUsed();
|
|
|
|
#if __BANK
|
|
if (DebugLighting::m_LODLightBucketIndex > -1)
|
|
{
|
|
startIndex = DebugLighting::m_LODLightBucketIndex;
|
|
endIndex = DebugLighting::m_LODLightBucketIndex + 1;
|
|
}
|
|
#endif
|
|
|
|
|
|
spdSphere lodLightSphere[LODLIGHT_CATEGORY_COUNT];
|
|
spdSphere waterReflectionLODLightSphere[LODLIGHT_CATEGORY_COUNT];
|
|
for (u32 i = 0; i < LODLIGHT_CATEGORY_COUNT; i++)
|
|
{
|
|
ScalarV vlodLightRange = ScalarV(CLODLights::GetUpdateLodLightRange((eLodLightCategory)i));
|
|
lodLightSphere[i] = spdSphere(vCameraPos, vlodLightRange);
|
|
waterReflectionLODLightSphere[i] = spdSphere(vWaterReflectionCameraPos, vlodLightRange);
|
|
}
|
|
|
|
CLODLightBucketNode* pNode = m_LODLightBuckets.GetFirst()->GetNext();
|
|
//Skip to the start Index
|
|
for(int i=0; i < startIndex; i++)
|
|
{
|
|
pNode = pNode->GetNext();
|
|
}
|
|
|
|
for(int i = startIndex; i < endIndex; i++)
|
|
{
|
|
CLODLightBucket *pBucket = &(pNode->item);
|
|
pNode = pNode->GetNext();
|
|
const spdAABB &physBounds = mapStore.GetPhysicalBounds(strLocalIndex(pBucket->mapDataSlotIndex));
|
|
|
|
CDistantLODLight *pBaseData = pBucket->pDistLights;
|
|
const eLodLightCategory currentCategory = (eLodLightCategory)pBaseData->m_category;
|
|
|
|
//Check if whole bucket is visible in any of the phases (main or water reflection)
|
|
if(cullPlanes.IntersectsAABB(physBounds) || (bCheckReflectionPhase && waterReflectioncullPlanes.IntersectsAABB(physBounds)))
|
|
{
|
|
//Not sure if we should put this check before or after the stream index stuff
|
|
#if __BANK
|
|
if( !DebugLighting::m_LODLightsVisibilityOnMainThread ||
|
|
( DebugLighting::m_LODLightsVisibilityOnMainThread &&
|
|
(physBounds.IntersectsSphere(lodLightSphere[currentCategory])|| (bCheckReflectionPhase && physBounds.IntersectsSphere(waterReflectionLODLightSphere[currentCategory])))))
|
|
#else
|
|
if(physBounds.IntersectsSphere(lodLightSphere[currentCategory]) || (bCheckReflectionPhase && physBounds.IntersectsSphere(waterReflectionLODLightSphere[currentCategory])))
|
|
#endif
|
|
{
|
|
// Add a ref to ensure this data doesn't vanish
|
|
fwMapDataStore::GetStore().AddRef(strLocalIndex(pBucket->mapDataSlotIndex), REF_RENDER);
|
|
gDrawListMgr->AddRefCountedModuleIndex(pBucket->mapDataSlotIndex, &fwMapDataStore::GetStore());
|
|
|
|
// Add bucket to render
|
|
LODLightsToRender.Push(pBucket);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::BuildDistLODLightsVisibility(CViewport *pViewport)
|
|
{
|
|
atFixedArray<CDistantLODLightBucket*, MAX_NUM_LOD_LIGHT_BUCKETS>* DistLODLightsToRender = GetDistLODLightsToRenderUpdateBuffers();
|
|
|
|
for (u32 i = 0; i < LODLIGHT_CATEGORY_COUNT; i++)
|
|
{
|
|
DistLODLightsToRender[i].Reset();
|
|
}
|
|
|
|
if(!m_LODLightsCanLoad)
|
|
{
|
|
// Swap for next frame
|
|
return;
|
|
}
|
|
|
|
// Setup cull planes (use exterior quad if in an interior or just the frustum)
|
|
const grcViewport& grcVP = pViewport->GetGrcViewport();
|
|
|
|
spdTransposedPlaneSet8 cullPlanes;
|
|
if(g_SceneToGBufferPhaseNew &&
|
|
g_SceneToGBufferPhaseNew->GetPortalVisTracker() &&
|
|
g_SceneToGBufferPhaseNew->GetPortalVisTracker()->GetInteriorLocation().IsValid()
|
|
BANK_ONLY(&& !g_distantLights.GetDisableStreetLightsVisibility()))
|
|
{
|
|
const bool bInteriorCullAll = !fwScan::GetScanResults().GetIsExteriorVisibleInGbuf();
|
|
|
|
if(bInteriorCullAll == false)
|
|
{
|
|
fwScreenQuad quad = fwScan::GetScanResults().GetExteriorGbufScreenQuad();
|
|
quad.GenerateFrustum(grcVP.GetCompositeMtx(), cullPlanes);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cullPlanes.Set(grcVP, true, true);
|
|
}
|
|
|
|
fwMapDataStore& mapStore = fwMapDataStore::GetStore();
|
|
|
|
u32 startIndex = 0;
|
|
u32 endIndex = m_DistantLODLightBuckets.GetNumUsed();
|
|
|
|
#if __BANK
|
|
if (DebugLighting::m_distantLODLightBucketIndex > -1)
|
|
{
|
|
startIndex = DebugLighting::m_distantLODLightBucketIndex;
|
|
endIndex = DebugLighting::m_distantLODLightBucketIndex + 1;
|
|
}
|
|
#endif
|
|
|
|
CDistantLODLightBucketNode* pNode = m_DistantLODLightBuckets.GetFirst()->GetNext();
|
|
//Skip to the start Index
|
|
for(int i=0; i < startIndex; i++)
|
|
{
|
|
pNode = pNode->GetNext();
|
|
}
|
|
|
|
for(int i = startIndex; i < endIndex; i++)
|
|
{
|
|
CDistantLODLightBucket *pBucket = &(pNode->item);
|
|
pNode = pNode->GetNext();
|
|
const spdAABB &physBounds = mapStore.GetPhysicalBounds(strLocalIndex(pBucket->mapDataSlotIndex));
|
|
if(cullPlanes.IntersectsAABB(physBounds) BANK_ONLY(|| g_distantLights.GetDisableStreetLightsVisibility()))
|
|
{
|
|
// Add a ref to ensure this data doesn't vanish
|
|
fwMapDataStore::GetStore().AddRef(strLocalIndex(pBucket->mapDataSlotIndex), REF_RENDER);
|
|
gDrawListMgr->AddRefCountedModuleIndex(pBucket->mapDataSlotIndex, &fwMapDataStore::GetStore());
|
|
|
|
DistLODLightsToRender[pBucket->pLights->m_category].Push(pBucket);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::RegisterBrokenLightsForEntity(CEntity *pEntity)
|
|
{
|
|
// LOD Lights
|
|
if(pEntity->GetIsTypeObject())
|
|
{
|
|
CObject *pObject = static_cast<CObject*>(pEntity);
|
|
CDummyObject* pDummy = pObject->GetRelatedDummy();
|
|
if(pDummy)
|
|
{
|
|
CBaseModelInfo* pModelInfo = pDummy->GetBaseModelInfo();
|
|
GET_2D_EFFECTS(pModelInfo);
|
|
for(int j=0;j<numEffects;j++)
|
|
{
|
|
C2dEffect *pEffect = a2dEffects[j];
|
|
if(pEffect->GetType() == ET_LIGHT )
|
|
{
|
|
//Displayf("Found a light in a broken object %s", pModelInfo->GetModelName());
|
|
Lights::RegisterBrokenLight(pDummy, j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::UnregisterBrokenLightsForEntity(CEntity *pEntity)
|
|
{
|
|
// LOD Lights
|
|
if(pEntity->GetIsTypeObject())
|
|
{
|
|
CObject *pObject = static_cast<CObject*>(pEntity);
|
|
CDummyObject* pDummy = pObject->GetRelatedDummy();
|
|
if(pDummy)
|
|
{
|
|
CBaseModelInfo* pModelInfo = pDummy->GetBaseModelInfo();
|
|
GET_2D_EFFECTS(pModelInfo);
|
|
|
|
for(int j=0;j<numEffects;j++)
|
|
{
|
|
C2dEffect *pEffect = a2dEffects[j];
|
|
if(pEffect->GetType() == ET_LIGHT )
|
|
{
|
|
u32 hash = GenerateLODLightHash(pEntity, j);
|
|
Lights::RemoveRegisteredBrokenLight(hash);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
// Whizzes through the vfxUtil/frags broken this frame stuff, and find objects that were broken this frame that have lights
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::CheckFragsForBrokenLights()
|
|
{
|
|
for(int i=0;i<vfxUtil::GetNumBrokenFrags();i++)
|
|
{
|
|
vfxBrokenFragInfo &brokenFrag = vfxUtil::GetBrokenFragInfo(i);
|
|
// Check if this frag has a parent that has a dummy that has lights
|
|
CEntity *pEntity = static_cast<CEntity*>(brokenFrag.pParentEntity.Get());
|
|
if(pEntity && pEntity->GetIsTypeObject())
|
|
{
|
|
CObject *pObj = (CObject*)pEntity;
|
|
CDummyObject* pDummy = pObj->GetRelatedDummy();
|
|
if(pDummy)
|
|
{
|
|
CBaseModelInfo* pModelInfo = pDummy->GetBaseModelInfo();
|
|
GET_2D_EFFECTS(pModelInfo);
|
|
for(int j=0;j<numEffects;j++)
|
|
{
|
|
C2dEffect *pEffect = a2dEffects[j];
|
|
if(pEffect->GetType() == ET_LIGHT )
|
|
{
|
|
//Displayf("Found a light in a broken object %s", pModelInfo->GetModelName());
|
|
Lights::RegisterBrokenLight(pDummy, j);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::UnbreakLODLight(CLightEntity *pLightEntity)
|
|
{
|
|
u32 hash = GenerateLODLightHash(pLightEntity);
|
|
Lights::RemoveRegisteredBrokenLight(hash);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::SetIfCanLoad()
|
|
{
|
|
u32 hour = CClock::GetHour();
|
|
|
|
if( hour >= LODLIGHT_TURN_OFF_TIME && hour < LODLIGHT_TURN_ON_TIME )
|
|
{
|
|
if( m_LODLightsCanLoad )
|
|
{ // Turn them off
|
|
m_LODLightsCanLoad = false;
|
|
TurnLODLightLoadingOnOff(m_LODLightsCanLoad);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !m_LODLightsCanLoad )
|
|
{ // Turn them on
|
|
m_LODLightsCanLoad = true;
|
|
TurnLODLightLoadingOnOff(m_LODLightsCanLoad);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::TurnLODLightLoadingOnOff(bool bOn)
|
|
{
|
|
// run over LODLight imap cache
|
|
for(int i = 0; i < m_LODLightImapIDXs.GetCount(); i++)
|
|
{
|
|
u16 iMapIDX = m_LODLightImapIDXs[i];
|
|
INSTANCE_STORE.GetBoxStreamer().SetIsCulled((s32)iMapIDX, !bOn);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::CreateLODLightImapIDXCache()
|
|
{
|
|
m_LODLightImapIDXs.Reset();
|
|
fwMapDataStore& mapStore = fwMapDataStore::GetStore();
|
|
|
|
for(int i = 0; i < mapStore.GetCount(); i++)
|
|
{
|
|
fwMapDataDef* pDef = mapStore.GetSlot(strLocalIndex(i));
|
|
if(pDef && pDef->GetIsValid() && pDef->IsLodLightSpecific())
|
|
{
|
|
m_LODLightImapIDXs.Grow() = (u16)i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLODLightManager::CacheLoadedLODLightImapIDX()
|
|
{
|
|
m_LODLightImapIDXs.Reset();
|
|
fwMapDataStore& mapStore = fwMapDataStore::GetStore();
|
|
|
|
// Load first LOD lights and then distant LOD lights so the cache can be safely used for unloading map data.
|
|
for(int i = 0; i < mapStore.GetCount(); i++)
|
|
{
|
|
strLocalIndex index(i);
|
|
fwMapDataDef* pDef = mapStore.GetSlot(index);
|
|
if(pDef && pDef->GetIsValid() && (pDef->GetContentFlags()&fwMapData::CONTENTFLAG_LOD_LIGHTS) && mapStore.HasObjectLoaded(index))
|
|
{
|
|
m_LODLightImapIDXs.Grow() = (u16)i;
|
|
}
|
|
}
|
|
for(int i = 0; i < mapStore.GetCount(); i++)
|
|
{
|
|
strLocalIndex index(i);
|
|
fwMapDataDef* pDef = mapStore.GetSlot(index);
|
|
if(pDef && pDef->GetIsValid() && (pDef->GetContentFlags()&fwMapData::CONTENTFLAG_DISTANT_LOD_LIGHTS) && mapStore.HasObjectLoaded(index))
|
|
{
|
|
m_LODLightImapIDXs.Grow() = (u16)i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLODLightManager::LoadLODLightImapIDXCache(u32 filterMask /* = LODLIGHT_IMAP_ANY */)
|
|
{
|
|
for(int i = 0; i < m_LODLightImapIDXs.GetCount(); i++)
|
|
{
|
|
strLocalIndex index(m_LODLightImapIDXs[i]);
|
|
ASSERT_ONLY(fwMapDataDef* pDef = fwMapDataStore::GetStore().GetSlot(index));
|
|
FatalAssertf(pDef && pDef->GetIsValid() && pDef->GetContentFlags()&fwMapData::CONTENTFLAG_MASK_LODLIGHTS,
|
|
"Unexpected invalid LOD light map data index");
|
|
if (HasLODLightImapFilterMask(index, filterMask) && !fwMapDataStore::GetStore().HasObjectLoaded(index))
|
|
{
|
|
fwMapDataStore::GetStore().StreamingRequest(index, STRFLAG_DONTDELETE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CLODLightManager::UnloadLODLightImapIDXCache(u32 filterMask /* = LODLIGHT_IMAP_ANY */)
|
|
{
|
|
// Ensure gRenderThreadInterface.Flush() is called before using in case any IMAP is in use.
|
|
for(int i = 0; i < m_LODLightImapIDXs.GetCount(); i++)
|
|
{
|
|
strLocalIndex index(m_LODLightImapIDXs[i]);
|
|
ASSERT_ONLY(fwMapDataDef* pDef = fwMapDataStore::GetStore().GetSlot(index));
|
|
FatalAssertf(pDef && pDef->GetIsValid() && pDef->GetContentFlags()&fwMapData::CONTENTFLAG_MASK_LODLIGHTS,
|
|
"Unexpected invalid LOD light map data index");
|
|
if (HasLODLightImapFilterMask(index, filterMask))
|
|
{
|
|
if (fwMapDataStore::GetStore().HasObjectLoaded(index))
|
|
{
|
|
fwMapDataStore::GetStore().ClearRequiredFlag(m_LODLightImapIDXs[i], STRFLAG_DONTDELETE);
|
|
fwMapDataStore::GetStore().SafeRemove(index);
|
|
}
|
|
fwMapDataStore::GetStore().SetStreamable(index, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CLODLightManager::HasLODLightImapFilterMask(strLocalIndex imapIndex, u32 filterMask)
|
|
{
|
|
return ((filterMask & LODLIGHT_IMAP_OWNED_BY_SCRIPT) && fwMapDataStore::GetStore().IsScriptManaged(imapIndex)) ||
|
|
((filterMask & LODLIGHT_IMAP_OWNED_BY_MAP_DATA) && !fwMapDataStore::GetStore().IsScriptManaged(imapIndex));
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::SetupRenderthreadFrameInfo()
|
|
{
|
|
DLC(dlCmdSetupLODLightsFrameInfo, ());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::ClearRenderthreadFrameInfo()
|
|
{
|
|
DLC(dlCmdClearLODLightsFrameInfo, ());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
void CLODLightManager::InitDLCCommands()
|
|
{
|
|
DLC_REGISTER_EXTERNAL(dlCmdSetupLODLightsFrameInfo);
|
|
DLC_REGISTER_EXTERNAL(dlCmdClearLODLightsFrameInfo);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
// Generates a hash based on the bounding box extents of the entity and the light ID
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
u32 CLODLightManager::GenerateLODLightHash(const CLightEntity *pLightEntity )
|
|
{
|
|
const CEntity *pSourceEntity = pLightEntity->GetParent();
|
|
Assert(pSourceEntity);
|
|
s32 lightID = pLightEntity->Get2dEffectId();
|
|
return GenerateLODLightHash(pSourceEntity, lightID );
|
|
}
|
|
|
|
u32 CLODLightManager::GenerateLODLightHash(const CEntity *pSourceEntity, s32 lightID )
|
|
{
|
|
s32 hashArray[7];
|
|
|
|
spdAABB boundBox;
|
|
pSourceEntity->GetAABB(boundBox);
|
|
|
|
Vector3 bbMin = VEC3V_TO_VECTOR3(boundBox.GetMin());
|
|
Vector3 bbMax = VEC3V_TO_VECTOR3(boundBox.GetMax());
|
|
|
|
bbMin *= 10.0f;
|
|
bbMax *= 10.0f;
|
|
|
|
hashArray[0] = static_cast<s32>(bbMin.x);
|
|
hashArray[1] = static_cast<s32>(bbMin.y);
|
|
hashArray[2] = static_cast<s32>(bbMin.z);
|
|
hashArray[3] = static_cast<s32>(bbMax.x);
|
|
hashArray[4] = static_cast<s32>(bbMax.y);
|
|
hashArray[5] = static_cast<s32>(bbMax.z);
|
|
hashArray[6] = static_cast<s32>(lightID);
|
|
|
|
return hash((u32*)hashArray, 7, 0);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
// Macros internal to hash()
|
|
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
|
#define mix(a,b,c) \
|
|
{ \
|
|
a -= c; a ^= rot(c, 4); c += b; \
|
|
b -= a; b ^= rot(a, 6); a += c; \
|
|
c -= b; c ^= rot(b, 8); b += a; \
|
|
a -= c; a ^= rot(c,16); c += b; \
|
|
b -= a; b ^= rot(a,19); a += c; \
|
|
c -= b; c ^= rot(b, 4); b += a; \
|
|
}
|
|
|
|
#define final(a,b,c) \
|
|
{ \
|
|
c ^= b; c -= rot(b,14); \
|
|
a ^= c; a -= rot(c,11); \
|
|
b ^= a; b -= rot(a,25); \
|
|
c ^= b; c -= rot(b,16); \
|
|
a ^= c; a -= rot(c,4); \
|
|
b ^= a; b -= rot(a,14); \
|
|
c ^= b; c -= rot(b,24); \
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
// k - the key, an array of uint32_t values
|
|
// length - the length of the key, as u32
|
|
// initval - the previous hash, or an arbitrary value
|
|
// ----------------------------------------------------------------------------------------------- //
|
|
|
|
u32 CLODLightManager::hash( const u32 *k, u32 length, u32 initval)
|
|
{
|
|
u32 a,b,c;
|
|
|
|
/* Set up the internal state */
|
|
a = b = c = 0xdeadbeef + (length<<2) + initval;
|
|
|
|
/* handle most of the key */
|
|
while (length > 3)
|
|
{
|
|
a += k[0];
|
|
b += k[1];
|
|
c += k[2];
|
|
mix(a,b,c);
|
|
length -= 3;
|
|
k += 3;
|
|
}
|
|
|
|
/* handle the last 3 uint32_t's, all the case statements fall through */
|
|
switch(length)
|
|
{
|
|
case 3 : c+=k[2];
|
|
case 2 : b+=k[1];
|
|
case 1 : a+=k[0];
|
|
final(a,b,c);
|
|
case 0: /* case 0: nothing left to add */
|
|
break;
|
|
}
|
|
/* report the result */
|
|
return c;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------------- //
|