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

856 lines
24 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// Crytek CryENGINE Source code
//
// File:EntityRender.cpp
// Description: rendering of the entity and other relatated to visials stuff
//
// History:
// 14.04.2001:Created by Vladimir Kajalin
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <IRenderer.h>
#include "Entity.h"
#include "EntitySystem.h"
#include <ISystem.h>
#include <I3DEngine.h>
#include <ILog.h>
#include <IRenderer.h>
#include "itimer.h"
//#include "list2.h"
#if defined(_DEBUG) && !defined(LINUX)
static char THIS_FILE[] = __FILE__;
#define DEBUG_CLIENTBLOCK new( _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define new DEBUG_CLIENTBLOCK
#endif
bool CEntity::DrawEntity(const SRendParams & _EntDrawParams)
{
FUNCTION_PROFILER( m_pISystem,PROFILE_3DENGINE );
int nRecursionLevel = (int)m_pISystem->GetIRenderer()->EF_Query(EFQ_RecurseLevel) - 1;
if(nRecursionLevel==0)
{ // movement detection (if no recursion)
m_vPrevDrawCenter = m_center;
m_vPrevDrawAngles = m_angles;
m_fPrevDrawScale = m_fScale;
}
if (m_bHidden)
return 0;
if(!GetRadius())
return 0;
// to check is something was really drawn
bool bSomethingWasDrawn = false;
// some parameters will be modified
SRendParams rParms = _EntDrawParams;
// enable lightmaps if alowed
/* if(GetRndFlags()&ERF_USELIGHTMAPS && HasLightmap())
{
rParms.pLightMapInfo = GetLightmap();
rParms.m_pLMTCBuffer = GetLightmapTexCoord();
}
else*/
{
rParms.pLightMapInfo = 0;
rParms.pLMTCBuffer = 0;
}
if (!gPrecacheResourcesMode)
{
// remember last rendered frames
if(nRecursionLevel>=0 && nRecursionLevel<=1)
SetDrawFrame( m_pISystem->GetIRenderer()->GetFrameID(), nRecursionLevel );
// If entity is drawn and it is set to be update only when visible, awake it for few frames.
if (m_eUpdateVisLevel == eUT_PhysicsVisible || m_eUpdateVisLevel == eUT_Visible)
{
m_awakeCounter = 2;
}
}
// gometry bbox test
if(!(GetRndFlags()&ERF_DONOTCHECKVIS))
if(!rParms.pShadowVolumeLightSource && !(rParms.dwFObjFlags & FOB_RENDER_INTO_SHADOWMAP))
{
AABB abEntityBBox(m_vBoxMin + m_center, m_vBoxMax + m_center);
if(m_bForceBBox)
{ // if bbox was forced - make it bigger for frustum culling
Vec3d vSize = m_vBoxMax - m_vBoxMin;
abEntityBBox = AABB(m_vBoxMin - vSize + m_center, m_vBoxMax + vSize + m_center);
}
if(!m_pISystem->GetViewCamera().IsAABBVisibleFast( abEntityBBox ))
return false;
}
// entity do not cast shadows from it own light
if((m_pDynLight && !GetContainer() && rParms.pShadowVolumeLightSource) || (m_pDynLight && m_pDynLight == rParms.pShadowVolumeLightSource))
return false;
if (!gPrecacheResourcesMode)
{
// [PETAR] We need to remember the last frame id when this entity was rendered
m_nLastVisibleFrameID = m_pISystem->GetIRenderer()->GetFrameID();
// Awake entity on the first time it is seen.
if (m_bSleeping)
SetSleep(false);
}
// set entity params
rParms.fScale = GetScale();
if(!(rParms.dwFObjFlags & FOB_RENDER_INTO_SHADOWMAP))
rParms.vPos = GetPos();
rParms.vAngles = GetAngles();
//[Timur][22/3/2003]
/*
// set custom materials
if(m_lstMaterials.Count())
rParms.pMaterials = &m_lstMaterials;*/
IMatInfo * pPrevMaterial = rParms.pMaterial;
rParms.pMaterial = m_pMaterial;
if(m_bHasEnvLighting)
rParms.dwFObjFlags |= FOB_ENVLIGHTING;
if(m_arrShaderParams.Num())
rParms.pShaderParams = &m_arrShaderParams;
// calculate entity matrix once for all entity objects
Matrix44 EntityMatrix;
if(rParms.dwFObjFlags & FOB_RENDER_INTO_SHADOWMAP)
{
//EntityMatrix.Identity();
//EntityMatrix.SetTranslation(rParms.vPos);
//EntityMatrix = GetRotationZYX44(-gf_DEGTORAD*rParms.vAngles)*EntityMatrix; //NOTE: angles in radians and negated
//EntityMatrix = GetScale33( Vec3d(rParms.fScale,rParms.fScale,rParms.fScale) )*EntityMatrix;
//OPTIMISED_BY_IVO
Matrix33diag diag = Vec3(rParms.fScale,rParms.fScale,rParms.fScale); //use diag-matrix for scaling
Matrix34 rt34 = Matrix34::CreateRotationXYZ( Deg2Rad(rParms.vAngles),rParms.vPos ); //set scaling and translation in one function call
EntityMatrix = rt34*diag; //optimised concatenation: m34*t*diag
}
else
{
//EntityMatrix.Identity();
//EntityMatrix = GetTranslationMat(GetPos())*EntityMatrix;
//EntityMatrix = GetRotationZYX44(-gf_DEGTORAD*rParms.vAngles)*EntityMatrix; //NOTE: angles in radians and negated
//EntityMatrix = GetScale33( Vec3d(rParms.fScale,rParms.fScale,rParms.fScale) )*EntityMatrix;
//OPTIMISED_BY_IVO
Matrix33diag diag = Vec3(rParms.fScale,rParms.fScale,rParms.fScale); //use diag-matrix for scaling
Matrix34 rt34 = Matrix34::CreateRotationXYZ( Deg2Rad(rParms.vAngles),GetPos() ); //set scaling and translation in one function call
EntityMatrix = rt34*diag; //optimised concatenation: m34*t*diag
}
EntityMatrix = GetTransposed44(EntityMatrix); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
// lod depends on distance and size and entity settings
int nLod = max(0,(int)(rParms.fDistance*GetLodRatioNormilized()/(m_pISystem->GetI3DEngine()->GetObjectsLODRatio()*GetRadius())));
// disable scissoring for entities inside portals
if(m_pVisArea && ((IVisArea*)m_pVisArea)->IsPortal())
rParms.dwFObjFlags |= FOB_NOSCISSOR;
// draw static components
for (unsigned int k=0; k<m_objects.size(); k++)
{
CEntityObject *cb = &m_objects[k];
IStatObj * obj = cb->object;
if (!obj || !(cb->flags & ETY_OBJ_INFO_DRAW))
continue;
// render
if (cb->flags & ETY_OBJ_USE_MATRIX)
{
rParms.pMatrix = &cb->mtx;
if (!rParms.pShadowVolumeLightSource)
obj->Render(rParms,Vec3(zero), nLod);
else if(GetRndFlags()&ERF_CASTSHADOWVOLUME)
obj->RenderShadowVolumes(&rParms);
}
else
{
if (rParms.pShadowVolumeLightSource)
{
rParms.pMatrix = &cb->mtx; // use matrix calculated on prev z/ambient pass
rParms.vPos(0,0,0);
rParms.vAngles(0,0,0);
if (GetRndFlags()&ERF_CASTSHADOWVOLUME)
obj->RenderShadowVolumes(&rParms);
}
else
{
//Matrix44 mat;
//mat.Identity();
//mat=GetTranslationMat(cb->pos)*mat;
//mat=GetRotationZYX44(-gf_DEGTORAD*cb->angles)*mat; //NOTE: angles in radians and negated
//OPTIMISED_BY_IVO
Matrix44 mat=Matrix34::CreateRotationXYZ( Deg2Rad(cb->angles),cb->pos);
mat=GetTransposed44(mat); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
mat = mat*EntityMatrix;
rParms.pMatrix = &mat;
obj->Render(rParms,Vec3(zero), nLod);
// cache for shadow volumes and decals
cb->mtx = mat;
}
}
bSomethingWasDrawn = true;
}
//[Timur] Always draw container if its present.
if (m_pContainer)
{
m_pContainer->OnDraw( rParms );
bSomethingWasDrawn = true;
}
// draw animated component
for (int i=0; i<MAX_ANIMATED_MODELS; i++)
{
ICryCharInstance * cmodel = m_pCryCharInstance[i];
if (cmodel && (cmodel->GetFlags() & CS_FLAG_DRAW_MODEL))
{
if (m_pContainer)
{
//[Timur] Container Is not used Only to draw characters. This is a general modification of entity.
//[Timur] m_pContainer->OnDraw( rParms );
}
else
{
SRendParams RenderParams = rParms;
//RenderParams.vAngles = m_physic && m_physic->GetType()==PE_ARTICULATED ? Vec3d(0,0,0) : m_angles;
//RenderParams.vAngles = m_angles;
if (rParms.pShadowVolumeLightSource)
{
if(GetRndFlags()&ERF_CASTSHADOWVOLUME)
cmodel->RenderShadowVolumes(&RenderParams, (GetRndFlags()&ERF_SELFSHADOW) ? 0 : 10);
}
else
cmodel->Draw(RenderParams,Vec3(123,123,123));
}
bSomethingWasDrawn = true;
}
}
DrawEntityDebugInfo(rParms);
// restore material to original.
rParms.pMaterial = pPrevMaterial;
return bSomethingWasDrawn;
}
void CEntity::DrawEntityDebugInfo(const SRendParams & rParms)
{
// debug
if(m_pEntitySystem->m_pEntityBBoxes->GetIVal())
if (!rParms.pShadowVolumeLightSource)
{
Vec3d mins,maxs;
GetBBox(mins,maxs);
m_pISystem->GetIRenderer()->Draw3dBBox(mins,maxs);
/*for (unsigned int k=0;k<m_objects.size();k++)
{
CEntityObject *cb = &m_objects[k];
IStatObj * obj = cb->object;
if (!obj)
continue;
maxs = obj->GetBoxMax() * m_fScale;
mins = obj->GetBoxMin() * m_fScale;
m_pISystem->GetIRenderer()->Draw3dBBox(m_center+mins,m_center+maxs);
}*/
}
// debug
if(m_pEntitySystem->m_pEntityHelpers->GetIVal())
if (!m_objects.empty())
{
std::vector < CEntityObject>::iterator oi;
for (oi = m_objects.begin(); oi != m_objects.end(); oi++)
{
CEntityObject eo =(*oi);
if (!eo.object)
continue;
{
CStatObj *so = (CStatObj*)eo.object;
Vec3d pos;
//CryQuat qRot;
int idx=0;
char* name;
while( name=(char*)eo.object->GetHelperById(idx++, pos) )
{
Vec3d hSize = Vec3d( .5f, .5f, .5f );
//Matrix44 mtx;
//mtx.Identity();
//mtx=GetTranslationMat(m_center)*mtx;
//mtx=GetRotationZYX44(-gf_DEGTORAD*m_angles)*mtx; //NOTE: angles in radians and negated
//OPTIMISED_BY_IVO
Matrix44 mtx = Matrix34::CreateRotationXYZ( Deg2Rad(m_angles),m_center);
mtx=GetTransposed44(mtx); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
pos = mtx.TransformPointOLD(pos);
Vec3d mins,maxs;
mins = pos - hSize;
maxs = pos + hSize;
m_pISystem->GetIRenderer()->Draw3dBBox(mins,maxs);
m_pISystem->GetIRenderer()->DrawLabel(pos, .73f, name);
}
}
}
}
}
// set bEntityHasLights flag if there are any light sources in entity objects
void CEntity::CheckEntityLightSourcesInEntityObjects()
{
m_bEntityHasLights = false;
// Static objects
for (unsigned int k=0; k<m_objects.size(); k++)
{
CEntityObject *cb = &m_objects[k];
IStatObj * obj = cb->object;
if (!obj)// || !(cb->flags & ETY_OBJ_INFO_DRAW))
continue;
if(obj->GetLightSources(0))
m_bEntityHasLights = true;
}
// Animated components
for (int i=0;i <MAX_ANIMATED_MODELS; i++)
{
ICryCharInstance * cmodel = m_pCryCharInstance[i];
if (cmodel && cmodel->GetBoundLight(0))
m_bEntityHasLights = true;
}
}
void CEntity::ProcessEntityLightSources()
{
//prepare entity matrix
//Matrix44 EntityMatrix;
//EntityMatrix.Identity();
//EntityMatrix=GetTranslationMat(m_center)*EntityMatrix;
//EntityMatrix=GetRotationZYX44(-gf_DEGTORAD*m_angles)*EntityMatrix; //NOTE: angles in radians and negated
//EntityMatrix=GetScale33( Vec3d(m_fScale,m_fScale,m_fScale) )*EntityMatrix;
FUNCTION_PROFILER( m_pISystem,PROFILE_ENTITY );
if (!m_pEntitySystem->m_pUpdateCoocooEgg->GetIVal())
return;
Matrix33diag diag = Vec3d(m_fScale,m_fScale,m_fScale); //use diag-matrix for scaling
Matrix34 rt34 = Matrix34::CreateRotationXYZ(Deg2Rad(m_angles),m_center); //set rotation and translation in one function call
Matrix44 EntityMatrix = rt34*diag; //optimised concatenation: m34*diag
EntityMatrix = GetTransposed44(EntityMatrix); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
// entity light id
int nLightId=0;
// Static objects
for (unsigned int k=0;k<m_objects.size();k++)
{
CEntityObject *cb = &m_objects[k];
IStatObj * obj = cb->object;
if (!obj || !(cb->flags & ETY_OBJ_INFO_DRAW))
continue;
if (cb->flags & ETY_OBJ_USE_MATRIX)
{
for(int i=0; obj->GetLightSources(i); i++)
m_pISystem->GetI3DEngine()->AddDynamicLightSource(*obj->GetLightSources(i),this,nLightId++,&cb->mtx);
}
else
{
//Matrix44 mat;
//mat.Identity();
//mat=GetTranslationMat(cb->pos)*mat;
//mat=GetRotationZYX44(-gf_DEGTORAD*cb->angles)*mat; //NOTE: angles in radians and negated
//OPTIMISED_BY_IVO
Matrix44 mat = Matrix34::CreateRotationXYZ( Deg2Rad(cb->angles),cb->pos);
mat=GetTransposed44(mat); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
mat = EntityMatrix*mat;
for(int i=0; obj->GetLightSources(i); i++)
m_pISystem->GetI3DEngine()->AddDynamicLightSource(*obj->GetLightSources(i),this,nLightId++,&mat);
}
}
// Animated objects
for (int i=0;i<MAX_ANIMATED_MODELS;i++)
{
ICryCharInstance * cmodel = m_pCryCharInstance[i];
if (cmodel && (cmodel->GetFlags() & CS_FLAG_DRAW_MODEL) && cmodel->GetBoundLight(0))
{
assert(!IsStatic());
Matrix44 LightMatrix;
if (m_pContainer)
{ // use character angles and entity pos
//LightMatrix.Identity();
//LightMatrix=GetTranslationMat(m_center)*LightMatrix;
//LightMatrix=GetRotationZYX44(-gf_DEGTORAD*GetAngles())*LightMatrix; //NOTE: angles in radians and negated
//OPTIMISED_BY_IVO
LightMatrix = Matrix34::CreateRotationXYZ( Deg2Rad(GetAngles()),m_center);
LightMatrix=GetTransposed44(LightMatrix); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
}
else
LightMatrix = EntityMatrix;
for(int i=0; cmodel->GetBoundLight(i); i++)
m_pISystem->GetI3DEngine()->AddDynamicLightSource(*cmodel->GetBoundLight(i),this,nLightId++,&LightMatrix);
}
}
}
void CEntity::SetEntityStatObj( unsigned int nSlot, IStatObj * pStatObj, Matrix44 * pMatrix )
{
if(nSlot>=0 /*&& nSlot<m_objects.size()*/) //PETAR: changed to be able to SET entity objects, not just replace them
{
if (nSlot >= m_objects.size())
m_objects.resize(nSlot+1);
if(pMatrix)
{
m_objects[nSlot].mtx = *pMatrix;
m_objects[nSlot].flags |=ETY_OBJ_USE_MATRIX;
}
else
m_objects[nSlot].flags &=~ETY_OBJ_USE_MATRIX;
// Release previous object.
if (m_objects[nSlot].object != pStatObj && m_objects[nSlot].object != NULL)
m_pISystem->GetI3DEngine()->ReleaseObject(m_objects[nSlot].object);
m_objects[nSlot].object = pStatObj;
}
}
IStatObj * CEntity::GetEntityStatObj( unsigned int nSlot, Matrix44* pMatrix, bool bReturnOnlyVisible)
{
if(nSlot>=0 && nSlot<m_objects.size() && (!bReturnOnlyVisible || m_objects[nSlot].flags & ETY_OBJ_INFO_DRAW))
{
if(pMatrix)
{
if(m_objects[nSlot].flags & ETY_OBJ_USE_MATRIX)
*pMatrix = m_objects[nSlot].mtx;
else
{
//OPTIMISED_BY_IVO
// make object matrix
Matrix33diag diag = Vec3(GetScale(),GetScale(),GetScale());
Matrix34 rt34 = Matrix34::CreateRotationXYZ( Deg2Rad(GetAngles()),GetPos() );
Matrix44 EntityMatrix = rt34*diag;
EntityMatrix = GetTransposed44(EntityMatrix);
Matrix44 ObjMatrix = Matrix34::CreateRotationXYZ( Deg2Rad(m_objects[nSlot].angles),m_objects[nSlot].pos);
ObjMatrix = GetTransposed44(ObjMatrix); //TODO: remove this after E3 and use Matrix34 instead of Matrix44
*pMatrix = ObjMatrix*EntityMatrix;
}
}
return m_objects[nSlot].object;
}
return 0;
}
ICryCharInstance* CEntity::GetEntityCharacter( unsigned int nSlot, Matrix44* pMatrix )
{
if(nSlot>=0 && nSlot<MAX_ANIMATED_MODELS)
{
if(pMatrix)
assert(0); // todo: entity should have matrix calculated once in entity Update()
return m_pCryCharInstance[nSlot];
}
return 0;
}
void CEntity::InitEntityRenderState()
{
if(!m_pEntityRenderState)
{
m_pEntityRenderState = m_pISystem->GetI3DEngine()->MakeEntityRenderState();
CheckEntityLightSourcesInEntityObjects();
}
}
bool CEntity::IsEntityHasSomethingToRender()
{
bool bItHas = false;
// test static component
for (unsigned int k=0; k<m_objects.size(); k++)
{
CEntityObject *cb = &m_objects[k];
IStatObj * obj = cb->object;
if (!obj || !(cb->flags & ETY_OBJ_INFO_DRAW))
continue;
bItHas = true;
break;
}
// test animated component
for (int i=0; i<MAX_ANIMATED_MODELS; i++)
{
ICryCharInstance * cmodel = m_pCryCharInstance[i];
if (cmodel && (cmodel->GetFlags() & CS_FLAG_DRAW_MODEL))
{
bItHas = true;
break;
}
}
return bItHas;
}
//////////////////////////////////////////////////////////////////////////
void CEntity::PlayParticleSoundEffects( IParticleEffect *pEffect )
{
}
// vlad's todo: move ParticleEmitter into 3dengine
int CEntity::CreateEntityParticleEmitter(int nSlotId, const ParticleParams & PartParams,
float fSpawnPeriod,Vec3d vOffSet,Vec3d vDir,
IParticleEffect *pEffect,float fScale)
{
if(nSlotId>16)
{
m_pISystem->GetILog()->Log("Error: CEntity::CreateEntityParticleEmitter: nSlotId=%d is out of range", nSlotId);
return -1;
}
if (!m_pParticleEmitters)
m_pParticleEmitters = new PatricleEmitters;
m_bUpdateEmitters = true;
if ((int)m_pParticleEmitters->size() <= nSlotId)
{
m_pParticleEmitters->resize(nSlotId+1);
}
EntPartEmitter &emitter = (*m_pParticleEmitters)[nSlotId];
emitter.pEmitter = m_pISystem->GetI3DEngine()->CreateParticleEmitter();
if (!pEffect)
{
emitter.pEmitter->SetParams( PartParams );
}
else
{
emitter.pEmitter->SetEffect( pEffect );
}
emitter.fScale = fScale;
emitter.vOffset = vOffSet;
emitter.vDir = vDir;
emitter.fSpawnPeriod = fSpawnPeriod;
emitter.pEffect = pEffect;
// Override spawn period.
emitter.pEmitter->SetSpawnPeriod( fSpawnPeriod );
emitter.pEmitter->SetUnlimitedLife(); // Unlimited lifetime.
emitter.pEmitter->SetEntity( this );
// Assign material only if entity doesnt contain any geometry.
if (GetNumObjects() == 0 && m_nMaxCharNum == 0)
emitter.pEmitter->SetMaterial( m_pMaterial );
InitEntityRenderState();
return nSlotId;
}
//////////////////////////////////////////////////////////////////////////
void CEntity::DeleteParticleEmitter(int nId)
{
if(m_pParticleEmitters && nId >= 0 && nId < (int)m_pParticleEmitters->size())
{
EntPartEmitter &emitter = (*m_pParticleEmitters)[nId];
if (emitter.pEmitter)
m_pISystem->GetI3DEngine()->DeleteParticleEmitter( emitter.pEmitter );
emitter.pEmitter = 0;
emitter.pEffect = 0;
}
}
//////////////////////////////////////////////////////////////////////////
void CEntity::UpdateParticleEmitters( SEntityUpdateContext &ctx )
{
if(!m_pParticleEmitters)
return;
FUNCTION_PROFILER( m_pISystem,PROFILE_ENTITY );
//[Timur]
//@FIXME !!!! this must not be here.
//@HACK
m_pISystem->GetI3DEngine()->RegisterEntity(this);
// if(GetEntityVisArea() && !IsEntityAreasVisible())
// return;
//float fDist = GetDistance(m_pISystem->GetViewCamera().GetPos(), GetPos());
float fCurrTime = ctx.fCurrTime;
// Keep emitters alive.
for (int i=0; i < (int)m_pParticleEmitters->size(); i++)
{
EntPartEmitter &emitter = (*m_pParticleEmitters)[i];
if (emitter.pEmitter)
{
// calculate entity rotation matrix
Matrix44 EntityMatrix;
EntityMatrix.SetIdentity();
//EntityMatrix.RotateMatrix_fix(GetAngles());
EntityMatrix=Matrix44::CreateRotationZYX(-gf_DEGTORAD*GetAngles())*EntityMatrix; //NOTE: angles in radians and negated
Vec3 pos = GetPos() + EntityMatrix.TransformVectorOLD( emitter.vOffset );
Vec3 dir = EntityMatrix.TransformVectorOLD( emitter.vDir );
//
emitter.pEmitter->SetPos( pos,dir,emitter.fScale );
// Assign material only if entity doesnt contain any geometry.
if (GetNumObjects() == 0 && m_nMaxCharNum == 0)
{
if (m_pMaterial)
emitter.pEmitter->SetMaterial( m_pMaterial );
else
emitter.pEmitter->SetMaterial( NULL );
}
}
}
//[kirill] this vould stop some entities with eUT_Always from being updated - so commented it out
// on first succesfull update - enable potential visibility check
// SetUpdateVisLevel(eUT_PotVisible);
}
bool CEntity::IsEntityAreasVisible()
{
if(!GetEntityRS())
return false;
IVisArea * pArea = (IVisArea *)m_pVisArea;
// test area vis
if(pArea && pArea->GetVisFrameId() == m_pISystem->GetIRenderer()->GetFrameID())
return true; // visible
if(m_pDynLight && !(m_pDynLight->m_Flags & DLF_THIS_AREA_ONLY)) // tmp hack, should be set from the script
{ // test neighbours
IVisArea * Areas[64];
int nCount = pArea->GetVisAreaConnections(Areas,64);
for (int i=0; i<nCount; i++)
if(Areas[i]->GetVisFrameId() == m_pISystem->GetIRenderer()->GetFrameID())
return true; // visible
}
return false; // not visible
}
bool CEntity::CheckUpdateVisLevel( SEntityUpdateContext &ctx,EEntityUpdateVisLevel eUpdateVisLevel )
{
switch(eUpdateVisLevel)
{
case eUT_Always: // always update
return true;
case eUT_InViewRange: // update if distance is less than camera view distance
{
bool bVisible = false;
if (ctx.nFrameID - GetDrawFrame() < MAX_FRAME_ID_STEP_PER_FRAME)
bVisible = true; // visible
float fDistSquared = GetLengthSquared( ctx.vCameraPos - GetPos() );
if (m_fUpdateRadius > 0)
{
// Within update radius.
if (fDistSquared < m_fUpdateRadius*m_fUpdateRadius)
return bVisible; // Update, because it is visible and within update radius.
else
return false; // Never update entity outside update radius.
}
return bVisible || fDistSquared < ctx.fMaxViewDistSquared;
}
case eUT_PotVisible: // update if entity visarea or terrain sector is visible
{
if (m_fUpdateRadius > 0)
{
// Within update radius.
float fDistSquared = GetLengthSquared( ctx.vCameraPos - GetPos() );
if (fDistSquared > m_fUpdateRadius*m_fUpdateRadius)
return false; // Out of update radius.
}
if (ctx.nFrameID - GetDrawFrame() < MAX_FRAME_ID_STEP_PER_FRAME)
return true; // visible
float fDistSquared = GetLengthSquared( ctx.vCameraPos - GetPos() );
if (fDistSquared > ctx.fMaxViewDistSquared)
return false; // not visible
float fAddRadius = m_fUpdateRadius;
// tmp hack for lights, will be removed when static light concept will be used
if (m_pDynLight && !(m_pDynLight->m_Flags & DLF_THIS_AREA_ONLY) && m_pDynLight->m_Origin!=Vec3d(0,0,0))
fAddRadius += 8;
return m_pISystem->GetI3DEngine()->IsPotentiallyVisible(this,fAddRadius);
}
case eUT_Visible: // update if visible
if (ctx.nFrameID - GetDrawFrame() < MAX_FRAME_ID_STEP_PER_FRAME)
{
if (m_fUpdateRadius > 0)
{
float fDistSquared = GetLengthSquared( ctx.vCameraPos - GetPos() );
// Within update radius.
if (fDistSquared < m_fUpdateRadius*m_fUpdateRadius)
return true; // Update, because it is visible and within update radius.
}
else
return true; // Update, because it is visible and no update radius specified.
}
break;
case eUT_Never: // newer update
return false;
case eUT_Physics: // Only update due to physics.
case eUT_PhysicsVisible:
case eUT_Unconditional:
return true;
}
// Not update.
return false;
}
//////////////////////////////////////////////////////////////////////////
void CEntity::SetMaterial( IMatInfo *pMatInfo )
{
m_pMaterial = pMatInfo;
if(m_pMaterial)
m_pMaterial->SetFlags(m_pMaterial->GetFlags()|MIF_WASUSED);
}
//////////////////////////////////////////////////////////////////////////
IMatInfo* CEntity::GetMaterial() const
{
return m_pMaterial;
}
//////////////////////////////////////////////////////////////////////////
void CEntity::PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime)
{
if(!GetEntityStatObj(0) || !GetEntityStatObj(0)->GetLeafBuffer())
return;
float fDistance = fPrevPortalDistance + GetPos().GetDistance(vPrevPortalPos);
float fMaxViewDist = GetMaxViewDist();
if(fDistance<fMaxViewDist && fDistance<m_pISystem->GetViewCamera().GetZMax())
{
for (unsigned int k=0; k<m_objects.size(); k++)
{
CEntityObject *cb = &m_objects[k];
IStatObj * obj = cb->object;
if (obj && (cb->flags & ETY_OBJ_INFO_DRAW))
obj->PreloadResources(fDistance,fTime,0);
}
for (int i=0; i<MAX_ANIMATED_MODELS; i++)
{
ICryCharInstance * cmodel = m_pCryCharInstance[i];
if (cmodel && (cmodel->GetFlags() & CS_FLAG_DRAW_MODEL))
cmodel->PreloadResources ( fDistance, 1.f, 0 );
}
}
}
float CEntity::GetMaxViewDist()
{
I3DEngine * p3DEngine = m_pISystem->GetI3DEngine();
return max(p3DEngine->GetObjectsMinViewDist(),
GetRenderRadius()*p3DEngine->GetObjectsViewDistRatio()*GetViewDistRatioNormilized());
}
void CEntity::SetShaderFloat(const char *Name, float Val)
{
char name[128];
int i;
strcpy(name, Name);
strlwr(name);
for (i=0; i<m_arrShaderParams.Num(); i++)
{
if (!strcmp(name, m_arrShaderParams[i].m_Name))
break;
}
if (i == m_arrShaderParams.Num())
{
SShaderParam pr;
strncpy(pr.m_Name, name, 32);
m_arrShaderParams.AddElem(pr);
}
m_arrShaderParams[i].m_Type = eType_FLOAT;
m_arrShaderParams[i].m_Value.m_Float = Val;
}