Files
GTASource/game/renderer/Entities/EntityDrawHandler.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1183 lines
37 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
// Title : EntityDrawHandler.cpp
// Author : Russ Schaaf
// Started : 18/11/2010
//
/////////////////////////////////////////////////////////////////////////////////
#include "renderer/Entities/EntityDrawHandler.h"
// Rage Headers
#include "crskeleton/skeletondata.h"
#include "grcore/grcorespu.h"
// Framework Headers
#if __BANK
#include "fwdebug/picker.h"
#endif // __BANK
// Game Headers
#include "cloth/charactercloth.h"
#include "cloth/ClothMgr.h"
#include "debug/Rendering/DebugDeferred.h"
#include "debug/Rendering/DebugLights.h"
#include "debug/SceneGeometryCapture.h"
#include "physics/physics.h"
#include "renderer/DrawLists/DrawListProfileStats.h"
#include "renderer/Lights/lights.h"
#include "renderer/OcclusionQueries.h"
#include "renderer/Renderer.h"
#include "renderer/RenderPhases/RenderPhaseCascadeShadows.h"
#include "renderer/RenderPhases/RenderPhaseReflection.h"
#include "renderer/RenderPhases/RenderPhaseWaterReflection.h"
#include "scene/Entity.h"
#include "scene/Lod/LodDrawable.h"
#include "scene/Lod/LodMgr.h"
#include "scene/streamer/SceneStreamerMgr.h"
#include "shaders/CustomShaderEffectBase.h"
#include "shaders/CustomShaderEffectGrass.h"
#include "shaders/CustomShaderEffectTint.h"
#include "shaders/CustomShaderEffectTree.h"
#include "shaders/CustomShaderEffectCable.h"
#include "streaming/streaming.h"
#include "renderer/Entities/InstancedEntityRenderer.h"
RENDER_OPTIMISATIONS()
//
//
//
//
CEntityDrawHandler::CEntityDrawHandler(CEntity* pEntity, rmcDrawable* pDrawable)
{
m_pDrawable = pDrawable;
m_pShaderEffect = NULL;
m_pActiveListLink = NULL;
// only add buildings and dummies to entity rendered list. Don't want peds, vehicles
// or objects in there
if(pEntity && (pEntity->GetIsTypeBuilding() || pEntity->GetIsTypeDummyObject()))
AddEntityToRenderedList(pEntity);
if(pDrawable)
{
// Setup lod flags
const rmcLodGroup &lodGroup = pDrawable->GetLodGroup();
m_phaseLODs =
(LODDrawable::CalculateDrawableLODFlags(lodGroup, CRenderer::RB_MODEL_SHADOW) << LODDrawable::LODFLAG_SHIFT_SHADOW ) |
(LODDrawable::CalculateDrawableLODFlags(lodGroup, CRenderer::RB_MODEL_REFLECTION) << LODDrawable::LODFLAG_SHIFT_REFLECTION) |
(LODDrawable::CalculateDrawableLODFlags(lodGroup, CRenderer::RB_MODEL_WATER) << LODDrawable::LODFLAG_SHIFT_WATER ) |
(LODDrawable::CalculateDrawableLODFlags(lodGroup, CRenderer::RB_MODEL_MIRROR) << LODDrawable::LODFLAG_SHIFT_MIRROR ) |
(LODDrawable::LODFLAG_NONE << LODDrawable::LODFLAG_SHIFT_DEFAULT ) ;
m_lastLODIdx = 0;
for (int i = LOD_COUNT - 1; i > 0; i--)
{
if (lodGroup.ContainsLod(i))
{
m_lastLODIdx = i;
break;
}
}
m_hasBones = pDrawable->GetSkeletonData() && (pDrawable->GetSkeletonData()->GetNumBones() > 1) ? 1 : 0;
if(Verifyf(pEntity, "CEntityDrawHandler called with NULL entity"))
{
CBaseModelInfo *pModelInfo = pEntity->GetBaseModelInfo();
Assert(pModelInfo);
#if __ASSERT
// cloth and glass panes can have no LODs ..
const fragType* pFragType = pModelInfo->GetFragType();
const bool bHasEnvCloths = pFragType ? (pFragType->GetNumEnvCloths() > 0) : false;
const bool bHasGlassPane = pFragType ? (pFragType->GetNumGlassPaneModelInfos() > 0) : false;
for (int i = m_lastLODIdx; i >= 0; i--) // make sure all the higher LODs exist
{
Assertf(lodGroup.ContainsLod(i) || ((bHasEnvCloths || bHasGlassPane) && i == 0), "%s: last LOD index is %d, but LOD index %d does not exist (model type = %d, entity type = %d)", pEntity->GetModelName(), m_lastLODIdx, i, pModelInfo->GetModelType(), pEntity->GetType());
}
#endif // __ASSERT
// [HACK GTAV]
const u32 uModelNameHash = pModelInfo->GetModelNameHash();
if( (uModelNameHash==MID_P_PARACHUTE1_S) ||
(uModelNameHash==MID_P_PARACHUTE1_SP_S) ||
(uModelNameHash==MID_P_PARACHUTE1_MP_S) ||
(uModelNameHash==MID_PIL_P_PARA_PILOT_SP_S) ||
(uModelNameHash==MID_LTS_P_PARA_PILOT2_SP_S) ||
(uModelNameHash==MID_SR_PROP_SPECRACES_PARA_S_01) ||
(uModelNameHash==MID_GR_PROP_GR_PARA_S_01) ||
(uModelNameHash==MID_XM_PROP_X17_PARA_SP_S) ||
(uModelNameHash==MID_TR_PROP_TR_PARA_SP_S_01A) ||
(uModelNameHash==MID_REH_PROP_REH_PARA_SP_S_01A) )
{
// BS#842523: special case to force lod=1 for parachute shadow:
u32 shadowLODFlag = (m_phaseLODs >> LODDrawable::LODFLAG_SHIFT_SHADOW) & LODDrawable::LODFLAG_MASK;
if (shadowLODFlag == LODDrawable::LODFLAG_NONE)
{
shadowLODFlag = LODDrawable::LODFLAG_FORCE_LOD_LEVEL | LOD_MED;
m_phaseLODs &= ~(LODDrawable::LODFLAG_MASK << LODDrawable::LODFLAG_SHIFT_SHADOW);
m_phaseLODs |= (shadowLODFlag << LODDrawable::LODFLAG_SHIFT_SHADOW);
}
}
}
}
}
CEntityDrawHandler::~CEntityDrawHandler()
{
u32 query = GetOcclusionQueryId();
if(query)
{
OcclusionQueries::OQFree(query);
SetOcclusionQueryId(0);
}
RemoveEntityFromRenderedList();
RemoveDrawable();
}
//
// name: CEntityDrawComponent::AddEntityToRenderedList
// description: Add the entity to the rendered list
void CEntityDrawHandler::AddEntityToRenderedList(CEntity* pEntity)
{
m_pActiveListLink = g_SceneStreamerMgr.GetStreamingLists().AddActive(pEntity);
#if STREAMING_VISUALIZE
// g_SceneStreamerMgr.GetStreamingLists().AddActiveForStreamingVisualize(pEntity);
#endif // STREAMING_VISUALIZE
}
//
// name: CEntityDrawComponent::RemoveEntityFromRenderedList
// description: Remove the entity from the rendered list
void CEntityDrawHandler::RemoveEntityFromRenderedList()
{
if (m_pActiveListLink)
{
#if __ASSERT
fwEntity *entity = m_pActiveListLink->item.GetEntity();
#endif // __ASSERT
#if STREAMING_VISUALIZE
// g_SceneStreamerMgr.GetStreamingLists().RemoveActiveForStreamingVisualize(entity);
#endif // STREAMING_VISUALIZE
// Make sure the strIndex hasn't changed throughout the lifetime of this object.
#if __ASSERT
Assert(entity);
Assert(entity->GetDrawHandlerPtr() == this);
u32 objIndex = entity->GetModelIndex();
strIndex archetypeIndex = fwArchetypeManager::GetStreamingModule()->GetStreamingIndex(strLocalIndex(objIndex));
Assertf(archetypeIndex == m_pActiveListLink->item.GetArchetypeIndex(), "The archetype index for %s has changed during its lifetime from %d to %d. Krehan and Landry have brought shame over their names.", entity->GetModelName(), archetypeIndex.Get(), m_pActiveListLink->item.GetArchetypeIndex().Get());
#endif // __ASSERT
g_SceneStreamerMgr.GetStreamingLists().GetActiveEntityList().RemoveEntity(m_pActiveListLink);
m_pActiveListLink = NULL;
}
}
//
//
//
//
fwCustomShaderEffect* CEntityDrawHandler::ShaderEffectCreateInstance(CBaseModelInfo *pModelInfo, CEntity *pEntity)
{
static sysSpinLockToken sSpinlock; //has to be static or global to be shared by threads
fwCustomShaderEffect *ret=NULL;
SYS_SPINLOCK_ENTER(sSpinlock);
CCustomShaderEffectBaseType *pMasterShaderEffectType = pModelInfo->GetCustomShaderEffectType();
if(pMasterShaderEffectType)
{
this->m_pShaderEffect = pMasterShaderEffectType->CreateInstance(pEntity);
Assert(this->m_pShaderEffect);
ret=this->m_pShaderEffect;
}
SYS_SPINLOCK_EXIT(sSpinlock);
return(ret);
}
//
// called just before Draw():
//
void CEntityDrawHandler::BeforeAddToDrawList(fwEntity *pEntity, u32 modelIndex, u32 renderMode, u32 bucket, u32 bucketMask, fwDrawDataAddParams* pBaseParams, bool bAlwaysSetCSE)
{
DL_PF_FUNC( TotalBeforeAddToDrawList );
Assert(CSystem::IsThisThreadId(SYS_THREAD_UPDATE));
CDrawDataAddParams *pGTAParams = (CDrawDataAddParams *) pBaseParams;
#if __DEV
Assert(pGTAParams->m_Magic == CDrawDataAddParams::MAGIC); // Someone didn't create the subclassed version of fwDrawDataAddParams!
#endif // __DEV
CEntity *pGTAEntity = (CEntity *) pEntity;
#if DRAWABLESPU_STATS || DRAWABLE_STATS
DLC(CSetDrawableStatContext, (pGTAEntity->GetDrawableStatsContext()));
#endif
bool runCSE = IsRenderingModes((eRenderMode)renderMode, rmStandard|rmSimpleDistFade);
runCSE |= (renderMode == rmSpecial && pEntity->IsBaseFlagSet(fwEntity::SUPPRESS_ALPHA) && bucket == CRenderer::RB_ALPHA );
// Don't run CSE during the water pass.
runCSE &= (bucket != CRenderer::RB_WATER);
if(m_pShaderEffect && runCSE)
{
// no standard CBs when local shaders variables may be present
CCustomShaderEffectBase* pCse = static_cast<CCustomShaderEffectBase*>(this->m_pShaderEffect);
pCse->AddToDrawList(modelIndex, true);
}
else if (bAlwaysSetCSE)
{
DLC(CCustomShaderEffectDC, (NULL)); // reset latest shader effect command
}
if (!DRAWLISTMGR->IsBuildingShadowDrawList())
{
// Only use local lights if this is not a cable (cables are not affected by local lights)
bool bUseLightsInArea = pGTAParams->m_SetupLights;
if(m_pShaderEffect && (m_pShaderEffect->GetType() == CSE_CABLE))
{
bool bLitCable = ((CCustomShaderEffectCable*)m_pShaderEffect)->IsLitCable() BANK_ONLY(&& DebugLights::m_cablesCanUseLocalLights);
if(!bLitCable)
{
bUseLightsInArea = false;
}
}
// If we're supposed to set up the closest lights for the shader, do so.
SetupLightsAndGlobalInInteriorFlag(pGTAEntity, renderMode, bucketMask, bUseLightsInArea);
}
}
//
//
//
//
void CEntityDrawHandler::AfterAddToDrawList(fwEntity *pEntity, u32 renderMode, fwDrawDataAddParams* pBaseParams)
{
DL_PF_FUNC( TotalAfterAddToDrawList );
Assert(CSystem::IsThisThreadId(SYS_THREAD_UPDATE));
if (!DRAWLISTMGR->IsBuildingShadowDrawList())
{
CEntity *pGTAEntity = (CEntity *) pEntity;
CDrawDataAddParams *pGTAParams = (CDrawDataAddParams *) pBaseParams;
// Only use local lights if this is not a cable (cables are not affected by local lights)
bool bUseLightsInArea = pGTAParams->m_SetupLights;
if(m_pShaderEffect && (m_pShaderEffect->GetType() == CSE_CABLE))
{
bool bLitCable = ((CCustomShaderEffectCable*)m_pShaderEffect)->IsLitCable() BANK_ONLY(&& DebugLights::m_cablesCanUseLocalLights);
if(!bLitCable)
{
bUseLightsInArea = false;
}
}
ResetLightOverride(pGTAEntity, renderMode, bUseLightsInArea);
}
if(this->m_pShaderEffect)
{
CCustomShaderEffectBase* pCse = static_cast<CCustomShaderEffectBase*>(this->m_pShaderEffect);
pCse->AddToDrawListAfterDraw();
DLC(CCustomShaderEffectDC, (NULL)); // reset latest shader effect command
}
}
// CDrawEntityDC with no custom shaders
class CBasicEntityPrototype : public IDrawListPrototype
{
public:
virtual void* AddDataForEntity(CEntity * entity, const CEntityDrawHandler * drawHandler, void * data);
virtual void Draw(u32 batchSize, void * data);
virtual u32 SizeOfElement();
private:
struct Data
{
u32 fullMatrix : 1;
u32 padding : 31;
DrawListAddress entityDraw;
};
private:
static const u32 sm_ElementSize;
};
const u32 CBasicEntityPrototype::sm_ElementSize = sizeof(CBasicEntityPrototype::Data);
void* CBasicEntityPrototype::AddDataForEntity(CEntity * entity, const CEntityDrawHandler * UNUSED_PARAM(drawHandler), void * data)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
if(Unlikely(entity->GetTransform().GetTypeIdentifier() & fwTransform::TYPE_FULL_TRANSFORM_MASK))
{
dataStruct->fullMatrix = true;
dataStruct->entityDraw = CDrawEntityFmDC::SharedData(entity);
}
else
{
dataStruct->fullMatrix = false;
dataStruct->entityDraw = CDrawEntityDC::SharedData(entity);
}
return (char*)data + sm_ElementSize;
}
void CBasicEntityPrototype::Draw(u32 batchSize, void * data)
{
for(u32 batchIndex = 0; batchIndex < batchSize; ++batchIndex)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
if(dataStruct->fullMatrix)
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawDataFm), dataStruct->entityDraw);
CEntityDrawDataFm * entityDraw = static_cast<CEntityDrawDataFm*>(entityDrawData);
entityDraw->Draw();
}
else
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawData), dataStruct->entityDraw);
CEntityDrawData * entityDraw = static_cast<CEntityDrawData*>(entityDrawData);
entityDraw->Draw();
}
data = (char*)data + sm_ElementSize;
}
}
u32 CBasicEntityPrototype::SizeOfElement()
{
return sm_ElementSize;
}
// CDrawEntityDC with call to set interior flag and alternate alpha update
class CBasicEntityReflectionPrototype : public IDrawListPrototype
{
public:
virtual void* AddDataForEntity(CEntity * entity, const CEntityDrawHandler * drawHandler, void * data);
virtual void Draw(u32 batchSize, void * data);
virtual u32 SizeOfElement();
private:
struct Data
{
u32 fullMatrix : 1;
u32 altAlpha : 8;
u32 padding : 23;
DrawListAddress entityDraw;
};
private:
static const u32 sm_ElementSize;
};
const u32 CBasicEntityReflectionPrototype::sm_ElementSize = sizeof(CBasicEntityReflectionPrototype::Data);
void* CBasicEntityReflectionPrototype::AddDataForEntity(CEntity * entity, const CEntityDrawHandler * UNUSED_PARAM(drawHandler), void * data)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
// Alternate alpha
if (entity->GetLodData().IsSlod3())
{
Vector3 entityPos;
const float objectRadius = entity->GetBoundCentreAndRadius(entityPos);
const float sphereRadius = CRenderPhaseReflection::ms_lodRanges[LODTYPES_DEPTH_SLOD3][1];
const float fadeDist = objectRadius * 0.15f;
const float distToCamera = (entityPos - RCC_VECTOR3(CRenderPhaseReflection::ms_cameraPos)).Mag();
const float alphaValue = Saturate(((objectRadius + sphereRadius) - distToCamera) / fadeDist);
dataStruct->altAlpha = u32(alphaValue * 255.0f);
}
else
{
dataStruct->altAlpha = 255;
}
if(entity->GetTransform().GetTypeIdentifier() & fwTransform::TYPE_FULL_TRANSFORM_MASK)
{
dataStruct->fullMatrix = true;
dataStruct->entityDraw = CDrawEntityFmDC::SharedData(entity);
}
else
{
dataStruct->fullMatrix = false;
dataStruct->entityDraw = CDrawEntityDC::SharedData(entity);
}
return (char*)data + sm_ElementSize;
}
void CBasicEntityReflectionPrototype::Draw(u32 batchSize, void * data)
{
for(u32 batchIndex = 0; batchIndex < batchSize; ++batchIndex)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
const float a = CShaderLib::DivideBy255(dataStruct->altAlpha);
CShaderLib::SetGlobalAlpha(a);
if(dataStruct->fullMatrix)
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawDataFm), dataStruct->entityDraw);
CEntityDrawDataFm * entityDraw = static_cast<CEntityDrawDataFm*>(entityDrawData);
entityDraw->Draw();
}
else
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawData), dataStruct->entityDraw);
CEntityDrawData * entityDraw = static_cast<CEntityDrawData*>(entityDrawData);
entityDraw->Draw();
}
data = (char*)data + sm_ElementSize;
}
}
u32 CBasicEntityReflectionPrototype::SizeOfElement()
{
return sm_ElementSize;
}
// CDrawEntityDC with call to set interior flag
class CBasicEntityInteriorPrototype : public IDrawListPrototype
{
public:
virtual void* AddDataForEntity(CEntity * entity, const CEntityDrawHandler * drawHandler, void * data);
virtual void Draw(u32 batchSize, void * data);
virtual u32 SizeOfElement();
private:
struct Data
{
u32 fullMatrix : 1;
u32 padding : 31;
DrawListAddress entityDraw;
};
private:
static const u32 sm_ElementSize;
};
const u32 CBasicEntityInteriorPrototype::sm_ElementSize = sizeof(CBasicEntityInteriorPrototype::Data);
void* CBasicEntityInteriorPrototype::AddDataForEntity(CEntity * entity, const CEntityDrawHandler * UNUSED_PARAM(drawHandler), void * data)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
if(entity->GetTransform().GetTypeIdentifier() & fwTransform::TYPE_FULL_TRANSFORM_MASK)
{
dataStruct->fullMatrix = true;
dataStruct->entityDraw = CDrawEntityFmDC::SharedData(entity);
}
else
{
dataStruct->fullMatrix = false;
dataStruct->entityDraw = CDrawEntityDC::SharedData(entity);
}
return (char*)data + sm_ElementSize;
}
void CBasicEntityInteriorPrototype::Draw(u32 batchSize, void * data)
{
for(u32 batchIndex = 0; batchIndex < batchSize; ++batchIndex)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
if(dataStruct->fullMatrix)
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawDataFm), dataStruct->entityDraw);
CEntityDrawDataFm * entityDraw = static_cast<CEntityDrawDataFm*>(entityDrawData);
entityDraw->Draw();
}
else
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawData), dataStruct->entityDraw);
CEntityDrawData * entityDraw = static_cast<CEntityDrawData*>(entityDrawData);
entityDraw->Draw();
}
data = (char*)data + sm_ElementSize;
}
}
u32 CBasicEntityInteriorPrototype::SizeOfElement()
{
return sm_ElementSize;
}
// shader effect tree with optional tint and draw entity full matrix
class CTreePrototype : public IDrawListPrototype
{
public:
virtual void* AddDataForEntity(CEntity * entity, const CEntityDrawHandler * drawHandler, void * data);
virtual void Draw(u32 batchSize, void * data);
virtual u32 SizeOfElement();
private:
struct Data
{
u32 modelIndex : 16;
u32 fullMatrix : 1;
u32 padding : 15;
DrawListAddress treeShader;
DrawListAddress tintShader;
DrawListAddress entityDraw;
};
private:
static const u32 sm_ElementSize;
};
const u32 CTreePrototype::sm_ElementSize = sizeof(CTreePrototype::Data);
void* CTreePrototype::AddDataForEntity(CEntity * entity, const CEntityDrawHandler * drawHandler, void * data)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
dataStruct->modelIndex = entity->GetModelIndex();
CCustomShaderEffectBase * shaderEffect = static_cast<CCustomShaderEffectBase*>(drawHandler->GetShaderEffect());
if(shaderEffect)
{
shaderEffect->AddDataForPrototype(&dataStruct->treeShader);
}
if(entity->GetTransform().GetTypeIdentifier() & fwTransform::TYPE_FULL_TRANSFORM_MASK)
{
dataStruct->fullMatrix = 1;
dataStruct->entityDraw = CDrawEntityFmDC::SharedData(entity);
}
else
{
dataStruct->fullMatrix = 0;
dataStruct->entityDraw = CDrawEntityDC::SharedData(entity);
}
return (char*)data + sm_ElementSize;
}
BankBool sDontDrawNonInstancedTrees = false;
void CTreePrototype::Draw(u32 batchSize, void * data)
{
if(sDontDrawNonInstancedTrees)
return;
const bool isShadowDrawList = static_cast<CDrawListMgr*>(gDrawListMgr)->IsExecutingShadowDrawList();
if(isShadowDrawList)
{
CRenderPhaseCascadeShadowsInterface::SetRasterizerState(CSM_RS_TWO_SIDED);
}
CCustomShaderEffectTree::EnableShaderVarCaching(false);
bool bSetShaderVarCaching = false;
for(u32 batchIndex = 0; batchIndex < batchSize; ++batchIndex)
{
Data * dataStruct = reinterpret_cast<Data*>(data);
void * treeShaderData = gDCBuffer->GetDataBlock(sizeof(CCustomShaderEffectTree), dataStruct->treeShader);
#if __PS3
void * tintShaderData = dataStruct->tintShader.IsNULL() ? NULL : gDCBuffer->ResolveDrawListAddress(dataStruct->tintShader);
#else
void * tintShaderData = dataStruct->tintShader.IsNULL() ? NULL : gDCBuffer->GetDataBlock(sizeof(CCustomShaderEffectTint), dataStruct->tintShader);
#endif
if(treeShaderData)
{
CCustomShaderEffectTree * treeShader = static_cast<CCustomShaderEffectTree*>(treeShaderData);
rmcDrawable* pDrawable = NULL;
CBaseModelInfo* pMI = CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(dataStruct->modelIndex)));
Assert(pMI);
if (pMI)
{
pDrawable = pMI->GetDrawable();
if (pDrawable)
{
treeShader->SetShaderVariables(pDrawable);
if(Unlikely(!bSetShaderVarCaching))
{
CCustomShaderEffectTree::EnableShaderVarCaching(true);
bSetShaderVarCaching = true;
}
if(tintShaderData)
{
CCustomShaderEffectTint * tintShader = static_cast<CCustomShaderEffectTint*>(tintShaderData);
tintShader->SetShaderVariables(pDrawable);
}
}
}
if(dataStruct->fullMatrix)
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawDataFm), dataStruct->entityDraw);
CEntityDrawDataFm * entityDraw = static_cast<CEntityDrawDataFm*>(entityDrawData);
entityDraw->Draw();
}
else
{
void * entityDrawData = gDCBuffer->GetDataBlock(sizeof(CEntityDrawData), dataStruct->entityDraw);
CEntityDrawData * entityDraw = static_cast<CEntityDrawData*>(entityDrawData);
entityDraw->Draw();
}
data = (char*)data + sm_ElementSize;
}
// cleanup
#if TINT_PALETTE_SET_IN_EDGE
if(tintShaderData)
{
SPU_COMMAND(GTA4__SetTintDescriptor,0);
cmd->tintDescriptorPtr = NULL;
cmd->tintDescriptorCount = 0;
cmd->tintShaderIdx = 0x00;
}
#endif
}
CCustomShaderEffectTree::EnableShaderVarCaching(false);
if(isShadowDrawList)
{
CRenderPhaseCascadeShadowsInterface::RestoreRasterizerState();
}
}
u32 CTreePrototype::SizeOfElement()
{
return sm_ElementSize;
}
CBasicEntityPrototype g_BasicEntityPrototype;
CBasicEntityInteriorPrototype g_BasicEntityInteriorPrototype;
CBasicEntityReflectionPrototype g_BasicEntityReflectionPrototype;
CTreePrototype g_TreePrototype;
bool g_prototype_batch = true;
IDrawListPrototype * CDrawListPrototypeManager::ms_Prototype = NULL;
u32 CDrawListPrototypeManager::ms_TimeStamp = 0xFFFFFFFF;
// This is the "cursor" within our current batch. Our next instance will be written here.
u8* CDrawListPrototypeManager::ms_PageBuffer;
u8* CDrawListPrototypeManager::ms_BasePageBuffer;
// This is the beginning of the current batch.
u8* CDrawListPrototypeManager::ms_PageBufferCurrentStart;
u32 CDrawListPrototypeManager::ms_PageBufferSize = 2048;
// This is the beginning of the current batch.
DrawListAddress CDrawListPrototypeManager::ms_Address;
// This is the beginning of the current batch.
DrawListAddress CDrawListPrototypeManager::ms_BaseAddress;
#if __ASSERT
u32 CDrawListPrototypeManager::ms_PageCreationTimestamp;
#endif // __ASSERT
void CDrawListPrototypeManager::Flush(bool forceAllocateNewBuffer)
{
Assert(sysThreadType::IsUpdateThread());
// Is there anything in the current batch?
if(ms_PageBuffer > ms_PageBufferCurrentStart)
{
Assertf((u32)(size_t)(ms_PageBuffer - ms_PageBufferCurrentStart) <= ms_PageBufferSize, "Prototype wrote outside page boundaries! Wrote %d bytes, buffer cursor %p, start %p", (u32)(size_t)(ms_PageBuffer - ms_PageBufferCurrentStart), ms_PageBuffer, ms_PageBufferCurrentStart);
Assertf(ms_PageCreationTimestamp == gDCBuffer->GetTimeStamp(), "Got stale prototype buffer - was created at %d, flushed at %d", ms_PageCreationTimestamp, gDCBuffer->GetTimeStamp());
// Send it off to the draw list. Let's find out how many elements there are.
u32 batchSize;
u32 dataSize = u32(ms_PageBuffer - ms_PageBufferCurrentStart);
batchSize = dataSize / ms_Prototype->SizeOfElement();
Assertf((dataSize % ms_Prototype->SizeOfElement()) == 0, "Error wrong batch size");
// Send off what we have so far.
DLC(CDrawPrototypeBatchDC, (ms_Prototype, batchSize, ms_Address));
// If we've exceeded the current page or if we're supposed to start a new page altogether,
// ditch the current one and create a new one.
if (ms_PageBuffer >= (ms_BasePageBuffer + ms_PageBufferSize) || forceAllocateNewBuffer)
{
AllocNewBuffer();
}
else
{
// Start a new batch within the page.
ms_Address.SetOffset(ms_Address.GetOffset() + dataSize);
ms_PageBufferCurrentStart = ms_PageBuffer;
Assertf(ms_PageBuffer == (u8*)gDCBuffer->ResolveDrawListAddress(ms_Address), "Addresses don't match up - expected %p, is %p", ms_PageBuffer, (u8*)gDCBuffer->ResolveDrawListAddress(ms_Address));
}
}
ms_Prototype = NULL;
}
void CEntityDrawHandler::SetupLightsAndGlobalInInteriorFlag(const CEntity* pEntity, u32 ASSERT_ONLY(renderMode), u32 bucketMask, bool bSetupLights)
{
bool bValidInterior = pEntity->GetInteriorLocation().IsValid();
const bool reflectionPhase =
gDrawListMgr->IsBuildingDrawList(DL_RENDERPHASE_REFLECTION_MAP) ||
gDrawListMgr->IsBuildingDrawList(DL_RENDERPHASE_WATER_REFLECTION) ||
gDrawListMgr->IsBuildingDrawList(DL_RENDERPHASE_MIRROR_REFLECTION);
if (bSetupLights)
{
Assert(renderMode != rmDebugMode);
spdAABB box = Lights::CalculatePartialDrawableBound( *pEntity, bucketMask, 0 );
DLC_Add( Lights::UseLightsInArea, box, bValidInterior, BANK_SWITCH(DebugDeferred::m_forceSetAll8Lights, false), reflectionPhase, false);
DLC_Add( CShaderLib::SetGlobalInInterior, bValidInterior );
if(pEntity->GetIsTypeObject())
if(static_cast< const CObject * >(pEntity)->GetUseLightOverride())
Lights::ApplyLightOveride(pEntity);
}
else if (DRAWLISTMGR->IsBuildingDrawSceneDrawList() || DRAWLISTMGR->IsBuildingGBufDrawList() || reflectionPhase)
{
DLC_Add( CShaderLib::SetGlobalInInterior, bValidInterior );
}
}
void CEntityDrawHandler::ResetLightOverride(const CEntity* pEntity, u32 ASSERT_ONLY(renderMode), bool bSetupLights)
{
if (bSetupLights)
{
Assert(renderMode != rmDebugMode);
if(pEntity->GetIsTypeObject())
if(static_cast< const CObject * >(pEntity)->GetUseLightOverride())
Lights::UnApplyLightOveride(pEntity);
}
}
#if __BANK
bool CEntityDrawHandler::ShouldSkipEntity(const CEntity* pEntity)
{
/*if (TiledScreenCapture::ShouldSkipEntity(pEntity))
return true;
else*/ if (SceneGeometryCapture::ShouldSkipEntity(pEntity))
return true;
else if (Unlikely(CEntity::ms_cullProps || CEntity::ms_renderOnlyProps))
{
if (pEntity && pEntity->GetBaseModelInfo() && pEntity->GetBaseModelInfo()->GetIsProp() && CEntity::ms_cullProps)
return true;
if (pEntity && pEntity->GetBaseModelInfo() && !pEntity->GetBaseModelInfo()->GetIsProp() && CEntity::ms_renderOnlyProps)
return true;
}
if(g_EnableSkipRenderingShaders)
{
rmcDrawable *pDrawable = pEntity->GetDrawable();
if(pDrawable)
{
grmShaderGroup *pShaderGroup = &pDrawable->GetShaderGroup();
if(pShaderGroup)
{
if(g_SkipRenderingGrassFur)
{
if( pShaderGroup->LookupShader("grass_fur") ||
pShaderGroup->LookupShader("grass_fur_mask") ||
pShaderGroup->LookupShader("grass_fur_tnt") )
{
return(true); // skip rendering
}
}
if(g_SkipRenderingTrees)
{
if( pShaderGroup->LookupShader("trees") ||
pShaderGroup->LookupShader("trees_camera_aligned") ||
pShaderGroup->LookupShader("trees_camera_facing") ||
pShaderGroup->LookupShader("trees_lod") ||
pShaderGroup->LookupShader("trees_lod_tnt") ||
pShaderGroup->LookupShader("trees_lod2") ||
pShaderGroup->LookupShader("trees_lod2d") ||
pShaderGroup->LookupShader("trees_normal") ||
pShaderGroup->LookupShader("trees_normal_diffspec") ||
pShaderGroup->LookupShader("trees_normal_diffspec_tnt") ||
pShaderGroup->LookupShader("trees_normal_spec") ||
pShaderGroup->LookupShader("trees_normal_spec_camera_aligned") ||
pShaderGroup->LookupShader("trees_normal_spec_camera_aligned_tnt") ||
pShaderGroup->LookupShader("trees_normal_spec_camera_facing") ||
pShaderGroup->LookupShader("trees_normal_spec_camera_facing_tnt") ||
pShaderGroup->LookupShader("trees_normal_spec_tnt") ||
pShaderGroup->LookupShader("trees_normal_spec_wind") ||
pShaderGroup->LookupShader("trees_shadow_proxy") ||
pShaderGroup->LookupShader("trees_tnt") )
{
return(true); // skip rendering
}
}
}
}
}// g_EnableSkipRenderingShaders...
return false;
}
#endif // __BANK
dlCmdBase* CEntityDrawHandler::AddBasicToDrawList(CEntityDrawHandler* pDrawHandler, fwEntity* pBaseEntity, fwDrawDataAddParams* pBaseParams ASSERT_ONLY(, bool bDoInstancedDataCheck))
{
DL_PF_FUNC( TotalAddToDrawList );
DL_PF_FUNC( EntityAddToDrawList );
CEntity* pEntity = static_cast<CEntity*>(pBaseEntity);
#if __BANK
if (ShouldSkipEntity(pEntity))
return NULL;
#endif // __BANK
Assert(pEntity->GetDrawHandlerPtr());
Assertf(!pEntity->m_nFlags.bIsFrag, "Someone changed the bIsFrag flag late!");
Assert(pEntity->GetBaseModelInfo());
Assertf(pEntity->GetBaseModelInfo()->GetNumRefs() > 0,"AddToDrawList %s but it has no refs. _Very_ dangerous", pEntity->GetBaseModelInfo()->GetModelName());
Assert(pDrawHandler->GetHasBones() == (pDrawHandler->GetDrawable() && pDrawHandler->GetDrawable()->GetSkeletonData() && (pDrawHandler->GetDrawable()->GetSkeletonData()->GetNumBones() > 1)));
if(pDrawHandler->GetHasBones())
{
return NULL;
}
#if __ASSERT
if(bDoInstancedDataCheck)
{
bool entityHasInstancedGeometry = false;
if(pEntity && pDrawHandler)
{
if(rmcDrawable *drawable = pDrawHandler->GetDrawable())
entityHasInstancedGeometry = drawable->HasInstancedGeometry();
}
Assert(!entityHasInstancedGeometry);
}
#endif
// We'll need the transform in CBasicEntityPrototype::AddDataForEntity(),
// and the archetype to get the model index in CEntityDrawData::Init().
// Prefetch these now to avoid hundreds, possibly thousands, of cache misses.
PrefetchDC(pEntity->GetTransformPtr());
PrefetchDC(pEntity->GetArchetype());
#if NORTH_CLOTHS && __ASSERT
bool bIsBendable = FALSE;
if(pEntity->GetIsTypeDummyObject())
{
CBaseModelInfo* pModel = pEntity->GetBaseModelInfo();
bIsBendable = (pModel->GetAttributes()==MODEL_ATTRIBUTE_IS_BENDABLE_PLANT);
}
Assert(!bIsBendable);
#endif // NORTH_CLOTHS
eRenderMode renderMode = DRAWLISTMGR->GetUpdateRenderMode();
IDrawListPrototype * prototype = NULL;
if(g_prototype_batch)
{
CDrawDataAddParams *pGTAParams = (CDrawDataAddParams *) pBaseParams;
#if __DEV
// Someone didn't create the subclassed version of fwDrawDataAddParams!
Assert(pGTAParams->m_Magic == CDrawDataAddParams::MAGIC);
#endif // __DEV
if (pGTAParams->m_SetupLights)
{
// no suitable prototypes
}
else if (gDrawListMgr->IsBuildingDrawList(DL_RENDERPHASE_REFLECTION_MAP))
{
if(pDrawHandler->GetShaderEffect() == NULL)
{
prototype = &g_BasicEntityReflectionPrototype;
}
}
else if (DRAWLISTMGR->IsBuildingDrawSceneDrawList() ||
gDrawListMgr->IsBuildingDrawList(DL_RENDERPHASE_MIRROR_REFLECTION))
{
if(pDrawHandler->GetShaderEffect() == NULL)
{
prototype = &g_BasicEntityInteriorPrototype;
}
}
else
{
if(pDrawHandler->GetShaderEffect() && renderMode == rmStandard)
{
if(pDrawHandler->GetShaderEffect()->GetType() == CSE_TREE)
{
//Cull trees intersecting the script vehicle hack...
if(CCustomShaderEffectGrass::IntersectsScriptFlattenAABB(pEntity))
return NULL;
prototype = &g_TreePrototype;
}
}
else
{
prototype = &g_BasicEntityPrototype;
}
}
}
CDrawListPrototypeManager::SetPrototype(prototype);
if(prototype)
{
CDrawListPrototypeManager::AddData(pEntity, pDrawHandler);
}
else
{
u32 bucket = DRAWLISTMGR->GetUpdateBucket();
u32 bucketMask = DRAWLISTMGR->GetUpdateBucketMask();
pDrawHandler->BeforeAddToDrawList(pEntity, pEntity->GetModelIndex(), renderMode, bucket, bucketMask, pBaseParams);
if(pEntity->GetTransform().GetTypeIdentifier() & fwTransform::TYPE_FULL_TRANSFORM_MASK)
{
DLC(CDrawEntityFmDC, (pEntity));
}
else
{
DLC(CDrawEntityDC, (pEntity));
}
pDrawHandler->AfterAddToDrawList(pEntity, renderMode, pBaseParams);
}
// nothing needs the return value for this type atm
return NULL;
}
dlCmdBase* CEntityDrawHandler::AddFragmentToDrawList(CEntityDrawHandler* pDrawHandler, fwEntity* pBaseEntity, fwDrawDataAddParams* pBaseParams ASSERT_ONLY(, bool bDoInstancedDataCheck))
{
DL_PF_FUNC( TotalAddToDrawList );
DL_PF_FUNC( FragAddToDrawList );
CEntity* pEntity = static_cast<CEntity*>(pBaseEntity);
Assertf(pEntity->m_nFlags.bIsFrag, "Someone changed the bIsFrag flag late!");
#if __BANK
if (ShouldSkipEntity(pEntity))
return NULL;
#endif // __BANK
#if __ASSERT
if(bDoInstancedDataCheck)
{
bool entityHasInstancedGeometry = false;
if(pEntity && pDrawHandler)
{
if(rmcDrawable *drawable = pDrawHandler->GetDrawable())
entityHasInstancedGeometry = drawable->HasInstancedGeometry();
}
Assert(!entityHasInstancedGeometry);
}
#endif
u32 modelIndex = pEntity->GetModelIndex();
#if __DEV
CBaseModelInfo* pModelInfo = pEntity->GetBaseModelInfo();
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"AddToDrawList %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
#endif //__DEV
#if NORTH_CLOTHS && __ASSERT
bool bIsBendable = FALSE;
if(pEntity->GetIsTypeDummyObject())
{
CBaseModelInfo* pModel = pEntity->GetBaseModelInfo();
bIsBendable = (pModel->GetAttributes()==MODEL_ATTRIBUTE_IS_BENDABLE_PLANT);
}
Assert(!bIsBendable);
#endif // NORTH_CLOTHS
eRenderMode renderMode = DRAWLISTMGR->GetUpdateRenderMode(); // get the render mode for the list we are building
u32 bucket = DRAWLISTMGR->GetUpdateBucket();
u32 bucketMask = DRAWLISTMGR->GetUpdateBucketMask();
pDrawHandler->BeforeAddToDrawList(pEntity, modelIndex, renderMode, bucket, bucketMask, pBaseParams, true);
CBaseModelInfo* pMI = pEntity->GetBaseModelInfo();
Assert(pMI);
// don't allow peds onto the drawlist as frag objects!
fragInst* pFragInst = pEntity->GetFragInst();
rmcDrawable *pClothDrawable = NULL;
environmentCloth* pEnvCloth = NULL;
if( pFragInst )
{
bool captureStats = false;
BANK_ONLY(captureStats = (g_PickerManager.GetSelectedEntity() == pBaseEntity);)
// Search for a cloth drawable
fragCacheEntry *cacheEntry = pFragInst->GetCacheEntry();
if( cacheEntry )
{
fragHierarchyInst* hierInst = cacheEntry->GetHierInst();
Assertf(hierInst,"No HierInst on a cached frag");
pEnvCloth = hierInst->envCloth;
if( pEnvCloth )
pClothDrawable = pEnvCloth->GetDrawable();
}
// Draw a cloth ?
if( pClothDrawable )
{
#if __BANK
if( g_DrawCloth )
#endif // __BANK
{
Assert( pEnvCloth );
gDrawListMgr->AddClothReference(pEnvCloth);
// Set material to trees to get back lighting to work
u8 matid = pEntity->GetDeferredMaterial();
if ((matid&DEFERRED_MATERIAL_CLEAR)==0){
matid = (matid&~DEFERRED_MATERIAL_CLEAR) |DEFERRED_MATERIAL_TREE;
}
Vector3 v = VEC3V_TO_VECTOR3(pEnvCloth->GetOffset());
grcDepthStencilStateHandle DSS = static_cast<CDrawListMgr*>(gDrawListMgr)->IsBuildingMirrorReflectionDrawList() ? CPhysics::GetClothManager()->GetInvertPassDSS() : CPhysics::GetClothManager()->GetPassDSS();
DLC( dlCmdDrawTwoSidedDrawable, (pClothDrawable, v, modelIndex, 255, pEntity->GetNaturalAmbientScale(), pEntity->GetArtificialAmbientScale(), matid, pEntity->GetInteriorLocation().IsValid(), CPhysics::GetClothManager()->GetPassRS(), DSS, captureStats, false, false, pEntity));
}
}
else if (pFragInst->GetType()->GetNumEnvCloths() == 0 && pMI->GetModelType() != MI_TYPE_PED)
{
// No cloth, no peds.
#if ENABLE_FRAG_OPTIMIZATION
if(pMI->GetModelType() == MI_TYPE_VEHICLE)
{
DLC(CDrawFragTypeVehicleDC, (pEntity));
}
else
#endif // ENABLE_FRAG_OPTIMIZATION
{
DLC(CDrawFragTypeDC, (pEntity));
}
}
}
else
{
DLC(CDrawFragTypeDC, (pEntity));
}
pDrawHandler->AfterAddToDrawList(pEntity, renderMode, pBaseParams);
// nothing needs the return value for this type atm
return NULL;
}
dlCmdBase* CEntityDrawHandler::AddBendableToDrawList(CEntityDrawHandler* pDrawHandler, fwEntity* pBaseEntity, fwDrawDataAddParams* pBaseParams ASSERT_ONLY(, bool bDoInstancedDataCheck))
{
DL_PF_FUNC( TotalAddToDrawList );
DL_PF_FUNC( BendableAddToDrawList );
CEntity* pEntity = static_cast<CEntity*>(pBaseEntity);
#if __BANK
if (ShouldSkipEntity(pEntity))
return NULL;
#endif // __BANK
#if __ASSERT
if(bDoInstancedDataCheck)
{
bool entityHasInstancedGeometry = false;
if(pEntity && pDrawHandler)
{
if(rmcDrawable *drawable = pDrawHandler->GetDrawable())
entityHasInstancedGeometry = drawable->HasInstancedGeometry();
}
Assert(!entityHasInstancedGeometry);
}
#endif
u32 modelIndex = pEntity->GetModelIndex();
#if __DEV
CBaseModelInfo* pModelInfo = pEntity->GetBaseModelInfo();
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"AddToDrawList %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
#endif //__DEV
#if NORTH_CLOTHS && __ASSERT
bool bIsBendable = FALSE;
if(pEntity->GetIsTypeDummyObject())
{
CBaseModelInfo* pModel = CModelInfo::GetBaseModelInfo(fwModelId(modelIndex));
bIsBendable = (pModel->GetAttributes()==MODEL_ATTRIBUTE_IS_BENDABLE_PLANT);
}
Assert(bIsBendable);
#endif // NORTH_CLOTHS
eRenderMode renderMode = DRAWLISTMGR->GetUpdateRenderMode(); // get the render mode for the list we are building
u32 bucket = DRAWLISTMGR->GetUpdateBucket();
u32 bucketMask = DRAWLISTMGR->GetUpdateBucketMask();
pDrawHandler->BeforeAddToDrawList(pEntity, modelIndex, renderMode, bucket, bucketMask, pBaseParams);
#if NORTH_CLOTHS
rmcLodGroup &lodGroup = pDrawHandler->GetDrawable()->GetLodGroup();
if(lodGroup.ContainsLod(LOD_MED))
{
DLC(CDrawEntityDC, (pEntity, 1)); // Bendables: draw entity as non-skinned LOD1
}
#endif //NORTH_CLOTHS...
pDrawHandler->AfterAddToDrawList(pEntity, renderMode, pBaseParams);
// nothing needs the return value for this type atm
return NULL;
}
dlCmdBase* CEntityInstancedBasicDrawHandler::AddToDrawList(fwEntity* pBaseEntity, fwDrawDataAddParams* pParams)
{
CEntity* pEntity = static_cast<CEntity*>(pBaseEntity);
if(g_InstancedBatcher.AddInstancedData(pEntity, this))
return NULL;
return CEntityDrawHandler::AddBasicToDrawList(this, pEntity, pParams ASSERT_ONLY(, false));
}
dlCmdBase* CEntityInstancedFragDrawHandler::AddToDrawList(fwEntity* pBaseEntity, fwDrawDataAddParams* pParams)
{
CEntity* pEntity = static_cast<CEntity*>(pBaseEntity);
if(g_InstancedBatcher.AddInstancedData(pEntity, this))
return NULL;
CDrawListPrototypeManager::Flush();
return CEntityDrawHandler::AddFragmentToDrawList(this, pEntity, pParams ASSERT_ONLY(, false));
}
dlCmdBase* CEntityInstancedBendableDrawHandler::AddToDrawList(fwEntity* pBaseEntity, fwDrawDataAddParams* pParams)
{
CEntity* pEntity = static_cast<CEntity*>(pBaseEntity);
if(g_InstancedBatcher.AddInstancedData(pEntity, this))
return NULL;
CDrawListPrototypeManager::Flush();
return CEntityDrawHandler::AddBendableToDrawList(this, pEntity, pParams ASSERT_ONLY(, false));
}