123
This commit is contained in:
328
Cry3DEngine/LightMan.cpp
Normal file
328
Cry3DEngine/LightMan.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
// New version of light sources management - not used yet
|
||||
|
||||
#include "3dEngine.h"
|
||||
#include "objman.h"
|
||||
#include "visareas.h"
|
||||
|
||||
#include "lightman.h"
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.14159f
|
||||
#endif
|
||||
|
||||
CLightManager::CLightManager()
|
||||
{
|
||||
m_arrLights = new std::map<int, LightsSet*>;
|
||||
}
|
||||
|
||||
CLightManager::~CLightManager()
|
||||
{
|
||||
for (LightsMap::iterator it = m_arrLights->begin(); it != m_arrLights->end(); ++it)
|
||||
{ // free lights lists
|
||||
LightsSet * pCellLights = (*it).second;
|
||||
delete pCellLights;
|
||||
}
|
||||
|
||||
m_arrLights->clear();
|
||||
delete m_arrLights;
|
||||
}
|
||||
|
||||
void CLightManager::GetLightBounds(CDLight * pLight, int &min_x, int &min_y, int &max_x, int &max_y)
|
||||
{
|
||||
// find lights 2d bounds
|
||||
Vec3d vRadius(pLight->m_fRadius,pLight->m_fRadius,pLight->m_fRadius);
|
||||
Vec3d vBoxMin = pLight->m_Origin - vRadius;
|
||||
Vec3d vBoxMax = pLight->m_Origin + vRadius;
|
||||
|
||||
// get 2d bounds in sectors array
|
||||
min_x = (int)(((vBoxMin.x - 1.f)/LIGHT_GRID_SIZE));
|
||||
min_y = (int)(((vBoxMin.y - 1.f)/LIGHT_GRID_SIZE));
|
||||
max_x = (int)(((vBoxMax.x + 1.f)/LIGHT_GRID_SIZE));
|
||||
max_y = (int)(((vBoxMax.y + 1.f)/LIGHT_GRID_SIZE));
|
||||
|
||||
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
|
||||
|
||||
if( min_x<0 ) min_x = 0; else if( min_x>=nTableSize ) min_x = nTableSize-1;
|
||||
if( min_y<0 ) min_y = 0; else if( min_y>=nTableSize ) min_y = nTableSize-1;
|
||||
if( max_x<0 ) max_x = 0; else if( max_x>=nTableSize ) max_x = nTableSize-1;
|
||||
if( max_y<0 ) max_y = 0; else if( max_y>=nTableSize ) max_y = nTableSize-1;
|
||||
}
|
||||
|
||||
void CLightManager::AddLight(CDLight * pLight)
|
||||
{
|
||||
int min_x, min_y, max_x, max_y;
|
||||
GetLightBounds(pLight, min_x, min_y, max_x, max_y);
|
||||
|
||||
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
|
||||
|
||||
for(int x=min_x; x<=max_x; x++)
|
||||
for(int y=min_y; y<=max_y; y++)
|
||||
{
|
||||
// find cell from position
|
||||
int nXY = x+y*nTableSize;
|
||||
LightsMap::iterator itTable = m_arrLights->find(nXY);
|
||||
LightsSet * pLightsSet = 0;
|
||||
if(itTable!=m_arrLights->end())
|
||||
pLightsSet = (*itTable).second;
|
||||
else
|
||||
{ // allocate new set if needed
|
||||
pLightsSet = new LightsSet;
|
||||
m_arrLights->insert(LightsMap::value_type(nXY,pLightsSet));
|
||||
}
|
||||
|
||||
// add light if not found
|
||||
LightsSet::iterator itLightsSet = pLightsSet->find(pLight);
|
||||
if(itLightsSet==pLightsSet->end())
|
||||
pLightsSet->insert(pLight);
|
||||
}
|
||||
}
|
||||
|
||||
void CLightManager::DeleteLight(CDLight*pLight)
|
||||
{
|
||||
int min_x, min_y, max_x, max_y;
|
||||
GetLightBounds(pLight, min_x, min_y, max_x, max_y);
|
||||
|
||||
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
|
||||
|
||||
for(int x=min_x; x<=max_x; x++)
|
||||
for(int y=min_y; y<=max_y; y++)
|
||||
{
|
||||
// find cell from position
|
||||
int nXY = x+y*nTableSize;
|
||||
LightsMap::iterator itTable = m_arrLights->find(nXY);
|
||||
LightsSet * pLightsSet = 0;
|
||||
if(itTable!=m_arrLights->end())
|
||||
{
|
||||
pLightsSet = (*itTable).second;
|
||||
|
||||
// delete light if found
|
||||
LightsSet::iterator itLightsSet = pLightsSet->find(pLight);
|
||||
if(itLightsSet!=pLightsSet->end())
|
||||
{
|
||||
pLightsSet->erase(itLightsSet);
|
||||
if(pLightsSet->empty())
|
||||
{
|
||||
delete pLightsSet;
|
||||
m_arrLights->erase(itTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CLightManager::GetLightsAffectingBBox(const Vec3d & vBoxMin, const Vec3d & vBoxMax, LightsSet * pOutputList)
|
||||
{
|
||||
pOutputList->clear();
|
||||
|
||||
// get 2d bounds in sectors array
|
||||
int min_x = (int)(((vBoxMin.x - 1.f)/LIGHT_GRID_SIZE));
|
||||
int min_y = (int)(((vBoxMin.y - 1.f)/LIGHT_GRID_SIZE));
|
||||
int max_x = (int)(((vBoxMax.x + 1.f)/LIGHT_GRID_SIZE));
|
||||
int max_y = (int)(((vBoxMax.y + 1.f)/LIGHT_GRID_SIZE));
|
||||
|
||||
int nTableSize = CTerrain::GetTerrainSize()/LIGHT_GRID_SIZE;
|
||||
|
||||
if( min_x<0 ) min_x = 0; else if( min_x>=nTableSize ) min_x = nTableSize-1;
|
||||
if( min_y<0 ) min_y = 0; else if( min_y>=nTableSize ) min_y = nTableSize-1;
|
||||
if( max_x<0 ) max_x = 0; else if( max_x>=nTableSize ) max_x = nTableSize-1;
|
||||
if( max_y<0 ) max_y = 0; else if( max_y>=nTableSize ) max_y = nTableSize-1;
|
||||
|
||||
for(int x=min_x; x<=max_x; x++)
|
||||
for(int y=min_y; y<=max_y; y++)
|
||||
{
|
||||
// find cell from position
|
||||
int nXY = x+y*nTableSize;
|
||||
LightsMap::iterator itTable = m_arrLights->find(nXY);
|
||||
LightsSet * pLightsSet = 0;
|
||||
if(itTable!=m_arrLights->end())
|
||||
{
|
||||
pLightsSet = (*itTable).second;
|
||||
|
||||
// add lights into output list if found
|
||||
for (LightsSet::iterator it = pLightsSet->begin(); it != pLightsSet->end(); ++it)
|
||||
{
|
||||
if(pOutputList->find(*it) == pOutputList->end())
|
||||
pOutputList->insert(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern int __cdecl C3DEngine__Cmp_LightAmount(const void* v1, const void* v2);
|
||||
|
||||
int CLightManager::MakeLMaskFromPositionAndActivateLights( const Vec3d vObjPos, const float fObjRadius,
|
||||
IEntityRender * pEntityRender, int nMaxLightBitsNum, CDLight ** pSelectedLights, int nMaxSelectedLights)
|
||||
{
|
||||
Vec3d vBoxMin, vBoxMax;
|
||||
pEntityRender->GetRenderBBox(vBoxMin, vBoxMax);
|
||||
GetLightsAffectingBBox(vBoxMin, vBoxMax, &m_setTmpDL_MMFP);
|
||||
|
||||
// make list of really affecting light sources
|
||||
m_lstTmpDLA_MMFP.Clear();
|
||||
for(LightsSet::iterator itLightsSet = m_setTmpDL_MMFP.begin(); itLightsSet != m_setTmpDL_MMFP.end(); ++itLightsSet)
|
||||
{
|
||||
CDLight * pDLight = (*itLightsSet);
|
||||
if(!pDLight || pDLight->m_fRadius < 0.5f || pDLight->m_Flags & DLF_FAKE)
|
||||
continue;
|
||||
|
||||
if (pDLight->m_pShader!=0 && (pDLight->m_pShader->GetLFlags() & LMF_DISABLE))
|
||||
continue; // fake
|
||||
|
||||
if(pEntityRender && pDLight->m_Flags & DLF_LM && pEntityRender->GetRndFlags() & ERF_USELIGHTMAPS && pEntityRender->HasLightmap(0))
|
||||
{ // in case of lightmaps
|
||||
if(pDLight->m_SpecColor == Col_Black)
|
||||
continue; // ignore specular only lights if specular disabled
|
||||
|
||||
if(pDLight->m_Flags & DLF_PROJECT)
|
||||
continue; // ignore specular only lights if projector since specular projectors not supported
|
||||
}
|
||||
|
||||
if(pDLight->m_Flags & DLF_PROJECT && pEntityRender)
|
||||
{ // check projector frustum
|
||||
// use pDLight->m_TextureMatrix to construct Plane
|
||||
/*GetRenderer()->Draw3dBBox(pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtX(), DPRIM_LINE);
|
||||
GetRenderer()->DrawLabel(pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtX(),1,"x");
|
||||
GetRenderer()->Draw3dBBox(pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtY(), DPRIM_LINE);
|
||||
GetRenderer()->DrawLabel(pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtY(),1,"y");
|
||||
GetRenderer()->Draw3dBBox(pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtZ(), DPRIM_LINE);
|
||||
GetRenderer()->DrawLabel(pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtZ(),1,"z");*/
|
||||
|
||||
if(GetCVars()->e_projector_exact_test)
|
||||
{ // test
|
||||
CCamera cam; // construct light camera
|
||||
cam.SetPos(pDLight->m_Origin);
|
||||
Vec3d Angles(pDLight->m_ProjAngles[1], 0, pDLight->m_ProjAngles[2]+90.0f);
|
||||
cam.SetAngle(Angles);
|
||||
cam.Init(1, 1, (pDLight->m_fLightFrustumAngle*2)/180.0f*PI, pDLight->m_fRadius, 1.0f, 0.1f);
|
||||
cam.Update();
|
||||
|
||||
Vec3d vBoxMin,vBoxMax;
|
||||
pEntityRender->GetRenderBBox(vBoxMin,vBoxMax);
|
||||
if (!cam.IsAABBVisibleFast(AABB(vBoxMin,vBoxMax)))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Plane p;
|
||||
p.CalcPlane( pDLight->m_Origin, pDLight->m_Origin+pDLight->m_TextureMatrix.GetOrtY(), pDLight->m_Origin-pDLight->m_TextureMatrix.GetOrtZ() );
|
||||
if( p.DistFromPlane(vObjPos) + fObjRadius < 0 )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// find amount of light
|
||||
float fDist = GetDistance(pDLight->m_Origin,vObjPos);
|
||||
float fLightAmount = 1.f - (fDist-fObjRadius) / (pDLight->m_fRadius);
|
||||
fLightAmount *=
|
||||
(pDLight->m_Color.r+pDLight->m_Color.g+pDLight->m_Color.b)*0.333f +
|
||||
(pDLight->m_SpecColor.r+pDLight->m_SpecColor.g+pDLight->m_SpecColor.b)*0.333f;
|
||||
|
||||
if(fLightAmount>0.05f)
|
||||
{
|
||||
// if entity is inside some area - allow lightsources only from this area
|
||||
if(pEntityRender)
|
||||
if((pDLight->m_Flags & DLF_THIS_AREA_ONLY) /*|| (pDLight->m_Flags & DLF_SUN)*/)
|
||||
{
|
||||
if(pEntityRender->GetEntityVisArea() && pDLight->m_pOwner!=(IEntityRender*)-1)
|
||||
{
|
||||
if( pDLight->m_pOwner && pDLight->m_pOwner->GetEntityRS() && pDLight->m_pOwner->m_pVisArea)
|
||||
{
|
||||
CVisArea * pLightArea = pDLight->m_pOwner->m_pVisArea;
|
||||
if(pEntityRender->GetEntityVisArea() != pLightArea)
|
||||
{ // try also portal volumes
|
||||
bool bNearFound = pEntityRender->m_pVisArea->FindVisArea(pLightArea, 1, true);
|
||||
if(!bNearFound)
|
||||
continue; // areas do not much
|
||||
}
|
||||
}
|
||||
else
|
||||
continue; // outdoor lsource
|
||||
}
|
||||
else // entity is outside
|
||||
if( pDLight->m_pOwner && pDLight->m_pOwner!=(IEntityRender*)-1 && pDLight->m_pOwner->GetEntityVisArea() && pDLight->m_pOwner!=(IEntityRender*)-1)
|
||||
continue; // indoor lsource should not affect outdoor entity
|
||||
}
|
||||
|
||||
DLightAmount la;
|
||||
la.pDLight = pDLight;
|
||||
la.fAmount = fLightAmount;
|
||||
m_lstTmpDLA_MMFP.Add(la);
|
||||
}
|
||||
}
|
||||
|
||||
int nDLightMask = 0;
|
||||
|
||||
if(!m_lstTmpDLA_MMFP.Count())
|
||||
return 0; // no lsources found
|
||||
|
||||
// sort by light amount
|
||||
qsort(&m_lstTmpDLA_MMFP[0], m_lstTmpDLA_MMFP.Count(), sizeof(m_lstTmpDLA_MMFP[0]), C3DEngine__Cmp_LightAmount);
|
||||
|
||||
// limit number of affective light sources
|
||||
for(int n=0; n<nMaxLightBitsNum && n<GetCVars()->e_max_entity_lights && n<m_lstTmpDLA_MMFP.Count(); n++)
|
||||
{
|
||||
LightsSet::iterator itLightsSet = m_setActiveLights.find(m_lstTmpDLA_MMFP[n].pDLight);
|
||||
if(itLightsSet==m_setActiveLights.end())
|
||||
{
|
||||
GetRenderer()->EF_ADDDlight(m_lstTmpDLA_MMFP[n].pDLight);
|
||||
m_setActiveLights.insert(m_lstTmpDLA_MMFP[n].pDLight);
|
||||
}
|
||||
|
||||
const int nId = m_lstTmpDLA_MMFP[n].pDLight->m_Id;
|
||||
|
||||
nDLightMask |= (1<<nId);
|
||||
|
||||
if(pSelectedLights && n<nMaxSelectedLights)
|
||||
pSelectedLights[n] = m_lstTmpDLA_MMFP[n].pDLight;
|
||||
}
|
||||
|
||||
return nDLightMask;
|
||||
}
|
||||
|
||||
void CLightManager::ClearFrameLights()
|
||||
{
|
||||
m_setActiveLights.clear();
|
||||
}
|
||||
|
||||
const Vec3d &CLightEntity::GetPos(bool) const
|
||||
{
|
||||
return m_vPos;//m_pLight->m_Origin;
|
||||
}
|
||||
|
||||
const Vec3d &CLightEntity::GetAngles(int) const
|
||||
{
|
||||
return m_pLight->m_ProjAngles;
|
||||
}
|
||||
|
||||
void CLightEntity::GetRenderBBox(Vec3d &vMin,Vec3d &vMax)
|
||||
{
|
||||
vMin = m_pLight->m_Origin - Vec3d(m_pLight->m_fRadius,m_pLight->m_fRadius,m_pLight->m_fRadius);
|
||||
vMax = m_pLight->m_Origin + Vec3d(m_pLight->m_fRadius,m_pLight->m_fRadius,m_pLight->m_fRadius);
|
||||
}
|
||||
|
||||
float CLightEntity::GetRenderRadius(void) const
|
||||
{
|
||||
return m_pLight->m_fRadius;
|
||||
}
|
||||
|
||||
float CLightEntity::GetMaxViewDist()
|
||||
{
|
||||
return GetRenderRadius()*GetCVars()->e_obj_view_dist_ratio*GetViewDistRatioNormilized();
|
||||
}
|
||||
|
||||
CLightEntity::CLightEntity()
|
||||
{
|
||||
m_pEntityRenderState = Get3DEngine()->MakeEntityRenderState();
|
||||
m_vPos.Set(0,0,0);
|
||||
}
|
||||
|
||||
CLightEntity::~CLightEntity()
|
||||
{
|
||||
Get3DEngine()->FreeEntityRenderState(this);
|
||||
((C3DEngine*)Get3DEngine())->FreeLightSourceComponents(m_pLight);
|
||||
Get3DEngine()->UnRegisterEntity(this);
|
||||
((C3DEngine*)Get3DEngine())->RemoveEntityLightSources(this);
|
||||
delete m_pLight; m_pLight = NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user