308 lines
11 KiB
C++
308 lines
11 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 "objman.h"
|
|
|
|
void CDecal::Process(bool & active, IRenderer * pIRenderer, const float fCurTime, C3DEngine * p3DEngine, IShader * pShader, CCamera* pCamera, float fSortOffset)
|
|
{
|
|
// todo: take entity orientation into account
|
|
m_nDynLMask = ((I3DEngine*)p3DEngine)->GetLightMaskFromPosition(m_pDecalOwner ? m_pDecalOwner->GetPos()+m_vPos : m_vPos, m_fSize);
|
|
|
|
uint nDynLightMask = m_nDynLMask;
|
|
|
|
// render StatObj decal
|
|
if(m_pStatObj)
|
|
{
|
|
Render3DObject();
|
|
return;
|
|
}
|
|
|
|
// Get decal alpha from life time
|
|
float fLifeTime = m_fLifeEndTime - fCurTime;
|
|
float fAlpha = fLifeTime*2;
|
|
if(fAlpha > 1.f)
|
|
fAlpha = 1.f;
|
|
else if(fAlpha<0)
|
|
{ // kill
|
|
active=0;
|
|
pIRenderer->DeleteLeafBuffer(m_pBigDecalLeafBuffer);
|
|
m_pBigDecalLeafBuffer=0;
|
|
return;
|
|
}
|
|
|
|
float fSizeK;
|
|
if(m_fGrowTime)
|
|
fSizeK = min(1.f, cry_sqrtf((fCurTime - m_fLifeBeginTime)/m_fGrowTime));
|
|
else
|
|
fSizeK = 1.f;
|
|
|
|
// if there is owner - transform decal from owner space into world space
|
|
if(m_pDecalOwner)
|
|
{
|
|
// if there is information about decal geometry - render complex decal and project texture on it
|
|
if(m_pBigDecalLeafBuffer && m_pBigDecalLeafBuffer->m_Indices.m_nItems)
|
|
{
|
|
// setup transformation
|
|
CCObject * pObj = pIRenderer->EF_GetObject(true);
|
|
pObj->m_SortId = fSortOffset;
|
|
|
|
Matrix44 objMat;
|
|
if(!m_pDecalOwner->GetEntityStatObj(m_nDecalOwnerComponentId, &objMat))
|
|
{
|
|
// GetLog()->Log("Error: CDecal::Process: m_nDecalOwnerComponentId is out of range: %d", m_nDecalOwnerComponentId);
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
pObj->m_Matrix = objMat;
|
|
pObj->m_ObjFlags |= FOB_TRANS_MASK;
|
|
|
|
p3DEngine->CheckDistancesToLightSources(nDynLightMask,m_pDecalOwner->GetPos(),m_pDecalOwner->GetRenderRadius(),m_pDecalOwner);
|
|
|
|
// pIRenderer->DrawBall(objMat.GetTranslation(),1) ;
|
|
|
|
pObj->m_DynLMMask = nDynLightMask;
|
|
|
|
// somehow it's need's to be twice bigger to be same as simple decals
|
|
float fSize2 = m_fSize*fSizeK*2.f;///m_pDecalOwner->GetScale();
|
|
if(fSize2<0.05f)
|
|
return;
|
|
|
|
// todo: transform basis into world space ?
|
|
|
|
// setup texgen
|
|
// S component
|
|
m_arrBigDecalCustomData[0] = m_vUp.x/fSize2;
|
|
m_arrBigDecalCustomData[1] = m_vUp.y/fSize2;
|
|
m_arrBigDecalCustomData[2] = m_vUp.z/fSize2;
|
|
|
|
float D0 =
|
|
m_arrBigDecalCustomData[0]*m_vPos.x +
|
|
m_arrBigDecalCustomData[1]*m_vPos.y +
|
|
m_arrBigDecalCustomData[2]*m_vPos.z;
|
|
|
|
m_arrBigDecalCustomData[3] = -D0+0.5f;
|
|
|
|
// T component
|
|
m_arrBigDecalCustomData[4] = m_vRight.x/fSize2;
|
|
m_arrBigDecalCustomData[5] = m_vRight.y/fSize2;
|
|
m_arrBigDecalCustomData[6] = m_vRight.z/fSize2;
|
|
|
|
float D1 =
|
|
m_arrBigDecalCustomData[4]*m_vPos.x +
|
|
m_arrBigDecalCustomData[5]*m_vPos.y +
|
|
m_arrBigDecalCustomData[6]*m_vPos.z;
|
|
|
|
m_arrBigDecalCustomData[7] = -D1+0.5f;
|
|
|
|
// pass attenuation info
|
|
m_arrBigDecalCustomData[8] = m_vPos.x;
|
|
m_arrBigDecalCustomData[9] = m_vPos.y;
|
|
m_arrBigDecalCustomData[10]= m_vPos.z;
|
|
m_arrBigDecalCustomData[11]= m_fSize;
|
|
|
|
if(m_pDecalOwner->GetEntityRenderType() == eERType_Vegetation)
|
|
{
|
|
CObjManager * pObjManager = ((C3DEngine*)p3DEngine)->GetObjManager();
|
|
CStatObjInst * pStatObjInst = (CStatObjInst *)m_pDecalOwner;
|
|
CStatObj * pBody = pObjManager->m_lstStaticTypes[pStatObjInst->m_nObjectTypeID].GetStatObj();
|
|
assert(pObjManager && pStatObjInst && pBody);
|
|
|
|
if(pObjManager && pStatObjInst && pBody && pStatObjInst->m_fFinalBending)
|
|
{
|
|
pBody->SetupBending(pObj,pStatObjInst->m_fFinalBending);
|
|
}
|
|
}
|
|
|
|
// draw complex decal using new indices and original object vertices
|
|
m_pBigDecalLeafBuffer->SetRECustomData(m_arrBigDecalCustomData, 0, fAlpha);
|
|
m_pBigDecalLeafBuffer->AddRenderElements(pObj);
|
|
}
|
|
else
|
|
{
|
|
// transform decal in software from owner space into world space and render as quad
|
|
Matrix44 objMat;
|
|
IStatObj * pEntObject = m_pDecalOwner->GetEntityStatObj(m_nDecalOwnerComponentId, &objMat);
|
|
assert(pEntObject);
|
|
|
|
Vec3d vPos = objMat.TransformPointOLD(m_vPos);
|
|
Vec3d vRight = objMat.TransformVectorOLD(m_vRight*m_fSize/m_pDecalOwner->GetScale());
|
|
Vec3d vUp = objMat.TransformVectorOLD(m_vUp*m_fSize/m_pDecalOwner->GetScale());
|
|
|
|
CDLight * pStrongestLightForTranspGeom = NULL;
|
|
p3DEngine->CheckDistancesToLightSources(nDynLightMask,vPos,m_fSize,0,1,&pStrongestLightForTranspGeom,1);
|
|
|
|
UCol uCol;
|
|
if(pStrongestLightForTranspGeom && pStrongestLightForTranspGeom->m_fRadius)
|
|
{
|
|
float fAtten = min(1.f,pStrongestLightForTranspGeom->m_fRadius/pStrongestLightForTranspGeom->m_Origin.GetDistance(m_vWSPos));
|
|
float fDot = max(0,(pStrongestLightForTranspGeom->m_Origin-m_vWSPos).normalized().Dot(m_vFront));
|
|
uCol.bcolor[0] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.r));
|
|
uCol.bcolor[1] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.g));
|
|
uCol.bcolor[2] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.b));
|
|
}
|
|
else
|
|
uCol.dcolor = 0;
|
|
|
|
uCol.bcolor[3] = fastftol_positive(fAlpha*255);
|
|
p3DEngine->GetObjManager()->AddPolygonToRenderer( m_nTexId, pShader, nDynLightMask,
|
|
vRight*fSizeK, vUp*fSizeK, uCol, ParticleBlendType_AlphaBased, m_vAmbient, vPos,
|
|
0,0,0,0,fSortOffset,0,0,
|
|
m_pDecalOwner->GetEntityRenderType() == eERType_Vegetation ? (CStatObjInst*)m_pDecalOwner : NULL);
|
|
}
|
|
}
|
|
else if(!m_bOnTheGround)
|
|
{ // draw small world space decal untransformed
|
|
CDLight * pStrongestLightForTranspGeom = NULL;
|
|
p3DEngine->CheckDistancesToLightSources(nDynLightMask,m_vPos,m_fSize,0,1,&pStrongestLightForTranspGeom,1);
|
|
UCol uCol;
|
|
if(pStrongestLightForTranspGeom && pStrongestLightForTranspGeom->m_fRadius)
|
|
{
|
|
float fAtten = min(1.f,pStrongestLightForTranspGeom->m_fRadius/pStrongestLightForTranspGeom->m_Origin.GetDistance(m_vWSPos));
|
|
float fDot = max(0,(pStrongestLightForTranspGeom->m_Origin-m_vWSPos).normalized().Dot(m_vFront));
|
|
uCol.bcolor[0] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.r));
|
|
uCol.bcolor[1] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.g));
|
|
uCol.bcolor[2] = uchar(min(255.f,355.f*fDot*fAtten*pStrongestLightForTranspGeom->m_Color.b));
|
|
}
|
|
else
|
|
uCol.dcolor = 0;
|
|
uCol.bcolor[3] = fastftol_positive(fAlpha*255);
|
|
p3DEngine->GetObjManager()->AddPolygonToRenderer( m_nTexId, pShader, nDynLightMask,
|
|
m_vRight*m_fSize*fSizeK, m_vUp*m_fSize*fSizeK, uCol, ParticleBlendType_AlphaBased, m_vAmbient, m_vPos,
|
|
0,0,0,0,fSortOffset);
|
|
}
|
|
|
|
/*{
|
|
Vec3d vPos = m_vPos + (m_pDecalOwner ? m_pDecalOwner->GetPos() : Vec3d(0,0,0));
|
|
pIRenderer->Draw3dBBox(vPos,vPos+m_vFront);
|
|
}*/
|
|
|
|
// process life time and disable decal when needed
|
|
// m_fLifeTime -= fFrameTime;
|
|
if(m_fLifeEndTime<fCurTime)
|
|
{
|
|
active=0;
|
|
pIRenderer->DeleteLeafBuffer(m_pBigDecalLeafBuffer);
|
|
m_pBigDecalLeafBuffer=0;
|
|
}
|
|
}
|
|
|
|
void CDecal::Render3DObject()
|
|
{
|
|
// draw
|
|
if(m_pStatObj)
|
|
{
|
|
Vec3d vAngles = m_vFront;
|
|
vAngles=ConvertVectorToCameraAngles(vAngles);
|
|
vAngles.x+=90;
|
|
|
|
//Matrix mat,mat1;
|
|
//mat.Identity();
|
|
//mat=GetRotationZYX44(-gf_DEGTORAD*vAngles)*mat; //NOTE: angles in radians and negated
|
|
//mat1.Identity();
|
|
//mat1=GetTranslationMat(m_vPos)*mat1;
|
|
//mat = mat * mat1;
|
|
|
|
//OPTIMISED_BY_IVO
|
|
Matrix44 mat = Matrix34::CreateRotationXYZ( Deg2Rad(vAngles), m_vPos );
|
|
mat = GetTransposed44(mat); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
|
|
|
|
SRendParams rParms;
|
|
rParms.pMatrix = &mat;
|
|
rParms.dwFObjFlags |= FOB_TRANS_MASK;
|
|
m_pStatObj->Render(rParms,Vec3(zero),0);
|
|
}
|
|
}
|
|
|
|
void CDecal::DrawBigDecalOnTerrain(C3DEngine * p3DEngine, IRenderer * pIRenderer, float fCurrTime)
|
|
{
|
|
// Get decal alpha from life time
|
|
float fLifeTime = m_fLifeEndTime - fCurrTime;
|
|
float fAlpha = fLifeTime*2;
|
|
if(fAlpha > 1.f)
|
|
fAlpha = 1.f;
|
|
else if(fAlpha<0)
|
|
return;
|
|
|
|
Vec3d vColor = p3DEngine->GetWorldColor();
|
|
pIRenderer->SetMaterialColor(vColor.x,vColor.y,vColor.z,fAlpha);
|
|
|
|
// calc area
|
|
int x1=int(m_vPos.x-m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
int y1=int(m_vPos.y-m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
int x2=int(m_vPos.x+CTerrain::GetHeightMapUnitSize()+m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
int y2=int(m_vPos.y+CTerrain::GetHeightMapUnitSize()+m_fSize*0.85)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
|
|
float fSizeK;
|
|
if(m_fGrowTime)
|
|
fSizeK = min(1.f, cry_sqrtf((fCurrTime - m_fLifeBeginTime)/m_fGrowTime));
|
|
else
|
|
fSizeK = 1.f;
|
|
|
|
float fRadius = m_fSize*fSizeK*2.f;
|
|
if(fRadius<0.05f)
|
|
return;
|
|
|
|
// limits
|
|
if(x1<0) x1=0;
|
|
if(y1<0) y1=0;
|
|
if(x2>=CTerrain::GetTerrainSize()) x2=CTerrain::GetTerrainSize();
|
|
if(y2>=CTerrain::GetTerrainSize()) y2=CTerrain::GetTerrainSize();
|
|
|
|
// fill buffer and draw
|
|
list2<struct_VERTEX_FORMAT_P3F_TEX2F> verts;
|
|
struct_VERTEX_FORMAT_P3F_TEX2F tmp;
|
|
|
|
Vec3d vOffset(0,0,0);
|
|
if(((C3DEngine*)p3DEngine)->GetObjManager())
|
|
vOffset = (pIRenderer->GetCamera().GetPos()-m_vPos)*0.01f*((C3DEngine*)p3DEngine)->GetObjManager()->m_fZoomFactor;
|
|
|
|
for(int x=x1; x<x2; x+=CTerrain::GetHeightMapUnitSize())
|
|
{
|
|
verts.Clear();
|
|
for(int y=y1; y<=y2; y+=CTerrain::GetHeightMapUnitSize())
|
|
{
|
|
tmp.xyz.x = (float)x;
|
|
tmp.xyz.y = (float)y;
|
|
tmp.xyz.z = p3DEngine->GetTerrainZ(x,y)+0.07f;
|
|
tmp.st[0] = (((float)x)-m_vPos.x)/fRadius+0.5f;
|
|
tmp.st[1] = 1.f-((((float)y)-m_vPos.y)/fRadius+0.5f);
|
|
|
|
tmp.xyz+=vOffset;
|
|
verts.Add(tmp);
|
|
|
|
tmp.xyz.x = (float)(x+CTerrain::GetHeightMapUnitSize());
|
|
tmp.xyz.y = (float)y;
|
|
tmp.xyz.z = p3DEngine->GetTerrainZ((x+CTerrain::GetHeightMapUnitSize()),y)+0.07f;
|
|
tmp.st[0] = (((float)(x+CTerrain::GetHeightMapUnitSize()))-m_vPos.x)/fRadius+0.5f;
|
|
tmp.st[1] = 1.f-((((float)y)-m_vPos.y)/fRadius+0.5f);
|
|
|
|
tmp.xyz+=vOffset;
|
|
verts.Add(tmp);
|
|
}
|
|
|
|
if(verts.Count())
|
|
{
|
|
pIRenderer->SetTexture(m_nTexId);
|
|
pIRenderer->SetTexClampMode(true);
|
|
pIRenderer->DrawTriStrip(&(CVertexBuffer (&verts[0].xyz.x,VERTEX_FORMAT_P3F_TEX2F)),verts.Count());
|
|
}
|
|
}
|
|
}
|