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

666 lines
23 KiB
C++

// NOTES:
// CRenderer::CreateLeafBufferInitialized creates a buffer with reserve of vertices and no indices.
// it can accept a fake pointer (like something on stack) for vertex array pointer.
// UpdateIndices() actually just copies the indices into the vertex buffer structure
#include "stdafx.h"
#include <StlUtils.h>
#include "CryGeometryInfo.h"
#include "CryEngineDecalInfo.h"
#include "VertexBufferArrayDrivers.h"
#include "CryCharDecalManager.h"
#include "CryCharDecalBuilder.h"
#include "CryCharDecal.h"
#include "CVars.h"
#include "MathUtils.h"
// nVertexAllocStep == 2^nVertexAllocStepLog2 is the step with which the vertex buffer will be enlarged when needed
enum {nVertexAllocStepLog2 = 8};
enum {nVertexAllocStep = (1 << nVertexAllocStepLog2)};
enum {nMaterialAllocStep = 1};
// the max number of vertices used for the character until the decals start to disappear
// note: this must be a multiple of nVertexAllocStep
enum {nMaxDecalVertices = (nVertexAllocStep * 6u)};
CryCharDecalManager::CStatistics CryCharDecalManager::g_Statistics;
CryCharDecalManager::CryCharDecalManager (class CryGeometryInfo* pGeomInfo):
m_pGeometry (pGeomInfo),
m_bNeedUpdateIndices (false)
{
m_pShader = g_GetIRenderer()->EF_LoadShader("DecalCharacter", eSH_World, EF_SYSTEM);
}
CryCharDecalManager::~CryCharDecalManager ()
{
DeleteLeafBuffer();
DeleteOldRenderElements();
if (!m_arrOldRE.empty())
{
if (!g_GetISystem()->IsQuitting())
g_LogToFile ("Warning: ~CryCharDecalManager: There are still %d render elements present that may be in rendering queue. But since destruction was requested, attempting to destruct those elements", m_arrOldRE.size());
for (unsigned i = 0; i < m_arrOldRE.size(); ++i)
m_arrOldRE[i].destruct();
}
}
// cleans up the old leaf buffers
void CryCharDecalManager::DeleteOldRenderElements()
{
for (RenderElementArray::iterator it = m_arrOldRE.begin(); it != m_arrOldRE.end();)
if (it->canDestruct())
{
it->destruct();
it = m_arrOldRE.erase(it);
}
else
++it;
}
//////////////////////////////////////////////////////////////////////////
// Calculates the required number of vertices for the current decal array
// If needed, recreates the current leaf buffer so that it contains the given
// number of vertices and reserved indices, both uninitialized.
// There are 0 used indices initially
void CryCharDecalManager::ReserveVertexBufferVertices (const Vec3d* pInPositions)
{
// first, calculate how many vertices we'll need
unsigned i, numDecals = (unsigned)m_arrDecals.size(), numVertices = 0;
for (i = 0; i < numDecals; ++i)
{
numVertices += m_arrDecals[i].numVertices();
#if DECAL_USE_HELPERS
numVertices += m_arrDecals[i].numHelperVertices();
#endif
}
while (numVertices > nMaxDecalVertices && !m_arrDecals.empty())
{
unsigned nDecalToDelete = (unsigned)(rand()%m_arrDecals.size());
numVertices -= m_arrDecals[nDecalToDelete].numVertices();
#if DECAL_USE_HELPERS
numVertices -= m_arrDecals[nDecalToDelete].numHelperVertices();
#endif
m_arrDecals.erase (m_arrDecals.begin()+nDecalToDelete);
}
unsigned numMaterials = groupMaterials();
// make sure the vertex buffer contains enough space for all vertices
if (m_RE.numVertices() >= g_MeshInfo.numVertices && m_RE.numMaterials() >= numMaterials)
return;// no need to reallocate
DeleteLeafBuffer();
// construct the data to initialize the new system buffer
unsigned numVerticesToReserve = (numVertices + (nVertexAllocStep-1)) & ~(nVertexAllocStep-1);
TElementaryArray<struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F> arrSourceVerts (numVerticesToReserve);
RefreshVertexBufferVertices (pInPositions, &arrSourceVerts[0]);
unsigned numMaterialsToReserve = numMaterials + nMaterialAllocStep;
if (numVerticesToReserve > numVertices)
memset (&arrSourceVerts[numVertices], 0, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F) * (numVerticesToReserve - numVertices));
m_RE.create (numVerticesToReserve, &arrSourceVerts[0], "AnimDecals", numMaterialsToReserve);
}
// sets up the given material to default state: just clean decal material
/*
void CryCharDecalManager::initDefaultMaterial (CMatInfo& rMat)
{
rMat.pRE = (CREOcLeaf*)GetRenderer()->EF_CreateRE(eDATA_OcLeaf);
rMat.pRE->m_pBuffer = m_pLeafBuffer;
rMat.pRE->m_pChunk = &rMat;
rMat.pRE->m_CustomTexBind[0] = 0x1000;
rMat.pShader = GetRenderer()->EF_LoadShader("DecalCharacter", -1, eSH_World, EF_SYSTEM);
}
*/
// Request (add) a new decal to the character
void CryCharDecalManager::Add (CryEngineDecalInfo& Decal)
{
//if (m_arrDecalRequests.empty())
// only 1 decal per frame is supported
m_arrDecalRequests.push_back(Decal);
}
// discards the decal request queue (not yet realized decals added through Add())
void CryCharDecalManager::DiscardRequests()
{
m_arrDecalRequests.clear();
}
// cleans up all decals, destroys the vertex buffer
void CryCharDecalManager::clear()
{
m_arrDecalRequests.clear();
m_arrDecals.clear();
DeleteLeafBuffer();
}
// deletes the leaf buffer
void CryCharDecalManager::DeleteLeafBuffer ()
{
if (m_RE.canDestruct())
m_RE.destruct();
else
{
m_arrOldRE.push_back(m_RE);
m_RE.detach();
}
}
// cleans up the dead decals
// updates indices if needed; doesn't update vertices
// sets m_bNeedUpdateIndices to true if it has added something (and therefore refresh of indices is required)
void CryCharDecalManager::DeleteOldDecals()
{
// if we delete one of the decals, we need to update indices;
// updating vertices is not our business
for (CDecalArray::iterator it = m_arrDecals.begin(); it != m_arrDecals.end();)
if (it->isDead())
{
m_bNeedUpdateIndices = true;
it = m_arrDecals.erase (it);
}
else
++it;
}
//////////////////////////////////////////////////////////////////////////
// realizes (creates geometry for) unrealized(requested) decals
// NOTE: this also fills the UVs in for the vertex stream
void CryCharDecalManager::Realize (const Vec3d* pPositions)
{
DeleteOldRenderElements();
// write the deformed vertices into the videobuffer
// NOTE:
// we write to the old videobuffer; in the case Realization reallocates the current buffer,
// the old videobuffer will still be rendered on this frame, so it must be updated now
// in case the following assert works, it means that the sequence of drawing/skinning
// has been changed; in this case remove this assert and switch the order of the following
// Refresh and Realize calls in order to avoid decal flickers.
//assert (!m_RE.getLeafBuffer() || GetRenderer()->GetFrameID() == m_RE.getLastRenderFrameID());
if (!m_arrDecalRequests.empty())
{
int nnn = 0;
}
RefreshVertexBufferVertices (pPositions);
if (m_bNeedUpdateIndices)
RefreshVertexBufferIndices ();
DeleteOldDecals();
RealizeNewDecalRequests (pPositions);
}
// if there are decal requests, then converts them into the decal objects
// reserves the vertex/updates the index buffers, if need to be
// sets m_bNeedUpdateIndices to true if it has added something (and therefore refresh of indices is required)
void CryCharDecalManager::RealizeNewDecalRequests (const Vec3d* pPositions)
{
if (m_arrDecalRequests.empty())
return; // nothing to udpate
// realize each unrealized decal, then clean up the array of unrealized decals
for (unsigned nDecal = 0; nDecal < m_arrDecalRequests.size(); ++nDecal)
{
CryEngineDecalInfo& Decal = m_arrDecalRequests[nDecal];
CryCharDecalBuilder builder (Decal, m_pGeometry, pPositions);
if (!builder.numDecalFaces())
continue; // we're not interested in this decal: we don't have any decals
// starts fading out all decals that are very close to this new one
//fadeOutCloseDecals (builder.getSourceLCS(), sqr(Decal.fSize/4));
g_Statistics.onDecalAdd (builder.numDecalVertices(), builder.numDecalFaces());
CryCharDecal NewDecal;
NewDecal.buildFrom (builder);
m_arrDecals.insert (std::lower_bound(m_arrDecals.begin(), m_arrDecals.end(), NewDecal), NewDecal);
//m_arrDecals.resize(m_arrDecals.size()+1);
//m_arrDecals.back().buildFrom (builder);
}
// after we realized the decal request, we don't need it anymore
m_arrDecalRequests.clear();
// make sure we have enough vertices
ReserveVertexBufferVertices(pPositions);
// need to recreate indices
m_bNeedUpdateIndices = true;
}
// starts fading out all decals that are close enough to the given point
// NOTE: the radius is m^2 - it's the square of the radius of the sphere
void CryCharDecalManager::fadeOutCloseDecals (const Vec3d& ptCenter, float fRadius2)
{
for (unsigned i = 0; i < m_arrDecals.size(); ++i)
{
if ( GetLengthSquared((m_arrDecals[i].getSourceLCS()-ptCenter)) < fRadius2)
m_arrDecals[i].startFadeOut (2);
}
}
// returns true if the Realize() needs to be called
// Since the Realize() updates the vertex buffers, creates decals from requests,
// it's always needed when there are decals
bool CryCharDecalManager::NeedRealize () const
{
return !m_arrDecals.empty() || !m_arrDecalRequests.empty()
// we don't actually need the vertices that Realize() receives in this case,
// but we need it to be called in order to free these buffers
|| !m_arrOldRE.empty();
}
void CopyVertex (Vec3d& vDst, const Vec3d& vSrc)
{
struct XYZ {unsigned x,y,z;};
assert (sizeof(XYZ) == 12 && sizeof(Vec3d) == 12);
(XYZ&)vDst = (XYZ&)vSrc;
}
// put the deformed vertices into the videobuffer of the given format,
// using the deformed character skin
void CryCharDecalManager::RefreshVertexBufferVertices (const Vec3d* pInPositions, struct_VERTEX_FORMAT_P3F_TEX2F* pDst)
{
// scan through all decals
CDecalArray::const_iterator itDecal = m_arrDecals.begin(), itDecalEnd = itDecal + m_arrDecals.size();
for (; itDecal != itDecalEnd; ++itDecal)
{
// for each decal, there are a number of vertices to fill in; so we fill them in.
// this is the number of vertices for the current decal
unsigned numDecalVertices = itDecal->numVertices();
for (unsigned nDecalVertex = 0; nDecalVertex < numDecalVertices; ++nDecalVertex)
{
const CryCharDecalVertex& rDecalVertex = itDecal->getVertex(nDecalVertex);
const Vec3d& vCharPosition = pInPositions[rDecalVertex.nVertex];
pDst->xyz = vCharPosition;
pDst->st[0] = rDecalVertex.uvNew.u;
pDst->st[1] = rDecalVertex.uvNew.v;
++pDst;
}
#if DECAL_USE_HELPERS
unsigned numHelperVertices = itDecal->numHelperVertices();
for (unsigned nHelperVertex = 0; nHelperVertex < numHelperVertices; ++nHelperVertex)
{
Vec3d vCharPosition = itDecal->getHelperVertex (nHelperVertex);
CryUV uvCharUV = itDecal->getHelperUV (nHelperVertex);
pDst->xyz = vCharPosition;
pDst->st[0] = uvCharUV.u;
pDst->st[1] = uvCharUV.v;
++pDst;
}
#endif
}
}
// put the deformed vertices into the videobuffer of the given format
void CryCharDecalManager::RefreshVertexBufferVertices (const Vec3d* pInPositions, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F* pDst)
{
// scan through all decals
CDecalArray::const_iterator itDecal = m_arrDecals.begin(), itDecalEnd = itDecal + m_arrDecals.size();
for (; itDecal != itDecalEnd; ++itDecal)
{
float fIntensity = itDecal->getIntensity() * 0.7f + 0.3f;
int nIntensity = (int)((float)0xFF * fIntensity);
DWORD dwColor = nIntensity | (nIntensity << 8) | (nIntensity << 16) | (nIntensity << 24);
// for each decal, there are a number of vertices to fill in; so we fill them in.
// this is the number of vertices for the current decal
unsigned numDecalVertices = itDecal->numVertices();
for (unsigned nDecalVertex = 0; nDecalVertex < numDecalVertices; ++nDecalVertex)
{
const CryCharDecalVertex& rDecalVertex = itDecal->getVertex(nDecalVertex);
const Vec3d& vCharPosition = pInPositions[rDecalVertex.nVertex];
pDst->xyz = vCharPosition;
pDst->color.dcolor = dwColor;
pDst->st[0] = (rDecalVertex.uvNew.u-0.5f) / fIntensity + 0.5f;
pDst->st[1] = (rDecalVertex.uvNew.v-0.5f) / fIntensity + 0.5f;
++pDst;
}
#if DECAL_USE_HELPERS
unsigned numHelperVertices = itDecal->numHelperVertices();
for (unsigned nHelperVertex = 0; nHelperVertex < numHelperVertices; ++nHelperVertex)
{
Vec3d vCharPosition = itDecal->getHelperVertex (nHelperVertex);
CryUV uvCharUV = itDecal->getHelperUV (nHelperVertex);
pDst->xyz = vCharPosition;
pDst->color.decolor = 0xFFFFFFFF;
pDst->st[0] = uvCharUV.u;
pDst->st[1] = uvCharUV.v;
++pDst;
}
#endif
}
}
// put the vertices out of the vertex/normal array (that belongs to the character) to the
// decal vertex array. Decal vertices are a bit shifted toward the vertex normals (extruded)
// to ensure the decals are above the character skin
void CryCharDecalManager::RefreshVertexBufferVertices (const Vec3d* pInPositions)
{
CLeafBuffer* pLB = m_RE.getLeafBuffer();
if (!pLB)
return;
CLeafBuffer* pVertexContainer = pLB->GetVertexContainer();
if (!pVertexContainer)
return;
if (pVertexContainer->m_pVertexBuffer == NULL)
m_RE.recreate();
m_RE.lock (true);
bool bNeedCopy = true;
{
// choose an optimized for the vertex format routine, if there is one
switch (pVertexContainer->m_pVertexBuffer->m_vertexformat)
{
case VERTEX_FORMAT_P3F_TEX2F:
RefreshVertexBufferVertices(pInPositions, (struct_VERTEX_FORMAT_P3F_TEX2F*)pVertexContainer->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData);
bNeedCopy = false;
break;
case VERTEX_FORMAT_P3F_COL4UB_TEX2F:
RefreshVertexBufferVertices(pInPositions, (struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)pVertexContainer->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData);
bNeedCopy = false;
break;
default:
assert (0);
break;
}
}
if (bNeedCopy)
{
// scan through all decals
CDecalArray::const_iterator itDecal = m_arrDecals.begin(), itDecalEnd = itDecal + m_arrDecals.size();
// fill out the following sparse arrays found inthe leaf buffer
CVertexBufferPosArrayDriver pOutPosition (m_RE.getLeafBuffer(), 0, false);
CVertexBufferUVArrayDriver pOutUV (m_RE.getLeafBuffer(), 0, false);
//CVertexBufferColorArrayDriver pOutColor (m_RE.getLeafBuffer(), 0, false);
for (; itDecal != itDecalEnd; ++itDecal)
{
// for each decal, there are a number of vertices to fill in; so we fill them in.
// this is the number of vertices for the current decal
unsigned numDecalVertices = itDecal->numVertices();
for (unsigned nDecalVertex = 0; nDecalVertex < numDecalVertices; ++nDecalVertex)
{
const CryCharDecalVertex& rDecalVertex = itDecal->getVertex(nDecalVertex);
const Vec3d& vCharPosition = pInPositions[rDecalVertex.nVertex];
//Vec3d vCharNormal = arrInNormals[rDecalVertex.nVertex];
// the decal mesh is slightly extruded and has the same normals
*pOutPosition = vCharPosition;/* + vCharNormal * 0.02f*/;
++pOutPosition;
//*pOutColor = 0xFFFFFFFF;
//++pOutColor;
*pOutUV = rDecalVertex.uvNew;
++pOutUV;
}
#if DECAL_USE_HELPERS
unsigned numHelperVertices = itDecal->numHelperVertices();
for (unsigned nHelperVertex = 0; nHelperVertex < numHelperVertices; ++nHelperVertex)
{
Vec3d vCharPosition = itDecal->getHelperVertex (nHelperVertex);
CryUV uvCharUV = itDecal->getHelperUV (nHelperVertex);
*pOutPosition = vCharPosition;
++pOutPosition;
//*pOutColor = 0xFFFFFFFF;
//++pOutColor;
*pOutUV = uvCharUV;
++pOutUV;
}
#endif
}
}
m_RE.unlock(true);
}
//////////////////////////////////////////////////////////////////////////
// recalculates the index array for the vertex buffer and replaces it (so that the vertex buffer is prepared for rendering)
// also makes sure the vertex buffer contains enough vertices to draw all the current decals (from m_arrDecals)
void CryCharDecalManager::RefreshVertexBufferIndices ()
{
m_bNeedUpdateIndices = false;
if (!m_RE.getLeafBuffer())
return; // nothing to update - no vertex buffer
if (m_RE.getLeafBuffer()->GetVertexContainer()->m_pVertexBuffer == NULL)
m_RE.recreate();
// calculate the number of required indices in the arrIndices array
unsigned numDecals = (unsigned)m_arrDecals.size();
unsigned numMaterials = groupMaterials ();
// now we know the number of indices required
if (g_MeshInfo.numIndices)
{
TElementaryArray<unsigned short> arrIndices;
arrIndices.reinit (g_MeshInfo.numIndices);
unsigned short* pIndex = &arrIndices[0];
// for each face, put the 3 indices referring to the vertex in the char decal manager
// vertex array
unsigned short nBaseVertexIndex = 0;
// scan through decals and add necessary indices (faces) to the index array
for (unsigned i = 0; i < m_arrDecals.size(); ++i)
{
const CryCharDecal& rDecal = m_arrDecals[i];
const CryCharDecalFace* pDecalFace = rDecal.getFaces(), *pDecalFaceEnd = pDecalFace + rDecal.numFaces();
// scan through decal faces, and add 3 indices for each face
for (; pDecalFace != pDecalFaceEnd; ++pDecalFace)
{
for (unsigned nVertexIndex = 0; nVertexIndex < 3; ++nVertexIndex)
*(pIndex++) = nBaseVertexIndex + (*pDecalFace)[nVertexIndex];
}
// after scanning the decal faces, update the vertex base - we'll keep vertices in sequence:
// 0th decal vertices first, then 1st decal vertices, etc. to the last decal.
nBaseVertexIndex += rDecal.numVertices();
#if DECAL_USE_HELPERS
// the same way - with the helper faces/vertices
// scan through all helper faces
for (unsigned nHelperFace = 0; nHelperFace < rDecal.numHelperFaces(); ++nHelperFace)
{
CryCharDecalFace faceHelper = rDecal.getHelperFace(nHelperFace);
for (unsigned nVertexIndex = 0; nVertexIndex < 3; ++nVertexIndex)
*(pIndex++) = nBaseVertexIndex + faceHelper[nVertexIndex];
}
nBaseVertexIndex += rDecal.numHelperVertices();
#endif
}
// we scanned through all decals, and vertex indices must be in the range and coinside
// with the number that we calculated beforehand
assert (g_MeshInfo.numVertices == nBaseVertexIndex);
m_RE.updateIndices(&arrIndices[0], g_MeshInfo.numIndices);
}
// now assign the materials from submesh infos
m_RE.resizeMaterials(numMaterials, m_pShader);
for (unsigned nMaterial = 0; nMaterial < numMaterials; ++nMaterial)
assignMaterial (nMaterial, g_SubmeshInfo[nMaterial].nTextureId, g_SubmeshInfo[nMaterial].nFirstIndex, g_SubmeshInfo[nMaterial].numIndices, g_SubmeshInfo[nMaterial].nFirstVertex, g_SubmeshInfo[nMaterial].numVertices);
}
// temporary locations for groupMaterials results
// the information about the decal mesh currently (after groupMaterials)
CryCharDecalManager::MeshInfo CryCharDecalManager::g_MeshInfo;
// the material groups
CryCharDecalManager::SubmeshInfo CryCharDecalManager::g_SubmeshInfo[CryCharDecalManager::g_numSubmeshInfos];
// returns the number of materials in g_SubmeshInfo
unsigned CryCharDecalManager::groupMaterials ()
{
// scan through all decals, grouping them by texture ids and
// watching the max number of types not reaching g_numSubmeshInfos
g_MeshInfo.numIndices = g_MeshInfo.numVertices = 0;
unsigned numDecals = (unsigned)m_arrDecals.size();
SubmeshInfo* pNext = g_SubmeshInfo; // the next available slot in the submesh info
SubmeshInfo* pEnd = g_SubmeshInfo + g_numSubmeshInfos;
for (unsigned i = 0; i < numDecals; ++i)
{
CryCharDecal& rDecal = m_arrDecals[i];
if ((pNext == g_SubmeshInfo || pNext[-1].nTextureId != rDecal.getTextureId())
&& pNext < pEnd) // we don't support more than the given amount of decal types
{
// add a new material group
pNext->nFirstIndex = g_MeshInfo.numIndices;
pNext->numIndices = 0;
pNext->nFirstVertex = g_MeshInfo.numVertices;
pNext->numVertices = 0;
pNext->nTextureId = rDecal.getTextureId();
++pNext;
}
g_MeshInfo.numIndices += rDecal.numFaces() * 3;
g_MeshInfo.numVertices += rDecal.numVertices();
#if DECAL_USE_HELPERS
g_MeshInfo.numIndices += rDecal.numHelperFaces() * 3;
g_MeshInfo.numVertices += rDecal.numHelperVertices();
#endif
pNext[-1].numIndices = g_MeshInfo.numIndices - pNext[-1].nFirstIndex;
pNext[-1].numVertices = g_MeshInfo.numVertices - pNext[-1].nFirstVertex;
}
return pNext - g_SubmeshInfo;
}
// assigns the given material to the given range of indices/vertices
void CryCharDecalManager::assignMaterial (unsigned nMaterial, int nTextureId, int nFirstIndex, int numIndices, int nFirstVertex, int numVertices)
{
m_RE.assignMaterial (nMaterial, m_pShader, g_GetCVars()->ca_DefaultDecalTexture()?0x1000:nTextureId, nFirstIndex, numIndices, nFirstVertex, numVertices);
/*if (!m_RE.getLeafBuffer())
return;
CMatInfo& rMatInfo = (*m_RE.getLeafBuffer()->m_pMats)[nMaterial];
rMatInfo.pRE->m_CustomTexBind[0] = nTextureId;
m_RE.getLeafBuffer()->SetChunk(m_pShader, nFirstVertex, numVertices, nFirstIndex, numIndices, nMaterial);
(*m_RE.getLeafBuffer()->m_pMats)[nMaterial].pRE->m_CustomTexBind[0] = GetCVars()->ca_DefaultDecalTexture()?0x1000 : nTextureId;*/
}
// adds the render data to the renderer, so that the current decals can be rendered
void CryCharDecalManager::AddRenderData (CCObject *pObj, const SRendParams & rRendParams)
{
if(!m_RE.getLeafBuffer() || !m_RE.getLeafBuffer()->m_pVertexBuffer || m_arrDecals.empty())
return; // we don't add render data if there's no vertex buffer or no decals
m_RE.render (pObj);
#if DECAL_USE_HELPERS
Vec3d vPos = rRendParams.vPos;
Vec3d vAngles = rRendParams.vAngles;
Matrix matTranRotMatrix;
if (rRendParams.pMatrix)
matTranRotMatrix = *rRendParams.pMatrix;
else
{
//matTranRotMatrix.Identity();
//matTranRotMatrix = GetTranslationMat(vPos)*matTranRotMatrix;
//matTranRotMatrix = GetRotationZYX44(-gf_DEGTORAD*vAngles )*matTranRotMatrix; //NOTE: angles in radians and negated
//OPTIMIZED_BY_IVO
matTranRotMatrix = Matrix34::GetRotationXYZ34( Deg2Rad(vAngles), vPos );
matTranRotMatrix = GetTransposed44(matTranRotMatrix); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
}
for (CDecalArray::iterator it = m_arrDecals.begin(); it != m_arrDecals.end(); ++it)
{
it->debugDraw(matTranRotMatrix);
}
#endif
}
void CryCharDecalManager::LogStatistics()
{
if (!g_Statistics.empty())
g_GetLog()->LogToFile ("%d decals created, %d total vertices, %d faces, %.1f vers/decal, %.1f faces/decal",
g_Statistics.numDecals, g_Statistics.numDecalVertices, g_Statistics.numDecalFaces,
g_Statistics.getAveVertsPerDecal(), g_Statistics.getAveFacesPerDecal());
}
void CryCharDecalManager::CStatistics::onDecalAdd (unsigned numVertices, unsigned numFaces)
{
++numDecals;
numDecalVertices += numVertices;
numDecalFaces += numFaces;
#ifdef _DEBUG
if (g_GetCVars()->ca_Debug())
{
char szBuf[1024];
sprintf (szBuf, "Decal added (%d vert, %d faces)\n", numVertices, numFaces);
#ifdef WIN32
OutputDebugString (szBuf);
#endif
#ifdef GAMECUBE
OSReport(szBuf);
#endif
}
#endif
}
// returns the memory usage by this object into the sizer
void CryCharDecalManager::GetMemoryUsage (ICrySizer* pSizer)
{
unsigned nSize = sizeof(*this);
nSize += capacityofArray (m_arrDecalRequests);
nSize += capacityofArray (m_arrDecals);
nSize += capacityofArray (m_arrOldRE);
pSizer->AddObject (this, nSize);
}
void CryCharDecalManager::debugDump()
{
unsigned numMaterials = groupMaterials ();
g_GetLog()->Log ("\001 %d decals: %d chunks used, mesh is %d verts %d indices", m_arrDecals.size(), numMaterials, g_MeshInfo.numVertices, g_MeshInfo.numIndices);
unsigned i;
for (i = 0; i < m_arrDecals.size(); ++i)
{
CryCharDecal& rDecal = m_arrDecals[i];
g_GetLog()->Log("\001 decal %3d: %d verts, %d faces, \"%s\" (texId=%d)",i, rDecal.numVertices(), rDecal.numFaces(), g_GetIRenderer()->EF_GetTextureByID(rDecal.getTextureId())->GetName(), rDecal.getTextureId());
}
for (i = 0; i < numMaterials; ++i)
{
SubmeshInfo &rSubmesh = g_SubmeshInfo[i];
g_GetLog()->Log ("\001 chunk %d: %d verts @%d, %d indices @%d, texture %d \"%s\"", i, rSubmesh.numVertices, rSubmesh.nFirstVertex, rSubmesh.numIndices, rSubmesh.nFirstIndex, rSubmesh.nTextureId, g_GetIRenderer()->EF_GetTextureByID(rSubmesh.nTextureId)->GetName());
}
}