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

680 lines
20 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: detail_grass.cpp
// Version: v1.00
// Created: 28/5/2001 by Vladimir Kajalin
// Compilers: Visual Studio.NET
// Description: create and draw grass/detail object volume right in front of camera
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "statobj.h"
#include "detail_grass.h"
#include <IXMLDOM.h>
// class to store vertex buffer for single grass object
struct GrassType : public Cry3DEngineBase
{
public:
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVertices;
uint * uipIndices, nIndCount, nVertCount;
int nTexID;
char sObjectFileName[256];
CStatObj * m_pObject;
GrassType(char * fname)
{ // load object and make buffers
memset(this,0,sizeof(*this));
strncpy(sObjectFileName,fname,sizeof(sObjectFileName));
m_pObject = new CStatObj( );
if(!m_pObject->Load(fname, NULL, evs_ShareAndSortForCache, false, false))
{
delete m_pObject;
m_pObject=0;
return;
}
int tris_count = 0;
CLeafBuffer * pLeafBuffer = m_pObject->GetLeafBuffer();
if(!pLeafBuffer)
return; // objects may have no leaf buffer created on dedicated server
pLeafBuffer->GetIndices(&tris_count);
tris_count/=3;
if(tris_count>12)
{
#if !defined(LINUX)
Warning( 0,0,"Detail object has more than 12 triangles, skiped: %s (%d tris)",fname,tris_count );
#endif
return;
}
nVertCount = pLeafBuffer->m_SecVertCount;
pVertices = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[nVertCount];
uipIndices = new uint[tris_count*3];
Vec3d vCenter = (m_pObject->GetBoxMax()+m_pObject->GetBoxMin())/2;
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pSecVerts = (struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)pLeafBuffer->m_pSecVertBuffer->m_VS[VSF_GENERAL].m_VData;
ushort *pInds = pLeafBuffer->GetIndices(NULL);
int nStrPos;
byte *pPos = pLeafBuffer->GetPosPtr(nStrPos, 0, true);
int nStrST;
byte *pST = pLeafBuffer->GetUVPtr(nStrST, 0, true);
for(int i=0; i<tris_count*3; i++)
{
uint id = pInds[i];
Vec3d *vSrcPos = (Vec3d *)&pPos[nStrPos*id];
float *fSrcST = (float *)&pST[nStrST*id];
pVertices[id].xyz.x = vSrcPos->x - vCenter.x;
pVertices[id].xyz.y = vSrcPos->y - vCenter.y;
pVertices[id].xyz.z = vSrcPos->z;// - pObject->GetBoxMin().z;
pVertices[id].st[0] = fSrcST[0];
pVertices[id].st[1] = fSrcST[1];
/* if(pLeafBuffer->m_pLoadedColors)
{
pVertices[id].r = pSecVerts[id].color[0];
pVertices[id].g = pSecVerts[id].color[1];
pVertices[id].b = pSecVerts[id].color[2];
pVertices[id].a = 255;
}
else*/
{
pVertices[id].color.dcolor = -1;
}
uipIndices[nIndCount++] = id;
}
if( m_pObject->GetLeafBuffer()->m_pMats->Count() &&
m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShader &&
m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShaderResources->m_Textures[EFTT_DIFFUSE] &&
m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShaderResources->m_Textures[EFTT_DIFFUSE]->m_TU.m_ITexPic )
{
nTexID = (m_pObject->GetLeafBuffer()->m_pMats->Get(0)->shaderItem.m_pShaderResources->m_Textures[EFTT_DIFFUSE]->m_TU.m_ITexPic)->GetTextureID();
}
else
{
nTexID = GetRenderer()->LoadTexture("none");
}
// assert(nTexID>=4096);
}
~GrassType()
{
delete m_pObject;
delete [] pVertices;
delete [] uipIndices;
}
int GetMemoryUsage()
{
return sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F) * nVertCount + sizeof(uint) * nIndCount;
}
};
// load objects
CDetailGrass::CDetailGrass(XDOM::IXMLDOMNodeListPtr pDetTexTagList)
{
memset(this,0,sizeof(*this));
// m_pGrassVertices = 0;
m_GrassVerticesCount = 0;
m_GrassFocusX = m_GrassFocusY = -CTerrain::GetTerrainSize(); // grass focus
m_nGrassDensity = 2;
if( !m_nGrassDensity )
return;
UpdateLoadingScreen("Loading detail objects ...");
m_GrassModelsArray.Clear();
// load detail textures
if (pDetTexTagList)
{
XDOM::IXMLDOMNodePtr pDetTexTag;
pDetTexTagList->reset();
pDetTexTag = pDetTexTagList->nextNode();
XDOM::IXMLDOMNodeListPtr pDetTexList;
pDetTexList = pDetTexTag->getElementsByTagName("SurfaceType");
if (pDetTexList)
{
pDetTexList->reset();
XDOM::IXMLDOMNodePtr pDetTex;
int nId = 0;
while (pDetTex = pDetTexList->nextNode())
{
XDOM::IXMLDOMNodeListPtr pDetailObjectsList = pDetTex->getElementsByTagName("DetailObjects");
pDetailObjectsList->reset();
XDOM::IXMLDOMNodePtr pDetailObject;
while(pDetailObject = pDetailObjectsList->nextNode())
{
XDOM::IXMLDOMNodeListPtr pObjList = pDetailObject->getElementsByTagName("Object");
if(pObjList)
{
XDOM::IXMLDOMNodePtr pObj;
pObjList->reset();
while(pObj = pObjList->nextNode())
{
XDOM::IXMLDOMNodePtr pName = pObj->getAttribute("Name");
char sObjectsName[256];
strcpy(sObjectsName,pName->getText());
if(!sObjectsName[0])
break;
// try to find already loaded
int l=0;
for(l=0; l<m_GrassModelsArray.Count(); l++)
{
if(strcmp(m_GrassModelsArray[l]->sObjectFileName,sObjectsName)==0)
break;
}
if(l>=m_GrassModelsArray.Count())
{ // not found
GrassType * triData = new GrassType( sObjectsName );
if(triData && (*triData).nIndCount)
m_GrassModelsArray.Add(triData);
else
{
delete triData;
break;
}
m_arrlstSurfaceObjects[nId].Add(triData);
}
else
{ // use already loaded
m_arrlstSurfaceObjects[nId].Add(m_GrassModelsArray[l]);
}
}
}
}
nId++;
}
}
}
UpdateLoadingScreen(" %d detail objects loaded", m_GrassModelsArray.Count());
m_GrassTID = 4096;
for(int t=0; t<m_GrassModelsArray.Count(); t++)
{
if(m_GrassModelsArray[t]->nTexID && m_GrassModelsArray[t]->nTexID != 4096)
{ // if some valid texture found - ise it for all objects
m_GrassTID = m_GrassModelsArray[t]->nTexID;
break;
}
}
if(!m_GrassTID && m_GrassModelsArray.Count())
{
#if !defined(LINUX)
Warning( 0,0,"Texture for detail objects was not loaded");
#endif
m_GrassTID = 0x1000;
}
if(!m_GrassModelsArray.Count())
return;
m_pShader = GetRenderer()->EF_LoadShader("TerrainDetailObjects", eSH_World, 0);
// make leaf buffer
// m_pGrassVertices = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[DETAIL_GRASS_PIP_BUFFER_SIZE];
m_GrassIndices.PreAllocate(DETAIL_GRASS_PIP_BUFFER_SIZE*3,DETAIL_GRASS_PIP_BUFFER_SIZE*3);
m_pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
0/*m_pGrassVertices*/, DETAIL_GRASS_PIP_BUFFER_SIZE, VERTEX_FORMAT_P3F_COL4UB_TEX2F,
m_GrassIndices.GetElements(), m_GrassIndices.Count(), R_PRIMV_TRIANGLES, "Grass", eBT_Dynamic, 1 , 0, PrepareBufferCallback, this);
m_pLeafBuffer->SetRECustomData(m_arrfShaderInfo);
assert(m_pLeafBuffer);
m_pLeafBuffer->SetChunk(m_pShader,0,DETAIL_GRASS_PIP_BUFFER_SIZE,0,m_GrassIndices.Count(),0);
}
bool CDetailGrass::PrepareBufferCallback(CLeafBuffer * pLeafBuffer, bool bNeedTangents)
{
CDetailGrass * pThis = (CDetailGrass *)pLeafBuffer->m_pCustomData;
// if(pTerrain->m_nRenderStackLevel==0)
{
// Matrix44 mat;
// pThis->GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d forward = -pThis->GetViewCamera().GetVCMatrixD3D9().GetColumn(2);
//CELL_CHANGED_BY_IVO
//forward(-mat.cell(2), -mat.cell(6), -mat.cell(10));
forward.Normalize();
if(!forward.x && !forward.y)
return false;
Vec3d vCamPos = pThis->GetViewCamera().GetPos();
int c_X = int(vCamPos.x + forward.x*CAMERA_GRASS_SHIFT);
int c_Y = int(vCamPos.y + forward.y*CAMERA_GRASS_SHIFT);
// GetRenderer()->DrawBall(c_X,c_Y,m_pTerrain->GetZApr(c_X,c_Y),1);
// check focus
float dx = float(c_X-pThis->m_GrassFocusX);
float dy = float(c_Y-pThis->m_GrassFocusY);
float d2 = (dx*dx+dy*dy);
if(d2>16 && pThis->m_pTerrain)
{
pThis->m_GrassFocusX = c_X;
pThis->m_GrassFocusY = c_Y;
if(pLeafBuffer->m_pVertexBuffer && pLeafBuffer->m_pVertexBuffer->m_vertexformat == VERTEX_FORMAT_P3F_COL4UB_TEX2F)
{
pThis->GetRenderer()->UpdateBuffer(pLeafBuffer->m_pVertexBuffer,0,0,0);
pThis->CreateSectorGrass(int(CAMERA_GRASS_SHIFT+2),int(1),
(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F*)pLeafBuffer->m_pVertexBuffer->m_VS[VSF_GENERAL].m_VData);
// unlock
pThis->GetRenderer()->UpdateBuffer(pLeafBuffer->m_pVertexBuffer, NULL, 0, true, 0, 1);
//pLeafBuffer->UpdateSysIndices(pThis->m_GrassIndices.GetElements(), pThis->m_GrassIndices.Count());
pLeafBuffer->UpdateVidIndices(pThis->m_GrassIndices.GetElements(), pThis->m_GrassIndices.Count());
if(pThis->m_GrassIndices.Count()==0)
pLeafBuffer->SetChunk(pThis->m_pShader,0,-1,0,-1,0);
else
pLeafBuffer->SetChunk(pThis->m_pShader,0,pThis->m_GrassVerticesCount,0,pThis->m_GrassIndices.Count(),0);
pLeafBuffer->SetShader(pThis->m_pShader,pThis->m_GrassTID);
}
else
{
assert(0);
}
}
// set alpha glow texgen params
const float fDistFadeK = 1.f/(CAMERA_GRASS_SHIFT*4.f);
pThis->m_arrfShaderInfo[2] = fDistFadeK;
pThis->m_arrfShaderInfo[3] = 0.5f-vCamPos.y*fDistFadeK;
pThis->m_arrfShaderInfo[4] = 0.5f-vCamPos.x*fDistFadeK;
// assert(pThis->m_pLeafBuffer && pThis->m_pLeafBuffer == pLeafBuffer);
if(pThis->m_pLeafBuffer) // lb may be not created yet, this call can come from CreateLeafBufferInitialized()
pThis->m_pLeafBuffer->SetRECustomData(pThis->m_arrfShaderInfo);
}
return true;
}
CDetailGrass::~CDetailGrass()
{
for(int i=0; i<m_GrassModelsArray.Count(); i++)
delete m_GrassModelsArray[i];
m_GrassModelsArray.Reset();
if(m_pLeafBuffer)
GetRenderer()->DeleteLeafBuffer(m_pLeafBuffer);
m_pLeafBuffer=0;
// delete [] m_pGrassVertices; m_pGrassVertices=0;
/// GetRenderer()->RemoveTexture(m_GrassTID);
}
// copy object into buffer
void CDetailGrass::AddIndexedArray(GrassType * o, float X, float Y, float Z, float fObjBr,
float fSizeRatio, float fXSign, float fYSign, int nSwapXY,
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices)
{
if(fObjBr > 1.f)
fObjBr = 1.f;
fObjBr *= 255.f;
assert(o->nIndCount%3 == 0);
for( uint i=0; i<o->nIndCount; i+=3 )
{
assert(o->uipIndices[i]<o->nVertCount);
m_GrassIndices.Add(o->uipIndices[i+0] + m_GrassVerticesCount);
assert(o->uipIndices[i+1]<o->nVertCount);
m_GrassIndices.Add(o->uipIndices[i+1] + m_GrassVerticesCount);
assert(o->uipIndices[i+2]<o->nVertCount);
m_GrassIndices.Add(o->uipIndices[i+2] + m_GrassVerticesCount);
}
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVert = &pGrassVertices[m_GrassVerticesCount];
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pSourceVert = &o->pVertices[0];
unsigned char grass_r = (unsigned char)fObjBr;
unsigned char grass_g = (unsigned char)fObjBr;
unsigned char grass_b = (unsigned char)fObjBr;
for(uint v=0; v<o->nVertCount; v++)
{
switch(nSwapXY)
{
case 0:
pVert->xyz.x = (pSourceVert->xyz.x*fSizeRatio)*fXSign + X;
pVert->xyz.y = (pSourceVert->xyz.y*fSizeRatio)*fYSign + Y;
pVert->xyz.z = (pSourceVert->xyz.z/fSizeRatio) + Z;
break;
case 1: // swap
pVert->xyz.x = (pSourceVert->xyz.y*fSizeRatio)*fXSign + X;
pVert->xyz.y = (pSourceVert->xyz.x*fSizeRatio)*fYSign + Y;
pVert->xyz.z = (pSourceVert->xyz.z/fSizeRatio) + Z;
break;
}
pVert->st[0] = pSourceVert->st[0];
pVert->st[1] = pSourceVert->st[1];
pVert->color.bcolor[0] = grass_r;
pVert->color.bcolor[1] = grass_g;
pVert->color.bcolor[2] = grass_b;
pVert->color.bcolor[3] = 255;
pVert++;
pSourceVert++;
}
m_GrassVerticesCount += o->nVertCount;
}
void CDetailGrass::CreateSectorGrassInUnit(const int x, const int y, const int nStep,
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices)
{
const float grass_level_min = m_pTerrain->GetWaterLevel() + 0.25f;
if(m_pTerrain->GetZSafe(m_GrassFocusX+x,m_GrassFocusY+y)<grass_level_min)
return;
if(m_GrassVerticesCount+4096 > DETAIL_GRASS_PIP_BUFFER_SIZE)
{
GetLog()->Log("CreateSectorGrass: grass buffer overflow");
GetLog()->Log("grass_verts = %d/%d", m_GrassVerticesCount, int(DETAIL_GRASS_PIP_BUFFER_SIZE));
return;
}
srand(((m_GrassFocusX+x)*(m_GrassFocusY+y)));
srand(rand());
srand(rand());
int nSurfaceID = 0;
int nUnitSize = CTerrain::GetHeightMapUnitSize();
// todo skip this if there is has_holes flag not set in sector
for(int _x = m_GrassFocusX+x-nUnitSize; _x <= m_GrassFocusX+x+nUnitSize; _x += nUnitSize)
for(int _y = m_GrassFocusY+y-nUnitSize; _y <= m_GrassFocusY+y+nUnitSize; _y += nUnitSize)
{
if(m_pTerrain->IsBurnedOut(_x-1,_y-1))
return;
nSurfaceID = m_pTerrain->GetSurfaceTypeID(_x-1,_y-1);
if(nSurfaceID == STYPE_HOLE)
return;
}
nSurfaceID = m_pTerrain->GetSurfaceTypeID(m_GrassFocusX+x,m_GrassFocusY+y);
if(nSurfaceID == STYPE_HOLE) return;
assert(nSurfaceID<MAX_SURFACE_TYPES_COUNT);
if(!m_arrlstSurfaceObjects[nSurfaceID].Count())
return;
assert(nStep == 1);
CVars * pCVars = GetCVars();
for(int i=0; i<m_nGrassDensity; i++)
{
float objX = (float)rnd() - 0.5f+(m_GrassFocusX+x);
float objY = (float)rnd() - 0.5f+(m_GrassFocusY+y);
/// if(m_pTerrain->IsBurnedOut((int)objX,(int)objY))
// continue;
int nObjIdId = rand() % m_arrlstSurfaceObjects[nSurfaceID].Count();
GrassType * o = m_arrlstSurfaceObjects[nSurfaceID][nObjIdId];
if(!o->nIndCount)
continue;
float objZ = m_pTerrain->GetZApr(objX,objY);
float fBr =
//pCVars->e_lighting_bit_test ?
//m_pTerrain->IsOnTheLight((int)objX,(int)objY) :
0.6f+0.4f*(float)m_pTerrain->IsOnTheLight((int)objX,(int)objY);
AddIndexedArray(o, objX,objY,objZ, fBr,
0.75f+rnd()*0.5f, // size, proportions
(rand() > RAND_MAX/2) ? 1.f : -1.f, // x sign
(rand() > RAND_MAX/2) ? 1.f : -1.f, // y sign
(rand() > RAND_MAX/2), // xy swap
pGrassVertices);
}
}
// generating sector grass mesh
void CDetailGrass::CreateSectorGrass(const int nRange, const int nStep, struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pGrassVertices)
{
m_GrassVerticesCount = 0;
m_GrassIndices.Clear();
if(!m_GrassModelsArray.Count())
return;
m_GrassFocusX = m_GrassFocusX/nStep*nStep;
m_GrassFocusY = m_GrassFocusY/nStep*nStep;
if(m_GrassFocusX-nRange<0 || m_GrassFocusY-nRange<0)
return;
if(m_GrassFocusX+nRange>=CTerrain::GetTerrainSize() || m_GrassFocusY+nRange>=CTerrain::GetTerrainSize())
return;
int nRangeX = nRange;
int nRangeY = nRange;
int nStepX = nStep;
int nStepY = nStep;
Vec3d vCamPos = GetViewCamera().GetPos();
if(vCamPos.x > m_GrassFocusX)
{
if(vCamPos.y > m_GrassFocusY)
{
for(int x=-nRangeX; x<= nRangeX; x+=nStepX)
for(int y=-nRangeY; y<= nRangeY; y+=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
else
{
for(int x=-nRangeX; x<= nRangeX; x+=nStepX)
for(int y= nRangeY; y>=-nRangeY; y-=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
}
else
{
if(vCamPos.y > m_GrassFocusY)
{
for(int x= nRangeX; x>=-nRangeX; x-=nStepX)
for(int y=-nRangeY; y<= nRangeY; y+=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
else
{
for(int x= nRangeX; x>=-nRangeX; x-=nStepX)
for(int y= nRangeY; y>=-nRangeY; y-=nStepY)
CreateSectorGrassInUnit(x, y , nStep, pGrassVertices);
}
}
// if(m_GrassVerticesCount>12000)
/* {
GetLog()->Log("grass_verts = %d/%d", m_GrassVerticesCount, int(DETAIL_GRASS_PIP_BUFFER_SIZE));
GetLog()->Log("grass_indic = %d", m_GrassIndices.Count());
}*/
}
void CDetailGrass::PreloadResources()
{
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(m_GrassTID);
if(pTexPic)
GetRenderer()->EF_PrecacheResource(pTexPic, 0, 1.f, 0);
}
// check focus and render
void CDetailGrass::RenderDetailGrass(CTerrain * pTerrain)
{
if( !GetCVars()->e_detail_objects || !m_nGrassDensity || !pTerrain || !m_pLeafBuffer )
return;
m_pTerrain = pTerrain;
if(!m_GrassTID)
return;
if(!(GetRenderer()->GetFeatures()&RFT_DIRECTACCESSTOVIDEOMEMORY))
return;
Vec3d vCamPos = GetViewCamera().GetPos();
const int map_border = 12;
if(vCamPos.x < map_border || vCamPos.x > CTerrain::GetTerrainSize()-map_border)
return;
if(vCamPos.y < map_border || vCamPos.y > CTerrain::GetTerrainSize()-map_border)
return;
// if(!m_pGrassVertices)
// return;
float camera_h = vCamPos.z - m_pTerrain->GetZSafe(vCamPos.x,vCamPos.y);
if(camera_h > 64 || camera_h < -8)
return;
/*
if(pTerrain->m_nRenderStackLevel==0)
{
Matrix44 mat;
GetRenderer()->GetModelViewMatrix(mat.GetData());
Vec3d forward = -mat.GetColumn(2);
//CELL_CHANGED_BY_IVO
//forward(-mat.cell(2), -mat.cell(6), -mat.cell(10));
forward.Normalize();
if(!forward.x && !forward.y)
return;
int c_X = int(vCamPos.x + forward.x*CAMERA_GRASS_SHIFT);
int c_Y = int(vCamPos.y + forward.y*CAMERA_GRASS_SHIFT);
// GetRenderer()->DrawBall(c_X,c_Y,m_pTerrain->GetZApr(c_X,c_Y),1);
// check focus
float dx = float(c_X-m_GrassFocusX);
float dy = float(c_Y-m_GrassFocusY);
float d2 = (dx*dx+dy*dy);
if(d2>16)
{
m_GrassFocusX = c_X;
m_GrassFocusY = c_Y;
PrepareBufferCallback(m_pLeafBuffer, 0, 0);
}
// set alpha glow texgen params
const float fDistFadeK = 1.f/(CAMERA_GRASS_SHIFT*4.f);
m_arrfShaderInfo[2] = fDistFadeK;
m_arrfShaderInfo[3] = 0.5f-vCamPos.y*fDistFadeK;
m_arrfShaderInfo[4] = 0.5f-vCamPos.x*fDistFadeK;
m_pLeafBuffer->SetRECustomData(m_arrfShaderInfo);
}
*/
// if(!m_GrassVerticesCount)
// return;
// find fog volume
Vec3d vPlus(30,30,30);
int nFogId;
for(nFogId = 0; nFogId<pTerrain->m_lstFogVolumes.Count(); nFogId++)
{
if(vCamPos.x > (pTerrain->m_lstFogVolumes[nFogId].vBoxMin-vPlus).x)
if(vCamPos.y > (pTerrain->m_lstFogVolumes[nFogId].vBoxMin-vPlus).y)
if(vCamPos.z > (pTerrain->m_lstFogVolumes[nFogId].vBoxMin-vPlus).z)
if(vCamPos.x < (pTerrain->m_lstFogVolumes[nFogId].vBoxMax+vPlus).x)
if(vCamPos.y < (pTerrain->m_lstFogVolumes[nFogId].vBoxMax+vPlus).y)
if(vCamPos.z < (pTerrain->m_lstFogVolumes[nFogId].vBoxMax+vPlus).z)
break;
}
int nDLMask = Get3DEngine()->GetLightMaskFromPosition(vCamPos, CAMERA_GRASS_SHIFT);
// render
CCObject * pObj = GetRenderer()->EF_GetObject(true);
if(GetRenderer()->EF_GetHeatVision())
pObj->m_ObjFlags |= FOB_HEATVISION;
pObj->m_Matrix.SetIdentity();
pObj->m_Color.a = 0.99f;
m_pLeafBuffer->m_vBoxMin = vCamPos;
m_pLeafBuffer->m_vBoxMax = vCamPos;
pObj->m_SortId = -1;
if(pTerrain->m_nRenderStackLevel==0)
m_pLeafBuffer->InvalidateVideoBuffer();
if(m_pLeafBuffer->m_Indices.m_nItems)
m_pLeafBuffer->AddRenderElements( pObj, nDLMask,-1, (nFogId<pTerrain->m_lstFogVolumes.Count()) ? pTerrain->m_lstFogVolumes[nFogId].nRendererVolumeID : 0, eS_TerrainDetailObjects );
else
{ // nothing to draw now but we must to add render element to be able to generate mesh right before rendering
m_pLeafBuffer->AddRenderElements( pObj, nDLMask,-1,
(nFogId<pTerrain->m_lstFogVolumes.Count()) ? pTerrain->m_lstFogVolumes[nFogId].nRendererVolumeID : 0 );
}
}
int CDetailGrass::GetMemoryUsage()
{
int nSize=0;
nSize += m_GrassIndices.GetMemoryUsage();
nSize += m_GrassModelsArray.GetMemoryUsage();
for(int i=0; i<m_GrassModelsArray.Count(); i++)
nSize += sizeof(*m_GrassModelsArray[i]) + m_GrassModelsArray[i]->GetMemoryUsage();
return nSize;
}