Files
FC1/Cry3DEngine/DecalManager.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

715 lines
22 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: decals.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: draw, create decals on the world
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DecalManager.h"
#include "3dengine.h"
#include <IStatObj.h>
#include "ObjMan.h"
#define COMPLEX_DECAL_MIN_SIZE 0.1f
CDecalManager::CDecalManager(C3DEngine * p3DEngine)
{
m_nCurDecal = 0;
memset(m_arrbActiveDecals,0,sizeof(m_arrbActiveDecals));
m_p3DEngine = p3DEngine;
m_pShader_ParticleLight = GetRenderer()->EF_LoadShader("ParticleLight", eSH_World, EF_SYSTEM);
m_pShader_Decal_VP = GetRenderer()->EF_LoadShader("Decal_VP", eSH_World, EF_SYSTEM);
m_pShader_Decal_2D_VP = GetRenderer()->EF_LoadShader("Decal_2D_VP", eSH_World, EF_SYSTEM);
}
// called from the renderer, draws immideately
void CDecalManager::DrawBigDecalsOnTerrain()
{
if(!GetCVars()->e_decals)
return;
//GetRenderer()->ResetToDefault();
GetRenderer()->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
GetRenderer()->SetColorOp(eCO_MODULATE, eCO_MODULATE, eCA_Texture|(eCA_Constant<<3), eCA_Texture|(eCA_Constant<<3));
GetRenderer()->SetCullMode(R_CULL_DISABLE);
Vec3d vColor = GetSystem()->GetI3DEngine()->GetWorldColor();//*
GetRenderer()->SetMaterialColor(vColor.x,vColor.y,vColor.z,1);
float fCurrTime = GetTimer()->GetCurrTime();
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
if(!m_arrDecals[i].m_pStatObj && m_arrDecals[i].m_bOnTheGround)
if( GetViewCamera().IsSphereVisibleFast( Sphere(m_arrDecals[i].m_vPos, m_arrDecals[i].m_fSize)) )
m_arrDecals[i].DrawBigDecalOnTerrain(m_p3DEngine, GetRenderer(), fCurrTime);
}
//GetRenderer()->ResetToDefault();
}
bool CDecalManager::AdjustDecalPosition( CryEngineDecalInfo & DecalInfo, bool bMakeFatTest )
{
Matrix44 objMat, objMatInv;
int nPartID = DecalInfo.nPartID;
IStatObj * pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(nPartID, &objMat, true);
while(!pEntObject && nPartID<16)
{ // find first visible entity component
pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(++nPartID, &objMat, true);
}
if(!pEntObject || !pEntObject->GetLeafBuffer()|| nPartID>=16)
return false;
// transform decal into object space
objMatInv = objMat;
objMatInv.Invert44();
// put into normal object space hit direction of projection
Vec3d vObjSpaceHitDirection = objMatInv.TransformVectorOLD(DecalInfo.vHitDirection);
// put into position object space hit position
Vec3d vObjSpacePos = objMatInv.TransformPointOLD(DecalInfo.vPos);
// get decal directions
Vec3d vRi(0,0,0), vUp(0,0,0);
if(fabs(vObjSpaceHitDirection.Dot(Vec3d(0,0,1)))>0.999f)
{ // horiz surface
vRi = Vec3d(0,1,0);
vUp = Vec3d(1,0,0);
}
else
{
vRi = vObjSpaceHitDirection.Cross(Vec3d(0,0,1));
vRi.Normalize();
vUp = vObjSpaceHitDirection.Cross(vRi);
vUp.Normalize();
}
vRi*=DecalInfo.fSize;
vUp*=DecalInfo.fSize;
Vec3d vObjSpaceOutPos(0,0,0), vObjSpaceOutNormal(0,0,0), vTmp;
CLeafBuffer * pLB = pEntObject->GetLeafBuffer();
if( pLB && pLB->m_pSecVertBuffer && pLB->m_SecVertCount &&
RayLeafBufferIntersection(pLB, vObjSpacePos, vObjSpaceHitDirection*0.1f, vObjSpaceOutPos, vObjSpaceOutNormal) )
{ // now check that none of decal sides will not fly in the air
Vec3d vDecalNormal = vObjSpaceOutNormal*DecalInfo.fSize;
if( !bMakeFatTest || (
RayLeafBufferIntersection(pLB, vObjSpaceOutPos+vUp, -vDecalNormal, vTmp, vTmp) &&
RayLeafBufferIntersection(pLB, vObjSpaceOutPos-vUp, -vDecalNormal, vTmp, vTmp) &&
RayLeafBufferIntersection(pLB, vObjSpaceOutPos+vRi, -vDecalNormal, vTmp, vTmp) &&
RayLeafBufferIntersection(pLB, vObjSpaceOutPos-vRi, -vDecalNormal, vTmp, vTmp) ))
{
DecalInfo.vPos = objMat.TransformPointOLD(vObjSpaceOutPos);
DecalInfo.vNormal = objMat.TransformVectorOLD(vObjSpaceOutNormal);
return true;
}
}
return false;
}
struct HitPosInfo {
HitPosInfo() { memset(this,0,sizeof(HitPosInfo)); }
Vec3d vPos,vNormal;
float fDistance;
};
int __cdecl CDecalManager__CmpHitPos(const void* v1, const void* v2)
{
HitPosInfo * p1 = (HitPosInfo*)v1;
HitPosInfo * p2 = (HitPosInfo*)v2;
if(p1->fDistance > p2->fDistance)
return 1;
else if(p1->fDistance < p2->fDistance)
return -1;
return 0;
}
bool CDecalManager::RayLeafBufferIntersection(CLeafBuffer * pLeafBuffer, const Vec3d & vInPos, const Vec3d & vInDir, Vec3d & vOutPos, Vec3d & vOutNormal)
{
// get position offset and stride
int nPosStride = 0;
byte * pPos = pLeafBuffer->GetPosPtr(nPosStride, 0, true);
// get indices
ushort *pInds = pLeafBuffer->GetIndices(0);
int nInds = pLeafBuffer->m_Indices.m_nItems;
assert(nInds%3 == 0);
HitPosInfo arrResult[16];
memset(arrResult,0,sizeof(arrResult));
int nResultCount=0;
// find faces
for(int i=0; i<nInds && nResultCount<16; i+=3)
{
// get tri vertices
Vec3d v0 = *((Vec3d*)&pPos[nPosStride*pInds[i+0]]);
Vec3d v1 = *((Vec3d*)&pPos[nPosStride*pInds[i+1]]);
Vec3d v2 = *((Vec3d*)&pPos[nPosStride*pInds[i+2]]);
// make line triangle intersection
Vec3d vResPos(0,0,0);
if( Intersect::Lineseg_Triangle(Lineseg(vInPos+vInDir, vInPos-vInDir), v0, v1, v2, vResPos) ||
Intersect::Lineseg_Triangle(Lineseg(vInPos-vInDir, vInPos+vInDir), v0, v1, v2, vResPos) )
{
arrResult[nResultCount].vPos = vResPos;
arrResult[nResultCount].vNormal = (v1-v0).Cross(v2-v0);
arrResult[nResultCount].vNormal.Normalize();
arrResult[nResultCount].fDistance = (vInPos-vInDir).GetDistance(vResPos);
nResultCount++;
}
}
if(nResultCount)
{ // return closest to the shooter
qsort(&arrResult, nResultCount, sizeof(arrResult[0]), CDecalManager__CmpHitPos);
vOutPos = arrResult[0].vPos;
vOutNormal = arrResult[0].vNormal;
}
return nResultCount!=0;
}
void CDecalManager::Spawn( CryEngineDecalInfo DecalInfo, float fMaxViewDistance, CTerrain * pTerrain )
{
Vec3d vCamPos = GetViewCamera().GetPos();
// DecalInfo.fLifeTime = 1000000000;
// DecalInfo.fSize = .5f;
// DecalInfo.m_fGrowTime = 4.f;
// DecalInfo.nPartID = -1;
// do not spawn if too far
float fZoom = m_p3DEngine->GetObjManager() ? m_p3DEngine->GetObjManager()->m_fZoomFactor : 1.f;
float fDecalDistance = L1Distance2D(DecalInfo.vPos, vCamPos);
if( fDecalDistance>fMaxViewDistance || fDecalDistance*fZoom>DecalInfo.fSize*ENTITY_DECAL_DIST_FACTOR*3.f )
return;
/* if(DecalInfo.pDecalOwner && DecalInfo.pDecalOwner->GetEntityRenderType() == eERType_Vegetation)
{
CStatObjInst * pStatObjInst = (CStatObjInst*)DecalInfo.pDecalOwner;
if(pStatObjInst->m_fFinalBending)
return; // do not spawn on bendable vegetations
}*/
// project decal to visible geoemtry
if(DecalInfo.bAdjustPos && DecalInfo.nPartID>=0 && DecalInfo.pDecalOwner && !AdjustDecalPosition( DecalInfo, DecalInfo.fSize<=COMPLEX_DECAL_MIN_SIZE ))
return;
// clamp all decal textures
GetRenderer()->SetTexture(DecalInfo.nTid);
GetRenderer()->SetTexClampMode(true);
// don't go crazy
if(DecalInfo.fSize > 4)
DecalInfo.fSize = 4;
if(DecalInfo.fSize > 1 && GetCVars()->e_decals_neighbor_max_life_time)
{ // force near decals to fade faster
float fCurrTime = GetTimer()->GetCurrTime();
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
if(m_arrDecals[i].m_vWSPos.GetDistance(DecalInfo.vPos) < m_arrDecals[i].m_fWSSize+DecalInfo.fSize)
if((m_arrDecals[i]).m_fLifeBeginTime < fCurrTime-0.1f)
if(m_arrDecals[i].m_fLifeEndTime > fCurrTime+GetCVars()->e_decals_neighbor_max_life_time)
m_arrDecals[i].m_fLifeEndTime = fCurrTime+GetCVars()->e_decals_neighbor_max_life_time;
}
}
// loop position in array
if(m_nCurDecal>=DECAL_COUNT)
m_nCurDecal=0;
// free old LB
GetRenderer()->DeleteLeafBuffer(m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer);
m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer=0;
// just in case
DecalInfo.vNormal.Normalize();
bool bBigDecalOnTheGround = false;
// remember object we need to follow
m_arrDecals[m_nCurDecal].m_nDecalOwnerComponentId = DecalInfo.nPartID;
m_arrDecals[m_nCurDecal].m_vWSPos = DecalInfo.vPos;
m_arrDecals[m_nCurDecal].m_fWSSize = DecalInfo.fSize;
// If owner entity and object is specified - make decal use entity geometry
float fObjScale = 1.f;
if(DecalInfo.pDecalOwner && DecalInfo.nPartID>=0 && DecalInfo.fSize>COMPLEX_DECAL_MIN_SIZE)
{ // get object pointer
Matrix44 objMat;
IStatObj * pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(DecalInfo.nPartID, &objMat);
if(pEntObject)
{
CLeafBuffer * pSourceLeafBuffer = pEntObject->GetLeafBuffer();
// transform decal into object space
objMat.Invert44();
// put into normal object space hit direction of projection
DecalInfo.vNormal = -objMat.TransformVectorOLD(DecalInfo.vHitDirection);
// put into position object space hit position
DecalInfo.vPos = objMat.TransformPointOLD(DecalInfo.vPos);
// find object scale
if(DecalInfo.pDecalOwner->GetEntityRenderType()==eERType_Vegetation)
fObjScale = DecalInfo.pDecalOwner->GetScale();
else
{
Vec3d vTest(0,0,1.f);
vTest = objMat.TransformVectorOLD(vTest);
fObjScale = 1.f/vTest.len();
}
if(fObjScale<0.01f)
return;
// transform size into object space
DecalInfo.fSize/=fObjScale;
// make decal geometry
m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer = MakeBigDecalLeafBuffer(pSourceLeafBuffer, DecalInfo.vPos,
DecalInfo.fSize, DecalInfo.vNormal, DecalInfo.nTid);
if(!m_arrDecals[m_nCurDecal].m_pBigDecalLeafBuffer)
return; // no geometry found
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(DecalInfo.nTid);
if(pTexPic)
{
pTexPic->SetFilter(FILTER_LINEAR);
pTexPic->SetClamp(true);
}
}
else
{
Warning( 0,0,"CDecalManager::Spawn: nPartID points to empty object");
return;
}
}
else if(DecalInfo.pDecalOwner &&
(!DecalInfo.pDecalOwner->IsStatic() || DecalInfo.pDecalOwner->GetEntityRenderType() == eERType_Vegetation) &&
DecalInfo.nPartID>=0)
{ // transform decal from world space into entity space
Matrix44 objMat;
IStatObj * pEntObject = DecalInfo.pDecalOwner->GetEntityStatObj(DecalInfo.nPartID, &objMat);
assert(pEntObject);
objMat.Invert44();
DecalInfo.vNormal = objMat.TransformVectorOLD(DecalInfo.vNormal);
DecalInfo.vNormal.Normalize();
DecalInfo.vPos = objMat.TransformPointOLD(DecalInfo.vPos);
// find object scale
if(DecalInfo.pDecalOwner->GetEntityRenderType()==eERType_Vegetation)
fObjScale = DecalInfo.pDecalOwner->GetScale();
else
{
Vec3d vTest(0,0,1.f);
vTest = objMat.TransformVectorOLD(vTest);
fObjScale = 1.f/vTest.len();
}
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(DecalInfo.nTid);
if(pTexPic)
{
pTexPic->SetFilter(FILTER_LINEAR);
pTexPic->SetClamp(true);
}
}
else
{
if(DecalInfo.fSize>COMPLEX_DECAL_MIN_SIZE && !DecalInfo.pDecalOwner &&
(DecalInfo.vPos.z-pTerrain->GetZApr(DecalInfo.vPos.x,DecalInfo.vPos.y))<DecalInfo.fSize)
{
int nUnitSize = CTerrain::GetHeightMapUnitSize();
int x1 = int(DecalInfo.vPos.x-DecalInfo.fSize)/nUnitSize*nUnitSize-nUnitSize;
int x2 = int(DecalInfo.vPos.x+DecalInfo.fSize)/nUnitSize*nUnitSize+nUnitSize;
int y1 = int(DecalInfo.vPos.y-DecalInfo.fSize)/nUnitSize*nUnitSize-nUnitSize;
int y2 = int(DecalInfo.vPos.y+DecalInfo.fSize)/nUnitSize*nUnitSize+nUnitSize;
for(int x=x1; x<=x2; x+=CTerrain::GetHeightMapUnitSize())
for(int y=y1; y<=y2; y+=CTerrain::GetHeightMapUnitSize())
if(pTerrain->GetHoleSafe(x,y))
return;
bBigDecalOnTheGround = true;
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(DecalInfo.nTid);
if(pTexPic)
{
pTexPic->SetFilter(FILTER_LINEAR);
pTexPic->SetClamp(true);
}
}
DecalInfo.pDecalOwner = NULL;
}
DecalInfo.vNormal.Normalize();
// spawn
m_arrDecals[m_nCurDecal].m_vPos = DecalInfo.vPos;
m_arrDecals[m_nCurDecal].m_vPos += DecalInfo.vNormal*0.01f/fObjScale;
m_arrDecals[m_nCurDecal].m_bOnTheGround = bBigDecalOnTheGround;
if(fabs(DecalInfo.vNormal.Dot(Vec3d(0,0,1)))>0.999f)
{ // horiz surface
m_arrDecals[m_nCurDecal].m_vRight = Vec3d(0,1,0);
m_arrDecals[m_nCurDecal].m_vUp = Vec3d(1,0,0);
}
else
{
m_arrDecals[m_nCurDecal].m_vRight = DecalInfo.vNormal.Cross(Vec3d(0,0,1));
m_arrDecals[m_nCurDecal].m_vRight.Normalize();
m_arrDecals[m_nCurDecal].m_vUp = DecalInfo.vNormal.Cross(m_arrDecals[m_nCurDecal].m_vRight);
m_arrDecals[m_nCurDecal].m_vUp.Normalize();
}
/*
// check that decal will look ok here
if(!DecalInfo.pDecalOwner && DecalInfo.fSize<=COMPLEX_DECAL_MIN_SIZE)
{
ray_hit hit;
float fSize = DecalInfo.fSize*2;
if(GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize + m_arrDecals[m_nCurDecal].m_vUp*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1)
&& GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize - m_arrDecals[m_nCurDecal].m_vUp*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1)
&& GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize + m_arrDecals[m_nCurDecal].m_vRight*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1)
&& GetPhysicalWorld()->RayWorldIntersection(
DecalInfo.vPos - DecalInfo.vNormal*fSize - m_arrDecals[m_nCurDecal].m_vRight*fSize, DecalInfo.vNormal*fSize*2,
ent_all, rwi_stop_at_pierceable,&hit,1))
{
int t=0; // ok
}
else
return; // position is bad
}
*/
// rotate vectors
AngleAxis rotation(DecalInfo.fAngle,DecalInfo.vNormal);
m_arrDecals[m_nCurDecal].m_vRight = rotation*m_arrDecals[m_nCurDecal].m_vRight;
m_arrDecals[m_nCurDecal].m_vUp = rotation*m_arrDecals[m_nCurDecal].m_vUp;
m_arrDecals[m_nCurDecal].m_vFront = DecalInfo.vNormal;
m_arrDecals[m_nCurDecal].m_fSize = DecalInfo.fSize;
m_arrDecals[m_nCurDecal].m_fLifeEndTime = GetTimer()->GetCurrTime() + DecalInfo.fLifeTime*GetCVars()->e_decals_life_time_scale;
m_arrDecals[m_nCurDecal].m_nTexId = DecalInfo.nTid;
m_arrDecals[m_nCurDecal].m_fAngle = DecalInfo.fAngle;
m_arrDecals[m_nCurDecal].m_pStatObj = DecalInfo.pStatObj;
m_arrDecals[m_nCurDecal].m_vAmbient = Get3DEngine()->GetAmbientColorFromPosition(DecalInfo.vPos);
m_arrDecals[m_nCurDecal].m_pDecalOwner = DecalInfo.pDecalOwner;
m_arrDecals[m_nCurDecal].m_fGrowTime = DecalInfo.m_fGrowTime;
m_arrDecals[m_nCurDecal].m_fLifeBeginTime = GetTimer()->GetCurrTime();
if(DecalInfo.pStatObj)
{
DecalInfo.pStatObj->RegisterUser();
CDecal tmp;
tmp.m_vPos = DecalInfo.vPos;
tmp.m_vFront = DecalInfo.vNormal;
tmp.m_nTexId = DecalInfo.nTid;
tmp.m_fSize = DecalInfo.fSize;
m_LightHoles.Add(tmp);
}
m_arrbActiveDecals[m_nCurDecal] = true;
m_nCurDecal++;
}
void CDecalManager::SubmitLightHolesToRenderer()
{
if(!this)
return;
for(int i=0; i<m_LightHoles.Count(); i++)
GetRenderer()->EF_SetLightHole(m_LightHoles[i].m_vPos,
m_LightHoles[i].m_vFront, m_LightHoles[i].m_nTexId, m_LightHoles[i].m_fSize);
m_LightHoles.Clear();
}
void CDecalManager::Render()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
if(!GetCVars()->e_decals || !m_p3DEngine->GetObjManager() || m_p3DEngine->GetCurrentLightSpec() < 1)
return;
CCamera * pCamera = &GetViewCamera();
Vec3d vCamPos = pCamera->GetPos();
float fCurrTime = GetTimer()->GetCurrTime();
IRenderer * pIRenderer = GetRenderer();
CObjManager * pObjManager = m_p3DEngine->GetObjManager();
float fZoom = m_p3DEngine->GetObjManager()->m_fZoomFactor;
float fWaterLevel = m_p3DEngine->GetWaterLevel();
// draw
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
CDecal * pDecal = &m_arrDecals[i];
if(L1Distance2D(vCamPos, pDecal->m_vWSPos)*fZoom < pDecal->m_fWSSize*ENTITY_DECAL_DIST_FACTOR)
{
float fSortOffset = pObjManager->GetSortOffset(pDecal->m_vWSPos,vCamPos,fWaterLevel);
pDecal->Process(m_arrbActiveDecals[i], pIRenderer, fCurrTime, m_p3DEngine, m_pShader_ParticleLight, pCamera, fSortOffset);
}
}
}
void CDecalManager::OnEntityDeleted(IEntityRender * pEntityRender)
{
/* if(pEntityRender && pEntityRender->GetEntityRenderType()!=eERType_Unknown)
{ // remove all decals, can happend only during editing or level unloading
memset(m_arrbActiveDecals,0,sizeof(m_arrbActiveDecals));
return;
}
*/
// remove decals of this entity
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i])
{
if(m_arrDecals[i].m_pDecalOwner == pEntityRender)
{
assert(pEntityRender->GetEntityRS());
m_arrbActiveDecals[i] = false;
if(m_arrDecals[i].m_pBigDecalLeafBuffer)
{
GetRenderer()->DeleteLeafBuffer(m_arrDecals[i].m_pBigDecalLeafBuffer);
m_arrDecals[i].m_pBigDecalLeafBuffer=0;
}
m_arrDecals[i].m_pDecalOwner = 0;
}
}
}
void CDecalManager::FillBigDecalIndices(CLeafBuffer * pLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, list2<ushort> * plstIndices)
{
// get position offset and stride
int nPosStride = 0, nNormStride = 0;
byte * pPos = pLeafBuffer->GetPosPtr(nPosStride, 0, true);
byte * pNorm = pLeafBuffer->GetNormalPtr(nNormStride, 0, true);
ushort *pInds = pLeafBuffer->GetIndices(0);
int nInds = pLeafBuffer->m_Indices.m_nItems;
assert(nInds%3 == 0);
plstIndices->Clear();
vProjDir.Normalize();
// Plane plane = GetPlane(vProjDir,vPos);
// fill decal indices
for(int i=0; i<nInds; i+=3)
{
// get tri vertices
Vec3d v0 = *((Vec3d*)&pPos[nPosStride*pInds[i+0]]);
Vec3d v1 = *((Vec3d*)&pPos[nPosStride*pInds[i+1]]);
Vec3d v2 = *((Vec3d*)&pPos[nPosStride*pInds[i+2]]);
// get tri normals
Vec3d n0 = *((Vec3d*)&pNorm[nNormStride*pInds[i+0]]);
Vec3d n1 = *((Vec3d*)&pNorm[nNormStride*pInds[i+1]]);
Vec3d n2 = *((Vec3d*)&pNorm[nNormStride*pInds[i+2]]);
// find bbox
Vec3d vBoxMin = v0; vBoxMin.CheckMin(v1); vBoxMin.CheckMin(v2);
Vec3d vBoxMax = v0; vBoxMax.CheckMax(v1); vBoxMax.CheckMax(v2);
if(vProjDir.IsZero())
{ // explo mode
// get dir to triangle
// Vec3d vCenter = (v0+v1+v2)*0.33333f;
// test the face
float fDot0 = (vPos-v0).Dot(n0);
float fDot1 = (vPos-v1).Dot(n1);
float fDot2 = (vPos-v2).Dot(n2);
float fTest = -0.15f;
if(fDot0 < fTest && fDot1 < fTest && fDot2 < fTest)
continue;
}
else
{
// get triangle normal
Vec3d vNormal = (v1-v0).Cross(v2-v0);
vNormal.Normalize();
// test the face
if(vNormal.Dot(vProjDir)<0)
continue;
}
if(Overlap::Sphere_AABB(Sphere(vPos, fRadius), AABB(vBoxMin,vBoxMax)))
{
plstIndices->Add(pInds[i+0]);
plstIndices->Add(pInds[i+1]);
plstIndices->Add(pInds[i+2]);
}
}
}
CLeafBuffer * CDecalManager::MakeBigDecalLeafBuffer(CLeafBuffer * pSourceLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, int nTexID)
{
if(!pSourceLeafBuffer || pSourceLeafBuffer->m_SecVertCount==0)
return 0;
// make indices of this decal
list2<ushort> lstIndices;
if(pSourceLeafBuffer && pSourceLeafBuffer->m_pSecVertBuffer && pSourceLeafBuffer->m_SecVertCount)
FillBigDecalIndices(pSourceLeafBuffer, vPos, fRadius, vProjDir, &lstIndices);
if(!lstIndices.Count())
return 0;
// make fake vert buffer with one vertex // todo: remove this
list2<struct_VERTEX_FORMAT_P3F_COL4UB> EmptyVertBuffer;
EmptyVertBuffer.Add(struct_VERTEX_FORMAT_P3F_COL4UB());
CLeafBuffer * pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
EmptyVertBuffer.GetElements(), EmptyVertBuffer.Count(), VERTEX_FORMAT_P3F_COL4UB,
lstIndices.GetElements(), lstIndices.Count(),
R_PRIMV_TRIANGLES, "BigDecal", eBT_Static, 1, nTexID);
pLeafBuffer->SetVertexContainer(pSourceLeafBuffer);
IShader * pShader = vProjDir.IsZero() ? m_pShader_Decal_VP : m_pShader_Decal_2D_VP;
pLeafBuffer->SetChunk(pShader, 0, pSourceLeafBuffer->m_SecVertCount, 0, lstIndices.Count());
pLeafBuffer->SetShader(pShader,nTexID);
return pLeafBuffer;
}
/*
CLeafBuffer * CDecalManager::MakeBigDecalLeafBuffer(CLeafBuffer * pSourceLeafBuffer, Vec3d vPos, float fRadius, Vec3d vProjDir, int nTexID)
{
if(!pSourceLeafBuffer || pSourceLeafBuffer->m_SecVertCount==0)
return 0;
// make indices of this decal
list2<ushort> lstIndices;
if(pSourceLeafBuffer && pSourceLeafBuffer->m_pSecVertBuffer && pSourceLeafBuffer->m_SecVertCount)
FillBigDecalIndices(pSourceLeafBuffer, vPos, fRadius, vProjDir, &lstIndices);
if(!lstIndices.Count())
return 0;
// make fake vert buffer with one vertex // todo: remove this
list2<struct_VERTEX_FORMAT_P3F_N> VertBuffer;
VertBuffer.PreAllocate(pSourceLeafBuffer->m_SecVertCount);
int nPosStride=0, nNormStride=0;
void * pPos = pSourceLeafBuffer->GetPosPtr(nPosStride);
void * pNorm = pSourceLeafBuffer->GetPosPtr(nNormStride);
for(int i=0; i<pSourceLeafBuffer->m_SecVertCount; i++)
{
struct_VERTEX_FORMAT_P3F_N vert;
vert.xyz = *(Vec3d*)((uchar*)pPos+nPosStride*i);
vert.normal = *(Vec3d*)((uchar*)pNorm+nNormStride*i);
vert.normal = vert.normal*5;
VertBuffer.Add(vert);
}
CLeafBuffer * pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
VertBuffer.GetElements(), VertBuffer.Count(), VERTEX_FORMAT_P3F_N,
lstIndices.GetElements(), lstIndices.Count(),
R_PRIMV_TRIANGLES, "BigDecal", eBT_Static, 1, nTexID);
pLeafBuffer->SetChunk(m_pShader_Decal_VP, 0, pSourceLeafBuffer->m_SecVertCount, 0, lstIndices.Count());
pLeafBuffer->SetShader(m_pShader_Decal_VP,nTexID);
return pLeafBuffer;
}
*/
void CDecalManager::GetMemoryUsage(ICrySizer*pSizer)
{
pSizer->Add (*this);
pSizer->AddContainer (m_LightHoles);
}
void CDecalManager::DeleteDecalsInRange( Vec3d vBoxMin, Vec3d vBoxMax, bool bDeleteBigTerrainDecals )
{
for(int i=0; i<DECAL_COUNT; i++)
if(m_arrbActiveDecals[i] && !m_arrDecals[i].m_bOnTheGround)
{
if(!m_arrDecals[i].m_pDecalOwner &&
m_arrDecals[i].m_vPos.x<vBoxMax.x &&
m_arrDecals[i].m_vPos.y<vBoxMax.y &&
m_arrDecals[i].m_vPos.z<vBoxMax.z &&
m_arrDecals[i].m_vPos.x>vBoxMin.x &&
m_arrDecals[i].m_vPos.y>vBoxMin.y &&
m_arrDecals[i].m_vPos.z>vBoxMin.z )
{
m_arrbActiveDecals[i] = false;
GetRenderer()->DeleteLeafBuffer(m_arrDecals[i].m_pBigDecalLeafBuffer);
m_arrDecals[i].m_pBigDecalLeafBuffer=0;
}
}
}
/*
struct CDebugLine
{
Vec3d v0,v1;
int nFrameId;
};
list2<CDebugLine> lstDebugLines;
void AddDebugLine(Vec3d v0, Vec3d v1, int nFrameId)
{
CDebugLine l;
l.v0 = v0;
l.v1 = v1;
l.nFrameId = nFrameId;
lstDebugLines.Add(l);
}
void DrawDebugLines(IRenderer*pRenderer)
{
for(int i=0; i<lstDebugLines.Count(); i++)
{
pRenderer->Draw3dPrim(lstDebugLines[i].v0,lstDebugLines[i].v1,DPRIM_LINE);
if(pRenderer->GetFrameID()>lstDebugLines[i].nFrameId+1000)
{
lstDebugLines.Delete(i);
i--;
}
}
}*/