Files
GTASource/game/vfx/decals/DecalManager.cpp

3158 lines
110 KiB
C++
Raw Normal View History

2025-02-23 17:40:52 +08:00
///////////////////////////////////////////////////////////////////////////////
//
// FILE: DecalManager.cpp
// BY : Mark Nicholson
// FOR : Rockstar North
// ON : 12 May 2010
// WHAT:
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// INCLUDES
///////////////////////////////////////////////////////////////////////////////
#include "DecalManager.h"
// rage
#include "math/random.h"
#include "phbound/boundcomposite.h"
#include "system/nelem.h"
#include "system/threadtype.h"
// framework
#include "grcore/debugdraw.h"
#include "fwsys/glue.h"
#include "vfx/channel.h"
#include "vfx/vfxutil.h"
#include "vfx/decal/decalmanager.h"
#include "vfx/decal/decalsettings.h"
// game
#include "camera/viewports/ViewportManager.h"
#include "control/replay/Effects/ProjectedTexturePacket.h"
#include "control/replay/Effects/ParticleVehicleFxPacket.h"
#include "Core/Game.h"
#include "Game/Weather.h"
#include "ModelInfo/PedModelInfo.h"
#include "ModelInfo/VehicleModelInfo.h"
#include "Network/Live/livemanager.h"
#include "Network/Live/NetworkClan.h"
#include "Network/Objects/Entities/NetObjVehicle.h"
#include "Peds/PlayerInfo.h"
#include "Peds/Ped.h"
#include "Peds/Rendering/PedVariationDS.h"
#include "Peds/Rendering/PedVariationStream.h"
#include "Peds/rendering/PedVariationPack.h"
#include "Physics/GtaInst.h"
#include "Physics/Physics.h"
#include "Renderer/Deferred/GBuffer.h"
#include "renderer/Entities/PedDrawHandler.h"
#include "renderer/lights/lights.h"
#include "Renderer/RenderTargets.h"
#include "renderer/PostProcessFX.h"
#include "Scene/DataFileMgr.h"
#include "Scene/World/GameWorld.h"
#include "Shaders/ShaderLib.h"
#include "Vehicles/Vehicle.h"
#include "Vfx/Decals/DecalAsyncTaskDesc.h"
#include "Vfx/Decals/DecalCallbacks.h"
#include "vfx/vehicleglass/VehicleGlassManager.h"
#include "Vfx/VfxHelper.h"
#include "Vfx/Misc/Fire.h"
#include "Vfx/Particles/PtfxManager.h"
#include "Vfx/Systems/VfxBlood.h"
#include "Vfx/Systems/VfxLiquid.h"
#include "Vfx/Systems/VfxMaterial.h"
#include "Vfx/Systems/VfxPed.h"
#include "Vfx/Systems/VfxWeapon.h"
#include "Vfx/Systems/VfxWheel.h"
#include "control/replay/effects/Particlebloodfxpacket.h"
///////////////////////////////////////////////////////////////////////////////
// OPTIMISATIONS - TURN ON IN OPTIMISATIONS.H
///////////////////////////////////////////////////////////////////////////////
VFX_DECAL_OPTIMISATIONS()
///////////////////////////////////////////////////////////////////////////////
// DEFINES
///////////////////////////////////////////////////////////////////////////////
#define DECAL_COLN_FLAG_MAP (1<<PH_INST_MAPCOL)
#define DECAL_COLN_FLAG_BUILDINGS (1<<PH_INST_BUILDING)
#define DECAL_COLN_FLAG_PEDS ((1<<PH_INST_PED) | (1<<PH_INST_FRAG_PED))
#define DECAL_COLN_FLAG_VEHICLES ((1<<PH_INST_VEH) | (1<<PH_INST_FRAG_VEH))
#define DECAL_COLN_FLAG_OBJECT ((1<<PH_INST_OBJECT) | (1<<PH_INST_FRAG_OBJECT) | (1<<PH_INST_FRAG_CACHE_OBJECT))
#define DECAL_COLN_FLAG_ALL (DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS | DECAL_COLN_FLAG_VEHICLES | DECAL_COLN_FLAG_OBJECT | DECAL_COLN_FLAG_PEDS)
#define DECAL_COLN_FLAG_ALL_BAR_PEDS (DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS | DECAL_COLN_FLAG_VEHICLES | DECAL_COLN_FLAG_OBJECT)
#define DECAL_NUM_GLASS_SHADERS (9)
#define DECAL_MAX_SHADER_STRING_LENGTH (64)
///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
///////////////////////////////////////////////////////////////////////////////
#if __PS3
DECLARE_TASK_INTERFACE(DecalProcessBound);
DECLARE_TASK_INTERFACE(DecalProcessDrawablesNonSkinned);
DECLARE_TASK_INTERFACE(DecalProcessDrawablesSkinned);
DECLARE_TASK_INTERFACE(DecalProcessSmashGroup);
#endif
CDecalManager g_decalMan;
decalTypeSettings g_typeSettings[DECALTYPE_NUM] =
{
// depth zShiftOffst polyRejectThreshold lodDistance fadeDistance cullDistance, canMergeInsts, wrapUV, useAniso, isPersistent, collisionFlags,
// DECALTYPE_BANG
{0.5f, 0.000f, 0.5f, 20.0f, 30.0f, 40.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_BLOOD_SPLAT
{0.5f, 0.005f, 0.3f, 30.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_FOOTPRINT
{0.3f, 0.003f, 0.3f, 10.0f, 20.0f, 25.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
// DECALTYPE_GENERIC_SIMPLE_COLN
{0.3f, 0.000f, 0.3f, 20.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
// DECALTYPE_GENERIC_COMPLEX_COLN
{0.3f, 0.000f, 0.3f, 20.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_GENERIC_SIMPLE_COLN_LONG_RANGE
{0.3f, 0.000f, 0.3f, 50.0f, 450.0f, 500.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
// DECALTYPE_GENERIC_COMPLEX_COLN_LONG_RANGE
{0.3f, 0.000f, 0.3f, 50.0f, 450.0f, 500.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_POOL_LIQUID
{0.3f, 0.009f, 0.3f, 30.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
// DECALTYPE_SCUFF
{0.5f, 0.000f, 0.5f, 20.0f, 30.0f, 40.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_TRAIL_SCRAPE
{0.3f, 0.000f, 0.5f, 15.0f, 25.0f, 30.0f, true, true, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_TRAIL_LIQUID
{0.3f, 0.008f, 0.3f, 20.0f, 50.0f, 60.0f, true, true, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_TRAIL_SKID
{0.3f, 0.003f, 0.3f, 20.0f, 50.0f, 60.0f, true, true, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_OBJECT},
// DECALTYPE_TRAIL_GENERIC
{0.3f, 0.000f, 0.3f, 20.0f, 50.0f, 60.0f, true, true, false, false, DECAL_COLN_FLAG_MAP},
// DECALTYPE_VEHICLE_BADGE
{0.3f, 0.000f, 0.3f, 0.0f, 50.0f, 60.0f, false, false, true, true, DECAL_COLN_FLAG_VEHICLES},
// DECALTYPE_VEHICLE_BADGE+1
{0.3f, 0.000f, 0.3f, 0.0f, 50.0f, 60.0f, false, false, true, true, DECAL_COLN_FLAG_VEHICLES},
// DECALTYPE_VEHICLE_BADGE+2
{0.3f, 0.000f, 0.3f, 0.0f, 50.0f, 60.0f, false, false, true, true, DECAL_COLN_FLAG_VEHICLES},
// DECALTYPE_VEHICLE_BADGE+3
{0.3f, 0.000f, 0.3f, 0.0f, 50.0f, 60.0f, false, false, true, true, DECAL_COLN_FLAG_VEHICLES},
// DECALTYPE_WEAPON_IMPACT
{0.3f, 0.003f, 0.3f, 20.0f, 30.0f, 40.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_WEAPON_IMPACT_SHOTGUN
{0.3f, 0.003f, 0.3f, 20.0f, 30.0f, 40.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_WEAPON_IMPACT_SMASHGROUP
{1.0f, 0.003f, 0.3f, 30.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_WEAPON_IMPACT_SMASHGROUP_SHOTGUN
{1.0f, 0.003f, 0.3f, 30.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_WEAPON_IMPACT_EXPLOSION_GROUND
{2.0f, 0.003f, 0.3f, 125.0f, 100.0f, 125.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
// DECALTYPE_WEAPON_IMPACT_EXPLOSION_VEHICLE (currently planes only - make depth massive so decals appear fine on jumbo jet)
{10.0f, 0.003f, -1.0f, 125.0f, 100.0f, 125.0f, false, false, false, false, DECAL_COLN_FLAG_VEHICLES},
// DECALTYPE_WEAPON_IMPACT_VEHICLE
{0.3f, 0.003f, 0.3f, 20.0f, 100.0f, 125.0f, false, false, false, false, DECAL_COLN_FLAG_ALL_BAR_PEDS},
// DECALTYPE_WEAPON_IMPACT_PED
// {0.1f, 0.003f, 0.3f, 20.0f, 30.0f, 40.0f, false, false, false, false, DECAL_COLN_FLAG_PEDS},
// DECALTYPE_LASER_SIGHT
// {0.3f, 0.010f, 0.0f, 0.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_ALL},
// DECALTYPE_MARKER
{1.0f, 0.001f, 0.3f, 50.0f, 50.0f, 60.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
// DECALTYPE_MARKER_LONG_RANGE
{1.0f, 0.001f, 0.3f, 50.0f, 450.0f, 500.0f, false, false, false, false, DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_BUILDINGS},
};
dev_u8 DECAL_VEHICLE_BADGE_TINT_R = 255;
dev_u8 DECAL_VEHICLE_BADGE_TINT_G = 255;
dev_u8 DECAL_VEHICLE_BADGE_TINT_B = 255;
dev_float DECAL_BLOOD_SPLAT_DRD_WIDTH_MULT = 0.5f;
///////////////////////////////////////////////////////////////////////////////
// CODE
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::Init()
{
m_emblemDesc.Invalidate();
m_txdHashName.Clear();
m_texHashName.Clear();
m_pTexture = nullptr;
}
///////////////////////////////////////////////////////////////////////////////
// Set
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::Set(EmblemDescriptor& emblemDesc)
{
m_emblemDesc = emblemDesc;
m_txdHashName.Clear();
m_texHashName.Clear();
m_pTexture = nullptr;
}
///////////////////////////////////////////////////////////////////////////////
// Set
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::Set(atHashWithStringNotFinal txdHashName, atHashWithStringNotFinal texHashName)
{
m_emblemDesc.Invalidate();
m_txdHashName = txdHashName;
m_texHashName = texHashName;
m_pTexture = nullptr;
}
///////////////////////////////////////////////////////////////////////////////
// Set
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::Set(EmblemDescriptor& emblemDesc, atHashWithStringNotFinal txdHashName, atHashWithStringNotFinal texHashName)
{
m_emblemDesc = emblemDesc;
m_txdHashName = txdHashName;
m_texHashName = texHashName;
m_pTexture = nullptr;
decalAssertf(IsValid(), "invalid vehicle badge desc settings");
}
///////////////////////////////////////////////////////////////////////////////
// Request
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeDesc::Request() const
{
if (IsUsingEmblem())
{
return NETWORK_CLAN_INST.GetCrewEmblemMgr().RequestEmblem(m_emblemDesc ASSERT_ONLY(, "CVehicleBadgeManager"));
}
else
{
return RequestTxd();
}
}
///////////////////////////////////////////////////////////////////////////////
// GetTexture
///////////////////////////////////////////////////////////////////////////////
grcTexture* CVehicleBadgeDesc::GetTexture()
{
#if __BANK
if (g_decalMan.GetDebugInterface().GetVehicleBadgeSimulateCloudIssues())
{
return nullptr;
}
#endif
if (IsUsingEmblem())
{
const char* pEmblemName = NETWORK_CLAN_INST.GetCrewEmblemMgr().GetEmblemName(m_emblemDesc);
if (pEmblemName)
{
fwTxd* pTxd = g_TxdStore.GetSafeFromName(pEmblemName);
if (pTxd)
{
m_pTexture = pTxd->Lookup(pEmblemName);
}
}
}
else
{
if (HasTxdLoaded())
{
fwTxd* pTxd = g_TxdStore.GetSafeFromName(m_txdHashName);
if (pTxd)
{
m_pTexture = pTxd->Lookup(m_texHashName);
}
}
}
return m_pTexture;
}
///////////////////////////////////////////////////////////////////////////////
// Release
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::Release() const
{
if (IsUsingEmblem())
{
NETWORK_CLAN_INST.GetCrewEmblemMgr().ReleaseEmblem(m_emblemDesc ASSERT_ONLY(, "CVehicleBadgeManager"));
}
}
///////////////////////////////////////////////////////////////////////////////
// IsFree
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeDesc::IsFree() const
{
return m_emblemDesc.IsValid()==false && m_txdHashName.IsNull() && m_texHashName.IsNull();
}
///////////////////////////////////////////////////////////////////////////////
// IsValid
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeDesc::IsValid() const
{
return (m_emblemDesc.IsValid()==false && m_txdHashName.IsNotNull() && m_texHashName.IsNotNull()) ||
(m_emblemDesc.IsValid() && m_txdHashName.IsNull() && m_texHashName.IsNull());
}
///////////////////////////////////////////////////////////////////////////////
// IsEqual
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeDesc::IsEqual(const CVehicleBadgeDesc& other) const
{
return m_emblemDesc==other.m_emblemDesc && m_txdHashName==other.m_txdHashName && m_texHashName==other.m_texHashName;
}
///////////////////////////////////////////////////////////////////////////////
// Serialise
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::Serialise(CSyncDataBase& serialiser)
{
bool usingEmblemDesc = IsUsingEmblem();
SERIALISE_BOOL(serialiser, usingEmblemDesc);
if (usingEmblemDesc && !serialiser.GetIsMaximumSizeSerialiser())
{
m_emblemDesc.Serialise(serialiser);
m_txdHashName.Clear();
m_texHashName.Clear();
m_pTexture = nullptr;
}
else
{
u32 txdHash = m_txdHashName.GetHash();
SERIALISE_HASH(serialiser, txdHash, "txd name");
m_txdHashName = txdHash;
u32 texHash = m_texHashName.GetHash();
SERIALISE_HASH(serialiser, texHash, "texture name");
m_texHashName = texHash;
m_emblemDesc.Invalidate();
m_pTexture = nullptr;
}
}
///////////////////////////////////////////////////////////////////////////////
// RequestTxd
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeDesc::RequestTxd() const
{
strLocalIndex txdSlot = g_TxdStore.FindSlotFromHashKey(m_txdHashName);
if (vfxVerifyf(txdSlot.IsValid(), "Texture dictionary %s not present or not registered with CStreaming", m_txdHashName.TryGetCStr()))
{
if (g_TxdStore.Get(txdSlot))
{
return true;
}
else
{
strIndex index = g_TxdStore.GetStreamingIndex(txdSlot);
return strStreamingEngine::GetInfo().RequestObject(index, STRFLAG_DONTDELETE|STRFLAG_FORCE_LOAD|STRFLAG_PRIORITY_LOAD);
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// HasTxdLoaded
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeDesc::HasTxdLoaded() const
{
strLocalIndex txdSlot = g_TxdStore.FindSlotFromHashKey(m_txdHashName);
if (vfxVerifyf(txdSlot.IsValid(), "Texture dictionary %s not present or not registered with CStreaming", m_txdHashName.TryGetCStr()))
{
strIndex index = g_TxdStore.GetStreamingIndex(txdSlot);
if (strStreamingEngine::GetInfo().GetStreamingInfoRef(index).GetStatus()==STRINFO_LOADED)
{
strStreamingEngine::GetInfo().ClearRequiredFlag(index, STRFLAG_DONTDELETE);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// AddTextureRef
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::AddTextureRef()
{
decalAssertf(m_pTexture, "trying to add a reference to an invalid texture");
if (m_pTexture)
{
m_pTexture->AddRef();
}
}
///////////////////////////////////////////////////////////////////////////////
// RemoveTextureRef
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeDesc::RemoveTextureRef()
{
decalAssertf(m_pTexture, "trying to add a reference to an invalid texture");
if (m_pTexture)
{
m_pTexture->DecRef();
}
}
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeData::Init()
{
m_badgeDesc.Init();
m_refCount = 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddRef
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeData::AddRef()
{
m_badgeDesc.AddTextureRef();
m_refCount++;
}
///////////////////////////////////////////////////////////////////////////////
// RemoveRef
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeData::RemoveRef(s32 decalId)
{
m_badgeDesc.RemoveTextureRef();
m_refCount--;
if (m_refCount==0)
{
grcTexture* pDiffuseMap = const_cast<grcTexture*>(grcTexture::None);
g_decalMan.PatchDiffuseMap(decalId, pDiffuseMap);
Init();
}
}
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeManager::Init()
{
m_requests.Resize(MAX_VEHICLE_BADGE_REQUESTS);
for (int i=0; i<MAX_VEHICLE_BADGE_REQUESTS; i++)
{
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
}
m_vehicleBadgeData.Resize(DECALID_VEHICLE_BADGE_NUM);
for (int i=0; i<DECALID_VEHICLE_BADGE_NUM; i++)
{
m_vehicleBadgeData[i].Init();
}
}
///////////////////////////////////////////////////////////////////////////////
// Shutdown
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeManager::Shutdown()
{
for (int i=0; i<MAX_VEHICLE_BADGE_REQUESTS; i++)
{
if (m_requests[i].m_currState != DECALREQUESTSTATE_NOT_ACTIVE)
{
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
}
}
for (int i=0; i<DECALID_VEHICLE_BADGE_NUM; i++)
{
for (int j=0; j<m_vehicleBadgeData[i].GetRefCount(); j++)
{
m_requests[i].m_badgeDesc.Release();
}
m_vehicleBadgeData[i].Init();
g_decalMan.Remove(DECALID_VEHICLE_BADGE_FIRST+i);
grcTexture* pDiffuseMap = const_cast<grcTexture*>(grcTexture::None);
g_decalMan.PatchDiffuseMap(DECALID_VEHICLE_BADGE_FIRST+i, pDiffuseMap);
}
}
///////////////////////////////////////////////////////////////////////////////
// CleanUpAfterFailure
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeManager::CleanUpAfterFailure(CVehicleBadgeRequestData* pRequest)
{
if (pRequest->m_currState>=DECALREQUESTSTATE_FAILED)
{
if (pRequest->m_currState>=DECALREQUESTSTATE_FAILED_CANT_GET_CLAN_TEXTURE)
{
pRequest->m_badgeDesc.Release();
}
if (pRequest->m_currState>=DECALREQUESTSTATE_FAILED_VEHICLE_NO_LONGER_VALID)
{
for (int j=0; j<DECALID_VEHICLE_BADGE_NUM; j++)
{
if (m_vehicleBadgeData[j].GetVehicleBadgeDesc().IsEqual(pRequest->m_badgeDesc))
{
m_vehicleBadgeData[j].RemoveRef(DECALID_VEHICLE_BADGE_FIRST+j);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Update
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeManager::Update()
{
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_currState!=DECALREQUESTSTATE_NOT_ACTIVE)
{
// increment the count since the request was made
m_requests[i].m_numFramesSinceRequest++;
// check for requests that have timed out
if (m_requests[i].m_numFramesSinceRequest>1000)
{
if (m_requests[i].m_currState>=DECALREQUESTSTATE_SUCCEEDED)
{
// the request is complete (succeeded or failed) - just deactivate the request
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
}
else if (m_requests[i].m_currState==DECALREQUESTSTATE_REQUESTING_BADGE)
{
// allow a little longer to get this data from the cloud
if (m_requests[i].m_numFramesSinceRequest>1500)
{
// the request is still trying to get the emblem from the cloud - time it out, it's taken too long
m_requests[i].m_badgeDesc.Release();
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
}
}
#if __ASSERT
else
{
decalAssertf(0, "vehicle badge request hasn't been queried in 1000 frames and hasn't finished (currState: %d)", m_requests[i].m_currState);
}
#endif
}
// check for the vehicle being deleted
if (m_requests[i].m_currState==DECALREQUESTSTATE_REQUESTING_BADGE)
{
grcTexture* pDiffuseMap = m_requests[i].m_badgeDesc.GetTexture();
if (pDiffuseMap)
{
m_requests[i].m_decalId = 0;
m_requests[i].m_currState = DECALREQUESTSTATE_FAILED_CANT_ADD_DATA_SLOT;
s32 idx = AddData(m_requests[i].m_badgeDesc);
if (idx>-1)
{
g_decalMan.PatchDiffuseMap(DECALID_VEHICLE_BADGE_FIRST+idx, pDiffuseMap);
m_requests[i].m_currState = DECALREQUESTSTATE_FAILED_VEHICLE_NO_LONGER_VALID;
if (m_requests[i].m_regdVeh)
{
const CVehicle* pVehicle = m_requests[i].m_regdVeh;
Mat34V vVehicleMtx = pVehicle->GetTransform().GetMatrix();
s32 validComponentIds[3] = {-1, -1, -1};
s32 boneIndex = pVehicle->GetBoneIndex((eHierarchyId)(VEH_BONNET));
if (boneIndex>-1)
{
validComponentIds[0] = pVehicle->GetVehicleFragInst()->GetComponentFromBoneIndex(boneIndex);
}
boneIndex = pVehicle->GetBoneIndex((eHierarchyId)(VEH_DOOR_DSIDE_F));
if (boneIndex>-1)
{
validComponentIds[1] = pVehicle->GetVehicleFragInst()->GetComponentFromBoneIndex(boneIndex);
}
boneIndex = pVehicle->GetBoneIndex((eHierarchyId)(VEH_DOOR_PSIDE_F));
if (boneIndex>-1)
{
validComponentIds[2] = pVehicle->GetVehicleFragInst()->GetComponentFromBoneIndex(boneIndex);
}
m_requests[i].m_currState = DECALREQUESTSTATE_FAILED_VEHICLE_BONE_NOT_VALID;
s32 badgeBoneIndex = m_requests[i].m_boneIndex;
if (badgeBoneIndex>-1)
{
Mat34V vBoneMtxWld;
CVfxHelper::GetMatrixFromBoneIndex(vBoneMtxWld, pVehicle, badgeBoneIndex);
m_requests[i].m_currState = DECALREQUESTSTATE_FAILED_VEHICLE_BONE_IS_ZERO;
if (IsZeroAll(vBoneMtxWld.GetCol0())==false)
{
Vec3V vPosWld = vBoneMtxWld.GetCol3();
vPosWld = vPosWld + (vVehicleMtx.GetCol0()*ScalarVFromF32(m_requests[i].m_vOffsetPos.GetXf()));
vPosWld = vPosWld + (vVehicleMtx.GetCol1()*ScalarVFromF32(m_requests[i].m_vOffsetPos.GetYf()));
vPosWld = vPosWld + (vVehicleMtx.GetCol2()*ScalarVFromF32(m_requests[i].m_vOffsetPos.GetZf()));
Vec3V vDirWld = Transform3x3(vVehicleMtx, m_requests[i].m_vDir);
Vec3V vSideWld = Transform3x3(vVehicleMtx, m_requests[i].m_vSide);
u32 probeFlags = ArchetypeFlags::GTA_VEHICLE_TYPE;
Vec3V vPosStart = vPosWld;
Vec3V vPosEnd = vPosStart + vDirWld;
const s32 MAX_PROBE_RESULTS = 4;
WorldProbe::CShapeTestHitPoint probeResult[MAX_PROBE_RESULTS];
WorldProbe::CShapeTestResults probeResults(probeResult, MAX_PROBE_RESULTS);
WorldProbe::CShapeTestProbeDesc probeDesc;
probeDesc.SetResultsStructure(&probeResults);
probeDesc.SetIncludeFlags(probeFlags);
probeDesc.SetIncludeEntity(pVehicle);
probeDesc.SetStartAndEnd(RCC_VECTOR3(vPosStart), RCC_VECTOR3(vPosEnd));
#if __BANK
if (g_decalMan.GetDebugInterface().GetVehicleBadgeProbeDebug())
{
grcDebugDraw::Line(vPosStart, vPosEnd, Color32(1.0f, 1.0f, 0.0f, 1.0), -30);
}
#endif
m_requests[i].m_currState = DECALREQUESTSTATE_FAILED_VEHICLE_PROBE_FAILED;
if (WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc, WorldProbe::PERFORM_SYNCHRONOUS_TEST))
{
for (int j=0; j<MAX_PROBE_RESULTS; j++)
{
CEntity* pHitEntity = CPhysics::GetEntityFromInst(probeResults[j].GetHitInst());
if (pHitEntity && pHitEntity==pVehicle)
{
if (pVehicle->GetVehicleType()==VEHICLE_TYPE_BIKE ||
probeResults[j].GetHitComponent()==validComponentIds[0] ||
probeResults[j].GetHitComponent()==validComponentIds[1] ||
probeResults[j].GetHitComponent()==validComponentIds[2])
{
u32 renderSettingIndex, renderSettingCount;
if (decalSettingsManager::FindRenderSettingInfo(DECALID_VEHICLE_BADGE_FIRST+idx, renderSettingIndex, renderSettingCount))
{
m_requests[i].m_decalId = g_decalMan.AddVehicleBadge(pVehicle, probeResults[j].GetHitComponent(), renderSettingIndex, renderSettingCount, probeResults[j].GetHitPositionV(), vDirWld, vSideWld, m_requests[i].m_size, m_requests[i].m_isForLocalPlayer, m_requests[i].m_badgeIndex, m_requests[i].m_alpha);
pVehicle->SetEmblemMaterialGroup(m_requests[i].m_isForLocalPlayer);
m_requests[i].m_currState = DECALREQUESTSTATE_APPLYING_DECAL;
}
break;
}
}
}
}
}
}
}
}
}
// tidy up if anything fails
CleanUpAfterFailure(&m_requests[i]);
}
else if (m_requests[i].m_currState==DECALREQUESTSTATE_APPLYING_DECAL)
{
// check if the decal is no longer pending
if (g_decalMan.IsDecalPending(m_requests[i].m_decalId)==false)
{
// it isn't - check that it has been applied
if (g_decalMan.DoesVehicleHaveBadge(m_requests[i].m_regdVeh, m_requests[i].m_badgeIndex))
{
m_requests[i].m_currState = DECALREQUESTSTATE_SUCCEEDED;
}
else
{
m_requests[i].m_currState = DECALREQUESTSTATE_FAILED_DECAL_DIDNT_APPLY;
}
}
// tidy up if anything fails
CleanUpAfterFailure(&m_requests[i]);
}
}
// remove any completed requests that are flagged
if (m_requests[i].m_removeOnceComplete)
{
if (m_requests[i].m_currState==DECALREQUESTSTATE_SUCCEEDED)
{
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
Remove(m_requests[i].m_regdVeh, m_requests[i].m_badgeIndex);
}
else if (m_requests[i].m_currState>=DECALREQUESTSTATE_FAILED)
{
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Request
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeManager::Request(const CVehicle* pVehicle, const CVehicleBadgeDesc& badgeDesc, s32 boneIndex, Vec3V_In vOffsetPos, Vec3V_In vDir, Vec3V_In vSide, float size, bool isForLocalPlayer, u32 badgeIndex, u8 alpha)
{
decalAssertf(badgeIndex < DECAL_NUM_VEHICLE_BADGES, "Vehicle Badge Index out of range");
// check that this vehicle doesn't already have a badge
decalBucket* pBucket = g_decalMan.FindFirstBucket(1<<(DECALTYPE_VEHICLE_BADGE+badgeIndex), pVehicle);
if (pBucket)
{
decalAssertf(0, "requesting a badge on a vehicle that already has one");
return false;
}
// check that a request isn't already in progress for this vehicle
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_currState!=DECALREQUESTSTATE_NOT_ACTIVE && m_requests[i].m_regdVeh==pVehicle && m_requests[i].m_badgeIndex==badgeIndex)
{
decalAssertf(0, "requesting a badge on a vehicle when one has already been requested");
return false;
}
}
bool hasRequested = false;
// check the validity of the request
if (pVehicle)
{
if (decalVerifyf(boneIndex>=0 && boneIndex<pVehicle->GetSkeletonData().GetNumBones(), "requesting a vehicle badge on an invalid bone index (%s %d)", pVehicle->GetDebugName(), boneIndex))
{
// need to request it
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_currState==DECALREQUESTSTATE_NOT_ACTIVE)
{
hasRequested = badgeDesc.Request();
if (hasRequested)
{
m_requests[i].m_currState = DECALREQUESTSTATE_REQUESTING_BADGE;
m_requests[i].m_badgeDesc = badgeDesc;
m_requests[i].m_regdVeh = pVehicle;
m_requests[i].m_boneIndex = boneIndex;
m_requests[i].m_vOffsetPos = vOffsetPos;
m_requests[i].m_vDir = vDir;
m_requests[i].m_vSide = vSide;
m_requests[i].m_size = size;
m_requests[i].m_numFramesSinceRequest = 0;
m_requests[i].m_removeOnceComplete = false;
m_requests[i].m_isForLocalPlayer = isForLocalPlayer;
m_requests[i].m_badgeIndex = badgeIndex;
m_requests[i].m_alpha = alpha;
}
break;
}
}
}
}
#if GTA_REPLAY
if( CReplayMgr::ShouldRecord() )
{
CReplayMgr::RecordFx<CPacketVehicleBadgeRequest>(
CPacketVehicleBadgeRequest(badgeDesc, boneIndex, vOffsetPos, vDir, vSide, size, isForLocalPlayer, badgeIndex, alpha),
pVehicle);
}
#endif
return hasRequested;
}
///////////////////////////////////////////////////////////////////////////////
// Abort
///////////////////////////////////////////////////////////////////////////////
bool CVehicleBadgeManager::Abort(const CVehicle* pVehicle)
{
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_regdVeh==pVehicle)
{
if (m_requests[i].m_currState==DECALREQUESTSTATE_REQUESTING_BADGE)
{
m_requests[i].m_badgeDesc.Release();
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
return true;
}
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// GetRequestState
///////////////////////////////////////////////////////////////////////////////
DecalRequestState_e CVehicleBadgeManager::GetRequestState(const CVehicle* pVehicle, const u32 badgeIndex)
{
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_currState!=DECALREQUESTSTATE_NOT_ACTIVE && m_requests[i].m_regdVeh==pVehicle && m_requests[i].m_badgeIndex == badgeIndex)
{
if (m_requests[i].m_currState==DECALREQUESTSTATE_REQUESTING_BADGE)
{
return DECALREQUESTSTATE_REQUESTING_BADGE;
}
else if (m_requests[i].m_currState==DECALREQUESTSTATE_APPLYING_DECAL)
{
return DECALREQUESTSTATE_APPLYING_DECAL;
}
else if (m_requests[i].m_currState==DECALREQUESTSTATE_SUCCEEDED)
{
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
return DECALREQUESTSTATE_SUCCEEDED;
}
else if (m_requests[i].m_currState>=DECALREQUESTSTATE_FAILED)
{
DecalRequestState_e failedState = m_requests[i].m_currState;
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
return failedState;
}
}
}
//decalAssertf(0, "querying the state of an invalid request");
return DECALREQUESTSTATE_NOT_ACTIVE;
}
///////////////////////////////////////////////////////////////////////////////
// RemoveCompletedRequests
///////////////////////////////////////////////////////////////////////////////
#if __BANK
void CVehicleBadgeManager::RemoveCompletedRequests()
{
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_currState==DECALREQUESTSTATE_SUCCEEDED ||
m_requests[i].m_currState>=DECALREQUESTSTATE_FAILED)
{
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
}
}
}
#endif
///////////////////////////////////////////////////////////////////////////////
// AddData
///////////////////////////////////////////////////////////////////////////////
s32 CVehicleBadgeManager::AddData(CVehicleBadgeDesc& badgeDesc)
{
// check if data already exists for this clan
s32 firstFreeIdx = -1;
for (int i=0; i<DECALID_VEHICLE_BADGE_NUM; i++)
{
if (m_vehicleBadgeData[i].GetVehicleBadgeDesc().IsEqual(badgeDesc))
{
// it does, add a ref and return the data
m_vehicleBadgeData[i].AddRef();
return i;
}
else if (firstFreeIdx==-1 && m_vehicleBadgeData[i].GetVehicleBadgeDesc().IsFree())
{
firstFreeIdx = i;
}
}
// no data exists - add it
if (decalVerifyf(firstFreeIdx>-1, "vehicle badge data is full"))
{
CVehicleBadgeData* pNewData = &m_vehicleBadgeData[firstFreeIdx];
pNewData->SetVehicleBadgeDesc(badgeDesc);
decalAssertf(pNewData->GetRefCount()==0, "vehicle badge data refcount isn't zero");
pNewData->AddRef();
return firstFreeIdx;
}
return -1;
}
///////////////////////////////////////////////////////////////////////////////
// Remove
///////////////////////////////////////////////////////////////////////////////
void CVehicleBadgeManager::Remove(const CVehicle* pVehicle, const u32 badgeIndex)
{
// check that a request isn't already in progress for this vehicle
for (int i=0; i<m_requests.GetCount(); i++)
{
if (m_requests[i].m_currState!=DECALREQUESTSTATE_NOT_ACTIVE && m_requests[i].m_regdVeh==pVehicle && m_requests[i].m_badgeIndex == badgeIndex)
{
if (m_requests[i].m_currState==DECALREQUESTSTATE_SUCCEEDED)
{
// the request has succeeded but the result hasn't been queried yet
// deactivate the request and remove the decal from the vehicle
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
break;
}
else if (m_requests[i].m_currState>=DECALREQUESTSTATE_FAILED)
{
// the request has failed but the result hasn't been queried yet
// just deactivate the request
m_requests[i].m_currState = DECALREQUESTSTATE_NOT_ACTIVE;
return;
}
else
{
// the request is still in progress
// let it continue and flag it to remove once completed
m_requests[i].m_removeOnceComplete = true;
return;
}
}
}
decalBucket* pBucket = g_decalMan.FindFirstBucket(1<<(DECALTYPE_VEHICLE_BADGE+badgeIndex), pVehicle);
if (pBucket)
{
u16 renderSettingsIndex = pBucket->GetRenderSettingsIndex();
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings)
{
u32 decalId = pRenderSettings->id;
if (decalVerifyf(decalId>=DECALID_VEHICLE_BADGE_FIRST && decalId<DECALID_VEHICLE_BADGE_FIRST+DECALID_VEHICLE_BADGE_NUM, "vehicle badge decal id out of range"))
{
CVehicleBadgeData* pData = &m_vehicleBadgeData[decalId-DECALID_VEHICLE_BADGE_FIRST];
if (decalVerifyf(pData->GetRefCount()>0, "invalid ref count on decal vehicle badge data"))
{
pData->GetVehicleBadgeDesc().Release();
pData->RemoveRef(decalId);
pVehicle->ClearEmblemMaterialGroup();
DECALMGR.Remove(pVehicle, -1, NULL, ~(1U<<(DECALTYPE_VEHICLE_BADGE+badgeIndex)));
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::Init(unsigned initMode)
{
if (initMode == INIT_CORE)
{
m_asyncTaskDescPool.Init(DECAL_MAX_ASYNC_PROCESS_INST_TASKS);
m_numNonPlayerVehicleBangsScuffsThisFrame = 0;
m_disablePetrolDecalsIgniting = false;
m_disablePetrolDecalsIgnitingThisFrame = false;
m_disablePetrolDecalsRecyclingThisFrame = false;
m_disableRenderingThisFrameUT = false;
m_disableRenderingThisFrameRT = false;
m_hasRunCompleteAsync = false;
m_disableFootprintsScriptThreadId = THREAD_INVALID;
m_disableFootprintsFromScript = false;
m_disableCompositeShotgunImpactsScriptThreadId = THREAD_INVALID;
m_disableCompositeShotgunImpactsFromScript = false;
m_disableScuffsScriptThreadId = THREAD_INVALID;
m_disableScuffsFromScript = false;
m_scriptedTrailData.m_isActive = false;
rage_new decalManager;
// Decal manager renderstate overiddes.
grcDepthStencilStateDesc depthStencilBlockIgnoreDesc;
depthStencilBlockIgnoreDesc.DepthFunc = rage::FixupDepthDirection(grcRSV::CMP_LESSEQUAL);
depthStencilBlockIgnoreDesc.DepthWriteMask = 0;
depthStencilBlockIgnoreDesc.StencilEnable = true;
depthStencilBlockIgnoreDesc.StencilReadMask = (DEFERRED_MATERIAL_TYPE_MASK ^ 0x2) | DEFERRED_MATERIAL_VEHICLE_BADGE_LOCAL_PLAYER;
depthStencilBlockIgnoreDesc.StencilWriteMask = 0x0;
depthStencilBlockIgnoreDesc.FrontFace.StencilFunc = grcRSV::CMP_NOTEQUAL;
depthStencilBlockIgnoreDesc.BackFace.StencilFunc = grcRSV::CMP_NOTEQUAL;
grcDepthStencilStateDesc depthStencilBlockExclusiveDesc;
depthStencilBlockExclusiveDesc.DepthFunc = rage::FixupDepthDirection(grcRSV::CMP_LESSEQUAL);
depthStencilBlockExclusiveDesc.DepthWriteMask = 0;
depthStencilBlockExclusiveDesc.StencilEnable = true;
depthStencilBlockExclusiveDesc.StencilReadMask = DEFERRED_MATERIAL_TYPE_MASK | DEFERRED_MATERIAL_VEHICLE_BADGE_LOCAL_PLAYER;
depthStencilBlockExclusiveDesc.StencilWriteMask = 0x0;
depthStencilBlockExclusiveDesc.FrontFace.StencilFunc = grcRSV::CMP_EQUAL;
depthStencilBlockExclusiveDesc.BackFace.StencilFunc = grcRSV::CMP_EQUAL;
grcDepthStencilStateHandle handleIgnore = grcStateBlock::CreateDepthStencilState(depthStencilBlockIgnoreDesc);
grcDepthStencilStateHandle handleExclusive = grcStateBlock::CreateDepthStencilState(depthStencilBlockExclusiveDesc);
DECALMGR.SetDynamicDecalDepthStencilState(DECAL_RENDER_PASS_VEHICLE_BADGE_LOCAL_PLAYER, handleExclusive, DEFERRED_MATERIAL_VEHICLE | DEFERRED_MATERIAL_VEHICLE_BADGE_LOCAL_PLAYER);
DECALMGR.SetStaticDecalDepthStencilState(DECAL_RENDER_PASS_VEHICLE_BADGE_LOCAL_PLAYER, handleExclusive, DEFERRED_MATERIAL_VEHICLE | DEFERRED_MATERIAL_VEHICLE_BADGE_LOCAL_PLAYER);
DECALMGR.SetDynamicDecalDepthStencilState(DECAL_RENDER_PASS_VEHICLE_BADGE_NOT_LOCAL_PLAYER, handleExclusive, DEFERRED_MATERIAL_VEHICLE);
DECALMGR.SetStaticDecalDepthStencilState(DECAL_RENDER_PASS_VEHICLE_BADGE_NOT_LOCAL_PLAYER, handleExclusive, DEFERRED_MATERIAL_VEHICLE);
// Only stencil test in deferred, forward decals still need to show up on peds (like broken windows and whatnot)
DECALMGR.SetDynamicDecalDepthStencilState(DECAL_RENDER_PASS_MISC, handleIgnore, DEFERRED_MATERIAL_PED);
DECALMGR.SetStaticDecalDepthStencilState(DECAL_RENDER_PASS_MISC, handleIgnore, DEFERRED_MATERIAL_PED);
#if GTA_REPLAY
m_ReplayMergedDecalEvents.Reset();
m_ReplayUVMultChanges.Reset();
#endif //GTA_REPLAY
# if __BANK
m_decalDebug.Init();
# endif
}
else if (initMode == INIT_AFTER_MAP_LOADED)
{
}
else if (initMode == INIT_SESSION)
{
m_vehicleBadgeMgr.Init();
}
decalManager *const dm = &DECALMGR;
dm->Init(initMode);
# if __PS3
dm->RegisterSpuTask(DECAL_DO_PROCESSBOUND, TASK_INTERFACE(DecalProcessBound));
dm->RegisterSpuTask(DECAL_DO_PROCESSDRAWABLESNONSKINNED, TASK_INTERFACE(DecalProcessDrawablesNonSkinned));
dm->RegisterSpuTask(DECAL_DO_PROCESSDRAWABLESSKINNED, TASK_INTERFACE(DecalProcessDrawablesSkinned));
dm->RegisterSpuTask(DECAL_DO_PROCESSSMASHGROUP, TASK_INTERFACE(DecalProcessSmashGroup));
# endif
static_cast<CDecalCallbacks*>(g_pDecalCallbacks)->GlobalInit(PGTAMATERIALMGR->GetMaterialArray());
//Create static blend state override after rage decal manager init
if (initMode == INIT_CORE)
{
#if APPLY_DOF_TO_ALPHA_DECALS
if (GRCDEVICE.GetDxFeatureLevel() > 1000)
{
grcBlendStateDesc blendDesc = dm->GetStaticBlendStateDesc();
PostFX::SetupBlendForDOF(blendDesc, false);
m_StaticForwardBlendState = grcStateBlock::CreateBlendState(blendDesc);
DECALMGR.SetOverrideBlendStateFunctor(MakeFunctorRet(OverrideStaticBlendStateFunctor));
}
#endif //APPLY_DOF_TO_ALPHA_DECALS
}
}
///////////////////////////////////////////////////////////////////////////////
// InitDefinitions
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::InitDefinitions ()
{
vfxUtil::InitTxd("fxdecal");
InitSettings();
}
///////////////////////////////////////////////////////////////////////////////
// InitSettings
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::InitSettings()
{
// read in the data
int numRenderSettingsFiles = 0;
decalRenderSettingsInfo renderSettingsInfos[DECAL_MAX_RENDER_SETTINGS_FILES];
const CDataFileMgr::DataFile* pData = DATAFILEMGR.GetFirstFile(CDataFileMgr::DECALS_FILE);
while (DATAFILEMGR.IsValid(pData))
{
renderSettingsInfos[numRenderSettingsFiles].pFilename = pData->m_filename;
numRenderSettingsFiles++;
pData = DATAFILEMGR.GetNextFile(pData);
}
DECALMGR.InitSettings(DECALTYPE_NUM, g_typeSettings, numRenderSettingsFiles, &renderSettingsInfos[0]);
}
#if RSG_PC
void CDecalManager::ResetShaders()
{
decalManager::GetInstance().ResetShaders();
static_cast<CDecalCallbacks*>(g_pDecalCallbacks)->ResetShaders();
}
#endif
///////////////////////////////////////////////////////////////////////////////
// Shutdown
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::Shutdown(unsigned shutdownMode)
{
if (shutdownMode == SHUTDOWN_CORE)
{
}
else if (shutdownMode == SHUTDOWN_WITH_MAP_LOADED)
{
vfxUtil::ShutdownTxd("fxdecal");
}
else if (shutdownMode == SHUTDOWN_SESSION)
{
m_vehicleBadgeMgr.Shutdown();
}
DECALMGR.Shutdown(shutdownMode);
if (shutdownMode == SHUTDOWN_CORE)
{
delete &DECALMGR;
m_asyncTaskDescPool.Shutdown();
}
}
///////////////////////////////////////////////////////////////////////////////
// UpdateCompleteAsync
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::UpdateCompleteAsync()
{
PF_PUSH_TIMEBAR("Decal Manager UpdateCompleteAsync");
decalAssert(!m_hasRunCompleteAsync);
DECALMGR.UpdateCompleteAsync();
m_hasRunCompleteAsync = true;
m_disableRenderingThisFrameRT = m_disableRenderingThisFrameUT;
m_disableRenderingThisFrameUT = false;
PF_POP_TIMEBAR();
}
///////////////////////////////////////////////////////////////////////////////
// UpdateStartAsync
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::UpdateStartAsync(float dt)
{
if (Unlikely(!m_hasRunCompleteAsync))
{
return;
}
m_hasRunCompleteAsync = false;
PF_PUSH_TIMEBAR("Decal Manager UpdateStartAsync");
m_numNonPlayerVehicleBangsScuffsThisFrame = 0;
const bool isGamePaused = fwTimer::IsGamePaused();
if (!isGamePaused REPLAY_ONLY( || CReplayMgr::IsEditModeActive() ) )
{
# if __BANK
m_decalDebug.Update();
# endif
m_vehicleBadgeMgr.Update();
}
decalManager *const dm = &DECALMGR;
dm->UpdateStartAsync(dt);
if (!isGamePaused)
{
// wash textures slightly if it's raining
if (g_DrawRand.GetRanged(0.0f, 2.0f)<g_weather.GetRain())
{
dm->Wash(0.004f, NULL, true);
}
// reset update flags
m_disablePetrolDecalsIgnitingThisFrame = false;
m_disablePetrolDecalsRecyclingThisFrame = false;
// debug
# if DECAL_SHOW_BROKEN_FRAG_MTX_PROBLEM
m_decalDebug.OutputPlayerVehicleWindscreenMatrix();
# endif
}
PF_POP_TIMEBAR();
}
///////////////////////////////////////////////////////////////////////////////
// Render
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::Render(decalRenderPass firstRenderPass, decalRenderPass lastRenderPass, bool bIsForwardPass, bool bResetRenderCtxIndex, bool bDynamicOnly)
{
u32 exceptionTypeFlags = 0;
if (m_disableRenderingThisFrameRT)
{
exceptionTypeFlags |= 1U<<DECALTYPE_MARKER | 1U<<DECALTYPE_MARKER_LONG_RANGE;
for (int i=0; i<DECAL_NUM_VEHICLE_BADGES; i++)
{
exceptionTypeFlags |= 1U<<(DECALTYPE_VEHICLE_BADGE+i);
}
exceptionTypeFlags = ~exceptionTypeFlags;
}
if (!CVfxHelper::ShouldRenderInGameUI())
{
exceptionTypeFlags |= 1U<<DECALTYPE_MARKER | 1U<<DECALTYPE_MARKER_LONG_RANGE;
}
if (exceptionTypeFlags!=0xffffffff)
{
DECALMGR.Render(firstRenderPass, lastRenderPass, exceptionTypeFlags, bIsForwardPass, bResetRenderCtxIndex, bDynamicOnly);
}
}
///////////////////////////////////////////////////////////////////////////////
// AllocAsyncTaskDesk
///////////////////////////////////////////////////////////////////////////////
decalAsyncTaskDescBase* CDecalManager::AllocAsyncTaskDesk()
{
return m_asyncTaskDescPool.AllocAsyncTaskDesk();
}
///////////////////////////////////////////////////////////////////////////////
// FreeAsyncTaskDesc
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::FreeAsyncTaskDesc(decalAsyncTaskDescBase* desc)
{
m_asyncTaskDescPool.FreeAsyncTaskDesc(desc);
}
///////////////////////////////////////////////////////////////////////////////
// RenderDebug
///////////////////////////////////////////////////////////////////////////////
#if __BANK
void CDecalManager::RenderDebug()
{
DECALMGR.RenderDebug();
}
#endif
///////////////////////////////////////////////////////////////////////////////
// InitWidgets
///////////////////////////////////////////////////////////////////////////////
#if __BANK
void CDecalManager::InitWidgets()
{
// init the framework widgets
DECALMGR.InitWidgets();
// init the game widgets
m_decalDebug.InitWidgets();
}
#endif
///////////////////////////////////////////////////////////////////////////////
// ReloadSettings
///////////////////////////////////////////////////////////////////////////////
#if __BANK
void CDecalManager::ReloadSettings()
{
InitSettings();
}
#endif
///////////////////////////////////////////////////////////////////////////////
// AddBang
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddBang(const VfxMaterialInfo_s& vfxMaterialInfo, const VfxCollInfo_s& vfxCollInfo)
{
#if __BANK
if (m_decalDebug.GetDisableDecalType(DECALTYPE_BANG))
{
return 0;
}
#endif
if (PGTAMATERIALMGR->GetMtlFlagNoDecal(vfxCollInfo.materialId))
{
return 0;
}
if (vfxCollInfo.regdEnt->GetType()==ENTITY_TYPE_PED)
{
return 0;
}
if (vfxMaterialInfo.decalRenderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(vfxMaterialInfo.decalRenderSettingIndex, vfxMaterialInfo.decalRenderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// calc the width
float width = vfxMaterialInfo.texWidthMin + vfxCollInfo.force*(vfxMaterialInfo.texWidthMax-vfxMaterialInfo.texWidthMin);
float length = width * g_DrawRand.GetRanged(vfxMaterialInfo.texLengthMultMin, vfxMaterialInfo.texLengthMultMax);
// calc normal
Vec3V vNewNormal = Normalize(vfxCollInfo.vNormalWld);
// calc side
Vec3V vSide;
if (CVfxHelper::GetRandomTangent(vSide, vNewNormal)==false)
{
return 0;
}
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_BANG;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = (s16)vfxCollInfo.roomId;
decalSettings.instSettings.vPosition = vfxCollInfo.vPositionWld;
decalSettings.instSettings.vDirection = -vNewNormal;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, length, decalSettingsManager::GetTypeSettings(DECALTYPE_BANG)->depth);
decalSettings.instSettings.colR = vfxMaterialInfo.decalColR;
decalSettings.instSettings.colG = vfxMaterialInfo.decalColG;
decalSettings.instSettings.colB = vfxMaterialInfo.decalColB;
decalSettings.instSettings.flipU = fwRandom::GetRandomTrueFalse();
decalSettings.instSettings.flipV = fwRandom::GetRandomTrueFalse();
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.duplicateRejectDist = vfxMaterialInfo.duplicateRejectDist;
decalSettings.pipelineSettings.maxOverlayRadius = vfxMaterialInfo.maxOverlayRadius;
// in MP only allow a single non player vehicle bang/scuff per frame
if (NetworkInterface::IsGameInProgress() && vfxCollInfo.regdEnt->GetIsTypeVehicle())
{
const CVehicle* pVehicle = static_cast<const CVehicle*>(vfxCollInfo.regdEnt.Get());
if (pVehicle && !pVehicle->ContainsLocalPlayer())
{
if (m_numNonPlayerVehicleBangsScuffsThisFrame == 1 BANK_ONLY(-1+m_decalDebug.GetMaxNonPlayerVehicleBangsScuffsPerFrame()))
{
return 0;
}
m_numNonPlayerVehicleBangsScuffsThisFrame++;
}
}
return AddSettings(vfxCollInfo.regdEnt, decalSettings);
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddBloodSplat
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddBloodSplat(const VfxBloodInfo_s& vfxBloodInfo, const VfxCollInfo_s& vfxCollInfo, float width, bool doSprayDecal, bool doMistDecal)
{
#if __BANK
if (m_decalDebug.GetDisableDecalType(DECALTYPE_BLOOD_SPLAT))
{
return 0;
}
#endif
if (vfxCollInfo.regdEnt->GetType()==ENTITY_TYPE_PED)
{
return 0;
}
#if __ASSERT
// we're not projecting onto a smash group - make sure the object is not smashable if we've got a glass collision
if (PGTAMATERIALMGR->GetIsSmashableGlass(vfxCollInfo.materialId) && IsEntitySmashable(vfxCollInfo.regdEnt))
{
decalAssertf(0, "trying to project onto a smashable object without using a smash group");
}
#endif
s32 renderSettingIndex;
s32 renderSettingCount;
if (doMistDecal)
{
if (PGTAMATERIALMGR->GetMtlFlagIsPorous(vfxCollInfo.materialId))
{
renderSettingIndex = vfxBloodInfo.mistSoakRenderSettingIndex;
renderSettingCount = vfxBloodInfo.mistSoakRenderSettingCount;
}
else
{
renderSettingIndex = vfxBloodInfo.mistNormRenderSettingIndex;
renderSettingCount = vfxBloodInfo.mistNormRenderSettingCount;
}
}
else if (doSprayDecal)
{
if (PGTAMATERIALMGR->GetMtlFlagIsPorous(vfxCollInfo.materialId))
{
renderSettingIndex = vfxBloodInfo.spraySoakRenderSettingIndex;
renderSettingCount = vfxBloodInfo.spraySoakRenderSettingCount;
}
else
{
renderSettingIndex = vfxBloodInfo.sprayNormRenderSettingIndex;
renderSettingCount = vfxBloodInfo.sprayNormRenderSettingCount;
}
}
else
{
if (PGTAMATERIALMGR->GetMtlFlagIsPorous(vfxCollInfo.materialId))
{
renderSettingIndex = vfxBloodInfo.splatSoakRenderSettingIndex;
renderSettingCount = vfxBloodInfo.splatSoakRenderSettingCount;
}
else
{
renderSettingIndex = vfxBloodInfo.splatNormRenderSettingIndex;
renderSettingCount = vfxBloodInfo.splatNormRenderSettingCount;
}
}
if (renderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// calc side
Vec3V vSide;
if (doSprayDecal)
{
if (CVfxHelper::GetRandomTangentAlign(vSide, vfxCollInfo.vNormalWld, vfxCollInfo.vDirectionWld)==false)
{
return 0;
}
}
else
{
if (CVfxHelper::GetRandomTangent(vSide, vfxCollInfo.vNormalWld)==false)
{
return 0;
}
}
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_BLOOD_SPLAT;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = (s16)vfxCollInfo.roomId;
decalSettings.instSettings.vPosition = vfxCollInfo.vPositionWld;
decalSettings.instSettings.vDirection = -vfxCollInfo.vNormalWld;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, width, decalSettingsManager::GetTypeSettings(DECALTYPE_BLOOD_SPLAT)->depth);
decalSettings.instSettings.totalLife = g_DrawRand.GetRanged(vfxBloodInfo.lifeMin, vfxBloodInfo.lifeMax);
decalSettings.instSettings.fadeInTime = vfxBloodInfo.fadeInTime;
decalSettings.instSettings.uvMultStart = g_DrawRand.GetRanged(vfxBloodInfo.growthMultMin, vfxBloodInfo.growthMultMax);
decalSettings.instSettings.uvMultEnd = 1.0f;
decalSettings.instSettings.uvMultTime = vfxBloodInfo.growthTime;
decalSettings.instSettings.colR = vfxBloodInfo.decalColR;
decalSettings.instSettings.colG = vfxBloodInfo.decalColG;
decalSettings.instSettings.colB = vfxBloodInfo.decalColB;
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.duplicateRejectDist = width*DECAL_BLOOD_SPLAT_DRD_WIDTH_MULT;
decalSettings.pipelineSettings.colnComponentId = (s16)vfxCollInfo.componentId;
#if DECAL_PROCESS_BREAKABLES
decalSettings.pipelineSettings.applyToBreakables = true; // blood should get applied to breakable glass
#endif
// override settings for glass collisions
if (PGTAMATERIALMGR->GetIsGlass(vfxCollInfo.materialId))
{
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_FORWARD;
}
int id = AddSettings(vfxCollInfo.regdEnt, decalSettings);
#if GTA_REPLAY
CReplayMgr::RecordFx<CPacketBloodDecal>(CPacketBloodDecal(decalSettings, id), vfxCollInfo.regdEnt);
#endif // GTA_REPLAY
return id;
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddFootprint
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddFootprint(int decalRenderSettingIndex, int decalRenderSettingCount, float width, float length, Color32 col, phMaterialMgr::Id mtlId, Vec3V_In vPos, Vec3V_In vNormal, Vec3V_In vSide, bool isLeftFoot, float life)
{
#if __BANK
if (m_decalDebug.GetDisableDecalType(DECALTYPE_FOOTPRINT))
{
return 0;
}
#endif
if (m_disableFootprintsFromScript)
{
return 0;
}
if (decalRenderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(decalRenderSettingIndex, decalRenderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// calc the width
if (width>0.0f && length>0.0f)
{
decalAssertf(mtlId==-1 || (mtlId&0xffffffffffffff00)==0, "decal exclusive mtl id contains other packed info");
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_FOOTPRINT;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.instSettings.vPosition = vPos;
decalSettings.instSettings.vDirection = -vNormal;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, length, decalSettingsManager::GetTypeSettings(DECALTYPE_FOOTPRINT)->depth);
decalSettings.instSettings.totalLife = life;
decalSettings.instSettings.colR = col.GetRed();
decalSettings.instSettings.colG = col.GetGreen();
decalSettings.instSettings.colB = col.GetBlue();
decalSettings.instSettings.alphaFront = col.GetAlpha();
decalSettings.instSettings.alphaBack = col.GetAlpha();
decalSettings.instSettings.flipU = isLeftFoot;
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.duplicateRejectDist = 0.025f;
decalSettings.pipelineSettings.exclusiveMtlId = mtlId;
// override the depth for 'deep' materials
if (PGTAMATERIALMGR->GetIsDeepNonWading(mtlId))
{
decalSettings.instSettings.vDimensions.SetZ(ScalarV(V_HALF));
}
return AddSettings(NULL, decalSettings);
}
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddGeneric
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddGeneric(DecalType_e decalType, s32 renderSettingIndex, s32 renderSettingCount, Vec3V_In vPos, Vec3V_In vDir, Vec3V_In vSide, float width, float height, float depth, float totalLife, float fadeInTime, float uvMultStart, float uvMultEnd, float uvMultTime, Color32 col, bool flipU, bool flipV, float duplicateRejectDist, bool isScripted, bool isDynamic REPLAY_ONLY(, float startLife))
{
#if __BANK
if ((decalType==DECALTYPE_GENERIC_SIMPLE_COLN && m_decalDebug.GetDisableDecalType(DECALTYPE_GENERIC_SIMPLE_COLN)) ||
(decalType==DECALTYPE_GENERIC_COMPLEX_COLN && m_decalDebug.GetDisableDecalType(DECALTYPE_GENERIC_COMPLEX_COLN)) ||
(decalType==DECALTYPE_GENERIC_SIMPLE_COLN_LONG_RANGE && m_decalDebug.GetDisableDecalType(DECALTYPE_GENERIC_SIMPLE_COLN_LONG_RANGE)) ||
(decalType==DECALTYPE_GENERIC_COMPLEX_COLN_LONG_RANGE && m_decalDebug.GetDisableDecalType(DECALTYPE_GENERIC_COMPLEX_COLN_LONG_RANGE)))
{
return 0;
}
#endif
// if the passed in depth is zero use the default
if (depth==0.0f)
{
depth = decalSettingsManager::GetTypeSettings(decalType)->depth;
}
if (renderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = (u16)decalType;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.bucketSettings.isScripted = isScripted;
decalSettings.instSettings.vPosition = vPos;
decalSettings.instSettings.vDirection = vDir;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, height, depth);
decalSettings.instSettings.totalLife = totalLife;
decalSettings.instSettings.fadeInTime = fadeInTime;
decalSettings.instSettings.uvMultStart = uvMultStart;
decalSettings.instSettings.uvMultEnd = uvMultEnd;
decalSettings.instSettings.uvMultTime = uvMultTime;
decalSettings.instSettings.colR = col.GetRed();
decalSettings.instSettings.colG = col.GetGreen();
decalSettings.instSettings.colB = col.GetBlue();
decalSettings.instSettings.alphaFront = col.GetAlpha();
decalSettings.instSettings.alphaBack = col.GetAlpha();
decalSettings.instSettings.flipU = flipU;
decalSettings.instSettings.flipV = flipV;
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.duplicateRejectDist = duplicateRejectDist;
#if GTA_REPLAY
//On replay if we add decals at the start of the clip that were added before recording started we need them to be visible
//and not faded out. If the life is under DECAL_INST_INV_FADE_TIME_UNITS_HZ they'll be faded even if the fadeInTime is 0.
decalSettings.lodSettings.currLife = startLife;
#endif //GTA_REPLAY
if (isDynamic)
{
decalSettings.pipelineSettings.method = DECAL_METHOD_DYNAMIC;
}
return AddSettings(NULL, decalSettings);
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddPool
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddPool(VfxLiquidType_e liquidType, s32 renderSettingIndex, s32 renderSettingCount, Vec3V_In vPosition, Vec3V_In vNormal, float startSize, float endSize, float growRate, u8 colnMtlId, Color32 col, bool isScripted)
{
#if __BANK
if (m_decalDebug.GetDisableDecalType(DECALTYPE_POOL_LIQUID))
{
return 0;
}
#endif
if (liquidType!=VFXLIQUID_TYPE_NONE)
{
if (liquidType==VFXLIQUID_TYPE_PETROL)
{
if (g_fireMan.ManageAddedPetrol(vPosition, 1.0f))
{
return 0;
}
}
VfxLiquidInfo_s& liquidInfo = g_vfxLiquid.GetLiquidInfo(liquidType);
if (PGTAMATERIALMGR->GetMtlFlagIsPorous((phMaterialMgr::Id)colnMtlId))
{
renderSettingIndex = liquidInfo.soakDecalPoolRenderSettingIndex;
renderSettingCount = liquidInfo.soakDecalPoolRenderSettingCount;
}
else
{
renderSettingIndex = liquidInfo.normDecalPoolRenderSettingIndex;
renderSettingCount = liquidInfo.normDecalPoolRenderSettingCount;
}
// multiply the liquid colour by the particle colour
u8 colR = static_cast<u8>(liquidInfo.decalColR * col.GetRedf());
u8 colG = static_cast<u8>(liquidInfo.decalColG * col.GetGreenf());
u8 colB = static_cast<u8>(liquidInfo.decalColB * col.GetBluef());
u8 colA = static_cast<u8>(liquidInfo.decalColA * col.GetAlphaf());
col = Color32(colR, colG, colB, colA);
}
if (renderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// calc the width
float width = endSize;
// calc tangent
Vec3V vSide;
if (CVfxHelper::GetRandomTangent(vSide, vNormal)==false)
{
return 0;
}
// check that the start and end sizes aren't zero
startSize = Max(startSize, 0.001f);
endSize = Max(endSize, 0.001f);
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_POOL_LIQUID;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.bucketSettings.isScripted = isScripted;
decalSettings.instSettings.vPosition = vPosition;
decalSettings.instSettings.vDirection = -vNormal;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, width, decalSettingsManager::GetTypeSettings(DECALTYPE_POOL_LIQUID)->depth);
decalSettings.instSettings.uvMultStart = startSize/endSize;
decalSettings.instSettings.uvMultEnd = growRate;
decalSettings.instSettings.colR = col.GetRed();
decalSettings.instSettings.colG = col.GetGreen();
decalSettings.instSettings.colB = col.GetBlue();
decalSettings.instSettings.alphaFront = col.GetAlpha();
decalSettings.instSettings.alphaBack = col.GetAlpha();
decalSettings.instSettings.liquidType = (s8)liquidType;
decalSettings.instSettings.isLiquidPool = true;
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
int id = AddSettings(NULL, decalSettings);
#if GTA_REPLAY
CReplayMgr::RecordFx<CPacketBloodPool>(CPacketBloodPool(decalSettings, id));
#endif // GTA_REPLAY
return id;
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddScuff
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddScuff(CEntity* pEntity, s32 renderSettingsIndex, Vec3V_In vPtA, Vec3V_InOut vPtB, Vec3V_In vNormal, float width, Color32 col, float life, u8 mtlId, float maxOverlayRadius, float duplicateRejectDist, bool REPLAY_ONLY(disableFadeInForReplay))
{
#if __BANK
if (m_decalDebug.GetDisableDecalType(DECALTYPE_SCUFF))
{
return 0;
}
#endif
if (m_disableScuffsFromScript)
{
return 0;
}
// test for early rejection
if (IsEqualAll(vPtA, vPtB))
{
return 0;
}
//
if (renderSettingsIndex>-1 && renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// calc the mid point
Vec3V vAtoB = vPtB-vPtA;
Vec3V vMidPt = vPtA + (vAtoB*ScalarV(V_HALF));
// calc the forward vector
Vec3V vForward = Normalize(vAtoB);
// calc the side vector
Vec3V vSide = Cross(vForward, vNormal);
vSide = Normalize(vSide);
// return if the forward and normal are equal (i.e. the cross product is zero)
if (MagSquared(vSide).Getf()==0.0f)
{
return 0;
}
// calc the new normal
Vec3V vNewNormal = Cross(vSide, vForward);
vNewNormal = Normalize(vNewNormal);
// calc the distance between the 2 points
float distAB = Mag(vAtoB).Getf();
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_SCUFF;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.instSettings.vPosition = vMidPt;
decalSettings.instSettings.vDirection = -vNewNormal;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, distAB, decalSettingsManager::GetTypeSettings(DECALTYPE_SCUFF)->depth);
decalSettings.instSettings.totalLife = life;
decalSettings.instSettings.colR = col.GetRed();
decalSettings.instSettings.colG = col.GetGreen();
decalSettings.instSettings.colB = col.GetBlue();
decalSettings.instSettings.alphaFront = col.GetAlpha();
decalSettings.instSettings.alphaBack = col.GetAlpha();
decalSettings.instSettings.flipU = fwRandom::GetRandomTrueFalse();
decalSettings.instSettings.flipV = fwRandom::GetRandomTrueFalse();
#if GTA_REPLAY
//on the first frame of replay we dont want these to fade in
if( disableFadeInForReplay )
decalSettings.instSettings.fadeInTime = 0.0f;
#endif //GTA_REPLAY
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.duplicateRejectDist = duplicateRejectDist;
decalSettings.pipelineSettings.maxOverlayRadius = maxOverlayRadius;
// override the depth for 'deep' materials
if (PGTAMATERIALMGR->GetIsDeepNonWading(mtlId))
{
decalSettings.instSettings.vDimensions.SetZ(ScalarV(V_HALF));
}
// in MP only allow a single non player vehicle bang/scuff per frame
if (NetworkInterface::IsGameInProgress() && pEntity->GetIsTypeVehicle())
{
const CVehicle* pVehicle = static_cast<const CVehicle*>(pEntity);
if (pVehicle && !pVehicle->ContainsLocalPlayer())
{
if (m_numNonPlayerVehicleBangsScuffsThisFrame == 1 BANK_ONLY(-1+m_decalDebug.GetMaxNonPlayerVehicleBangsScuffsPerFrame()))
{
return 0;
}
m_numNonPlayerVehicleBangsScuffsThisFrame++;
}
}
int decalId = AddSettings(pEntity, decalSettings);
return decalId;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddTrail
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddTrail(DecalType_e decalType, VfxLiquidType_e liquidType, s32 renderSettingsIndex, Vec3V_In vPtA, Vec3V_InOut vPtB, Vec3V_In vNormal, float width, Color32 col, u8 alphaBack, float life, u8 mtlId, float& currLength, Vec3V_Ptr pvJoinVerts, bool isScripted, DecalTrailPiece_e trailPiece)
{
#if __BANK
if ((decalType==DECALTYPE_TRAIL_SKID && m_decalDebug.GetDisableDecalType(DECALTYPE_TRAIL_SKID)) ||
(decalType==DECALTYPE_TRAIL_SCRAPE && m_decalDebug.GetDisableDecalType(DECALTYPE_TRAIL_SCRAPE)) ||
(decalType==DECALTYPE_TRAIL_LIQUID && m_decalDebug.GetDisableDecalType(DECALTYPE_TRAIL_LIQUID)) ||
(decalType==DECALTYPE_TRAIL_GENERIC && m_decalDebug.GetDisableDecalType(DECALTYPE_TRAIL_GENERIC)))
{
return 0;
}
#endif
// test for early rejection
if (IsEqualAll(vPtA, vPtB))
{
return 0;
}
// override liquid decal render settings
if (liquidType!=VFXLIQUID_TYPE_NONE)
{
if (liquidType==VFXLIQUID_TYPE_PETROL)
{
g_fireMan.ManageAddedPetrol(vPtA, 0.25f);
}
VfxLiquidInfo_s& liquidInfo = g_vfxLiquid.GetLiquidInfo(liquidType);
if (PGTAMATERIALMGR->GetMtlFlagIsPorous((phMaterialMgr::Id)mtlId))
{
if (trailPiece==DECALTRAIL_IN)
{
renderSettingsIndex = GetRenderSettingsIndex(liquidInfo.soakDecalTrailInRenderSettingIndex, liquidInfo.soakDecalTrailInRenderSettingCount);
}
else if (trailPiece==DECALTRAIL_MID)
{
renderSettingsIndex = GetRenderSettingsIndex(liquidInfo.soakDecalTrailMidRenderSettingIndex, liquidInfo.soakDecalTrailMidRenderSettingCount);
}
else if (trailPiece==DECALTRAIL_OUT)
{
renderSettingsIndex = GetRenderSettingsIndex(liquidInfo.soakDecalTrailOutRenderSettingIndex, liquidInfo.soakDecalTrailOutRenderSettingCount);
}
}
else
{
if (trailPiece==DECALTRAIL_IN)
{
renderSettingsIndex = GetRenderSettingsIndex(liquidInfo.normDecalTrailInRenderSettingIndex, liquidInfo.normDecalTrailInRenderSettingCount);
}
else if (trailPiece==DECALTRAIL_MID)
{
renderSettingsIndex = GetRenderSettingsIndex(liquidInfo.normDecalTrailMidRenderSettingIndex, liquidInfo.normDecalTrailMidRenderSettingCount);
}
else if (trailPiece==DECALTRAIL_OUT)
{
renderSettingsIndex = GetRenderSettingsIndex(liquidInfo.normDecalTrailOutRenderSettingIndex, liquidInfo.normDecalTrailOutRenderSettingCount);
}
}
}
//
if (renderSettingsIndex>-1 && renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// calc the mid point
Vec3V vAtoB = vPtB-vPtA;
Vec3V vMidPt = vPtA + (vAtoB*ScalarV(V_HALF));
// calc the forward vector
Vec3V vForward = Normalize(vAtoB);
// calc the side vector
Vec3V vSide = Cross(vForward, vNormal);
vSide = Normalize(vSide);
// return if the forward and normal are equal (i.e. the cross product is zero)
if (MagSquared(vSide).Getf()==0.0f)
{
return 0;
}
// calc the new normal
Vec3V vNewNormal = Cross(vSide, vForward);
vNewNormal = Normalize(vNewNormal);
// grcDebugDraw::Line(vPtA, vPtB, Color32(1.0f, 0.0f, 0.0f, 1.0f), Color32(1.0f, 1.0f, 1.0f, 0.5f), -200);
// grcDebugDraw::Line(vMidPt, vMidPt+(vNormal*ScalarVFromF32(0.2f)), Color32(0.0f, 1.0f, 0.0f, 1.0f), Color32(0.0f, 1.0f, 0.0f, 1.0f), -200);
// grcDebugDraw::Line(vMidPt, vMidPt+(vNewNormal*ScalarVFromF32(0.2f)), Color32(1.0f, 1.0f, 0.0f, 1.0f), Color32(1.0f, 1.0f, 0.0f, 1.0f), -200);
// calc the distance between the 2 points
float distAB = Mag(vAtoB).Getf();
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = (u16)decalType;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.bucketSettings.isScripted = isScripted;
decalSettings.instSettings.vPosition = vMidPt;
decalSettings.instSettings.vDirection = -vNewNormal;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, distAB, decalSettingsManager::GetTypeSettings(decalType)->depth);
decalSettings.instSettings.currWrapLength = currLength;
decalSettings.instSettings.totalLife = life;
decalSettings.instSettings.colR = col.GetRed();
decalSettings.instSettings.colG = col.GetGreen();
decalSettings.instSettings.colB = col.GetBlue();
decalSettings.instSettings.alphaFront = col.GetAlpha();
decalSettings.instSettings.alphaBack = alphaBack;
decalSettings.instSettings.liquidType = (s8)liquidType;
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.hasJoinVerts = true;
SetJoinVerts(decalSettings.pipelineSettings, pvJoinVerts);
// override the depth for 'deep' materials
if (PGTAMATERIALMGR->GetIsDeepNonWading(mtlId))
{
decalSettings.instSettings.vDimensions.SetZ(ScalarV(V_HALF));
}
int decalId = AddSettings(NULL, decalSettings);
// update the current length of the mark
GetJoinVerts(decalSettings.pipelineSettings, pvJoinVerts);
currLength += distAB;
#if GTA_REPLAY
CReplayMgr::RecordFx<CPacketTrailDecal>(CPacketTrailDecal(decalSettings, mtlId, decalId));
#endif // GTA_REPLAY
return decalId;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddVehicleBadge
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddVehicleBadge(const CVehicle* pVehicle, s32 componentId, s32 renderSettingIndex, s32 renderSettingCount, Vec3V_In vPos, Vec3V_In vDir, Vec3V_In vSide, float size, bool isForLocalPlayer, u32 badgeIndex, u8 alpha)
{
decalAssertf(badgeIndex < DECAL_NUM_VEHICLE_BADGES, "Vehicle Badge Index out of range");
#if __BANK
if (m_decalDebug.GetDisableDecalType(DecalType_e(DECALTYPE_VEHICLE_BADGE+badgeIndex)))
{
return 0;
}
#endif
if (renderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = (u16)(DECALTYPE_VEHICLE_BADGE+badgeIndex);
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.instSettings.vPosition = vPos;
decalSettings.instSettings.vDirection = vDir;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(size, size, decalSettingsManager::GetTypeSettings(DECALTYPE_VEHICLE_BADGE+badgeIndex)->depth);
decalSettings.instSettings.colR = DECAL_VEHICLE_BADGE_TINT_R;
decalSettings.instSettings.colG = DECAL_VEHICLE_BADGE_TINT_G;
decalSettings.instSettings.colB = DECAL_VEHICLE_BADGE_TINT_B;
decalSettings.instSettings.alphaFront = alpha;
decalSettings.instSettings.alphaBack = alpha;
#if GTA_REPLAY
//force the decal to be on rather than fade in if we're adding as part of a clip.
if( CReplayMgr::IsEditModeActive() )
{
decalSettings.lodSettings.currLife = DECAL_INST_INV_FADE_TIME_UNITS_HZ;
}
#endif
decalSettings.pipelineSettings.renderPass = isForLocalPlayer ? DECAL_RENDER_PASS_VEHICLE_BADGE_LOCAL_PLAYER : DECAL_RENDER_PASS_VEHICLE_BADGE_NOT_LOCAL_PLAYER;
decalSettings.pipelineSettings.method = DECAL_METHOD_DYNAMIC;
decalSettings.pipelineSettings.colnComponentId = (s16)componentId;
decalSettings.pipelineSettings.useColnEntityOnly = true;
return AddSettings(const_cast<CVehicle*>(pVehicle), decalSettings);
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddWeaponImpact
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddWeaponImpact(const VfxWeaponInfo_s& vfxWeaponInfo, const VfxCollInfo_s& vfxCollInfo, void* pSmashGroup, CEntity* pSmashEntity, s32 smashMatrixId, bool applyBulletproofGlassTextureSwap, bool lookupCentreOfVehicleFromBone)
{
if (vfxCollInfo.regdEnt->GetType()==ENTITY_TYPE_PED)
{
return 0;
}
#if __ASSERT
if (pSmashGroup)
{
// we're projecting onto a smash group - check that the object is smashable
decalAssertf(IsEntitySmashable(vfxCollInfo.regdEnt), "trying to project a smash texture onto a non smashable object");
decalAssertf(PGTAMATERIALMGR->GetIsSmashableGlass(vfxCollInfo.materialId), "trying to project onto non smashable glass material");
}
else
{
// we're not projecting onto a smash group - make sure the object is not smashable if we've got a glass collision
if (PGTAMATERIALMGR->GetIsSmashableGlass(vfxCollInfo.materialId) && IsEntitySmashable(vfxCollInfo.regdEnt))
{
decalAssertf(0, "trying to project onto a smashable object without using a smash group");
}
}
#endif
if (PGTAMATERIALMGR->GetMtlFlagNoDecal(vfxCollInfo.materialId))
{
return 0;
}
// check if this is a normal or stretch weapon impact
float dot = Max(0.0f, Dot(-vfxCollInfo.vDirectionWld, vfxCollInfo.vNormalWld).Getf());
float width = g_DrawRand.GetRanged(vfxWeaponInfo.minTexSize, vfxWeaponInfo.maxTexSize);
float height = width;
s32 decalRenderSettingIndex = vfxWeaponInfo.decalRenderSettingIndex;
s32 decalRenderSettingCount = vfxWeaponInfo.decalRenderSettingCount;
Vec3V vSide;
if (vfxWeaponInfo.stretchDot>0.0f && dot<vfxWeaponInfo.stretchDot)
{
if (CVfxHelper::GetRandomTangentAlign(vSide, vfxCollInfo.vNormalWld, vfxCollInfo.vDirectionWld)==false)
{
return 0;
}
height = width + (width*(vfxWeaponInfo.stretchMult*((vfxWeaponInfo.stretchDot-dot)/vfxWeaponInfo.stretchDot)));
decalRenderSettingIndex = vfxWeaponInfo.stretchRenderSettingIndex;
decalRenderSettingCount = vfxWeaponInfo.stretchRenderSettingCount;
}
else
{
if (CVfxHelper::GetRandomTangent(vSide, vfxCollInfo.vNormalWld)==false)
{
return 0;
}
}
if (applyBulletproofGlassTextureSwap)
{
g_decalMan.FindRenderSettingInfo(14501, decalRenderSettingIndex, decalRenderSettingCount);
}
if (vfxCollInfo.isSnowball)
{
// snowball specific hack
g_decalMan.FindRenderSettingInfo(DECALID_SNOWBALL, decalRenderSettingIndex, decalRenderSettingCount);
}
if (vfxCollInfo.isFMJAmmo && vfxCollInfo.regdEnt->GetIsTypeVehicle() && !PGTAMATERIALMGR->GetIsGlass(vfxCollInfo.materialId))
{
// full metal jacket hack
g_decalMan.FindRenderSettingInfo(14505, decalRenderSettingIndex, decalRenderSettingCount);
}
if (decalRenderSettingIndex>-1)
{
s32 renderSettingsIndex = GetRenderSettingsIndex(decalRenderSettingIndex, decalRenderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_WEAPON_IMPACT;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.subType = (u32)vfxCollInfo.isExitFx;
decalSettings.bucketSettings.roomId = (s16)vfxCollInfo.roomId;
decalSettings.instSettings.vPosition = vfxCollInfo.vPositionWld;
decalSettings.instSettings.vDirection = -vfxCollInfo.vNormalWld;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(DECALTYPE_WEAPON_IMPACT)->depth);
decalSettings.instSettings.totalLife = g_DrawRand.GetRanged(vfxWeaponInfo.minLifeTime, vfxWeaponInfo.maxLifeTime);
decalSettings.instSettings.fadeInTime = vfxWeaponInfo.fadeInTime;
decalSettings.instSettings.colR = vfxWeaponInfo.decalColR;
decalSettings.instSettings.colG = vfxWeaponInfo.decalColG;
decalSettings.instSettings.colB = vfxWeaponInfo.decalColB;
decalSettings.instSettings.alphaFront = vfxWeaponInfo.decalColA;
decalSettings.instSettings.alphaBack = vfxWeaponInfo.decalColA;
decalSettings.instSettings.flipU = fwRandom::GetRandomTrueFalse();
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = DECAL_METHOD_STATIC;
decalSettings.pipelineSettings.duplicateRejectDist = vfxWeaponInfo.duplicateRejectDist;
decalSettings.pipelineSettings.maxOverlayRadius = vfxWeaponInfo.maxOverlayRadius;
decalSettings.pipelineSettings.dontApplyToGlass = true;
if (vfxWeaponInfo.useExclusiveMtl)
{
decalAssertf(vfxCollInfo.materialId==-1 || (vfxCollInfo.materialId&0xffffffffffffff00)==0, "decal exclusive mtl id contains other packed info");
decalSettings.pipelineSettings.exclusiveMtlId = vfxCollInfo.materialId;
}
if (applyBulletproofGlassTextureSwap)
{
decalSettings.pipelineSettings.duplicateRejectDist *= 0.25f;
}
#if __BANK
if (g_vfxWeapon.GetBulletImpactDecalOverridesActive())
{
decalSettings.pipelineSettings.duplicateRejectDist = g_vfxWeapon.GetBulletImpactDecalDuplicateRejectDistOverride();
decalSettings.pipelineSettings.maxOverlayRadius = g_vfxWeapon.GetBulletImpactDecalMaxOverlayRadiusOverride();
}
#endif
CEntity* pEntity = vfxCollInfo.regdEnt;
// override some settings for a smash group
if (pSmashGroup)
{
pEntity = pSmashEntity;
decalSettings.bucketSettings.pSmashGroup = pSmashGroup;
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_WEAPON_IMPACT_SMASHGROUP;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(DECALTYPE_WEAPON_IMPACT_SMASHGROUP)->depth);
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_FORWARD;
decalSettings.pipelineSettings.colnComponentId = (s16)smashMatrixId;
decalSettings.pipelineSettings.useColnEntityOnly = true;
if (pEntity->GetIsTypeVehicle())
{
decalSettings.pipelineSettings.isVehicleGlass = true;
}
// make sure that any smash groups get a collision going into the vehicle
// as the smash group is single sided
if (pSmashEntity && pSmashEntity->GetIsTypeVehicle())
{
Vec3V vCentreOfVehicle = pSmashEntity->GetMatrix().GetCol3();
if (lookupCentreOfVehicleFromBone)
{
// we could look into always taking this branch for vehicles since it's likely to be
// more accurate to consider the "inside" of the vehicle the place where the steering wheel
// is that just the local origin of the vehicle model itself
const CVehicle* pVehicle = static_cast<const CVehicle*>(pSmashEntity);
s32 boneIndex = pVehicle->GetBoneIndex((eHierarchyId)(VEH_STEERING_WHEEL));
if (boneIndex <= -1)
{
boneIndex = pVehicle->GetBoneIndex((eHierarchyId)(VEH_CAR_STEERING_WHEEL));
}
if (boneIndex > -1)
{
Mat34V vBoneMtxWld;
CVfxHelper::GetMatrixFromBoneIndex(vBoneMtxWld, pVehicle, boneIndex);
vCentreOfVehicle = vBoneMtxWld.GetCol3();
}
}
// get vector from smash position to centre of vehicle
Vec3V vSmashToCentre = vCentreOfVehicle - vfxCollInfo.vPositionWld;
vSmashToCentre = Normalize(vSmashToCentre);
if (Dot(vSmashToCentre, vfxCollInfo.vNormalWld).Getf()>0.0f)
{
decalSettings.instSettings.vDirection = vfxCollInfo.vNormalWld;
}
}
}
// override some settings for glass collisions
else if (PGTAMATERIALMGR->GetIsGlass(vfxCollInfo.materialId))
{
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_FORWARD;
decalSettings.pipelineSettings.useColnEntityOnly = true;
decalSettings.pipelineSettings.onlyApplyToGlass = true;
decalSettings.pipelineSettings.dontApplyToGlass = false;
}
// override some settings for emissive collisions
else if (PGTAMATERIALMGR->GetIsEmissive(vfxCollInfo.materialId))
{
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_FORWARD;
}
// override some settings for car soft top windows
else if (PGTAMATERIALMGR->UnpackMtlId(vfxCollInfo.materialId)==PGTAMATERIALMGR->g_idCarSoftTopClear)
{
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_FORWARD;
decalSettings.pipelineSettings.useColnEntityOnly = true;
decalSettings.pipelineSettings.onlyApplyToGlass = true;
decalSettings.pipelineSettings.dontApplyToGlass = false;
}
// override some settings for other clear materials
else if (PGTAMATERIALMGR->UnpackMtlId(vfxCollInfo.materialId)==PGTAMATERIALMGR->g_idPlasticClear ||
PGTAMATERIALMGR->UnpackMtlId(vfxCollInfo.materialId)==PGTAMATERIALMGR->g_idPlasticHollowClear ||
PGTAMATERIALMGR->UnpackMtlId(vfxCollInfo.materialId)==PGTAMATERIALMGR->g_idPlasticHighDensityClear)
{
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_FORWARD;
decalSettings.pipelineSettings.useColnEntityOnly = true;
}
// override some settings for a shotgun
if (vfxCollInfo.weaponGroup==WEAPON_EFFECT_GROUP_SHOTGUN)
{
if (m_disableCompositeShotgunImpactsFromScript==false)
{
// change the type
decalSettings.bucketSettings.typeSettingsIndex++;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(decalSettings.bucketSettings.typeSettingsIndex)->depth);
// check if it's against a vehicle/object - reject if one has already been applied to the vehicle/object this frame
if (vfxCollInfo.regdEnt->GetIsTypeVehicle() || vfxCollInfo.regdEnt->GetIsTypeObject())
{
if (DECALMGR.IsWaitingToAdd(1<<decalSettings.bucketSettings.typeSettingsIndex, vfxCollInfo.regdEnt))
{
return 0;
}
if (vfxWeaponInfo.shotgunDecalRenderSettingIndex==-1)
{
return 0;
}
// set the new render settings index
s32 shotgunRenderSettingIndex = vfxWeaponInfo.shotgunDecalRenderSettingIndex;
s32 shotgunRenderSettingCount = vfxWeaponInfo.shotgunDecalRenderSettingCount;
if (applyBulletproofGlassTextureSwap)
{
g_decalMan.FindRenderSettingInfo(14502, shotgunRenderSettingIndex, shotgunRenderSettingCount);
}
s32 renderSettingsIndex = GetRenderSettingsIndex(shotgunRenderSettingIndex, shotgunRenderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// override the render settings
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
}
}
// scale the dimensions
decalSettings.instSettings.vDimensions *= Vec3V(vfxWeaponInfo.shotgunTexScale, vfxWeaponInfo.shotgunTexScale, 1.0f);
}
}
}
// override some settings for explosions
else if (vfxCollInfo.weaponGroup>=WEAPON_EFFECT_GROUP_ROCKET && vfxCollInfo.weaponGroup<=WEAPON_EFFECT_GROUP_EXPLOSION)
{
if (vfxCollInfo.regdEnt->GetIsTypeVehicle())
{
const CVehicle* pVehicle = static_cast<const CVehicle*>(vfxCollInfo.regdEnt.Get());
if (pVehicle && pVehicle->GetStatus() == STATUS_WRECKED)
{
return 0;
}
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_WEAPON_IMPACT_EXPLOSION_VEHICLE;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(DECALTYPE_WEAPON_IMPACT_EXPLOSION_VEHICLE)->depth);
}
else
{
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_WEAPON_IMPACT_EXPLOSION_GROUND;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(DECALTYPE_WEAPON_IMPACT_EXPLOSION_GROUND)->depth);
}
}
else if (vfxCollInfo.weaponGroup==WEAPON_EFFECT_GROUP_VEHICLE_MG)
{
decalSettings.bucketSettings.typeSettingsIndex = DECALTYPE_WEAPON_IMPACT_VEHICLE;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(DECALTYPE_WEAPON_IMPACT_VEHICLE)->depth);
}
#if __BANK
if ((decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT)) ||
(decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT_SHOTGUN && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT_SHOTGUN)) ||
(decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT_SMASHGROUP && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT_SMASHGROUP)) ||
(decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT_SMASHGROUP_SHOTGUN && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT_SMASHGROUP_SHOTGUN)) ||
(decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT_EXPLOSION_GROUND && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT_EXPLOSION_GROUND)) ||
(decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT_EXPLOSION_VEHICLE && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT_EXPLOSION_VEHICLE)) ||
(decalSettings.bucketSettings.typeSettingsIndex==DECALTYPE_WEAPON_IMPACT_VEHICLE && m_decalDebug.GetDisableDecalType(DECALTYPE_WEAPON_IMPACT_VEHICLE)))
{
return 0;
}
#endif
return AddSettings(pEntity, decalSettings);
}
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// RegisterMarker
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::RegisterMarker(s32 renderSettingIndex, s32 renderSettingCount, Vec3V_In vPos, Vec3V_In vDir, Vec3V_In vSide, float width, float height, Color32 col, bool isLongRange, bool isDynamic, bool alignToCamRot)
{
DecalType_e decalType = DECALTYPE_MARKER;
if (isLongRange)
{
decalType = DECALTYPE_MARKER_LONG_RANGE;
}
#if __BANK
if ((decalType==DECALTYPE_MARKER && m_decalDebug.GetDisableDecalType(DECALTYPE_MARKER)) ||
(decalType==DECALTYPE_MARKER_LONG_RANGE && m_decalDebug.GetDisableDecalType(DECALTYPE_MARKER_LONG_RANGE)))
{
return 0;
}
#endif
s32 renderSettingsIndex = GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
if (renderSettingsIndex<DECAL_MAX_RENDER_SETTINGS)
{
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(renderSettingsIndex);
if (pRenderSettings->pDiffuseMap)
{
// set up the decal settings
decalUserSettings decalSettings;
decalSettings.bucketSettings.typeSettingsIndex = (u16)decalType;
decalSettings.bucketSettings.renderSettingsIndex = (u16)renderSettingsIndex;
decalSettings.bucketSettings.roomId = INTLOC_INVALID_INDEX;
decalSettings.bucketSettings.subType = alignToCamRot ? 1 : 0;
decalSettings.instSettings.vPosition = vPos;
decalSettings.instSettings.vDirection = vDir;
decalSettings.instSettings.vSide = vSide;
decalSettings.instSettings.vDimensions = Vec3V(width, height, decalSettingsManager::GetTypeSettings(decalType)->depth);
decalSettings.instSettings.colR = col.GetRed();
decalSettings.instSettings.colG = col.GetGreen();
decalSettings.instSettings.colB = col.GetBlue();
decalSettings.instSettings.alphaFront = col.GetAlpha();
decalSettings.instSettings.alphaBack = col.GetAlpha();
decalSettings.instSettings.singleFrame = true;
decalSettings.pipelineSettings.renderPass = DECAL_RENDER_PASS_MISC;
decalSettings.pipelineSettings.method = isDynamic ? DECAL_METHOD_DYNAMIC : DECAL_METHOD_STATIC;
#if DECAL_PROCESS_BREAKABLES
decalSettings.pipelineSettings.applyToBreakables = true;
#endif
return AddSettings(NULL, decalSettings);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// AddReplaySettings
///////////////////////////////////////////////////////////////////////////////
#if GTA_REPLAY
int CDecalManager::AddSettingsReplay(CEntity* pEntity, decalUserSettings& settings)
{
return AddSettings(pEntity, settings);
}
#endif // GTA_REPLAY
///////////////////////////////////////////////////////////////////////////////
// AddSettings
///////////////////////////////////////////////////////////////////////////////
int CDecalManager::AddSettings(CEntity* pEntity, decalUserSettings& settings)
{
// verify the dimensions are valid (url:bugstar:1734342)
decalAssertf(IsFiniteAll(settings.instSettings.vDimensions), "non finite decal dimensions found");
// don't let any decals be applied to a physics inst that isn't a frag inst (where a frag inst exists)
if (settings.pipelineSettings.useColnEntityOnly)
{
if (pEntity==NULL)
{
return 0;
}
phInst* pInst = static_cast<CDecalCallbacks*>(g_pDecalCallbacks)->GetPhysInstFromEntity(pEntity);
if (pEntity->m_nFlags.bIsFrag && !IsFragInst(pInst))
{
return 0;
}
}
// don't let any decals be applied to mutliplayer vehicles that are being 'respotted'
if (NetworkInterface::IsGameInProgress() && pEntity && pEntity->GetIsTypeVehicle())
{
CVehicle* pVehicle = static_cast<CVehicle*>(pEntity);
if (pVehicle && pVehicle->IsBeingRespotted())
{
return 0;
}
}
// check if the decal is underwater
const decalRenderSettings* pRenderSettings = decalSettingsManager::GetRenderSettings(settings.bucketSettings.renderSettingsIndex);
if (pRenderSettings && (pRenderSettings->createUnderwater==false || pRenderSettings->fadeUnderwater==true))
{
float waterDepth;
CVfxHelper::GetWaterDepth(settings.instSettings.vPosition, waterDepth);
if (waterDepth>0.0f)
{
if (pRenderSettings->createUnderwater==false)
{
return 0;
}
else if (pRenderSettings->fadeUnderwater)
{
settings.instSettings.totalLife = DECAL_FADE_OUT_TIME;
}
}
}
#if __BANK
settings.instSettings.vDimensions.SetXf(Max(0.01f, settings.instSettings.vDimensions.GetXf() * m_decalDebug.GetSizeMult()));
settings.instSettings.vDimensions.SetYf(Max(0.01f, settings.instSettings.vDimensions.GetYf() * m_decalDebug.GetSizeMult()));
if (m_decalDebug.GetDisableDuplicateRejectDistances())
{
settings.pipelineSettings.duplicateRejectDist = 0.0f;
}
if (m_decalDebug.GetDisableOverlays())
{
settings.pipelineSettings.maxOverlayRadius = 0.0f;
}
#endif
// verify the dimensions are valid (url:bugstar:1734342)
decalAssertf(IsFiniteAll(settings.instSettings.vDimensions), "non finite decal dimensions found");
bool overridePauseCheck = false; // Apply decal regardless of the game being paused
// If the replay is playing back then override the pause check as we need
// decals to be added when the replay playback state is paused.
REPLAY_ONLY(overridePauseCheck = CReplayMgr::IsEditModeActive();)
return DECALMGR.AddSettings(pEntity, settings, overridePauseCheck);
}
///////////////////////////////////////////////////////////////////////////////
// FindRenderSettingInfo
///////////////////////////////////////////////////////////////////////////////
bool CDecalManager::FindRenderSettingInfo(u32 renderSettingId, s32& renderSettingIndex, s32& renderSettingCount)
{
if (decalVerifyf(decalSettingsManager::FindRenderSettingInfo(renderSettingId, (u32&)renderSettingIndex, (u32&)renderSettingCount), "cannot find render setting information"))
{
return true;
}
renderSettingIndex = -1;
renderSettingCount = 0;
return false;
}
///////////////////////////////////////////////////////////////////////////////
// GetRenderSettingsIndex
///////////////////////////////////////////////////////////////////////////////
s32 CDecalManager::GetRenderSettingsIndex(u32 renderSettingIndex, u32 renderSettingCount)
{
s32 index = decalSettingsManager::GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
#if __BANK
if (m_decalDebug.GetOverrideDiffuseMap())
{
if (decalSettingsManager::FindRenderSettingInfo(m_decalDebug.GetOverrideDiffuseMapId(), renderSettingIndex, renderSettingCount))
{
index = decalSettingsManager::GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
}
}
else if (m_decalDebug.GetUseTestDiffuseMap())
{
if (decalSettingsManager::FindRenderSettingInfo(DECALID_TEST_WRAP, renderSettingIndex, renderSettingCount))
{
index = decalSettingsManager::GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
}
}
else if (m_decalDebug.GetUseTestDiffuseMap2())
{
if (decalSettingsManager::FindRenderSettingInfo(DECALID_TEST_ROUND, renderSettingIndex, renderSettingCount))
{
index = decalSettingsManager::GetRenderSettingsIndex(renderSettingIndex, renderSettingCount);
}
}
#endif
return index;
}
///////////////////////////////////////////////////////////////////////////////
// Remove
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::Remove(const fwEntity* pEntity, const int boneIndex, const void* pSmashGroup, u32 exceptionTypeFlags)
{
// check if we're trying to remove a vehicle badge
// we need to make sure the ref counting updates when this happens
for (int i=0; i<DECAL_NUM_VEHICLE_BADGES; i++)
{
if (pEntity && pEntity->GetType()==ENTITY_TYPE_VEHICLE && pSmashGroup==NULL)
{
if ((exceptionTypeFlags & (1<<(DECALTYPE_VEHICLE_BADGE+i)))==0)
{
const CVehicle* pVehicle = static_cast<const CVehicle*>(pEntity);
if (pVehicle)
{
if (DoesVehicleHaveBadge(pVehicle, i))
{
RemoveVehicleBadge(pVehicle, i);
}
}
}
}
}
DECALMGR.Remove(pEntity, boneIndex, pSmashGroup, exceptionTypeFlags);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx(CPacketDecalRemove(boneIndex), (const CEntity*)pEntity);
}
#endif // GTA_REPLAY
}
///////////////////////////////////////////////////////////////////////////////
// SetJoinVerts
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::SetJoinVerts(decalPipelineSettings& pipelineSettings, Vec3V_Ptr pvJoinVerts)
{
if (!IsZeroAll(pvJoinVerts[0]))
{
pipelineSettings.vPassedJoinVerts[0] = pvJoinVerts[0];
pipelineSettings.vPassedJoinVerts[1] = pvJoinVerts[1];
pipelineSettings.vPassedJoinVerts[2] = pvJoinVerts[2];
pipelineSettings.vPassedJoinVerts[3] = pvJoinVerts[3];
}
else
{
pipelineSettings.vPassedJoinVerts[0] = Vec3V(V_ZERO);
}
}
///////////////////////////////////////////////////////////////////////////////
// GetJoinVerts
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::GetJoinVerts(decalPipelineSettings& pipelineSettings, Vec3V_Ptr pvJoinVerts)
{
pvJoinVerts[0] = pipelineSettings.vReturnedJoinVerts[0];
pvJoinVerts[1] = pipelineSettings.vReturnedJoinVerts[1];
pvJoinVerts[2] = pipelineSettings.vReturnedJoinVerts[2];
pvJoinVerts[3] = pipelineSettings.vReturnedJoinVerts[3];
}
///////////////////////////////////////////////////////////////////////////////
// RequestReplayVehicleBadge
///////////////////////////////////////////////////////////////////////////////
#if GTA_REPLAY
bool CDecalManager::RequestReplayVehicleBadge(const CVehicle* pVehicle, const CVehicleBadgeDesc& badgeDesc, s32 boneIndex, Vec3V_In vOffsetPos, Vec3V_In vDir, Vec3V_In vSide, float size, bool isForLocalPlayer, u32 badgeIndex, u8 alpha)
{
if (boneIndex>-1)
{
bool retc = m_vehicleBadgeMgr.Request(pVehicle, badgeDesc, boneIndex, vOffsetPos, vDir, vSide, size, isForLocalPlayer, badgeIndex, alpha);
return retc;
}
return false;
}
#endif // GTA_REPLAY
///////////////////////////////////////////////////////////////////////////////
// ProcessVehicleBadge
///////////////////////////////////////////////////////////////////////////////
bool CDecalManager::ProcessVehicleBadge(const CVehicle* pVehicle, const CVehicleBadgeDesc& badgeDesc, s32 boneIndex, Vec3V_In vOffsetPos, Vec3V_In vDir, Vec3V_In vSide, float size, bool isForLocalPlayer, u32 badgeIndex, u8 alpha)
{
decalAssertf(badgeDesc.IsValid(), "invalid badgeDesc passed to ProcessVehicleBadge - an emblem desc or a texture must be specified and not both");
if (boneIndex>-1)
{
#if !__FINAL
if (NetworkInterface::IsGameInProgress() && pVehicle && pVehicle->GetNetworkObject() && pVehicle->IsNetworkClone())
{
vehicleDebugf3("CDecalManager::ProcessVehicleBadge RECEIVE model[%s][%s] boneIndex[%d] vOffsetPos[%f %f %f] vDir[%f %f %f] vSide[%f %f %f] size[%f]",pVehicle->GetModelName(),pVehicle->GetNetworkObject()->GetLogName(),boneIndex,vOffsetPos.GetXf(),vOffsetPos.GetYf(),vOffsetPos.GetZf(),vDir.GetXf(),vDir.GetYf(),vDir.GetZf(),vSide.GetXf(),vSide.GetYf(),vSide.GetZf(),size);
}
#endif
bool retc = m_vehicleBadgeMgr.Request(pVehicle, badgeDesc, boneIndex, vOffsetPos, vDir, vSide, size, isForLocalPlayer, badgeIndex, alpha);
if (NetworkInterface::IsGameInProgress() && retc && pVehicle && pVehicle->GetNetworkObject() && !pVehicle->IsNetworkClone())
{
CNetObjVehicle* pNetObjVehicle = (CNetObjVehicle*) pVehicle->GetNetworkObject();
if (pNetObjVehicle)
{
#if !__FINAL
vehicleDebugf3("CDecalManager::ProcessVehicleBadge LOCAL model[%s][%s] boneIndex[%d] vOffsetPos[%f %f %f] vDir[%f %f %f] vSide[%f %f %f] size[%f]",pVehicle->GetModelName(),pVehicle->GetNetworkObject()->GetLogName(),boneIndex,vOffsetPos.GetXf(),vOffsetPos.GetYf(),vOffsetPos.GetZf(),vDir.GetXf(),vDir.GetYf(),vDir.GetZf(),vSide.GetXf(),vSide.GetYf(),vSide.GetZf(),size);
#endif
pNetObjVehicle->SetVehicleBadge(badgeDesc, boneIndex, vOffsetPos, vDir, vSide, size, badgeIndex, alpha);
}
}
#if !__FINAL
else if (NetworkInterface::IsGameInProgress() && pVehicle && pVehicle->GetNetworkObject() && !pVehicle->IsNetworkClone())
{
vehicleDebugf3("CDecalManager::ProcessVehicleBadge (FAILED m_vehicleBadgeMgr.Request) LOCAL model[%s][%s] boneIndex[%d] vOffsetPos[%f %f %f] vDir[%f %f %f] vSide[%f %f %f] size[%f]",pVehicle->GetModelName(),pVehicle->GetNetworkObject()->GetLogName(),boneIndex,vOffsetPos.GetXf(),vOffsetPos.GetYf(),vOffsetPos.GetZf(),vDir.GetXf(),vDir.GetYf(),vDir.GetZf(),vSide.GetXf(),vSide.GetYf(),vSide.GetZf(),size);
}
#endif
return retc;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// RemoveVehicleBadge
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::RemoveVehicleBadge(const CVehicle* pVehicle, const u32 badgeIndex)
{
if (pVehicle)
{
m_vehicleBadgeMgr.Remove(pVehicle, badgeIndex);
if (NetworkInterface::IsGameInProgress() && !pVehicle->IsNetworkClone())
{
CNetObjVehicle* pNetObjVehicle = (CNetObjVehicle*) pVehicle->GetNetworkObject();
if (pNetObjVehicle)
{
pNetObjVehicle->ResetVehicleBadge(badgeIndex);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// RemoveAllVehicleBadges
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::RemoveAllVehicleBadges(const CVehicle* pVehicle)
{
if (pVehicle)
{
for (int i=0; i<DECAL_NUM_VEHICLE_BADGES; i++)
{
m_vehicleBadgeMgr.Remove(pVehicle, i);
if (NetworkInterface::IsGameInProgress() && !pVehicle->IsNetworkClone())
{
CNetObjVehicle* pNetObjVehicle = (CNetObjVehicle*) pVehicle->GetNetworkObject();
if (pNetObjVehicle)
{
pNetObjVehicle->ResetVehicleBadge(i);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// GetVehicleBadgeRequestState
///////////////////////////////////////////////////////////////////////////////
DecalRequestState_e CDecalManager::GetVehicleBadgeRequestState(const CVehicle* pVehicle, const u32 badgeIndex)
{
return m_vehicleBadgeMgr.GetRequestState(pVehicle,badgeIndex);
}
///////////////////////////////////////////////////////////////////////////////
// GetVehicleBadgeRequestState
///////////////////////////////////////////////////////////////////////////////
#if __BANK
void CDecalManager::RemoveCompletedVehicleBadgeRequests()
{
return m_vehicleBadgeMgr.RemoveCompletedRequests();
}
#endif
///////////////////////////////////////////////////////////////////////////////
// DoesVehicleHaveBadge
///////////////////////////////////////////////////////////////////////////////
bool CDecalManager::DoesVehicleHaveBadge(const CVehicle* pVehicle, u32 badgeIndex)
{
if (pVehicle)
{
return (FindFirstBucket( 1<<(DECALTYPE_VEHICLE_BADGE+badgeIndex), pVehicle )!=NULL);
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// AbortVehicleBadgeRequests
///////////////////////////////////////////////////////////////////////////////
bool CDecalManager::AbortVehicleBadgeRequests(const CVehicle* pVehicle)
{
return m_vehicleBadgeMgr.Abort(pVehicle);
}
///////////////////////////////////////////////////////////////////////////////
// StartScriptedTrail
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::StartScriptedTrail(DecalType_e decalType, VfxLiquidType_e liquidType, s32 renderSettingsIndex, float width, Color32 col)
{
decalAssertf(m_scriptedTrailData.m_isActive==false, "trying to start a new scripted trail before a previous one has ended");
m_scriptedTrailData.m_isActive = true;
m_scriptedTrailData.m_decalType = decalType;
m_scriptedTrailData.m_liquidType = liquidType;
m_scriptedTrailData.m_renderSettingsIndex = renderSettingsIndex;
m_scriptedTrailData.m_width = width;
m_scriptedTrailData.m_colour = col;
m_scriptedTrailData.m_currLength = 0.0f;
m_scriptedTrailData.m_prevAlphaMult = 0.0f;
m_scriptedTrailData.m_prevPos = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[0] = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[1] = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[2] = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[3] = Vec3V(V_ZERO);
}
///////////////////////////////////////////////////////////////////////////////
// AddScriptedTrailInfo
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::AddScriptedTrailInfo(Vec3V_In vPos_In, float alphaMult, bool isScripted)
{
decalAssertf(m_scriptedTrailData.m_isActive, "trying to add info to a scripted trail that hasn't been started");
Vec3V vPos = vPos_In;
Vec3V vNormal = Vec3V(V_Z_AXIS_WZERO);
if (IsZeroAll(m_scriptedTrailData.m_prevPos)==false)
{
Color32 col = m_scriptedTrailData.m_colour;
col.SetAlpha(static_cast<u8>(col.GetAlpha()*alphaMult));
u8 alphaBack = static_cast<u8>(m_scriptedTrailData.m_prevAlphaMult*255);
g_decalMan.AddTrail(m_scriptedTrailData.m_decalType, m_scriptedTrailData.m_liquidType, m_scriptedTrailData.m_renderSettingsIndex, m_scriptedTrailData.m_prevPos, vPos, vNormal, m_scriptedTrailData.m_width, col, alphaBack, -1.0f, 0, m_scriptedTrailData.m_currLength, &m_scriptedTrailData.m_joinVerts[0], isScripted);
}
m_scriptedTrailData.m_prevPos = vPos;
m_scriptedTrailData.m_prevAlphaMult = alphaMult;
}
///////////////////////////////////////////////////////////////////////////////
// EndScriptedTrail
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::EndScriptedTrail()
{
decalAssertf(m_scriptedTrailData.m_isActive, "trying to stop a scripted trail that hasn't been started");
m_scriptedTrailData.m_isActive = false;
m_scriptedTrailData.m_width = 0.0f;
m_scriptedTrailData.m_currLength = 0.0f;
m_scriptedTrailData.m_prevAlphaMult = 0.0f;
m_scriptedTrailData.m_prevPos = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[0] = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[1] = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[2] = Vec3V(V_ZERO);
m_scriptedTrailData.m_joinVerts[3] = Vec3V(V_ZERO);
}
///////////////////////////////////////////////////////////////////////////////
// SetDisableFootprints
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::SetDisableFootprints(bool val, scrThreadId scriptThreadId)
{
if (vfxVerifyf(m_disableFootprintsScriptThreadId==THREAD_INVALID || m_disableFootprintsScriptThreadId==scriptThreadId, "trying to disable footprint decals when this is already in use by another script"))
{
m_disableFootprintsFromScript = val;
m_disableFootprintsScriptThreadId = scriptThreadId;
}
}
///////////////////////////////////////////////////////////////////////////////
// SetDisableCompositeShotgunImpacts
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::SetDisableCompositeShotgunImpacts(bool val, scrThreadId scriptThreadId)
{
if (vfxVerifyf(m_disableCompositeShotgunImpactsScriptThreadId==THREAD_INVALID || m_disableCompositeShotgunImpactsScriptThreadId==scriptThreadId, "trying to disable footprint decals when this is already in use by another script"))
{
m_disableCompositeShotgunImpactsFromScript = val;
m_disableCompositeShotgunImpactsScriptThreadId = scriptThreadId;
}
}
///////////////////////////////////////////////////////////////////////////////
// SetDisableScuffs
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::SetDisableScuffs(bool val, scrThreadId scriptThreadId)
{
if (vfxVerifyf(m_disableScuffsScriptThreadId==THREAD_INVALID || m_disableScuffsScriptThreadId==scriptThreadId, "trying to disable scuff decals when this is already in use by another script"))
{
m_disableScuffsFromScript = val;
m_disableScuffsScriptThreadId = scriptThreadId;
}
}
///////////////////////////////////////////////////////////////////////////////
// ApplyWheelTrailHackForArenaMode
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::ApplyWheelTrailHackForArenaMode(bool enable)
{
if (enable)
{
g_typeSettings[DECALTYPE_TRAIL_SKID].collisionFlags = DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_OBJECT | DECAL_COLN_FLAG_BUILDINGS;
}
else
{
g_typeSettings[DECALTYPE_TRAIL_SKID].collisionFlags = DECAL_COLN_FLAG_MAP | DECAL_COLN_FLAG_OBJECT;
}
}
///////////////////////////////////////////////////////////////////////////////
// RemoveScript
///////////////////////////////////////////////////////////////////////////////
void CDecalManager::RemoveScript(scrThreadId scriptThreadId)
{
if (scriptThreadId==m_disableFootprintsScriptThreadId)
{
m_disableFootprintsFromScript = false;
m_disableFootprintsScriptThreadId = THREAD_INVALID;
}
if (scriptThreadId==m_disableCompositeShotgunImpactsScriptThreadId)
{
m_disableCompositeShotgunImpactsFromScript = false;
m_disableCompositeShotgunImpactsScriptThreadId = THREAD_INVALID;
}
if (scriptThreadId==m_disableScuffsScriptThreadId)
{
m_disableScuffsFromScript = false;
m_disableScuffsScriptThreadId = THREAD_INVALID;
}
}
grcBlendStateHandle CDecalManager::OverrideStaticBlendStateFunctor(decalRenderPass pass)
{
#if APPLY_DOF_TO_ALPHA_DECALS
if (CPtFxManager::UseParticleDOF() && (pass == DECAL_RENDER_PASS_FORWARD))
{
return g_decalMan.GetStaticForwardBlendState();
}
#endif //APPLY_DOF_TO_ALPHA_DECALS
return grcStateBlock::BS_Invalid;
}
void CDecalManager::DecalMerged(int REPLAY_ONLY(oldDecalId), int REPLAY_ONLY(newDecalId))
{
#if GTA_REPLAY
//Only do this in game and not on replay playback.
if( !CReplayMgr::IsReplayInControlOfWorld() )
{
if( g_decalMan.m_ReplayMergedDecalEvents.size() >= MAX_REPLAY_MERGED_DECAL_EVENTS )
{
AssertMsg(false, "m_ReplayMergedDecalEvents ran out of space");
return;
}
replayMergedDecalEvent &eventData = g_decalMan.m_ReplayMergedDecalEvents.Append();
eventData.newDecalId = newDecalId;
eventData.oldDecalId = oldDecalId;
}
#endif //GTA_REPLAY
}
void CDecalManager::LiquidUVMultChanged(int REPLAY_ONLY(decalId), float REPLAY_ONLY(uvMult), Vec3V_In REPLAY_ONLY(pos))
{
#if GTA_REPLAY
//Only do this in game and not on replay playback.
if( !CReplayMgr::IsReplayInControlOfWorld() )
{
if( g_decalMan.m_ReplayUVMultChanges.size() >= MAX_REPLAY_UV_MULT_CHANGES )
{
Warningf("m_ReplayUVMultChanges ran out of space");
return;
}
replayUVMultChanges &eventData = g_decalMan.m_ReplayUVMultChanges.Append();
eventData.decalId = decalId;
eventData.uvMult = uvMult;
eventData.pos = pos;
}
#endif //GTA_REPLAY
}
#if GTA_REPLAY
void CDecalManager::ResetReplayDecalEvents()
{
m_ReplayMergedDecalEvents.Reset();
m_ReplayUVMultChanges.Reset();
}
int CDecalManager::ProcessMergedDecals(int decalId)
{
for( u32 i = 0; i < m_ReplayMergedDecalEvents.size(); i++)
{
if( m_ReplayMergedDecalEvents[i].oldDecalId == decalId )
return m_ReplayMergedDecalEvents[i].newDecalId;
}
return decalId;
}
float CDecalManager::ProcessUVMultChanges(int decalId, Vec3V vPos)
{
float uvMult = -1.0f;
for( u32 i = 0; i < m_ReplayUVMultChanges.size(); i++)
{
float dist = VEC3V_TO_VECTOR3(vPos - m_ReplayUVMultChanges[i].pos).Mag2();
if( m_ReplayUVMultChanges[i].decalId == decalId || dist < 0.5f )
uvMult = Max(uvMult, m_ReplayUVMultChanges[i].uvMult);
}
return uvMult;
}
#endif //GTA_REPLAY