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

3047 lines
103 KiB
C++

//
// FILE : DrawableDataStructs.cpp
// PURPOSE : structs to establish data required to draw entities. effectively handles the extraction of necessary data from
// entity type objects to create drawable data type objects which are wholly independent of the entity.
// AUTHOR : john.
// CREATED : 1/06/2009
//
/////////////////////////////////////////////////////////////////////////////////
// rage headers
#include "breakableglass/bgdrawable.h"
#include "fragment/tune.h"
#if __BANK
#include "fwdebug/picker.h"
#endif // __BANK
#include "fwscene/stores/drawablestore.h"
#include "fwscene/stores/fragmentstore.h"
#include "fwtl/pool.h"
#include "vector/quaternion.h"
#include "fwrenderer/instancing.h"
#include "entity/camerarelativeextension.h"
#if __DEV
#include "rmcore/lodgroup.h"
#endif // __DEV
//game headers
#include "camera/CamInterface.h"
#include "debug/Rendering/DebugDeferred.h"
#include "grmodel/matrixset.h"
#include "ModelInfo/ModelInfo.h"
#include "ModelInfo/ModelInfo_Factories.h"
#include "modelinfo/PedModelInfo.h"
#include "peds/Ped.h"
#include "peds/PedTuning.h"
#include "peds/rendering/PedVariationStream.h"
#include "peds/rendering/PedVariationPack.h"
#include "physics/breakable.h"
#include "renderer/Debug/EntitySelect.h"
#include "renderer/Deferred/DeferredLighting.h"
#include "renderer/DrawLists/DrawableDataStructs.h"
#include "renderer/DrawLists/drawList.h"
#include "renderer/Entities/PedDrawHandler.h"
#include "renderer/Entities/EntityBatchDrawHandler.h"
#include "renderer/RenderPhases/RenderPhaseDebugOverlay.h"
#include "renderer/RenderPhases/RenderPhaseWaterReflection.h"
#include "renderer/RenderPhases/RenderPhaseCascadeShadows.h"
#include "renderer/RenderPhases/RenderPhaseFX.h"
#include "scene/debug/PostScanDebug.h"
#include "scene/Entity.h"
#include "scene/EntityBatch.h"
#include "scene/lod/LodScale.h"
#include "scene/lod/LodDrawable.h"
#include "scene/world/GameWorld.h"
#include "shaders/CustomShaderEffectGrass.h"
#include "shaders/CustomShaderEffectVehicle.h"
#include "shaders/CustomShaderEffectPed.h"
#include "Vehicles/VehicleFactory.h"
#include "vfx/decal/DecalManager.h"
#if __PPU
#include "rmcore/drawablespu.h"
#endif
#define PROFILE_DATASTRUCTS 0
#if PROFILE_DATASTRUCTS
#include "profile/element.h"
PF_PAGE(DrawableDataStructs_Init_Page, "Drawable Data Structures Init()");
PF_GROUP(EntityDrawData_Init_Group);
PF_LINK(DrawableDataStructs_Init_Page, EntityDrawData_Init_Group);
PF_TIMER(EntityDrawData__Init, EntityDrawData_Init_Group);
PF_PAGE(DrawableDataStructs_Draw_Page, "Drawable Data Structures Draw()");
PF_GROUP(EntityDrawData_Draw_Group);
PF_LINK(DrawableDataStructs_Draw_Page, EntityDrawData_Draw_Group);
PF_TIMER(EntityDrawDataSimple__Draw, EntityDrawData_Draw_Group);
PF_TIMER(EntityDrawDataFM__Draw, EntityDrawData_Draw_Group);
PF_PAGE(DrawableDataStructs_Count_Init_Page, "Drawable Data Structures Init Count");
PF_GROUP(EntityDrawData_Init_Count_Group);
PF_LINK(DrawableDataStructs_Count_Init_Page, EntityDrawData_Init_Count_Group);
PF_COUNTER(EntityDrawDataSimpleCount__Init, EntityDrawData_Init_Count_Group);
PF_COUNTER(EntityDrawDataFMCount__Init, EntityDrawData_Init_Count_Group);
#endif
RENDER_OPTIMISATIONS();
PF_PAGE(DrawableDataStructs_Page, "Validate Str Indices Cache");
PF_GROUP(DrawableDataStructs_Group);
PF_LINK(DrawableDataStructs_Page, DrawableDataStructs_Group);
#if __BANK
// Set this to true to add GCM/PIX markers for every model that is being rendered
bool g_AddModelGcmMarkers = false;
inline void BeginModelGcmMarker(const CBaseModelInfo *pModelInfo)
{
if (g_AddModelGcmMarkers)
{
const char *name = pModelInfo->GetModelName();
PIXBegin(0, name);
}
DEV_ONLY(rmcLodGroup::debugRenderModel = pModelInfo->GetModelName());
}
inline void EndModelGcmMarker()
{
if (g_AddModelGcmMarkers)
{
PIXEnd();
}
}
#else // __BANK
__forceinline void BeginModelGcmMarker(const CBaseModelInfo * /*pModelInfo*/) {}
__forceinline void EndModelGcmMarker() {}
#endif // __BANK
#if __DEV
inline void ValidateStreamingIndexCache(fwModelId modelId, CBaseModelInfo* ASSERT_ONLY(pModelInfo))
{
if (dlDrawListMgr::StrIndicesValidationEnabled())
{
strStreamingModule* streamingModule = fwArchetypeManager::GetStreamingModule();
s32 objIndex = modelId.ConvertToStreamingIndex().Get();
Assertf(gDrawListMgr->ValidateModuleIndexHasBeenCached(objIndex, streamingModule), "Failed to find cached streaming index for %s", pModelInfo->GetModelName());
}
}
#else // __DEV
__forceinline void ValidateStreamingIndexCache(fwModelId, CBaseModelInfo*) {}
#endif // __DEV
__forceinline u32 AdjustAlpha(u32 alpha, bool shouldForceAlphaForWaterReflection)
{
#if __BANK
if (Unlikely(CPostScanDebug::GetOverrideGBufBitsEnabled()))
{
if (CPostScanDebug::GetOverrideGBufVisibilityType() == VIS_PHASE_WATER_REFLECTION)
{
if (gDrawListMgr->IsExecutingDrawList(DL_RENDERPHASE_GBUF) ||
gDrawListMgr->IsExecutingDrawList(DL_RENDERPHASE_DRAWSCENE) ||
gDrawListMgr->IsExecutingDrawList(DL_RENDERPHASE_DEBUG) ||
gDrawListMgr->IsExecutingDrawList(DL_RENDERPHASE_DEBUG_OVERLAY))
{
if (shouldForceAlphaForWaterReflection)
{
return LODTYPES_ALPHA_VISIBLE;
}
}
}
}
#endif // __BANK
// Usual case is not shouldForceAlpha == false, so check that first so we
// can avoid both the call to IsExecutingDrawList() and the branch misprediction.
if (gDrawListMgr->IsExecutingDrawList(DL_RENDERPHASE_REFLECTION_MAP))
{
return LODTYPES_ALPHA_VISIBLE;
}
if (!shouldForceAlphaForWaterReflection || !gDrawListMgr->IsExecutingDrawList(DL_RENDERPHASE_WATER_REFLECTION))
{
return alpha;
}
// this causes SLOD3's etc. to cover up the LODs unfortunately, but
// without it we can't render lower LODs in place of higher LODs ..
return LODTYPES_ALPHA_VISIBLE;
}
/***************************** CEntityDrawDataCommon definitions *****************************/
#if __BANK
void CEntityDrawDataCommon::InitFromEntity(fwEntity* pEntity)
{
#if ENTITYSELECT_ENABLED_BUILD
m_entityId = CEntityIDHelper::ComputeEntityID(pEntity);
#endif // ENTITYSELECT_ENABLED_BUILD
#if __PS3
m_contextStats = static_cast<CEntity*>(pEntity)->GetDrawableStatsContext();
#endif // __PS3
m_captureStats = g_PickerManager.GetIndexOfEntityWithinResultsArray(pEntity) > -1;
}
bool CEntityDrawDataCommon::SetShaderParams(int renderBucket)
{
return SetShaderParamsStatic(m_entityId, renderBucket);
}
bool CEntityDrawDataCommon::SetShaderParamsStatic(entitySelectID ENTITYSELECT_ONLY(entityId), int ENTITYSELECT_ONLY(renderBucket))
{
#if ENTITYSELECT_ENABLED_BUILD
CEntitySelect::BindEntityIDShaderParam(entityId);
if (!CRenderPhaseDebugOverlayInterface::BindShaderParams(entityId, renderBucket))
{
return false; // don't draw
}
#endif // ENTITYSELECT_ENABLED_BUILD
return true;
}
u8 CEntityDrawDataCommon::GetContextStats() const
{
#if __PS3
return m_contextStats;
#else
return (u8)DRAWLISTMGR->GetDrawableStatContext();
#endif
}
#endif // __BANK
// CEntityDrawData relies on the following transforms being 32 bytes
CompileTimeAssert(sizeof(fwSimpleTransform) == 32);
CompileTimeAssert(sizeof(fwSimpleScaledTransform) == 32);
CompileTimeAssert(sizeof(fwIdentityTransform) == 16);
// initialise this type of drawable data from the entity
void CEntityDrawData::Init(CEntity *pEntity)
{
#if PROFILE_DATASTRUCTS
PF_FUNC(EntityDrawData__Init);
PF_INCREMENT(EntityDrawDataSimpleCount__Init);
#endif
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_fadeAlpha = pEntity->GetAlpha();
m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_allowAlphaBlend = !pEntity->IsBaseFlagSet(fwEntity::HAS_OPAQUE) && pEntity->IsBaseFlagSet(fwEntity::HAS_DECAL);
m_matID = pEntity->GetDeferredMaterial();
m_phaseLODs = pEntity->GetPhaseLODs();
m_lastLODIdx = pEntity->GetLastLODIdx();
m_interior = pEntity->GetInteriorLocation().IsValid();
#if __ASSERT
fwTransform::Type type = pEntity->GetTransform().GetTypeIdentifier();
FatalAssertf(type == fwTransform::TYPE_SIMPLE || type == fwTransform::TYPE_SIMPLE_SCALED || type == fwTransform::TYPE_IDENTITY, "Transform error - entity '%s' (%p) expected to have simple/identity transform, but has type %d", pEntity->GetModelName(), pEntity, type);
#endif
const __vector4 *pPackVector = reinterpret_cast<const __vector4*>(&pEntity->GetTransform());
m_vector0 = pPackVector[0];
m_vector1 = pPackVector[1];
m_fadeDist = pEntity->GetUseAltFadeDistance();
// Get the model index last - it needs to deref the archetype, and we've
// prefetched that some time ago - doing this last gives us some more time
// for it to come in.
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
Assert(pEntity->GetDrawHandlerPtr());
m_pDrawable = static_cast<CEntityDrawHandler&>(pEntity->GetDrawHandler()).GetDrawable();
}
void SubmitDrawTree( const Drawable* pDrawable, const Matrix34& mat, u32 bucketMask, int LODLevel, u16 drawableStat, bool isShadowPass )
{
// Cache previous state
const grcRasterizerStateHandle rs_prev = grcStateBlock::RS_Active;
// Either draw 2-Pass front & back or 1-Pass double-sided
const bool twoPassTrees = BANK_SWITCH(CRenderer::TwoPassTreeRenderingEnabled(), false);
if ( !twoPassTrees )
{
// Set front face culling
if (isShadowPass)
{
CRenderPhaseCascadeShadowsInterface::SetRasterizerState(CSM_RS_TWO_SIDED);
}
else
{
CShaderLib::SetFacingBackwards(false); //When face culling is disabled, trees will use VFACE register for proper normal flipping, so don't flip twice!
CShaderLib::SetDisableFaceCulling();
}
}
pDrawable->Draw(mat, bucketMask, LODLevel, drawableStat);
if(twoPassTrees)
{
if (isShadowPass){
CRenderPhaseCascadeShadowsInterface::SetRasterizerState(CSM_RS_CULL_FRONT);
}
else{
CShaderLib::SetFrontFaceCulling();
CShaderLib::SetFacingBackwards(CRenderer::TwoPassTreeNormalFlipping());
}
pDrawable->Draw(mat, bucketMask, LODLevel, drawableStat);
}
// Restore previous state
if (isShadowPass)
CRenderPhaseCascadeShadowsInterface::RestoreRasterizerState();
else{
grcStateBlock::SetRasterizerState(rs_prev);
CShaderLib::SetFacingBackwards(false);
}
}
static bank_float g_NearClipOverrideValue = 0.046f;
static bank_float g_FovOverrideValue = 50.0f;
#if __DEV
static bool g_bypass_CEntityDrawData = false;
static bool g_bypass_CEntityDrawDataFm = false;
static bool g_bypass_CEntityDrawDataStreamPed = false;
static bool g_bypass_CEntityDrawDataPedBIG = false;
static bool g_bypass_CEntityDrawDataBreakableGlass = false;
static bool g_bypass_CEntityDrawDataFragType = false;
static bool g_bypass_CEntityDrawDataSkinned = false;
static bool g_bypass_CEntityDrawDataFrag = false;
static bool g_bypass_CEntityDrawDataDetachedPedProp = false;
static bool g_bypass_CEntityDrawDataVehicleVar = false;
void InitBypassWidgets(bkBank& bk)
{
bk.PushGroup("DrawableDataStruct Bypass", false);
{
bk.AddToggle("g_bypass_CEntityDrawData ", &g_bypass_CEntityDrawData );
bk.AddToggle("g_bypass_CEntityDrawDataFm ", &g_bypass_CEntityDrawDataFm );
bk.AddToggle("g_bypass_CEntityDrawDataStreamPed ", &g_bypass_CEntityDrawDataStreamPed );
bk.AddToggle("g_bypass_CEntityDrawDataPedBIG ", &g_bypass_CEntityDrawDataPedBIG );
bk.AddToggle("g_bypass_CEntityDrawDataBreakableGlass ", &g_bypass_CEntityDrawDataBreakableGlass );
bk.AddToggle("g_bypass_CEntityDrawDataFragType ", &g_bypass_CEntityDrawDataFragType );
bk.AddToggle("g_bypass_CEntityDrawDataSkinned ", &g_bypass_CEntityDrawDataSkinned );
bk.AddToggle("g_bypass_CEntityDrawDataFrag ", &g_bypass_CEntityDrawDataFrag );
bk.AddToggle("g_bypass_CEntityDrawDataDetachedPedProp", &g_bypass_CEntityDrawDataDetachedPedProp);
bk.AddToggle("g_bypass_CEntityDrawDataVehicleVar ", &g_bypass_CEntityDrawDataVehicleVar );
}
bk.PopGroup();
}
#endif // __DEV
static bank_bool s_zTestFPV = false;
#if __BANK
void InitRenderWidgets(bkBank& bk)
{
bk.PushGroup("First Person");
{
bk.AddSlider("Near clip override value", &g_NearClipOverrideValue, 0.0f, 5.0f, 0.0001f);
bk.AddSlider("FOV override value", &g_FovOverrideValue, 1.0f, 180.0f, 0.1f);
bk.AddToggle("Z-test in FPV?", &s_zTestFPV);
}
bk.PopGroup();
}
#endif // __BANK
void SubmitDraw( const Drawable* pDrawable, const Matrix34& mat, u32 bucketMask, int LODLevel, u16 drawableStat, bool useTreeRendering, bool isShadowPass )
{
if ( useTreeRendering )
SubmitDrawTree(pDrawable, mat, bucketMask, LODLevel, drawableStat, isShadowPass );
else
pDrawable->Draw(mat, bucketMask, LODLevel, drawableStat);
}
#if __BANK
bool s_bShowLODAndCrossfades = false;
void DrawLODLevel(const Matrix34& matrix, s32 lodLevel1, u32 fade1, s32 lodLevel2, u32 fade2)
{
if (s_bShowLODAndCrossfades)
{
char LODLevel[64];
sprintf(LODLevel, "[(%d,%03d) : (%d,%03d)", lodLevel1, fade1, lodLevel2, fade2);
grcDebugDraw::Text(matrix.d + Vector3(0.f,0.f,1.3f), CRGBA(255, 255, 128, 255), LODLevel);
}
}
#endif // __BANK
__forceinline void EntityDraw( u32 modelInfoIdx,
const CBaseModelInfo* pModelInfo,
rmcDrawable* pDrawable,
#if RAGE_INSTANCED_TECH
u32 viewportInstancedRenderBit,
#endif
u32 fadeAlpha,
bool forceAlphaForWaterReflection,
bool allowAlphaBlend,
u32 naturalAmb,
u32 artificialAmb,
u32 matID,
bool forceMaterial,
const Matrix34 &matrix,
LODDrawable::crossFadeDistanceIdx fadeDist,
u32 phaseLODs,
u32 lastLODIdx,
bool isInterior,
bool noZTest,
bool noColourWrite
#if __BANK
,entitySelectID entityId
,u32 contextStats
,u32 captureStats
#endif // __BANK
)
{
{
BeginModelGcmMarker(pModelInfo);
u32 bucket = DRAWLISTMGR->GetRtBucket();
Assert(pDrawable == pModelInfo->GetDrawable());
if (pDrawable BANK_ONLY(&& CEntityDrawDataCommon::SetShaderParamsStatic(entityId, bucket) ))
{
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(captureStats);
if(captureStats)
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
#if __PPU
// Estimate the amount of GCM buffer space we might need, and reserve it once now.
const unsigned byteCount =
sizeof(spuCmd_grcEffect__SetGlobalFloatCommon) + sizeof(Vector4) // SetGlobal_Alpha_EmissiveScale_AmbientScale
+ 3*sizeof(spuCmd_grcEffect__SetDefaultRenderState) // SetGlobalDeferredMaterial, twice, and SetStippleAlpha
+ sizeof(spuCmd_rmcDrawable__Draw) // drawable draw
+ 64; // some slop
if (GCM_CONTEXT->current + byteCount/4 > GCM_CONTEXT->end)
GCM_CONTEXT->callback(GCM_CONTEXT, 0);
#endif
const u32 actualFadeAlpha = AdjustAlpha(fadeAlpha, forceAlphaForWaterReflection);
const eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
const u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
const bool isShadowDrawList = DRAWLISTMGR->IsExecutingShadowDrawList();
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool isHeightmapDrawList = DRAWLISTMGR->IsExecutingRainCollisionMapDrawList();
bool bDontWriteDepth = pModelInfo->GetDontWriteZBuffer() && (bucket == CRenderer::RB_ALPHA) && !isShadowDrawList;
const bool setAlpha = ( IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList ) ||
(isGBufferDrawList && allowAlphaBlend);
const bool setStipple = isGBufferDrawList && !allowAlphaBlend;
const bool crossFadeSetAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple) && !isGBufferDrawList;
const bool crossFadeSetStipple = isGBufferDrawList ;
const bool isTree = pModelInfo->GetIsTree();
const bool useTreeRendering = (isTree && (bucket == CRenderer::RB_CUTOUT)) && (CRenderer::TwoPassTreeShadowRenderingEnabled() || isGBufferDrawList);
const bool forceMaterialID = forceMaterial;
CShaderLib::SetGlobals((u8)naturalAmb, (u8)artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, noZTest, noColourWrite);
CShaderLib::SetGlobalDeferredMaterial(matID, forceMaterialID);
CShaderLib::SetGlobalInInterior(isInterior);
// detect models without LOD0, as it's fatal further down the pipeline:
Assertf(pDrawable->GetLodGroup().ContainsLod(LOD_HIGH), "Fatal: Object '%s' has no LOD0, which may crash the game!", pModelInfo->GetModelName());
u32 LODFlag = (phaseLODs >> DRAWLISTMGR->GetDrawListLODFlagShift()) & LODDrawable::LODFLAG_MASK;
u32 LODLevel = 0;
s32 crossFade = -1;
float dist = LODDrawable::CalcLODDistance(matrix.d);
if (LODFlag != LODDrawable::LODFLAG_NONE)
{
if (LODFlag & LODDrawable::LODFLAG_FORCE_LOD_LEVEL)
{
LODLevel = LODFlag & ~LODDrawable::LODFLAG_FORCE_LOD_LEVEL;
}
else
{
LODDrawable::CalcLODLevelAndCrossfadeForProxyLod(pDrawable, dist, LODFlag, LODLevel, crossFade, fadeDist, lastLODIdx);
}
}
else
{
LODDrawable::CalcLODLevelAndCrossfade(pDrawable, dist, LODLevel, crossFade, fadeDist, lastLODIdx ASSERT_ONLY(, pModelInfo) );
}
if ((LODFlag != LODDrawable::LODFLAG_NONE || isShadowDrawList || isHeightmapDrawList) && crossFade > -1)
{
if (crossFade < 128 && LODLevel+1 < LOD_COUNT && pDrawable->GetLodGroup().ContainsLod(LODLevel+1))
{
LODLevel = LODLevel+1;
}
crossFade = -1;
}
else if (actualFadeAlpha < 255) // Entity + cross fade fade: we can't deal with this, nuke crossFade
{
crossFade = -1;
}
DbgSetDrawableModelIdxForSpu((u16)modelInfoIdx);
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(viewportInstancedRenderBit);
#endif
if (HAS_RENDER_MODE_SHADOWS_ONLY(IsRenderingShadows(renderMode) ||) grmModel::GetForceShader())
{
#if !RAGE_SUPPORT_TESSELLATION_TECHNIQUES
pDrawable->DrawNoShaders(matrix, bucketMask, LODLevel);
#else
pDrawable->DrawNoShadersTessellationControlled(matrix, bucketMask, LODLevel);
#endif
}
else
{
#if __ASSERT
// trying to catch this assert in lodgroup.cpp earlier when we know which model it is
// "Not enough matrices in model. You probably tried to draw an articulated drawable without a skeleton."
if(pDrawable)
{
rmcLod &lod = pDrawable->GetLodGroup().GetLod(LOD_HIGH);
for(int i=0; i<lod.GetCount(); i++)
{
if(lod.GetModel(i))
{
grmModel &model = *lod.GetModel(i);
int idx = model.GetMatrixIndex();
Assertf(idx == 0, "%s:Entity(Building) is skinned or parented to more matricies that the 1 it's allowed", pModelInfo->GetModelName());
}
}
}
#endif // __ASSERT
#if __BANK
const bool bNeedsDepthStateRestore = DebugDeferred::StencilMaskOverlaySelectedBegin(captureStats != 0);
#endif // __BANK
// check if crossfading - need to render twice if so.
if ((renderMode==rmStandard || isGBufferDrawList) && crossFade > -1)
{
Assert(LODLevel+1 < LOD_COUNT && pDrawable->GetLodGroup().ContainsLod(LODLevel+1));
Assert(actualFadeAlpha == 255);
u32 fadeAlphaN1 = crossFade;
u32 fadeAlphaN2 = 255 - crossFade;
const bool dontWritedepthN1 = false;
const bool dontWritedepthN2 = false;
// cross fade ignore allowAlphaBlend flag...
#if !RSG_ORBIS && !RSG_DURANGO
s32 previousTechnique = -1;
bool techOverride = CShaderLib::UsesStippleFades() && isGBufferDrawList;
if (techOverride)
{
// On DX11 we can't use the D3DRS_MULTISAMPLEMASK for fade withough MSAA (as on 360) so for the fade pass.
// It needs to be manually inserted into the shader itself. For DX11, as we don't want to add it to
// all shaders, it's been added to the alphaclip passes and we force the technique here.
previousTechnique = grmShaderFx::GetForcedTechniqueGroupId();
if (previousTechnique == DeferredLighting::GetSSATechniqueGroup())
{
grmShaderFx::SetForcedTechniqueGroupId(DeferredLighting::GetSSAAlphaClipTechniqueGroup());
}
else
{
grmShaderFx::SetForcedTechniqueGroupId(DeferredLighting::GetAlphaClipTechniqueGroup());
}
}
#endif // !RSG_ORBIS
if (fadeAlphaN1 > 0)
{
CShaderLib::SetGlobals((u8)naturalAmb, (u8)artificialAmb, crossFadeSetAlpha, fadeAlphaN1, crossFadeSetStipple, false, fadeAlphaN1, dontWritedepthN1, false, false);
SubmitDraw( pDrawable, matrix, bucketMask, LODLevel, (u16)BANK_SWITCH_NT(contextStats,0), useTreeRendering, isShadowDrawList || isHeightmapDrawList);
}
if (fadeAlphaN2 > 0)
{
CShaderLib::SetGlobals((u8)naturalAmb, (u8)artificialAmb, crossFadeSetAlpha, fadeAlphaN2, crossFadeSetStipple, true, fadeAlphaN1, dontWritedepthN2, false, false);
SubmitDraw( pDrawable, matrix, bucketMask, LODLevel+1, (u16)BANK_SWITCH_NT(contextStats,0), useTreeRendering, isShadowDrawList || isHeightmapDrawList);
}
#if !RSG_ORBIS && !RSG_DURANGO
if (techOverride)
{
grmShaderFx::SetForcedTechniqueGroupId(previousTechnique);
}
#endif // !RSG_ORBIS
#if __BANK
if (isGBufferDrawList)
{
DrawLODLevel(matrix, LODLevel, fadeAlphaN1, LODLevel+1, fadeAlphaN2);
}
#endif // __BANK
}
else
{
#if !RSG_ORBIS && !RSG_DURANGO
s32 previousTechnique = -1;
bool techOverride = isTree && (actualFadeAlpha<255) && (bucket != CRenderer::RB_CUTOUT) && isGBufferDrawList && CShaderLib::UsesStippleFades() ;
if (techOverride)
{
// On DX11 we can't use the D3DRS_MULTISAMPLEMASK for fade withough MSAA (as on 360) so for the fade pass.
// It needs to be manually inserted into the shader itself. For DX11, as we don't want to add it to
// all shaders, it's been added to the alphaclip passes and we force the technique here.
previousTechnique = grmShaderFx::GetForcedTechniqueGroupId();
grmShaderFx::SetForcedTechniqueGroupId(DeferredLighting::GetAlphaClipTechniqueGroup());
}
#endif // !RSG_ORBIS && !RSG_DURANGO
if( noColourWrite )
{
SubmitDraw( pDrawable, matrix, CRenderer::GenerateBucketMask(CRenderer::RB_ALPHA), LODLevel, (u16)BANK_SWITCH_NT(contextStats,0), useTreeRendering, isShadowDrawList || isHeightmapDrawList);
}
else
{
SubmitDraw( pDrawable, matrix, bucketMask, LODLevel, (u16)BANK_SWITCH_NT(contextStats,0), useTreeRendering, isShadowDrawList || isHeightmapDrawList);
}
#if !RSG_ORBIS && !RSG_DURANGO
if (techOverride)
{
grmShaderFx::SetForcedTechniqueGroupId(previousTechnique);
}
#endif // !RSG_ORBIS && !RSG_DURANGO
#if __BANK
if (isGBufferDrawList)
{
DrawLODLevel(matrix, LODLevel, 255, 0, 999);
}
#endif // __BANK
}
#if __BANK
DebugDeferred::StencilMaskOverlaySelectedEnd(bNeedsDepthStateRestore);
#endif // __BANK
}
DbgCleanDrawableModelIdxForSpu();
// restore depth/stencil state
if (bDontWriteDepth)
{
CShaderLib::SetDefaultDepthStencilBlock();
}
if (noColourWrite)
{
CShaderLib::ResetBlendState();
}
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT);
CShaderLib::ResetAlpha(setAlpha || crossFadeSetAlpha, setStipple || crossFadeSetStipple);
#if DEBUG_ENTITY_GPU_COST
if(captureStats)
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(captureStats);
#endif
}//if(pDrawable)...
EndModelGcmMarker();
}
}
void CEntityDrawData::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawData) { return; })
#if PROFILE_DATASTRUCTS
PF_FUNC(EntityDrawDataSimple__Draw);
#endif
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(m_modelInfoIdx)));
PrefetchDC(pModelInfo);
Assert(pModelInfo);
if( pModelInfo )
{
Matrix34 matrix;
fwTransform *pTransform = reinterpret_cast<fwTransform*>(&m_vector0);
pTransform->GetNonOrthoMatrixCopy(reinterpret_cast<Mat34V&>(matrix));
#if WATER_REFLECTION_OFFSET_TRICK
if (DRAWLISTMGR && DRAWLISTMGR->IsExecutingWaterReflectionDrawList())
{
CRenderPhaseWaterReflectionInterface::ApplyWaterReflectionOffset(RC_VEC4V(matrix.d), m_modelInfoIdx);
}
#endif // WATER_REFLECTION_OFFSET_TRICK
LODDrawable::crossFadeDistanceIdx fadeDist = m_fadeDist ? LODDrawable::CFDIST_ALTERNATE : LODDrawable::CFDIST_MAIN;
EntityDraw(m_modelInfoIdx,
pModelInfo,
m_pDrawable,
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit,
#endif
m_fadeAlpha,
m_forceAlphaForWaterReflection,
m_allowAlphaBlend,
m_naturalAmb,
m_artificialAmb,
m_matID,
false,
matrix,
fadeDist,
m_phaseLODs,
m_lastLODIdx
,m_interior
,false
,false
#if __BANK
,m_commonData.GetEntityID()
,m_commonData.GetContextStats()
,m_commonData.GetCaptureStats()
#endif // __BANK
);
}
}
void CEntityDrawDataFm::Init(CEntity *pEntity)
{
#if PROFILE_DATASTRUCTS
PF_FUNC(EntityDrawData__Init);
PF_INCREMENT(EntityDrawDataFMCount__Init);
#endif
#if __ASSERT
fwTransform::Type type = pEntity->GetTransform().GetTypeIdentifier();
Assertf(type & fwTransform::TYPE_FULL_TRANSFORM_MASK, "Transform error - %s was expected to have a full transform, but has transform type %d",
pEntity->GetModelName(), type);
#endif
// Copy the matrix over first
pEntity->GetTransform().GetNonOrthoMatrixCopy(*reinterpret_cast<Mat34V*>(this));
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
#if RAGE_INSTANCED_TECH
m_pack0.m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
m_pack1.m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_pack1.m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_pack1.m_fadeAlpha = pEntity->GetAlpha();
m_pack2.m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_pack2.m_allowAlphaBlend = !pEntity->IsBaseFlagSet(fwEntity::HAS_OPAQUE) && pEntity->IsBaseFlagSet(fwEntity::HAS_DECAL);
m_pack2.m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_pack2.m_matID = pEntity->GetDeferredMaterial();
#if __BANK
#if ENTITYSELECT_ENABLED_BUILD
m_entityId = CEntityIDHelper::ComputeEntityID(pEntity);
#endif // ENTITYSELECT_ENABLED_BUILD
#if __PS3
m_pack2.m_contextStats = pEntity->GetDrawableStatsContext();
#endif // __PS3
m_pack2.m_captureStats = g_PickerManager.GetIndexOfEntityWithinResultsArray(pEntity) > -1;
#endif // __BANK
m_pack3.m_phaseLODs = pEntity->GetPhaseLODs();
m_pack3.m_fadeDist = pEntity->GetUseAltFadeDistance();
m_pack3.m_lastLODIdx = pEntity->GetLastLODIdx();
m_pack3.m_interior = pEntity->GetInteriorLocation().IsValid();
m_pack3.m_closeToCam = pEntity->IsExtremelyCloseToCamera();
m_pack3.m_fpv = pEntity->IsProtectedBaseFlagSet(fwEntity::HAS_FPV);
m_pack3.m_forceAlpha = pEntity->IsBaseFlagSet(fwEntity::FORCE_ALPHA);
}
// draw this data
void CEntityDrawDataFm::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawDataFm) { return; })
#if PROFILE_DATASTRUCTS
PF_FUNC(EntityDrawDataFM__Draw);
#endif
// unpack fields - grab model info index first, so we cna check if its non-null & prefetch it.
const u32 modelInfoIdx = m_pack1.m_modelInfoIdx;
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(modelInfoIdx)));
PrefetchDC(pModelInfo);
Assert(pModelInfo);
if( pModelInfo )
{
// unpack fields
#if RAGE_INSTANCED_TECH
u32 viewportInstanceRenderBit = m_pack0.m_viewportInstancedRenderBit;
#endif
u32 modelInfoIdx = m_pack1.m_modelInfoIdx;
u32 fadeAlpha = m_pack1.m_fadeAlpha;
u8 naturalAmb = m_pack1.m_naturalAmb;
u8 artificialAmb = m_pack2.m_artificialAmb;
u8 matID = m_pack2.m_matID;
bool forceMaterial = m_pack3.m_forceAlpha && DRAWLISTMGR->IsExecutingDrawSceneDrawList();
bool forceAlpha = m_pack2.m_forceAlphaForWaterReflection;
bool allowAlphaBlend = m_pack2.m_allowAlphaBlend;
u32 phaseLODs = m_pack3.m_phaseLODs;
u32 lastLODIdx = m_pack3.m_lastLODIdx;
bool isInterior = m_pack3.m_interior;
LODDrawable::crossFadeDistanceIdx fadeDist = m_pack3.m_fadeDist ? LODDrawable::CFDIST_ALTERNATE : LODDrawable::CFDIST_MAIN;
#if WATER_REFLECTION_OFFSET_TRICK
Matrix34 matrix = *reinterpret_cast<Matrix34*>(this);
if (DRAWLISTMGR && DRAWLISTMGR->IsExecutingWaterReflectionDrawList())
{
CRenderPhaseWaterReflectionInterface::ApplyWaterReflectionOffset(RC_VEC4V(matrix.d), modelInfoIdx);
}
#else
const Matrix34& matrix = *reinterpret_cast<Matrix34*>(this);
#endif
float prevNearClip = 0.0f;
if(m_pack3.m_closeToCam)
{
prevNearClip = grcViewport::GetCurrent()->GetNearClip();
grcViewport::GetCurrent()->SetNearClip(g_NearClipOverrideValue);
}
bool noTest = m_pack3.m_closeToCam;
if(m_pack3.m_closeToCam)
{
noTest = !s_zTestFPV;
}
// Use camera at the origin for FPV objects
grcViewport* pPreFPVViewport = NULL;
grcViewport fpsVp;
if(m_pack3.m_fpv && m_pack3.m_closeToCam && (DRAWLISTMGR->IsExecutingGBufDrawList() || DRAWLISTMGR->IsExecutingDrawSceneDrawList()))
{
fpsVp = *grcViewport::GetCurrent();
fpsVp.SetWorldIdentity();
fpsVp.Perspective(g_FovOverrideValue, fpsVp.GetAspectRatio(), fpsVp.GetNearClip(), fpsVp.GetFarClip());
Mat34V mat(fpsVp.GetCameraMtx());
mat.SetCol3(Vec3V(0.0f, 0.0f, 0.0f));
fpsVp.SetCameraMtx(mat);
pPreFPVViewport = grcViewport::SetCurrent(&fpsVp);
}
bool noColorWrite = false;
if(m_pack3.m_fpv && m_pack3.m_closeToCam && (DRAWLISTMGR->IsExecutingGBufDrawList()))
{
noColorWrite = true;
}
EntityDraw( modelInfoIdx,
pModelInfo,
pModelInfo->GetDrawable(),
#if RAGE_INSTANCED_TECH
viewportInstanceRenderBit,
#endif
fadeAlpha,
forceAlpha,
allowAlphaBlend,
naturalAmb,
artificialAmb,
matID,
forceMaterial,
matrix,
fadeDist,
phaseLODs,
lastLODIdx,
isInterior,
noTest,
noColorWrite
#if __BANK
,m_entityId
,PS3_SWITCH(m_pack2.m_contextStats, DRAWLISTMGR->GetDrawableStatContext())
,m_pack2.m_captureStats
#endif // __BANK
);
// Restore FPV viewport if needed
if(pPreFPVViewport)
{
grcViewport::SetCurrent(pPreFPVViewport);
}
if(m_pack3.m_closeToCam)
{
grcViewport::GetCurrent()->SetNearClip(prevNearClip);
}
}
}
void CEntityInstancedDrawData::Init(CEntity* pEntity, grcInstanceBuffer *ib, int lod)
{
#if __BANK
BANK_ONLY(m_commonData.InitFromEntity(pEntity));
//NOTE: This currently only works for entity batches. So if we're drawing normal instanced entities, reset common data so entity ID is invalid. (Rather then always selecting 1st entity in batch.)
// ENTITYSELECT_ONLY(m_commonData = pEntity->GetIsTypeInstanceList() ? m_commonData : CEntityDrawDataCommon());
#endif
//Per-model data
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
Assertf((lod & ~0xFF) == 0, "WARNING: LOD storage is 8 bits. Can not store supplied LOD of %d!", lod);
m_LODIndex = static_cast<u8>(lod);
m_matID = pEntity->GetDeferredMaterial();
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
//Per-instance data. (Already computed & packed for us.)
#if IB_ALLOW_DL_ALLOCATION
if(ib && ib->GetAllocationType() == grcInstanceBuffer::ALLOC_DRAWLIST)
{
m_HasDLAddress = true;
reinterpret_cast<DrawListAddress&>(m_IBAddr.InstanceBufferOffset) = static_cast<fwInstanceBuffer *>(ib)->GetDrawListAddress();
}
else
#endif // IB_ALLOW_DL_ALLOCATION
{
m_HasDLAddress = false;
m_IBAddr.InstanceBufferPtr = ib;
}
}
void CEntityInstancedDrawData::Draw()
{
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo *pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
if(Verifyf(pModelInfo, "NULL model returned from model info idx: %d", m_modelInfoIdx))
{
const u32 bucketMask = gDrawListMgr->GetRtBucketMask();
rmcDrawable *pDrawable = pModelInfo->GetDrawable();
if(pDrawable && Verifyf(pDrawable->GetLodGroup().ContainsLod(m_LODIndex), "WARNING: Instanced model '%s' doesn't seem to have LOD Level %d.", pModelInfo->GetModelName(), m_LODIndex))
{
// detect models without LOD0, as it's fatal further down the pipeline:
Assertf(pDrawable->GetLodGroup().ContainsLod(0), "Fatal: Object '%s' has no LOD0, which may crash the game!", pModelInfo->GetModelName()); //Necessary??
grcInstanceBuffer *ib = NULL;
#if IB_ALLOW_DL_ALLOCATION
if(m_HasDLAddress && !reinterpret_cast<DrawListAddress&>(m_IBAddr.InstanceBufferOffset).IsNULL())
{
static const u32 instBuffSize = static_cast<u32>(sizeof(fwInstanceBuffer));
ib = reinterpret_cast<grcInstanceBuffer *>(gDCBuffer->GetDataBlock(instBuffSize, reinterpret_cast<DrawListAddress&>(m_IBAddr.InstanceBufferOffset)));
}
else
#endif // IB_ALLOW_DL_ALLOCATION
{
ib = m_IBAddr.InstanceBufferPtr;
}
if(ib)
{
BANK_ONLY(m_commonData.SetShaderParams(DRAWLISTMGR->GetRtBucket()));
CShaderLib::SetGlobalDeferredMaterial(m_matID);
#if RAGE_INSTANCED_TECH
if (grcViewport::GetInstancing())
{
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
grcViewport::RegenerateInstVPMatrices(Mat44V(V_IDENTITY),(int)ib->GetCount());
}
#endif
pDrawable->DrawInstanced(ib, bucketMask, m_LODIndex);
}
}
}
}
void CGrassBatchDrawData::Init(CGrassBatch* pEntity)
{
BANK_ONLY(m_commonData.InitFromEntity(pEntity));
//Grass Batch Entity Data
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_fadeAlpha = pEntity->GetAlpha();
#if !GRASS_BATCH_CS_CULLING
m_LODIndex = pEntity->ComputeLod();
#endif
m_matID = pEntity->GetDeferredMaterial();
m_interior = pEntity->GetInteriorLocation().IsValid();
GRASS_BATCH_CS_CULLING_SWITCH(pEntity->GetCurrentCSParams(m_CSParams), m_vb = pEntity->GetInstanceVertexBuffer());
m_startInst = 0;
if(fwDrawData *dh = pEntity->GetDrawHandlerPtr())
{
if(CCustomShaderEffectGrass *cse = static_cast<CCustomShaderEffectGrass *>(dh->GetShaderEffect()))
{
float rv = cse->GetLodFadeInstRange().GetXf();
if (!DRAWLISTMGR->IsBuildingGBufDrawList())
{
float numInst = cse->GetLodFadeInstRange().GetZf();
rv = Min((numInst - rv) * CGrassBatch::GetShadowLODFactor() + rv, numInst-1.f);
}
m_startInst = static_cast<u32>(rv);
}
}
}
void CGrassBatchDrawData::Draw()
{
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo *pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
if(Verifyf(pModelInfo, "NULL model returned from model info idx: %d", m_modelInfoIdx))
{
rmcDrawable *pDrawable = pModelInfo->GetDrawable();
if(pDrawable)
{
BANK_ONLY(m_commonData.SetShaderParams(DRAWLISTMGR->GetRtBucket()));
CShaderLib::SetGlobals(static_cast<u8>(m_naturalAmb), static_cast<u8>(m_artificialAmb), true, m_fadeAlpha, false, false, m_fadeAlpha, false, false, false);
CShaderLib::SetGlobalDeferredMaterial(m_matID);
CShaderLib::SetGlobalInInterior(m_interior);
const u32 bucketMask = gDrawListMgr->GetRtBucketMask();
GRASS_BATCH_CS_CULLING_ONLY(bool isCSActive = m_CSParams.IsActive());
GRASS_BATCH_CS_CULLING_ONLY(int lodCount = isCSActive ? LOD_COUNT : 1);
GRASS_BATCH_CS_CULLING_ONLY(for(int i = 0; i < lodCount; ++i))
{
GRASS_BATCH_CS_DYNAMIC_BUFFERS_ONLY(if(m_CSParams.m_AppendBufferMem[i] || !isCSActive))
GRASS_BATCH_CS_PRE_ALLOCATE_BUFFERS_ONLY(if(m_CSParams.m_AppendInstBuffer[i] || !isCSActive))
{
int lod = static_cast<int>(GRASS_BATCH_CS_CULLING_SWITCH(m_CSParams.m_LODIdx + i, m_LODIndex));
CGrassBatchDrawHandler::DrawInstancedGrass(*pDrawable, GRASS_BATCH_CS_CULLING_SWITCH(m_CSParams, m_vb), bucketMask, lod, m_startInst);
}
}
//Free temp buffer
GRASS_BATCH_CS_DYNAMIC_BUFFERS_ONLY(if(isCSActive) m_CSParams.m_IndirectBufferMem.free());
CShaderLib::SetGlobalAlpha(1.0f);
}
}
}
void CGrassBatchDrawData::DispatchComputeShader()
{
#if GRASS_BATCH_CS_CULLING
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo *pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
if(Verifyf(pModelInfo, "NULL model returned from model info idx: %d", m_modelInfoIdx))
{
rmcDrawable *pDrawable = pModelInfo->GetDrawable();
if(pDrawable)
{
//Call to dispatch compute job.
CGrassBatchDrawHandler::DispatchComputeShader(*pDrawable, m_CSParams);
}
}
#endif //GRASS_BATCH_CS_CULLING
}
#if __WIN32PC
void CGrassBatchDrawData::CopyStructureCount()
{
CGrassBatchDrawHandler::CopyStructureCount(m_CSParams);
}
#endif
#if RAGE_INSTANCED_TECH
#if __BANK // Entity select Id alter sizes between __BANK and not.
CompileTimeAssert(sizeof(CEntityDrawDataFm) == 80);
CompileTimeAssert(sizeof(CEntityDrawData) == 80);
#else
CompileTimeAssert(sizeof(CEntityDrawDataFm) == 64);
CompileTimeAssert(sizeof(CEntityDrawData) == 64);
#endif
#else
CompileTimeAssert(sizeof(CEntityDrawDataFm) == 64);
// CompileTimeAssertSize(CEntityDrawData,0,0);
CompileTimeAssert(sizeof(CEntityDrawData) == (__BANK || __64BIT ? 64 : 48));
#endif
// EJ: Memory Optimization
const crSkeleton *GetSkeletonForDrawIgnoringDrawlist(const CEntity *entity);
void CEntityDrawDataPedPropsBase::Init(CEntity* pEntity, Matrix34* pMatrix, u32 boneCount, u32 matrixSetCount, s32* propDataIndices)
{
m_pPropGfxData = NULL;
if (pEntity->GetType() == ENTITY_TYPE_PED)
{
Assert(pEntity->GetIsTypePed());
// get the mtxs that the props are attached to
CPed* pPed = reinterpret_cast<CPed*>(pEntity);
m_pPropGfxData = pPed->GetPedDrawHandler().GetPedPropRenderGfx();
m_propData = pPed->GetPedDrawHandler().GetPropData();
CPedModelInfo* pModelInfo = static_cast<CPedModelInfo*>(pEntity->GetBaseModelInfo());
Assert(pModelInfo /*&& pModelInfo->GetIsStreamedGfx()*/);
s32 boneIdxs[MAX_PROPS_PER_PED];
ASSERT_ONLY(const u32 numProps =) CPedPropsMgr::GetPropBoneIdxs(boneIdxs, boneCount, pModelInfo->GetVarInfo(), pPed->GetPedDrawHandler().GetPropData(), propDataIndices);
Assert(numProps == boneCount);
// Matrix set idx 0: Default skeleton matrices (I.e. first person skeleton if in first person, else third person skeleton), world space
CPedPropsMgr::GetPropMatrices(pMatrix, pPed->GetSkeleton(), boneIdxs, boneCount, pPed->GetPedDrawHandler().GetPropData(), propDataIndices, false);
if(matrixSetCount > 1)
{
Assert(matrixSetCount == 3);
Assert(pEntity->IsProtectedBaseFlagSet(fwEntity::HAS_FPV));
const crSkeleton* pSkeleton = GetSkeletonForDrawIgnoringDrawlist(pPed);
Matrix34 camToPed;
fwCameraRelativeExtension* extension = pEntity->GetExtension<fwCameraRelativeExtension>();
if(extension)
{
camToPed.Inverse(RC_MATRIX34(extension->m_cameraOffset));
}
else
{
camToPed.Identity();
}
// Matrix set idx 1: Third person skeleton matrices, world space (For reflections, etc)
pMatrix += boneCount;
CPedPropsMgr::GetPropMatrices(pMatrix, pSkeleton, boneIdxs, boneCount, pPed->GetPedDrawHandler().GetPropData(), propDataIndices, false);
// Matrix set idx 2: First person skeleton matrices, local space (For props in first person)
pMatrix += boneCount;
CPedPropsMgr::GetPropMatrices(pMatrix, pPed->GetSkeleton(), boneIdxs, boneCount, pPed->GetPedDrawHandler().GetPropData(), propDataIndices, true);
// Transform bones into correct view space for first person
Mat34V camMtxV = RageCameraMtxToGameCameraMtx(dlCmdSetCurrentViewport::GetCurrentViewport_UpdateThread()->GetCameraMtx());
camMtxV.SetCol3(Vec3V(0.0f, 0.0f, 0.0f));
Matrix34 propsOffsetMtx;
propsOffsetMtx.Dot(camToPed, RC_MATRIX34(camMtxV));
for(u32 i=0; i<boneCount; ++i)
{
Matrix34 m;
m.Dot(pMatrix[i], propsOffsetMtx);
pMatrix[i] = m;
}
}
}
else if (pEntity->GetType() == ENTITY_TYPE_OBJECT)
{
m_pPropGfxData = CGameWorld::FindLocalPlayer()->GetPedDrawHandler().GetPedPropRenderGfx();
}
else
{
Assertf(false, "Unhandled type\n");
}
if (m_pPropGfxData)
m_pPropGfxData->AddRefsToGfx();
}
// initialise this type of drawable data from the entity
void CEntityDrawDataStreamPed::Init(CEntity *pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
#if __ASSERT
CPedModelInfo* pModelInfo = static_cast<CPedModelInfo*>(pEntity->GetBaseModelInfo());
Assert(pModelInfo);
// check that it is _really_ a streamed ped
if (!pModelInfo->GetIsStreamedGfx())
{
Assert(false);
}
#endif // __ASSERT
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_bIsInInterior = pEntity->GetInteriorLocation().IsValid();
m_fadeAlpha = pEntity->GetAlpha();
//m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_matID = pEntity->GetDeferredMaterial();
m_rootMatrix = MAT34V_TO_MATRIX34(pEntity->GetMatrix());
m_bIsFPV = false;
if(pEntity->IsProtectedBaseFlagSet(fwEntity::HAS_FPV))
{
fwCameraRelativeExtension* extension = pEntity->GetExtension<fwCameraRelativeExtension>();
if(extension)
{
m_rootMatrixFPV = RC_MATRIX34(extension->m_cameraOffset);
m_bIsFPV = true;
}
}
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
m_bAddToMotionBlurMask = pEntity->m_nFlags.bAddtoMotionBlurMask;
if (pEntity->GetType() == ENTITY_TYPE_PED)
{
Assert(pEntity->GetIsTypePed());
CPed* pPed = reinterpret_cast<CPed*>(pEntity);
m_pGfxData = pPed->GetPedDrawHandler().GetPedRenderGfx();
Assert(m_pGfxData);
m_pGfxData->AddRefsToGfx();
m_bIsFPSSwimming = pPed->GetIsFPSSwimming();
m_bBlockHideInFirstPersonFlag = pPed->GetPedResetFlag(CPED_RESET_FLAG_DisableHelmetCullFPS);
m_bSupportsHairTint = pPed->HasHeadBlend();
}
else if (pEntity->GetType() == ENTITY_TYPE_OBJECT)
{
m_pGfxData = CGameWorld::FindLocalPlayer()->GetPedDrawHandler().GetPedRenderGfx();
Assert(m_pGfxData);
m_pGfxData->AddRefsToGfx();
m_bIsFPSSwimming = false;
m_bBlockHideInFirstPersonFlag = false;
}
else
{
Assertf(false, "Unhandled type\n");
}
}
void CEntityDrawDataStreamPed::Draw(CAddCompositeSkeletonCommand& skeletonCmd, CEntityDrawDataPedPropsBase* pProps, u8 lodIdx, u32 perComponentWetness)
{
DEV_ONLY(if (g_bypass_CEntityDrawDataStreamPed) { return; })
eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
#if __BANK
u32 bucket = DRAWLISTMGR->GetRtBucket();
#endif
u16 contextStats = BANK_SWITCH_NT(m_commonData.GetContextStats(), 0);
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CPedModelInfo* pMI = static_cast<CPedModelInfo*>(CModelInfo::GetBaseModelInfo(modelId));
Assert(pMI);
Assertf(pMI->GetNumRefs() > 0,"Rendering %s but it has no refs. _Very_ dangerous", pMI->GetModelName());
Assertf(m_pGfxData, "m_pGfxData is NULL for Streamed Ped %s", pMI->GetModelName());
#if __DEV
if (dlDrawListMgr::StrIndicesValidationEnabled())
{
Assertf(m_pGfxData->ValidateStreamingIndexHasBeenCached(), "Stream Index not cached for Streamed Ped %s", pMI->GetModelName());
}
#endif
ValidateStreamingIndexCache(modelId, pMI);
BeginModelGcmMarker(pMI);
// extract the skeleton data from the drawable for this modelInfo
rmcDrawable* pDrawable = pMI->GetDrawable();
Assert(pDrawable);
if (pDrawable BANK_ONLY(&& m_commonData.SetShaderParams(bucket)))
{
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
u32 fadeAlpha = m_fadeAlpha;//AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool isGBufferOrSceneDrawList = isGBufferDrawList || DRAWLISTMGR->IsExecutingDrawSceneDrawList();
const bool bDontWriteDepth = false;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, fadeAlpha, setStipple, false, fadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalDeferredMaterial(m_matID);
CShaderLib::SetGlobalInInterior(m_bIsInInterior);
// Setup FPV viewport if required
grcViewport* pPreFPVViewport = NULL;
Matrix34 rootMatrix;
grcViewport fpsVp;
if(m_bIsFPV && isGBufferOrSceneDrawList)
{
fpsVp = *grcViewport::GetCurrent();
fpsVp.SetWorldIdentity();
Mat34V mat(fpsVp.GetCameraMtx());
mat.SetCol3(Vec3V(0.0f, 0.0f, 0.0f));
fpsVp.SetCameraMtx(mat);
pPreFPVViewport = grcViewport::SetCurrent(&fpsVp);
Mat34V cam = RageCameraMtxToGameCameraMtx(mat);
Matrix34 fpvInverse;
fpvInverse.Inverse(m_rootMatrixFPV);
rootMatrix.Dot(fpvInverse, RC_MATRIX34(cam));
}
else
rootMatrix = m_rootMatrix;
const bool isSeeThroughDrawList = DRAWLISTMGR->IsExecutingSeeThroughDrawList();
if (isSeeThroughDrawList)
{
RenderPhaseSeeThrough::SetGlobals();
}
CCustomShaderEffectBase* pShaderEffect = CCustomShaderEffectDC::GetLatestShader();
Assert(pShaderEffect);
Assert(dynamic_cast<CCustomShaderEffectPed*>(pShaderEffect) != NULL);
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
CCustomShaderEffectPed* pPedShaderEffect = NULL;
if (pShaderEffect){
pPedShaderEffect = static_cast<CCustomShaderEffectPed*>(pShaderEffect);
Assert(pDrawable->GetSkeletonData());
if (lodIdx >= pMI->GetNumAvailableLODs() && pMI->GetSuperlodType() == SLOD_KEEP_LOWEST)
lodIdx = pMI->GetNumAvailableLODs() - 1;
if (lodIdx < pMI->GetNumAvailableLODs())
{
CPedVariationStream::RenderPed(pMI, rootMatrix, skeletonCmd, m_pGfxData, pPedShaderEffect, bucketMask, renderMode, contextStats, lodIdx, perComponentWetness, m_bIsFPSSwimming, m_bIsFPV && isGBufferOrSceneDrawList, m_bAddToMotionBlurMask, m_bSupportsHairTint);
}
else
{
skeletonCmd.Execute(0); // superlod matrix set is copied into component 0, we need to set it as the current one before we render
CPedVariationPack::RenderSLODPed(rootMatrix, dlCmdAddCompositeSkeleton::GetCurrentMatrixSet(), bucketMask, renderMode, CCustomShaderEffectDC::GetLatestShader(), pMI->GetSuperlodType());
}
}
// draw props for player
if (pProps)
{
// If there's only one matrix set, use the first matrix set (Default skeleton)
if(pProps->GetNumMatrixSets() == 1)
{
CPedPropsMgr::RenderPropsInternal(pMI, rootMatrix, pProps->GetGfxData(), pProps->GetMatrices(0), pProps->GetMatrixCount(), pProps->GetPropData(), pProps->GetPropDataIndices(), bucketMask, renderMode, m_bAddToMotionBlurMask, lodIdx, pPedShaderEffect, m_bBlockHideInFirstPersonFlag);
}
// If we have >1 sets, and this is not the g-buffer or scene draw list, use the second matrix set (Third person skeleton, world space)
else if(!isGBufferOrSceneDrawList)
{
CPedPropsMgr::RenderPropsInternal(pMI, rootMatrix, pProps->GetGfxData(), pProps->GetMatrices(1), pProps->GetMatrixCount(), pProps->GetPropData(), pProps->GetPropDataIndices(), bucketMask, renderMode, m_bAddToMotionBlurMask, lodIdx, pPedShaderEffect, m_bBlockHideInFirstPersonFlag);
}
// If we have >1 sets, and this is the g-buffer or scene draw list, use the third matrix set (Third person skeleton, adjusted matrices)
else
{
CPedPropsMgr::RenderPropsInternal(pMI, rootMatrix, pProps->GetGfxData(), pProps->GetMatrices(2), pProps->GetMatrixCount(), pProps->GetPropData(), pProps->GetPropDataIndices(), bucketMask, renderMode, m_bAddToMotionBlurMask, lodIdx, pPedShaderEffect, m_bBlockHideInFirstPersonFlag);
}
}
DbgCleanDrawableModelIdxForSpu();
// Restore FPV viewport if needed
if(m_bIsFPV && isGBufferOrSceneDrawList)
{
grcViewport::SetCurrent(pPreFPVViewport);
}
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT);
CShaderLib::ResetAlpha(setAlpha,setStipple);
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
}//if(pDrawable)...
EndModelGcmMarker();
}
void CEntityDrawDataPedBIG::Init(CEntity* pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_fadeAlpha = pEntity->GetAlpha();
//m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_matID = pEntity->GetDeferredMaterial();
m_bIsInInterior = pEntity->GetInteriorLocation().IsValid();
m_rootMatrix = MAT34V_TO_MATRIX34(pEntity->GetMatrix());
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
Assert(pEntity->GetIsDynamic());
// we can possible be dealing with a CPed or CDummyPed here
if (pEntity->GetType() == ENTITY_TYPE_PED)
{
CPed* pPed = static_cast<CPed*>(pEntity); // incorrect assumption (can come from dummyPed and cutsceneObject too)
// shader hasn't been setup for this vardata
CPedModelInfo* pMI = static_cast<CPedModelInfo*>(CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(m_modelInfoIdx))));
#if __DEV
Assert(pMI);
Assertf(pPed->GetPedDrawHandler().GetVarData().IsShaderSetup(), "adding %s to drawList but doesn't have initialised shader. Error.\n",pMI->GetModelName());
#endif //__DEV
m_varData = pPed->GetPedDrawHandler().GetVarData();
m_varData.ResetHasComponentHiLOD();
u32 drawblIdx = 0;
// TODO: test well .. .find better solution - svetli
for(int i = 0; i < PV_MAX_COMP; ++i)
{
//Cache the hi Detail flag into ped variation data to save a few cycles in the look up.
ePedVarComp componentId = static_cast<ePedVarComp>(i);
drawblIdx = m_varData.GetPedCompIdx(componentId);
if (drawblIdx != PV_NULL_DRAWBL && pMI->GetVarInfo())
{
m_varData.SetHasComponentHiLOD((u8)i, pMI->GetVarInfo()->HasComponentFlagsSet(componentId, drawblIdx, PV_FLAG_HIGH_DETAIL));
}
clothVariationData* clothVarData = m_varData.GetClothData(componentId);
if( clothVarData )
gDrawListMgr->AddCharClothReference( clothVarData );
}
// ToDo JW : these are coming in as arguments in the original version...
bool bHiLOD = (pPed->GetPedDrawHandler().GetVarData().GetIsHighLOD() || !pMI->GetVarInfo()->HasLowLODs());
grbTargetManager* pBlendShapeManager = pPed->GetTargetManager();
if(pBlendShapeManager)
{
m_bUseBlendShapes = true;
}
m_hiLOD = bHiLOD;
m_bAddToMotionBlurMask = pPed->m_nFlags.bAddtoMotionBlurMask;
m_bIsFPSSwimming = pPed->GetIsFPSSwimming();
}
else if (pEntity->GetType() == ENTITY_TYPE_OBJECT)
{
m_bUseBlendShapes = true;
m_hiLOD = true;
m_bAddToMotionBlurMask = false;
m_bIsFPSSwimming = false;
}
else
{
Assertf(false, "Unhandled object\n");
}
}
void CEntityDrawDataPedBIG::Draw(u8 lodIdx, CEntityDrawDataPedPropsBase* pProps)
{
DEV_ONLY(if (g_bypass_CEntityDrawDataPedBIG) { return; })
eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
#if __BANK
u32 bucket = DRAWLISTMGR->GetRtBucket();
#endif
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CPedModelInfo* pModelInfo = static_cast<CPedModelInfo*>(CModelInfo::GetBaseModelInfo(modelId));
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"Rendering %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
ValidateStreamingIndexCache(modelId, pModelInfo);
BeginModelGcmMarker(pModelInfo);
grmMatrixSet* ms = dlCmdAddSkeleton::GetCurrentMatrixSet();
rmcDrawable* pDrawable = pModelInfo->GetDrawable();
Assert(pDrawable);
if (!pDrawable BANK_ONLY(|| !m_commonData.SetShaderParams(bucket))){
return;
}
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
// --- draw the high detail model ---
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
if (lodIdx >= pModelInfo->GetNumAvailableLODs() && pModelInfo->GetSuperlodType() == SLOD_KEEP_LOWEST)
lodIdx = pModelInfo->GetNumAvailableLODs() - 1;
CCustomShaderEffectPed* pPedShaderEffect = NULL;
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool bDontWriteDepth = false;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
const u32 actualFadeAlpha = m_fadeAlpha;//AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalInInterior(m_bIsInInterior);
const bool isSeeThroughDrawList = DRAWLISTMGR->IsExecutingSeeThroughDrawList();
if (isSeeThroughDrawList)
{
RenderPhaseSeeThrough::SetGlobals();
}
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
if (lodIdx < pModelInfo->GetNumAvailableLODs())
{
CShaderLib::SetGlobalDeferredMaterial(m_matID);
CCustomShaderEffectBase* pShaderEffect = CCustomShaderEffectDC::GetLatestShader();
Assert(pShaderEffect);
Assert(dynamic_cast<CCustomShaderEffectPed*>(pShaderEffect) != NULL);
if (pShaderEffect){
pPedShaderEffect = static_cast<CCustomShaderEffectPed*>(pShaderEffect);
CPedVariationPack::RenderPed(pModelInfo, m_rootMatrix, ms, m_varData, pPedShaderEffect, bucketMask, lodIdx, renderMode,
m_bUseBlendShapes, m_bAddToMotionBlurMask, m_bIsFPSSwimming);
}
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT);
}
else
{
CShaderLib::SetGlobalDeferredMaterial(m_matID);
CPedVariationPack::RenderSLODPed(m_rootMatrix, ms, bucketMask, renderMode, CCustomShaderEffectDC::GetLatestShader(), pModelInfo->GetSuperlodType());
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT);
}
DbgCleanDrawableModelIdxForSpu();
CShaderLib::ResetAlpha(setAlpha,setStipple);
// --- draw the props for this ped ---
if (pProps && pProps->GetPropData().GetNumActiveProps() == 0)
{
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
return;
}
// extract the skeleton data from the drawable for this modelInfo
if (lodIdx < pModelInfo->GetNumAvailableLODs())
{
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx); // not accurate - it's not prop modelIdx
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalDeferredMaterial(m_matID);
CShaderLib::SetGlobalInInterior(m_bIsInInterior);
// draw props for player
if (pProps)
{
// EJ: Memory Optimization
CPedPropsMgr::RenderPropsInternal(pModelInfo, m_rootMatrix, pProps->GetGfxData(), pProps->GetMatrices(0), pProps->GetMatrixCount(), pProps->GetPropData(), pProps->GetPropDataIndices(), bucketMask, renderMode, m_bAddToMotionBlurMask, lodIdx, pPedShaderEffect);
}
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT);
CShaderLib::ResetAlpha(setAlpha,setStipple);
DbgCleanDrawableModelIdxForSpu();
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
}//if(pDrawable)...
EndModelGcmMarker();
}
CEntityDrawDataBreakableGlass::CEntityDrawDataBreakableGlass(bgDrawable& drawable, const bgDrawableDrawData &bgDrawData, const CEntity *entity)
: m_drawable(&drawable),
m_transforms(bgDrawData.GetTransforms()),
m_numTransforms(bgDrawData.GetNumTransforms()),
m_matrix(bgDrawData.GetMatrix()),
m_crackTexMatrix(bgDrawData.GetCrackTexMatrix()),
m_crackTexOffset(bgDrawData.GetCrackTexOffset()),
m_pBuffers(bgDrawData.GetBuffers()),
m_lod(bgDrawData.GetLOD()),
m_pCrackStarMap(bgDrawData.GetCrackStarMap()),
m_naturalAmb(entity->GetNaturalAmbientScale()),
m_artificialAmb(entity->GetArtificialAmbientScale()),
m_bIsInInterior(entity->GetInteriorLocation().IsValid())
{
sysMemCpy(m_arrPieceIndexCount, bgDrawData.GetPieceIndexCount(), sizeof(m_arrPieceIndexCount));
sysMemCpy(m_arrCrackIndexCount, bgDrawData.GetCrackIndexCount(), sizeof(m_arrCrackIndexCount));
drawable.MarkRenderedThisFrame();
}
void CEntityDrawDataBreakableGlass::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawDataBreakableGlass) { return; })
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, false, 0, false, false, 0, false, false, false);
CShaderLib::SetGlobalInInterior(m_bIsInInterior);
m_drawable->Draw(m_transforms, m_numTransforms, m_matrix, m_crackTexMatrix, m_crackTexOffset, m_pBuffers, m_pCrackStarMap, m_lod, m_arrPieceIndexCount, m_arrCrackIndexCount, bucketMask);
}
// initialize this type of drawable data from the entity
void CEntityDrawDataFragType::Init(CEntity *pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_bIsInterior = pEntity->GetInteriorLocation().IsValid();
m_fadeAlpha = pEntity->GetAlpha();
m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_matID = pEntity->GetDeferredMaterial();
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
m_matrix = MAT34V_TO_MATRIX34(pEntity->GetNonOrthoMatrix());
m_phaseLODs = pEntity->GetPhaseLODs();
m_lastLODIdx = pEntity->GetLastLODIdx();
#if ENABLE_FRAG_OPTIMIZATION
InitExtras(pEntity);
#endif // ENABLE_FRAG_OPTIMIZATION
}
void CEntityDrawDataFragType::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawDataFragType) { return; })
eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
#if __BANK
u32 bucket = DRAWLISTMGR->GetRtBucket();
#endif
// add a ref to this object
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"Rendering %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
ValidateStreamingIndexCache(modelId, pModelInfo);
// extract the skeleton data from the drawable for this modelInfo
if (pModelInfo)
{
BeginModelGcmMarker(pModelInfo);
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
const fragType* pFragType = pModelInfo->GetFragType();
Assert(pFragType);
rmcDrawable* pFragDrawable = pFragType->GetCommonDrawable();
Assert(pFragDrawable);
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
if (pFragDrawable BANK_ONLY(&& m_commonData.SetShaderParams(bucket)))
{
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool bDontWriteDepth = false;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
const u32 actualFadeAlpha = AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalDeferredMaterial(m_matID);
CShaderLib::SetGlobalInInterior(m_bIsInterior);
CBreakable localBreakable;
g_pBreakable = &localBreakable;
localBreakable.SetRenderMode(renderMode);
localBreakable.SetDrawBucketMask(bucketMask);
localBreakable.SetModelType((int)pModelInfo->GetModelType());
localBreakable.SetEntityAlpha(m_fadeAlpha);
localBreakable.SetLODFlags(m_phaseLODs, m_lastLODIdx);
#if RSG_PC || __ASSERT
localBreakable.SetModelInfo(pModelInfo);
#endif // RSG_PC || __ASSERT
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
#if __BANK
const bool bNeedsDepthStateRestore = DebugDeferred::StencilMaskOverlaySelectedBegin(m_commonData.GetCaptureStats() != 0);
#endif // __BANK
#if ENABLE_FRAG_OPTIMIZATION
pFragType->Draw(0, m_matrix, gDrawListMgr->GetCalcPosDrawableLOD(), NULL, GetSharedMatrixSetOverride(), NULL );
DrawExtras();
#else
pFragType->Draw(0, m_matrix, gDrawListMgr->GetCalcPosDrawableLOD(), NULL, NULL );
#endif
#if __BANK
DebugDeferred::StencilMaskOverlaySelectedEnd(bNeedsDepthStateRestore);
#endif // __BANK
g_pBreakable = NULL;
/* localBreakable.SetEntityAlpha(255);
localBreakable.SetModelType(-1);
localBreakable.SetRenderMode(rmNIL);
localBreakable.SetDrawBucketMask(0);
localBreakable.SetLODFlags(LODDrawable::LODFLAG_NONE_ALL, 0); */
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT);
CShaderLib::ResetAlpha(setAlpha,setStipple);
}//if(pFragDrawable)...
DbgCleanDrawableModelIdxForSpu();
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
#endif
EndModelGcmMarker();
}//if(pModelInfo)...
}
#if ENABLE_FRAG_OPTIMIZATION
void CEntityDrawDataFragTypeVehicle::InitExtras(CEntity* pEntity)
{
const CVehicle* pVehicle = static_cast<CVehicle*>(pEntity);
const fragInst* pFragInst = pVehicle->GetFragInst();
const grmMatrixSet* pSharedMatrixSet = pFragInst->GetType()->GetSharedMatrixSet();
const void* id = pFragInst;
dlSharedDataInfo *pSharedDataInfo = gDCBuffer->LookupSharedDataById(DL_MEMTYPE_MATRIXSET, id);
m_dataSize = grmMatrixSet::ComputeSize(pSharedMatrixSet->GetMatrixCount());
if (pSharedDataInfo)
{
m_dataAddress = gDCBuffer->LookupSharedData(DL_MEMTYPE_MATRIXSET, *pSharedDataInfo);
}
else
{
pSharedDataInfo = &gDCBuffer->GetSharedMemData(DL_MEMTYPE_MATRIXSET).AllocateSharedData(id);
#if __PS3
m_dataSize += 3;
m_dataSize &= 0xfffffffc;
grmMatrixSet* pDest = gDCBuffer->AllocateObjectFromPagedMemory<grmMatrixSet>(DPT_TRIPLE_BUFFERED, m_dataSize, false, m_dataAddress);
#else
grmMatrixSet* pDest = static_cast<grmMatrixSet*>(gDCBuffer->AddDataBlock(NULL, m_dataSize, m_dataAddress));
#endif
gDCBuffer->AllocateSharedData(DL_MEMTYPE_MATRIXSET, *pSharedDataInfo, m_dataSize, m_dataAddress);
grmMatrixSet::Create(pDest, pSharedMatrixSet->GetMatrixCount());
}
grmMatrixSet* pMatrixSet = GetSharedMatrixSetOverride();
pMatrixSet->CopySet(*pSharedMatrixSet);
grmMatrixSet::MatrixType* pMatrices = pMatrixSet->GetMatrices();
s32 iFirstExtra = VEH_EXTRA_1;
if(pVehicle->GetVehicleType() == VEHICLE_TYPE_HELI)
{
iFirstExtra = VEH_EXTRA_12;
}
for(s32 i = iFirstExtra; i <= VEH_LAST_EXTRA; ++i)
{
const eHierarchyId hierarchyId = static_cast<eHierarchyId>(i);
if(!pVehicle->GetIsExtraOn(hierarchyId))
{
const s32 iBoneIndex = pVehicle->GetBoneIndex(hierarchyId);
if(iBoneIndex != -1)
{
pMatrices[iBoneIndex].Zero();
if(pFragInst)
{
const crBoneData* boneData = pFragInst->GetType()->GetSkeletonData().GetBoneData(iBoneIndex);
const crBoneData* pNext = boneData->GetChild();
while(pNext)
{
pMatrices[pNext->GetIndex()].Zero();
pNext = pNext->GetNext();
}
}
}
}
}
}
void CEntityDrawDataFragTypeVehicle::DrawExtras()
{
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
if(pModelInfo->GetModelType() == MI_TYPE_VEHICLE)
{
float dist = -10.0f;
float distSq = m_matrix.d.Dist2(FRAGMGR->GetInterestMatrix().d);
if(distSq < square(FRAGTUNE->GetGlobalMaxDrawingDistance()))
{
dist = sqrtf(distSq);
}
if(dist >= 0.0f)
{
u32 bucket = DRAWLISTMGR->GetRtBucket();
u8 wheelBurstRatios[NUM_VEH_CWHEELS_MAX][2];
memset(wheelBurstRatios, 0, sizeof(wheelBurstRatios));
FragDrawCarWheels((CVehicleModelInfo*)pModelInfo, m_matrix, NULL, 0, bucket, false, wheelBurstRatios/*m_wheelBurstRatios*/, dist, 0/*m_flags*/, NULL, false, 1.0f/*m_lodMult*/);
}
}
}
#endif // ENABLE_FRAG_OPTIMIZATION
// initialise this type of drawable data from the entity
void CEntityDrawDataSkinned::Init(CEntity *pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
m_isWeaponModelInfo = 0;
m_isHD = 0;
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_bIsInterior = pEntity->GetInteriorLocation().IsValid();
m_fadeAlpha = pEntity->GetAlpha();
m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_matID = pEntity->GetDeferredMaterial();
m_rootMatrix = MAT34V_TO_MATRIX34(pEntity->GetNonOrthoMatrix());
m_phaseLODs = pEntity->GetPhaseLODs();
m_lastLODIdx = pEntity->GetLastLODIdx();
m_bIsFPV = false;
if(Unlikely(pEntity->IsProtectedBaseFlagSet(fwEntity::HAS_FPV)))
{
fwAttachmentEntityExtension* pExtension = pEntity->GetAttachmentExtension();
fwEntity* pParent = NULL;
// Get root matrix for first person skeleton
Mat34V mat(V_IDENTITY);
if(pExtension && pExtension->FindParentAndOffsetWithCameraRelativeExtension(pParent, mat))
{
Matrix34 rootRelParent;
rootRelParent.Inverse(RC_MATRIX34(mat));
fwCameraRelativeExtension* pParentExt = pParent->GetExtension<fwCameraRelativeExtension>();
FastAssert(pParentExt);
Matrix34 parentMtx = RC_MATRIX34(pParentExt->m_cameraOffset);
m_rootMatrixFPV.Dot(parentMtx, rootRelParent);
// And get root matrix based on the third person skeleton
pParent = pExtension->GetAttachParent();
m_rootMatrix.Identity();
while(pParent)
{
// Grab parent skeleton
const crSkeleton* pSkel = GetSkeletonForDrawIgnoringDrawlist((CEntity*)pParent);
// Get attach offset matrix
Matrix34 matOffset;
matOffset.FromQuaternion(pExtension->GetAttachQuat());
matOffset.d = pExtension->GetAttachOffset();
// Get offset relative to parent and multiply
if(pExtension->GetOtherAttachBone() > -1)
{
parentMtx.Dot(matOffset, RCC_MATRIX34(pSkel->GetObjectMtx(pExtension->GetOtherAttachBone())));
m_rootMatrix.Dot(parentMtx);
}
// Next parent...
pExtension = pParent->GetAttachmentExtension();
if(!pExtension || !pExtension->GetAttachParent())
{
// Multiply by entity matrix on last attachment
Mat34V parentMatrix = pParent->GetMatrix();
m_rootMatrix.Dot(RCC_MATRIX34(parentMatrix));
pParent = NULL;
}
else
{
pParent = pExtension->GetAttachParent();
}
}
m_bIsFPV = true;
}
}
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
const CObject* pObject = static_cast<CObject*>(pEntity);
m_bAddToMotionBlurMask = pObject->m_nFlags.bAddtoMotionBlurMask;
}
void CEntityDrawDataSkinned::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawDataSkinned) { return; })
u32 bucket = DRAWLISTMGR->GetRtBucket();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
u16 contextStats = BANK_SWITCH_NT(m_commonData.GetContextStats(), 0);
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
Assert(pModelInfo);
ValidateStreamingIndexCache(modelId, pModelInfo);
BeginModelGcmMarker(pModelInfo);
// extract the skeleton data from the drawable for this modelInfo
rmcDrawable* pDrawable;
if (m_isWeaponModelInfo && m_isHD)
{
CWeaponModelInfo *pWInfo = static_cast<CWeaponModelInfo*>(pModelInfo);
strLocalIndex drawableIndex = strLocalIndex(pWInfo->GetHDDrawableIndex());
if (drawableIndex != -1)
{
pDrawable = g_DrawableStore.Get(drawableIndex);
}
else
{
pDrawable = pModelInfo->GetDrawable();
}
}
else
{
pDrawable = pModelInfo->GetDrawable();
}
Assert(pDrawable);
if (pDrawable BANK_ONLY(&& m_commonData.SetShaderParams(bucket)))
{
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
const eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool isShadowDrawList = DRAWLISTMGR->IsExecutingShadowDrawList();
const bool isGBufferOrSceneDrawList = isGBufferDrawList || DRAWLISTMGR->IsExecutingDrawSceneDrawList();
const bool bDontWriteDepth = pModelInfo->GetDontWriteZBuffer() && (bucket == CRenderer::RB_ALPHA) && !isShadowDrawList;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
const u32 actualFadeAlpha = AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalDeferredMaterial(m_matID, m_isWeaponModelInfo && isGBufferOrSceneDrawList);
CShaderLib::SetGlobalInInterior(m_bIsInterior);
// Setup FPV viewport if required
grcViewport* pPreFPVViewport = NULL;
Matrix34 rootMatrix;
grcViewport fpsVp;
if(m_bIsFPV && isGBufferOrSceneDrawList)
{
fpsVp = *grcViewport::GetCurrent();
fpsVp.SetWorldIdentity();
Mat34V mat(fpsVp.GetCameraMtx());
mat.SetCol3(Vec3V(0.0f, 0.0f, 0.0f));
fpsVp.SetCameraMtx(mat);
pPreFPVViewport = grcViewport::SetCurrent(&fpsVp);
Mat34V cam = RageCameraMtxToGameCameraMtx(mat);
Matrix34 fpvInverse;
fpvInverse.Inverse(m_rootMatrixFPV);
rootMatrix.Dot(fpvInverse, RC_MATRIX34(cam));
// We want to keep the emissive bits on weapon in firts person
// When the emp as gone off.
CShaderLib::SetGlobalEmissiveScale(1.0f,true);
}
else
rootMatrix = m_rootMatrix;
grmMatrixSet *ms = dlCmdAddSkeleton::GetCurrentMatrixSet();
u32 LODFlag = (m_phaseLODs >> DRAWLISTMGR->GetDrawListLODFlagShift()) & LODDrawable::LODFLAG_MASK;
u32 LODLevel = 0;
s32 crossFade = -1;
float dist = LODDrawable::CalcLODDistance(rootMatrix.d);
if (LODFlag != LODDrawable::LODFLAG_NONE)
{
if (LODFlag & LODDrawable::LODFLAG_FORCE_LOD_LEVEL)
{
LODLevel = LODFlag & ~LODDrawable::LODFLAG_FORCE_LOD_LEVEL;
}
else
{
LODDrawable::CalcLODLevelAndCrossfadeForProxyLod(pDrawable, dist, LODFlag, LODLevel, crossFade, LODDrawable::CFDIST_MAIN, m_lastLODIdx);
}
}
else
{
LODDrawable::CalcLODLevelAndCrossfade(pDrawable, dist, LODLevel, crossFade, LODDrawable::CFDIST_MAIN, m_lastLODIdx ASSERT_ONLY(, pModelInfo));
}
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
#if HAS_RENDER_MODE_SHADOWS
if( IsRenderingShadowsSkinned(renderMode) )
{
#if !RAGE_SUPPORT_TESSELLATION_TECHNIQUES
pDrawable->DrawSkinnedNoShaders(rootMatrix, *ms, bucketMask, LODLevel, rmcDrawableBase::RENDER_SKINNED);
#else
pDrawable->DrawSkinnedNoShadersTessellationControlled(rootMatrix, *ms, bucketMask, LODLevel, rmcDrawableBase::RENDER_SKINNED);
#endif
}
else if( IsRenderingShadowsNotSkinned(renderMode) )
{
// ToDo JW : why do we need to do this here? (ie. drawing a skinned entity non-skinned?)
pDrawable->DrawSkinnedNoShaders(rootMatrix, *ms, bucketMask, LODLevel, rmcDrawableBase::RENDER_NONSKINNED);
}
else
#endif // HAS_RENDER_MODE_SHADOWS
{
#if __BANK
const bool bNeedsDepthStateRestore = DebugDeferred::StencilMaskOverlaySelectedBegin(m_commonData.GetCaptureStats() != 0);
#endif // __BANK
if( m_bAddToMotionBlurMask )
{
CShaderLib::BeginMotionBlurMask();
}
pDrawable->DrawSkinned(rootMatrix, *ms, bucketMask, LODLevel, contextStats);
if( m_bAddToMotionBlurMask )
{
CShaderLib::EndMotionBlurMask();
}
#if __BANK
DebugDeferred::StencilMaskOverlaySelectedEnd(bNeedsDepthStateRestore);
#endif // __BANK
}
DbgCleanDrawableModelIdxForSpu();
// Restore FPV viewport and emissive if needed
if(m_bIsFPV && isGBufferOrSceneDrawList)
{
grcViewport::SetCurrent(pPreFPVViewport);
CShaderLib::SetGlobalEmissiveScale(1.0f,false);
}
if (bDontWriteDepth)
{
CShaderLib::SetDefaultDepthStencilBlock();
}
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT, m_isWeaponModelInfo && isGBufferOrSceneDrawList);
CShaderLib::ResetAlpha(setAlpha,setStipple);
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
}//if(pDrawable)...
EndModelGcmMarker();
}
// initialise this type of drawable data from the entity
void CEntityDrawDataFrag::Init(CEntity *pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
memset( m_wheelBurstRatios, 0, sizeof(m_wheelBurstRatios) );
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
Assert(pEntity->GetIsDynamic());
CDynamicEntity* pDynamicEntity = static_cast<CDynamicEntity*>(pEntity);
fragInst* pFragInst = pDynamicEntity->GetFragInst();
Assert(pFragInst);
m_currentLOD = (s8)pFragInst->GetCurrentPhysicsLOD();
m_rootMatrix = RCC_MATRIX34(pFragInst->GetMatrix());
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_bIsInterior = pEntity->GetInteriorLocation().IsValid();
m_fadeAlpha = pEntity->GetAlpha();
m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_matID = pEntity->GetDeferredMaterial();
m_matLocalPlayerEmblem = false;
m_forceSetMaterial = pEntity->GetIsTypeVehicle() && pEntity->IsBaseFlagSet(fwEntity::FORCE_ALPHA);
if(pDynamicEntity->GetIsTypeVehicle())
{
if(((CVehicle*)pDynamicEntity)->IsLocalPlayerEmblemMaterialGroup())
{
m_matLocalPlayerEmblem = true;
}
}
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
#if __DEV
const fragType* type = pFragInst->GetType();
Assert(type);
// make a copy of the child damage array
Assertf( pFragInst->GetTypePhysics()->GetNumChildren() < MAX_FRAG_CHILDREN, "[ART] : too many frag children (more than 64) in %s\n",CModelInfo::GetBaseModelInfoName(fwModelId(strLocalIndex(m_modelInfoIdx))));
#endif //__DEV
PopulateBitFields(pFragInst, m_damagedBits, m_destroyedBits);
m_flags = 0; // always seems to be init'ed to 0
m_phaseLODs = pEntity->GetPhaseLODs();
m_lastLODIdx = pEntity->GetLastLODIdx();
m_lodMult = 1.f;
m_lowLodMult = 1.f;
m_isWrecked = false;
m_clampedLod = -1;
if (pDynamicEntity->GetIsTypeVehicle())
{
CVehicle* veh = (CVehicle*)pDynamicEntity;
m_lodMult = veh->GetLodMultiplier();
m_isWrecked = veh->GetStatus() == STATUS_WRECKED;
m_clampedLod = veh->GetClampedRenderLod();
// bump lod distance (but only on for the low lod!) for broken vehicles so we don't see doors/bumpers pop and things like that
if (!veh->InheritsFromBike())
{
bool bumpLod = veh->GetHavePartsBrokenOff();
if (!bumpLod)
{
s32 numDoors = veh->GetNumDoors();
for (s32 i = 0; i < numDoors; ++i)
{
CCarDoor* door = veh->GetDoor(i);
if (door && door->GetDoorRatio() > 0.01f)
{
bumpLod = true;
break;
}
}
}
if (bumpLod)
m_lowLodMult = 2.f;
}
}
// fallen off vehicle mod, need to use the right mod drawable
m_modAssetIdx = -1;
m_drawModOnTop = true;
m_fragMod = true;
if (pDynamicEntity->GetIsTypeObject())
{
CObject* obj = (CObject*)pDynamicEntity;
if (obj->m_nObjectFlags.bVehiclePart && obj->GetVehicleModSlot() > -1)
{
CVehicle* veh = (CVehicle*)obj->GetFragParent();
if (veh)
{
CVehicleStreamRenderGfx* gfx = veh->GetVariationInstance().GetVehicleRenderGfx();
if (gfx)
{
u8 modSlot = (u8)obj->GetVehicleModSlot();
m_drawModOnTop = false;
m_modMatrix = m_rootMatrix;
if (modSlot >= VMT_RENDERABLE + MAX_LINKED_MODS)
{
// broken wheel
m_fragMod = false;
m_renderGfx = gfx;
m_renderGfx->AddRefsToGfx();
}
else
{
// broken frag part
m_modAssetIdx = gfx->GetFragIndex(modSlot).Get();
if (m_modAssetIdx != -1 && g_FragmentStore.Get(strLocalIndex(m_modAssetIdx)))
{
g_FragmentStore.AddRef(strLocalIndex(m_modAssetIdx), REF_RENDER);
gDrawListMgr->AddRefCountedModuleIndex(m_modAssetIdx, &g_FragmentStore);
}
// render original drawable too if the mod doesn't turn it off
m_drawModOnTop = veh->GetVariationInstance().ShouldDrawOriginalForSlot(veh, modSlot);
// the original geometry (e.g a bumper) is part of the main vehicle and offset from the center
// the mod is a standalone drawable so we need to offset it manually
// this is pretty crap, we could maybe decouple the vehicle entirely from fallen off mods
s32 modBoneIdx = veh->GetVariationInstance().GetModBoneIndex(modSlot);
if (modBoneIdx != -1)
{
int boneIdx = veh->GetBoneIndex((eHierarchyId)modBoneIdx);
if (boneIdx != -1)
{
crSkeleton* skel = GetSkeletonFromFragInst(pFragInst);
if (skel)
{
Matrix34 boneMat;
skel->GetGlobalMtx(boneIdx, RC_MAT34V(boneMat));
m_modMatrix = boneMat;
}
}
}
int iTurnOffCount = veh->GetVariationInstance().GetNumBonesToTurnOffForSlot(modSlot);
if(iTurnOffCount > 0)
{
Matrix34 boneMat;
for (s32 iTurnOff = 0; iTurnOff < iTurnOffCount; ++iTurnOff)
{
s32 bone = veh->GetVariationInstance().GetBoneToTurnOffForSlot(modSlot, iTurnOff);
if (bone == -1)
continue;
int boneIdx = veh->GetBoneIndex((eHierarchyId)bone);
crSkeleton* pSkeleton = GetSkeletonFromFragInst(pFragInst);
if (boneIdx != -1 && pSkeleton)
{
if(pFragInst)
{
const crBoneData* boneData = pFragInst->GetType()->GetSkeletonData().GetBoneData(boneIdx);
Assert(boneData->GetIndex() == boneIdx);
//only zero out the non-root matrices because we need the matrix cannot be restored.
if (boneData->GetParent() && boneData->GetParent()->GetIndex() != 0)
{
pSkeleton->GetGlobalMtx(boneIdx, RC_MAT34V(boneMat));
boneMat.Zero3x3();
pSkeleton->SetGlobalMtx(boneIdx, RCC_MAT34V(boneMat));
const crBoneData* next = boneData->GetChild();
while (next)
{
pSkeleton->SetGlobalMtx(next->GetIndex(), RCC_MAT34V(boneMat));
next = next->GetNext();
}
}
}
}
}
}
}
}
}
}
}
}
void CEntityDrawDataFrag::Draw(bool damaged)
{
DEV_ONLY(if (g_bypass_CEntityDrawDataFrag) { return; })
eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
u32 bucket = DRAWLISTMGR->GetRtBucket();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"Rendering %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
ValidateStreamingIndexCache(modelId, pModelInfo);
// extract the skeleton data from the drawable for this modelInfo
if (pModelInfo)
{
BeginModelGcmMarker(pModelInfo);
const fragType* overrideFragType = NULL;
if (m_fragMod && m_modAssetIdx != -1)
{
overrideFragType = g_FragmentStore.Get(strLocalIndex(m_modAssetIdx));
}
const fragType* type = pModelInfo->GetFragType();
if (!type)
{
#if __ASSERT
Displayf("Error in CEntityDrawDataFrag::Draw() with model %s", pModelInfo->GetModelName());
Assertf(!pModelInfo->GetHasLoaded(), "Model %s has had its resources unloaded even though its part of a draw list", pModelInfo->GetModelName());
Assertf(pModelInfo->GetDrawableType() == fwArchetype::DT_FRAGMENT, "The Drawble type must be DT_FRAGMENT, its %d", pModelInfo->GetDrawableType());
Assertf(type, "Failed to get fragType for Model %s", pModelInfo->GetModelName());
#endif //__ASSERT
Displayf("frag index %d : model index : %d : model hash : %x",pModelInfo->GetFragmentIndex(), m_modelInfoIdx, pModelInfo->GetModelNameHash());
Quitf(ERR_GFX_DRAW_DATA,"NULL fragType returned from pModelInfo->GetFragType() - Please save the core dump from this run!!!");
}
rmcDrawable* pFragDrawable = type->GetCommonDrawable();
Assert(pFragDrawable);
if (pFragDrawable BANK_ONLY(&& m_commonData.SetShaderParams(bucket)))
{
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool isDrawSceneDrawList = DRAWLISTMGR->IsExecutingDrawSceneDrawList();
const bool bDontWriteDepth = false;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
const u32 actualFadeAlpha = AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
const u32 actualmatid = m_matID | ( m_matLocalPlayerEmblem ? DEFERRED_MATERIAL_VEHICLE_BADGE_LOCAL_PLAYER : 0);
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalDeferredMaterial(actualmatid, m_forceSetMaterial && isDrawSceneDrawList);
CShaderLib::SetGlobalInInterior(m_bIsInterior);
CBreakable localBreakable;
g_pBreakable = &localBreakable;
localBreakable.SetDrawBucketMask(bucketMask);
localBreakable.SetRenderMode((eRenderMode)renderMode);
localBreakable.SetModelType((int)pModelInfo->GetModelType());
localBreakable.SetEntityAlpha(m_fadeAlpha);
localBreakable.SetLODFlags(m_phaseLODs, m_lastLODIdx);
localBreakable.SetIsWreckedVehicle(m_isWrecked);
localBreakable.SetClampedLod(m_clampedLod);
localBreakable.SetLowLodMultiplier(m_lowLodMult);
#if RSG_PC || __ASSERT
localBreakable.SetModelInfo(pModelInfo);
#endif // RSG_PC || __ASSERT
Assert(pFragDrawable->GetSkeletonData());
grmMatrixSet *ms = dlCmdAddSkeleton::GetCurrentMatrixSet();
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
// calculate dist here only if we'll draw the wheels but not any vehicle part, otherwise don't bother
// as we'll get back a dist value from FragDraw
float dist = -10.0f;
if ((m_flags & CDrawFragDC::CAR_WHEEL) || ((m_flags & CDrawFragDC::CAR_PLUS_WHEELS) && !m_drawModOnTop && !overrideFragType))
{
float distSq = m_rootMatrix.d.Dist2(FRAGMGR->GetInterestMatrix().d);
if(distSq < square(FRAGTUNE->GetGlobalMaxDrawingDistance()))
dist = sqrtf(distSq);
}
else
{
// render original drawable from the modelinfo if the mod didn't turn off the bone
if (m_drawModOnTop)
FragDraw(m_currentLOD, pModelInfo, ms, m_rootMatrix, m_damagedBits, m_destroyedBits, dist, m_flags, m_lodMult, damaged, type);
// render the mod drawable
if (overrideFragType)
FragDraw(m_currentLOD, pModelInfo, NULL, m_modMatrix, m_damagedBits, m_destroyedBits, dist, m_flags, m_lodMult, damaged, overrideFragType);
}
if(dist >= 0.0f && ((m_flags & CDrawFragDC::CAR_PLUS_WHEELS) || (m_flags & CDrawFragDC::CAR_WHEEL)))
{
#if __BANK
if (!DRAWLISTMGR->IsExecutingDebugOverlayDrawList() || !grmModel::HasCustomShaderParamsFunc()) // TODO -- support wheels properly in wireframe with custom shader params func
#endif // __BANK
{
FragDrawCarWheels((CVehicleModelInfo*)pModelInfo, m_rootMatrix, ms, m_destroyedBits, bucket, (m_flags & (CDrawFragDC::WHEEL_BURST_RATIOS|CDrawFragDC::IS_LOCAL_PLAYER)) != 0, m_wheelBurstRatios, dist, m_flags, m_fragMod ? NULL : m_renderGfx, false, m_lodMult);
}
}
g_pBreakable = NULL;
/* localBreakable.SetLowLodMultiplier(m_lowLodMult);
localBreakable.SetClampedLod(-1);
localBreakable.SetIsWreckedVehicle(false);
localBreakable.SetEntityAlpha(255);
localBreakable.SetModelType(-1);
localBreakable.SetRenderMode(rmNIL);
localBreakable.SetDrawBucketMask(0);
localBreakable.SetLODFlags(LODDrawable::LODFLAG_NONE_ALL, 0); */
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT, m_forceSetMaterial && isDrawSceneDrawList MSAA_EDGE_PROCESS_FADING_ONLY(, m_matLocalPlayerEmblem));
CShaderLib::ResetAlpha(setAlpha,setStipple);
DbgCleanDrawableModelIdxForSpu();
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
}//if(pFragDrawable)...
EndModelGcmMarker();
}//if(pModelInfo)...
}
// initialise the single ped prop draw data from the source entity
void CEntityDrawDataDetachedPedProp::Init(CEntity* pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
m_mat = MAT34V_TO_MATRIX34(pEntity->GetMatrix());
m_modelInfoIdx = fwModelId::MI_INVALID;
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_bIsInterior = pEntity->GetInteriorLocation().IsValid();
m_fadeAlpha = pEntity->GetAlpha();
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
//m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
//m_matID = pEntity->GetDeferredMaterial();
Assert(pEntity->GetIsTypeObject());
CObject* pObject = static_cast<CObject*>(pEntity);
m_modelHash = pObject->uPropData.m_propIdxHash;
m_TexHash = pObject->uPropData.m_texIdxHash;
// add refs either to pack dictionaries or streamed assets
CBaseModelInfo* bmi = CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(pObject->uPropData.m_parentModelIdx)));
if (bmi && bmi->GetModelType() == MI_TYPE_PED)
{
CPedModelInfo* pmi = (CPedModelInfo*)bmi;
strLocalIndex DwdIdx = strLocalIndex(pmi->GetPropsFileIndex());
if (DwdIdx.Get() != -1)
{
// pack ped
if (Verifyf(g_DwdStore.Get(DwdIdx), "Dwd '%s' for detached object is streamed out!", g_DwdStore.GetName(DwdIdx)))
{
g_DwdStore.AddRef(DwdIdx, REF_RENDER);
gDrawListMgr->AddRefCountedModuleIndex(DwdIdx.Get(), &g_DwdStore);
}
strLocalIndex txdIdx = strLocalIndex(g_DwdStore.GetParentTxdForSlot(DwdIdx));
if (txdIdx != -1)
{
if (Verifyf(g_TxdStore.Get(txdIdx), "Txd '%s' for detached object is streamed out!", g_TxdStore.GetName(txdIdx)))
{
g_TxdStore.AddRef(txdIdx, REF_RENDER);
gDrawListMgr->AddRefCountedModuleIndex(txdIdx.Get(), &g_TxdStore);
}
}
}
else
{
// streamed ped
strLocalIndex dwdIdx = strLocalIndex(g_DwdStore.FindSlot(m_modelHash));
if (dwdIdx != -1)
{
if (Verifyf(g_DwdStore.Get(dwdIdx), "Dwd '%s' for detached object is streamed out!", g_DwdStore.GetName(dwdIdx)))
{
g_DwdStore.AddRef(dwdIdx, REF_RENDER);
gDrawListMgr->AddRefCountedModuleIndex(dwdIdx.Get(), &g_DwdStore);
}
}
strLocalIndex txdIdx = strLocalIndex(g_TxdStore.FindSlot(m_TexHash));
if (txdIdx != -1)
{
if (Verifyf(g_TxdStore.Get(txdIdx), "Txd '%s' for detached object is streamed out!", g_TxdStore.GetName(txdIdx)))
{
g_TxdStore.AddRef(txdIdx, REF_RENDER);
gDrawListMgr->AddRefCountedModuleIndex(txdIdx.Get(), &g_TxdStore);
}
}
}
}
m_bAddToMotionBlurMask = pObject->m_nFlags.bAddtoMotionBlurMask;
CPed* parentPed = static_cast<CPed*>(pObject->GetFragParent());
if (parentPed && parentPed->GetPedDrawHandler().GetPedPropRenderGfx())
{
parentPed->GetPedDrawHandler().GetPedPropRenderGfx()->AddRefsToGfx();
}
if (Verifyf(parentPed, "Trying to render a detached ped prop with no parent ped!"))
{
m_modelInfoIdx = static_cast<u16>(parentPed->GetModelIndex());
gDrawListMgr->AddArchetypeReference(parentPed->GetModelIndex());
}
}
void CEntityDrawDataDetachedPedProp::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawDataDetachedPedProp) { return; })
eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
#if __BANK
u32 bucket = DRAWLISTMGR->GetRtBucket();
if (!m_commonData.SetShaderParams(bucket)) { return; };
#endif
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool bDontWriteDepth = false;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
const u32 actualFadeAlpha = m_fadeAlpha;//AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
u32 matId = DEFERRED_MATERIAL_PED;
if (m_bIsInterior) matId |= DEFERRED_MATERIAL_INTERIOR;
CShaderLib::SetGlobalDeferredMaterial(matId);
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalInInterior(m_bIsInterior);
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CPedModelInfo* pModelInfo = static_cast<CPedModelInfo*>(CModelInfo::GetBaseModelInfo(modelId));
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"Rendering %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
ValidateStreamingIndexCache(modelId, pModelInfo);
BeginModelGcmMarker(pModelInfo);
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
CPedPropsMgr::RenderPropAtPosn(pModelInfo, m_mat, m_modelHash, m_TexHash, bucketMask, renderMode, m_bAddToMotionBlurMask, NULL, ANCHOR_NONE);
DbgCleanDrawableModelIdxForSpu();
EndModelGcmMarker();
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
}
// initialize the vehicle variation draw data from the source entity
void CEntityDrawDataVehicleVar::Init(CEntity* pEntity)
{
#if __BANK
m_commonData.InitFromEntity(pEntity);
#endif // __BANK
Assertf(pEntity->GetIsTypeVehicle(), "Entity %s isn't of type vehicle!", pEntity->GetModelName());
CVehicle* pVeh = static_cast<CVehicle*>(pEntity);
Assert(pVeh);
fragInst* pFragInst = pVeh->GetFragInst();
Assert(pFragInst);
m_rootMatrix = RCC_MATRIX34(pFragInst->GetMatrix());
pVeh->GetVehicleDrawHandler().CopyVariationInstance(m_variation);
m_variation.GetVehicleRenderGfx()->AddRefsToGfx();
Matrix34 boneMat;
for (s32 i = 0; i < VMT_RENDERABLE + MAX_LINKED_MODS; ++i)
{
s32 modBoneIdx = m_variation.GetModBoneIndex((u8)i);
if (modBoneIdx == -1)
continue;
int boneIdx = pVeh->GetBoneIndex((eHierarchyId)modBoneIdx);
if (boneIdx > -1)
{
pVeh->GetGlobalMtx(boneIdx, boneMat);
m_mat[i] = m_variation.GetVehicleRenderGfx()->GetMatrix((u8)i);
m_mat[i].d = boneMat.d;
}
}
FastAssert(pEntity->GetModelIndex() != fwArchetypeManager::INVALID_STREAM_SLOT);
m_modelInfoIdx = static_cast<u16>(pEntity->GetModelIndex());
m_naturalAmb = pEntity->GetNaturalAmbientScale();
m_artificialAmb = pEntity->GetArtificialAmbientScale();
m_fadeAlpha = pEntity->GetAlpha();
m_bIsInterior = pEntity->GetInteriorLocation().IsValid();
// m_forceAlphaForWaterReflection = CRenderPhaseWaterReflectionInterface::ShouldEntityForceUpAlpha(pEntity);
m_matID = pEntity->GetDeferredMaterial();
m_matLocalPlayerEmblem = false;
m_forceSetMaterial = pEntity->GetIsTypeVehicle() && pEntity->IsBaseFlagSet(fwEntity::FORCE_ALPHA);
if(pEntity->GetIsTypeVehicle())
{
if(((CVehicle*)pEntity)->IsLocalPlayerEmblemMaterialGroup())
{
m_matLocalPlayerEmblem = true;
}
}
#if RAGE_INSTANCED_TECH
m_viewportInstancedRenderBit = pEntity->GetViewportInstancedRenderBit();
#endif
m_bAddToMotionBlurMask = pVeh->m_nFlags.bAddtoMotionBlurMask;
#if __DEV
const fragType* type = pFragInst->GetType();
Assert(type);
// make a copy of the child damage array
Assertf( pFragInst->GetTypePhysics()->GetNumChildren() < MAX_FRAG_CHILDREN, "[ART] : too many frag children (more than 64) in %s\n",CModelInfo::GetBaseModelInfoName(fwModelId(strLocalIndex(m_modelInfoIdx))));
#endif //__DEV
PopulateBitFields(pFragInst, m_damagedBits, m_destroyedBits);
m_hasBurstWheels = false;
m_lodMult = pVeh->GetLodMultiplier();
m_isHd = pVeh->GetIsCurrentlyHD();
m_isWrecked = pVeh->GetStatus() == STATUS_WRECKED;
m_clampedLod = pVeh->GetClampedRenderLod();
m_lowLodMult = 1.f;
// bump lod distance (but only on for the low lod!) for broken vehicles so we don't see doors/bumpers pop and things like that
if (!pVeh->InheritsFromBike())
{
bool bumpLod = pVeh->GetHavePartsBrokenOff();
if (!bumpLod)
{
s32 numDoors = pVeh->GetNumDoors();
for (s32 i = 0; i < numDoors; ++i)
{
CCarDoor* door = pVeh->GetDoor(i);
if (door && door->GetDoorRatio() > 0.01f)
{
bumpLod = true;
break;
}
}
}
if (bumpLod)
m_lowLodMult = 2.f;
}
}
void CEntityDrawDataVehicleVar::Draw()
{
DEV_ONLY(if (g_bypass_CEntityDrawDataVehicleVar) { return; })
eRenderMode renderMode = DRAWLISTMGR->GetRtRenderMode();
u32 bucket = DRAWLISTMGR->GetRtBucket();
u32 bucketMask = DRAWLISTMGR->GetRtBucketMask();
u16 contextStats = BANK_SWITCH_NT(m_commonData.GetContextStats(), 0);
fwModelId modelId((strLocalIndex(m_modelInfoIdx)));
CVehicleModelInfo* pModelInfo = static_cast<CVehicleModelInfo*>(CModelInfo::GetBaseModelInfo(modelId));
Assert(pModelInfo);
Assertf(pModelInfo->GetNumRefs() > 0,"Rendering %s but it has no refs. _Very_ dangerous", pModelInfo->GetModelName());
Assertf(m_variation.GetNumMods(), "Rendering vehicle variation with no active mods!");
Assertf(m_variation.GetVehicleRenderGfx(), "Rendering vehicle with no render data");
#if __DEV
if (dlDrawListMgr::StrIndicesValidationEnabled())
{
Assertf(m_variation.GetVehicleRenderGfx()->ValidateStreamingIndexHasBeenCached(), "Failed to find cached streaming indices for %s", pModelInfo->GetModelName());
}
#endif
ValidateStreamingIndexCache(modelId, pModelInfo);
BeginModelGcmMarker(pModelInfo);
DbgSetDrawableModelIdxForSpu(m_modelInfoIdx);
#if DEBUG_ENTITY_GPU_COST
START_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StartDebugEntityTimer();
}
#endif
const bool isGBufferDrawList = DRAWLISTMGR->IsExecutingGBufDrawList();
const bool isDrawSceneDrawList = DRAWLISTMGR->IsExecutingDrawSceneDrawList();
const bool bDontWriteDepth = false;
const bool setAlpha = IsNotRenderingModes(renderMode, rmSimpleNoFade|rmSimple|rmSimpleDistFade) &&
!isGBufferDrawList;
const bool setStipple = isGBufferDrawList;
const u32 actualFadeAlpha = m_fadeAlpha;//AdjustAlpha(m_fadeAlpha, m_forceAlphaForWaterReflection);
const u32 actualmatid = m_matID | ( m_matLocalPlayerEmblem ? DEFERRED_MATERIAL_VEHICLE_BADGE_LOCAL_PLAYER : 0);
CShaderLib::SetGlobals(m_naturalAmb, m_artificialAmb, setAlpha, actualFadeAlpha, setStipple, false, actualFadeAlpha, bDontWriteDepth, false, false);
CShaderLib::SetGlobalDeferredMaterial(actualmatid,m_forceSetMaterial && isDrawSceneDrawList);
CShaderLib::SetGlobalInInterior(m_bIsInterior);
CBreakable localBreakable;
g_pBreakable = &localBreakable;
localBreakable.SetDrawBucketMask(bucketMask);
localBreakable.SetRenderMode((eRenderMode)renderMode);
localBreakable.SetModelType((int)pModelInfo->GetModelType());
localBreakable.SetEntityAlpha(m_fadeAlpha);
localBreakable.SetIsVehicleMod(true);
localBreakable.SetIsHd(m_isHd);
localBreakable.SetIsWreckedVehicle(m_isWrecked);
localBreakable.SetClampedLod((s8)m_clampedLod);
localBreakable.SetLowLodMultiplier(m_lowLodMult);
CVehicleStreamRenderGfx* renderGfx = m_variation.GetVehicleRenderGfx();
grmMatrixSet* ms = dlCmdAddSkeleton::GetCurrentMatrixSet();
CCustomShaderEffectBase* pCSE = CCustomShaderEffectDC::GetLatestShader();
Assert(pCSE);
CCustomShaderEffectVehicle* pCSEVehicle = (CCustomShaderEffectVehicle*)pCSE;
Assert(pCSEVehicle);
#if __PPU && USE_EDGE
const grcTexture *pVehicleDamageTex = NULL;
void *pEdgeVehicleDamageTex = NULL;
bool bIsEdgeVehicle = false;
if(pModelInfo->GetModelType()==MI_TYPE_VEHICLE)
{
CCustomShaderEffectVehicle *pShader = pCSEVehicle;
if(pShader)
{
bIsEdgeVehicle = true;
pVehicleDamageTex = pCSEVehicle->GetDamageTex();
if(pVehicleDamageTex && pShader->GetEnableDamage())
{
const CellGcmTexture* gcmTex = reinterpret_cast<const CellGcmTexture*>(pVehicleDamageTex->GetTexturePtr());
// damage texture format: is it X32_FLOAT linear?
Assertf(gcmTex->format==(CELL_GCM_TEXTURE_X32_FLOAT|CELL_GCM_TEXTURE_LN), "Vehicle Damage: Unrecognized texture format (not FLOAT32 linear)!");
// damage texture in main memory?
Assertf(gcm::IsValidMainOffset(gcmTex->offset)==TRUE, "Vehicle Damage: Texture not in MAIN memory!");
pEdgeVehicleDamageTex = gcm::MainPtr(gcmTex->offset);
AlignedAssertf(u32(pEdgeVehicleDamageTex), 16, "pEdgeVehicleDamageTex=0x%X not 16-aligned!", (u32)pEdgeVehicleDamageTex);
#if SPU_GCM_FIFO
SPU_COMMAND(GTA4__SetDamageTexture,0xff);
cmd->damageTexture = pEdgeVehicleDamageTex;
cmd->boundRadius = pShader->GetBoundRadius();
#endif //SPU_GCM_FIFO...
}
else
{
#if SPU_GCM_FIFO
SPU_COMMAND(GTA4__SetDamageTexture,0xff);
cmd->damageTexture = NULL;
cmd->boundRadius = 0.0f;
#endif //SPU_GCM_FIFO...
}
}// if(pShader)...
}//if(MI_TYPE_VEHICLE)...
#endif //__PPU && USE_EDGE...
float dist = m_rootMatrix.d.Dist(camInterface::GetPos());
#if __BANK
dist = dist / CVehicleFactory::ms_vehicleLODScaling;
#endif //__BANK
#if RAGE_INSTANCED_TECH
grcViewport::SetViewportInstancedRenderBit(m_viewportInstancedRenderBit);
#endif
for (s32 i = 0; i < VMT_RENDERABLE + MAX_LINKED_MODS; i++)
{
if (!m_variation.IsModVisible((u8)i))
{
continue;
}
const u8* mods = m_variation.GetMods();
const u8* linkedMods = m_variation.GetLinkedMods();
s32 linkedModIndex = (i - VMT_RENDERABLE);
bool renderableMod = (i < VMT_RENDERABLE);
s32 modIndex = renderableMod ? i : linkedModIndex;
u16 modEntry = renderableMod ? mods[modIndex] : linkedMods[modIndex];
if (modEntry == INVALID_MOD)
{
continue;
}
fragType* type = renderGfx->GetFrag((u8)i);
if (!type)
{
continue;
}
rmcDrawable* damagedDrawable = type->GetDamagedDrawable();
rmcDrawable* drawable = (damagedDrawable != NULL) ? damagedDrawable : type->GetCommonDrawable();
if (!drawable)
{
continue;
}
if (type)
{
grmMatrixSet* sharedSet = type->GetSharedMatrixSet();
fragDrawable* toDraw = type->GetCommonDrawable();
Assert(toDraw);
#if (__XENON || __PS3)
rmcLodGroup& LodGroup = toDraw->GetLodGroup();
if (!LodGroup.ContainsLod(1) && (dist > (LodGroup.GetLodThresh(0) * g_LodScale.GetGlobalScaleForRenderThread() * m_lodMult)))
{
continue;
}
#endif // (__XENON || __PS3)
if (LODDrawable::IsRenderingLowestCascade())
{ // don't need these in the lowest cascade
continue;
}
CCustomShaderEffectVehicleType* pModType = renderGfx->GetFragCSEType((u8)i);
if (type->GetSkinned())
{
// set shader variables for vehicle mod:
static dev_bool bEnableCSE1 = true;
if(bEnableCSE1)
{
// replace main vehicle Type with mod Type:
CCustomShaderEffectVehicleType* oldType = pModType->SwapType(pCSEVehicle);
Assert(oldType);
#if !USE_GPU_VEHICLEDEFORMATION
#if __PPU && USE_EDGE && SPU_GCM_FIFO
SPU_COMMAND(GTA4__SetDamageTextureOffset,0);
cmd->damageTexOffset = m_variation.GetBonePosition((u8)i);
#endif //SPU_GCM_FIFO...
#endif
pCSEVehicle->SetShaderVariables(toDraw, m_variation.GetBonePosition((u8)i));
oldType->SwapType(pCSEVehicle);
}
localBreakable.AddToDrawBucket(*toDraw, m_mat[i], NULL, sharedSet, dist, contextStats, m_lodMult, false);
#if !USE_GPU_VEHICLEDEFORMATION
#if __PPU && USE_EDGE && SPU_GCM_FIFO
SPU_COMMAND(GTA4__SetDamageTextureOffset,0);
cmd->damageTexOffset = VEC3_ZERO;
#endif //SPU_GCM_FIFO...
#endif
}
else
{
if (fragTune::IsInstantiated())
{
dist += FRAGTUNE->GetLodDistanceBias();
}
//in this case, we have a list of entities to draw...
for (u64 child = 0; child < type->GetPhysics(0)->GetNumChildren(); ++child)
{
fragTypeChild* childType = type->GetPhysics(0)->GetAllChildren()[child];
// TODO: the destroy/damage bits are wrong, update
toDraw = NULL;
bool destroyed = ((m_destroyedBits & ((u64)1<<child)) != 0);
if (!destroyed)
{
bool broken = ((m_damagedBits & ((u64)1<<child)) != 0);
broken &= (childType->GetDamagedEntity() != NULL);
toDraw = broken ? childType->GetDamagedEntity() : childType->GetUndamagedEntity();
}
if (toDraw)
{
const rmcLodGroup& lod = toDraw->GetLodGroup();
if (!fragTune::IsInstantiated() || dist < FRAGTUNE->GetGlobalMaxDrawingDistance() + lod.GetCullRadius())
{
// set shader variables for vehicle mod:
static dev_bool bEnableCSE2 = true;
if(bEnableCSE2)
{
// replace main vehicle Type with mod Type:
CCustomShaderEffectVehicleType *oldType = pModType->SwapType(pCSEVehicle);
Assert(oldType);
pCSEVehicle->SetShaderVariables(toDraw);
// swap back to old type!
oldType->SwapType(pCSEVehicle);
}
localBreakable.AddToDrawBucket(*toDraw, m_mat[i], ms, sharedSet, dist, contextStats, m_lodMult, false);
#if __PFDRAW
toDraw->ProfileDraw(NULL, &m_mat[i], lod.ComputeLod(0.f)); // should we use dist here instead of 0.f?
#endif
}
}
}
}
} // if(type)...
}// for (s32 i = 0; i < VMT_RENDERABLE; i++)...
// render wheels
if (m_variation.HasCustomWheels() || m_variation.HasCustomRearWheels())
{
#if __BANK
if (!DRAWLISTMGR->IsExecutingDebugOverlayDrawList() || !grmModel::HasCustomShaderParamsFunc()) // TODO -- support wheels properly in wireframe with custom shader params func
#endif // __BANK
{
FragDrawCarWheels((CVehicleModelInfo*)pModelInfo, m_rootMatrix, ms, m_destroyedBits, bucket, m_hasBurstWheels, m_wheelBurstRatios, dist, 0, m_variation.GetVehicleRenderGfx(), m_variation.CanHaveRearWheels(), m_lodMult);
}
}
#if __PPU && USE_EDGE
if(bIsEdgeVehicle)
{
pEdgeVehicleDamageTex = NULL;
#if SPU_GCM_FIFO
SPU_COMMAND(GTA4__SetDamageTexture,0x00);
cmd->damageTexture = NULL;
cmd->boundRadius = 0.0f;
#endif //SPU_GCM_FIFO...
}
#endif //__PPU && USE_EDGE...
g_pBreakable = NULL;
/* localBreakable.SetLowLodMultiplier(m_lowLodMult);
localBreakable.SetClampedLod(-1);
localBreakable.SetIsWreckedVehicle(false);
localBreakable.SetIsHd(false);
localBreakable.SetIsVehicleMod(false);
localBreakable.SetEntityAlpha(255);
localBreakable.SetModelType(-1);
localBreakable.SetRenderMode(rmNIL);
localBreakable.SetDrawBucketMask(0); */
CShaderLib::SetGlobalDeferredMaterial(DEFERRED_MATERIAL_DEFAULT, m_forceSetMaterial && isDrawSceneDrawList MSAA_EDGE_PROCESS_FADING_ONLY(, m_matLocalPlayerEmblem));
CShaderLib::ResetAlpha(setAlpha,setStipple);
DbgCleanDrawableModelIdxForSpu();
#if DEBUG_ENTITY_GPU_COST
if(m_commonData.GetCaptureStats())
{
gDrawListMgr->StopDebugEntityTimer();
}
STOP_SPU_STAT_RECORD(m_commonData.GetCaptureStats());
#endif
EndModelGcmMarker();
}