Added initial version of LOS, and updated minimap to show both LOS and water.
LOS issues still outstanding: - LOS looks ugly because of quad tesselation into 2 triangles - Quad tesselation is unspecified by OpenGL (in fact using GL_QUADS on LOS quads seemed to give different tesselations than it did for the underlying terrain quads, but terrain rendering also used GL_QUADS). This should be fixed once we decide on the quad tesselation issue. - Units with traits.vision.permanent set are visible through FOW even if you havent seen them before; this should only be true when you have seen them before. But it gets even more complicated - if a permanent unit seen through FOW dies or gets upgraded or something, perhaps you should remember the old version. I'm not completely sure how to do this (probably involves cloning its actor somehow). This was SVN commit r2876.
This commit is contained in:
parent
7ebdefec4b
commit
0ed2815c8b
@ -17,6 +17,8 @@
|
||||
#include "HFTracer.h"
|
||||
#include "TextureManager.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "LOSManager.h"
|
||||
#include "Bound.h"
|
||||
#include "Pyrogenesis.h"
|
||||
#include "Hotkey.h"
|
||||
#include "ConfigDB.h"
|
||||
@ -142,10 +144,6 @@ void CGameView::Render()
|
||||
PROFILE_START( "render models" );
|
||||
RenderModels(m_pWorld->GetUnitManager(), m_pWorld->GetProjectileManager());
|
||||
PROFILE_END( "render models" );
|
||||
MICROLOG(L"render water");
|
||||
PROFILE_START( "render water" );
|
||||
RenderWater(m_pWorld->GetTerrain());
|
||||
PROFILE_END( "render water" );
|
||||
}
|
||||
|
||||
void CGameView::RenderTerrain(CTerrain *pTerrain)
|
||||
@ -162,35 +160,43 @@ void CGameView::RenderTerrain(CTerrain *pTerrain)
|
||||
}
|
||||
}
|
||||
|
||||
void CGameView::RenderWater(CTerrain *pTerrain)
|
||||
{
|
||||
CFrustum frustum=m_Camera.GetFrustum();
|
||||
u32 patchesPerSide=pTerrain->GetPatchesPerSide();
|
||||
for (uint j=0; j<patchesPerSide; j++) {
|
||||
for (uint i=0; i<patchesPerSide; i++) {
|
||||
CPatch* patch=pTerrain->GetPatch(i,j);
|
||||
if (frustum.IsBoxVisible (CVector3D(0,0,0),patch->GetBounds())) {
|
||||
g_Renderer.SubmitWater(patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameView::RenderModels(CUnitManager *pUnitMan, CProjectileManager *pProjectileMan)
|
||||
{
|
||||
CFrustum frustum=m_Camera.GetFrustum();
|
||||
CLOSManager* losMgr = m_pWorld->GetLOSManager();
|
||||
|
||||
const std::vector<CUnit*>& units=pUnitMan->GetUnits();
|
||||
for (uint i=0;i<units.size();++i) {
|
||||
if (frustum.IsBoxVisible(CVector3D(0,0,0),units[i]->GetModel()->GetBounds())) {
|
||||
for (uint i=0;i<units.size();++i)
|
||||
{
|
||||
int status = losMgr->GetUnitStatus(units[i], g_Game->GetLocalPlayer());
|
||||
if (frustum.IsBoxVisible(CVector3D(0,0,0), units[i]->GetModel()->GetBounds())
|
||||
&& status != UNIT_HIDDEN)
|
||||
{
|
||||
CColor color;
|
||||
if(status == UNIT_VISIBLE)
|
||||
{
|
||||
color = CColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
else // status == UNIT_REMEMBERED
|
||||
{
|
||||
color = CColor(0.7f, 0.7f, 0.7f, 1.0f);
|
||||
}
|
||||
units[i]->GetModel()->SetShadingColor(color);
|
||||
|
||||
PROFILE( "submit models" );
|
||||
SubmitModelRecursive(units[i]->GetModel());
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<CProjectile*>& projectiles=pProjectileMan->GetProjectiles();
|
||||
for (uint i=0;i<projectiles.size();++i) {
|
||||
if (frustum.IsBoxVisible(CVector3D(0,0,0),projectiles[i]->GetModel()->GetBounds())) {
|
||||
for (uint i=0;i<projectiles.size();++i)
|
||||
{
|
||||
const CBound& bound = projectiles[i]->GetModel()->GetBounds();
|
||||
CVector3D centre;
|
||||
bound.GetCentre(centre);
|
||||
if (frustum.IsBoxVisible(CVector3D(0,0,0), bound)
|
||||
&& losMgr->GetStatus(centre.X, centre.Z, g_Game->GetLocalPlayer()) == LOS_VISIBLE)
|
||||
{
|
||||
PROFILE( "submit projectiles" );
|
||||
SubmitModelRecursive(projectiles[i]->GetModel());
|
||||
}
|
||||
|
@ -52,12 +52,8 @@ class CGameView: public CJSObject<CGameView>
|
||||
float m_ZoomDelta;
|
||||
|
||||
// RenderTerrain: iterate through all terrain patches and submit all patches
|
||||
// in viewing frustum to the renderer, for terrain painting
|
||||
// in viewing frustum to the renderer, for terrain, water and LOS painting
|
||||
void RenderTerrain(CTerrain *pTerrain);
|
||||
|
||||
// RenderWater: iterate through all terrain patches and submit all patches
|
||||
// in viewing frustum to the renderer, for water painting
|
||||
void RenderWater(CTerrain *pTerrain);
|
||||
|
||||
// RenderModels: iterate through model list and submit all models in viewing
|
||||
// frustum to the Renderer
|
||||
|
@ -164,6 +164,29 @@ CMiniPatch* CTerrain::GetTile(i32 x, i32 z)
|
||||
return &patch->m_MiniPatches[z%PATCH_SIZE][x%PATCH_SIZE];
|
||||
}
|
||||
|
||||
float CTerrain::getVertexGroundLevel(int x, int z) const
|
||||
{
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
else if (x >= (int) m_MapSize)
|
||||
{
|
||||
x = m_MapSize - 1;
|
||||
}
|
||||
|
||||
if (z < 0)
|
||||
{
|
||||
z = 0;
|
||||
}
|
||||
else if (z >= (int) m_MapSize)
|
||||
{
|
||||
z = m_MapSize - 1;
|
||||
}
|
||||
|
||||
return HEIGHT_SCALE * m_Heightmap[z*m_MapSize + x];
|
||||
}
|
||||
|
||||
float CTerrain::getExactGroundLevel(float x, float y) const
|
||||
{
|
||||
x /= (float)CELL_SIZE;
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
{
|
||||
return( ( v.x >= 0.0f ) && ( v.x <= (float)( m_MapSize * CELL_SIZE ) ) && ( v.y >= 0.0f ) && ( v.y <= (float)( m_MapSize * CELL_SIZE ) ) );
|
||||
}
|
||||
float getVertexGroundLevel( int x, int y ) const ;
|
||||
float getExactGroundLevel( float x, float y ) const ;
|
||||
inline float getExactGroundLevel( const CVector2D& v ) const { return( getExactGroundLevel( v.x, v.y ) ); }
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "CConsole.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "ObjectEntry.h"
|
||||
#include "LOSManager.h"
|
||||
|
||||
extern CConsole* g_Console;
|
||||
|
||||
@ -78,6 +79,8 @@ void CUnitManager::DeleteAll()
|
||||
// unit; return the closest unit, or null if everything missed
|
||||
CUnit* CUnitManager::PickUnit(const CVector3D& origin,const CVector3D& dir) const
|
||||
{
|
||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||
|
||||
// closest object found so far
|
||||
CUnit* hit = 0;
|
||||
// distance to closest object found so far
|
||||
@ -89,7 +92,8 @@ CUnit* CUnitManager::PickUnit(const CVector3D& origin,const CVector3D& dir) cons
|
||||
CUnit* unit=m_Units[i];
|
||||
float tmin,tmax;
|
||||
|
||||
if (unit->GetModel()->GetBounds().RayIntersect(origin,dir,tmin,tmax))
|
||||
if (unit->GetModel()->GetBounds().RayIntersect(origin,dir,tmin,tmax)
|
||||
&& losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
|
||||
{
|
||||
// Point of closest approach
|
||||
CVector3D obj;
|
||||
|
@ -11,9 +11,11 @@
|
||||
#include "graphics/Unit.h"
|
||||
#include "UnitManager.h"
|
||||
#include "Entity.h"
|
||||
|
||||
#include "Bound.h"
|
||||
#include "Model.h"
|
||||
#include "Terrain.h"
|
||||
#include "Profile.h"
|
||||
#include "LOSManager.h"
|
||||
|
||||
|
||||
|
||||
@ -22,11 +24,11 @@ extern int g_mouse_x, g_mouse_y;
|
||||
extern float g_MaxZoomHeight, g_YMinOffset;
|
||||
bool HasClicked=false;
|
||||
|
||||
static unsigned int ScaleColor(unsigned int color,float x)
|
||||
static unsigned int ScaleColor(unsigned int color, float x)
|
||||
{
|
||||
unsigned int r=uint(float(color & 0xff)*x);
|
||||
unsigned int g=uint(float((color>>8) & 0xff)*x);
|
||||
unsigned int b=uint(float((color>>16) & 0xff)*x);
|
||||
unsigned int r = uint(float(color & 0xff) * x);
|
||||
unsigned int g = uint(float((color>>8) & 0xff) * x);
|
||||
unsigned int b = uint(float((color>>16) & 0xff) * x);
|
||||
return (0xff000000 | r | g<<8 | b<<16);
|
||||
}
|
||||
|
||||
@ -63,6 +65,8 @@ void CMiniMap::Draw()
|
||||
if(!m_Handle)
|
||||
GenerateMiniMapTexture();
|
||||
|
||||
Rebuild();
|
||||
|
||||
g_Renderer.BindTexture(0, m_Handle);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
@ -93,6 +97,8 @@ void CMiniMap::Draw()
|
||||
CUnit *unit = NULL;
|
||||
CVector2D pos;
|
||||
|
||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
@ -102,13 +108,13 @@ void CMiniMap::Draw()
|
||||
for(; iter != units.end(); ++iter)
|
||||
{
|
||||
unit = (CUnit *)(*iter);
|
||||
if(unit && unit->GetEntity())
|
||||
if(unit && unit->GetEntity() && losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
|
||||
{
|
||||
CEntity* entity = unit->GetEntity();
|
||||
CStrW& type = entity->m_minimapType;
|
||||
|
||||
if(type==L"Unit" || type==L"Structure" || type==L"Hero") {
|
||||
// Set the player colour
|
||||
// Use the player colour
|
||||
const SPlayerColour& colour = unit->GetEntity()->GetPlayer()->GetColour();
|
||||
glColor3f(colour.r, colour.g, colour.b);
|
||||
}
|
||||
@ -278,6 +284,11 @@ void CMiniMap::GenerateMiniMapTexture()
|
||||
|
||||
void CMiniMap::Rebuild()
|
||||
{
|
||||
PROFILE_START("rebuild minimap");
|
||||
|
||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||
CPlayer* player = g_Game->GetLocalPlayer();
|
||||
|
||||
u32 mapSize = m_Terrain->GetVerticesPerSide();
|
||||
u32 x = 0;
|
||||
u32 y = 0;
|
||||
@ -289,23 +300,55 @@ void CMiniMap::Rebuild()
|
||||
u32 *dataPtr = m_Data + ((y + j) * (mapSize - 1)) + x;
|
||||
for(u32 i = 0; i < w; i++)
|
||||
{
|
||||
int hmap = ((int)m_Terrain->GetHeightMap()[(y + j) * mapSize + x + i]) >> 8;
|
||||
int val = (hmap / 3) + 170;
|
||||
CMiniPatch *mp = m_Terrain->GetTile(x + i, y + j);
|
||||
u32 color = 0;
|
||||
if(mp)
|
||||
ELOSStatus status = losMgr->GetStatus((int) i, (int) j, player);
|
||||
if(status == LOS_UNEXPLORED)
|
||||
{
|
||||
CTextureEntry *tex = mp->Tex1 ? g_TexMan.FindTexture(mp->Tex1) : 0;
|
||||
color = tex ? tex->GetBaseColor() : 0xffffffff;
|
||||
*dataPtr++ = 0xff000000;
|
||||
}
|
||||
else
|
||||
color = 0xffffffff;
|
||||
{
|
||||
u32 color = 0;
|
||||
|
||||
float avgHeight = ( m_Terrain->getVertexGroundLevel((int)i, (int)j)
|
||||
+ m_Terrain->getVertexGroundLevel((int)i+1, (int)j)
|
||||
+ m_Terrain->getVertexGroundLevel((int)i, (int)j+1)
|
||||
+ m_Terrain->getVertexGroundLevel((int)i+1, (int)j+1)
|
||||
) / 4.0f;
|
||||
|
||||
if(avgHeight < g_Renderer.m_WaterHeight)
|
||||
{
|
||||
color = 0xff304080;
|
||||
}
|
||||
else
|
||||
{
|
||||
int hmap = ((int)m_Terrain->GetHeightMap()[(y + j) * mapSize + x + i]) >> 8;
|
||||
int val = (hmap / 3) + 170;
|
||||
|
||||
CMiniPatch *mp = m_Terrain->GetTile(x + i, y + j);
|
||||
if(mp)
|
||||
{
|
||||
CTextureEntry *tex = mp->Tex1 ? g_TexMan.FindTexture(mp->Tex1) : 0;
|
||||
color = tex ? tex->GetBaseColor() : 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = 0xffffffff;
|
||||
}
|
||||
|
||||
color = ScaleColor(color, float(val) / 255.0f);
|
||||
}
|
||||
|
||||
float losFactor = (status==LOS_VISIBLE ? 1.0f : 0.7f);
|
||||
|
||||
*dataPtr++ = ScaleColor(color, losFactor);
|
||||
}
|
||||
|
||||
*dataPtr++ = ScaleColor(color, ((float)val) / 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
UploadTexture();
|
||||
|
||||
PROFILE_END("rebuild minimap");
|
||||
}
|
||||
|
||||
void CMiniMap::UploadTexture()
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "UnitManager.h"
|
||||
#include "EntityManager.h"
|
||||
#include "Projectile.h"
|
||||
#include "LOSManager.h"
|
||||
|
||||
#define LOG_CATEGORY "world"
|
||||
|
||||
@ -32,7 +33,8 @@ CWorld::CWorld(CGame *pGame):
|
||||
m_Terrain(),
|
||||
m_UnitManager(g_UnitMan),
|
||||
m_EntityManager(*(new CEntityManager())),
|
||||
m_ProjectileManager(*(new CProjectileManager()))
|
||||
m_ProjectileManager(*(new CProjectileManager())),
|
||||
m_LOSManager(*(new CLOSManager()))
|
||||
{}
|
||||
|
||||
void CWorld::Initialize(CGameAttributes *pAttribs)
|
||||
|
@ -8,6 +8,7 @@ class CGameAttributes;
|
||||
class CUnitManager;
|
||||
class CEntityManager;
|
||||
class CProjectileManager;
|
||||
class CLOSManager;
|
||||
|
||||
class CWorld
|
||||
{
|
||||
@ -20,6 +21,7 @@ class CWorld
|
||||
CUnitManager &m_UnitManager;
|
||||
CEntityManager &m_EntityManager;
|
||||
CProjectileManager &m_ProjectileManager;
|
||||
CLOSManager &m_LOSManager;
|
||||
|
||||
public:
|
||||
CWorld(CGame *pGame);
|
||||
@ -38,8 +40,12 @@ public:
|
||||
{ return &m_Terrain; }
|
||||
inline CUnitManager *GetUnitManager()
|
||||
{ return &m_UnitManager; }
|
||||
inline CEntityManager *GetEntityManager()
|
||||
{ return &m_EntityManager; }
|
||||
inline CProjectileManager *GetProjectileManager()
|
||||
{ return &m_ProjectileManager; }
|
||||
inline CLOSManager *GetLOSManager()
|
||||
{ return &m_LOSManager; }
|
||||
|
||||
private:
|
||||
// squelch "unable to generate" warnings
|
||||
|
@ -31,6 +31,10 @@
|
||||
#include "CLogger.h"
|
||||
#include "ps/Game.h"
|
||||
#include "Profile.h"
|
||||
#include "Game.h"
|
||||
#include "World.h"
|
||||
#include "Player.h"
|
||||
#include "LOSManager.h"
|
||||
|
||||
#include "Model.h"
|
||||
#include "ModelDef.h"
|
||||
@ -814,6 +818,8 @@ void CRenderer::ApplyShadowMap()
|
||||
|
||||
void CRenderer::RenderPatches()
|
||||
{
|
||||
//return; //TODO: remove this, lol
|
||||
|
||||
PROFILE(" render patches ");
|
||||
|
||||
// switch on wireframe if we need it
|
||||
@ -918,24 +924,22 @@ void CRenderer::RenderWater()
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
for(size_t i=0; i<m_WaterPatches.size(); i++)
|
||||
for(size_t i=0; i<m_VisiblePatches.size(); i++)
|
||||
{
|
||||
CPatch* patch = m_WaterPatches[i];
|
||||
CPatch* patch = m_VisiblePatches[i];
|
||||
|
||||
for(int dx=0; dx<PATCH_SIZE; dx++)
|
||||
{
|
||||
for(int dz=0; dz<PATCH_SIZE; dz++)
|
||||
{
|
||||
int x = (patch->m_X*PATCH_SIZE + dx) * CELL_SIZE;
|
||||
int z = (patch->m_Z*PATCH_SIZE + dz) * CELL_SIZE;
|
||||
int x = (patch->m_X*PATCH_SIZE + dx);
|
||||
int z = (patch->m_Z*PATCH_SIZE + dz);
|
||||
|
||||
// is any corner of the tile below the water height? if not, no point rendering it
|
||||
bool shouldRender = false;
|
||||
for(int j=0; j<4; j++)
|
||||
{
|
||||
float vertX = x + DX[j]*CELL_SIZE;
|
||||
float vertZ = z + DZ[j]*CELL_SIZE;
|
||||
float terrainHeight = terrain->getExactGroundLevel(vertX, vertZ);
|
||||
float terrainHeight = terrain->getVertexGroundLevel(x + DX[j], z + DZ[j]);
|
||||
if(terrainHeight < m_WaterHeight)
|
||||
{
|
||||
shouldRender = true;
|
||||
@ -949,9 +953,9 @@ void CRenderer::RenderWater()
|
||||
|
||||
for(int j=0; j<4; j++)
|
||||
{
|
||||
float vertX = x + DX[j]*CELL_SIZE;
|
||||
float vertZ = z + DZ[j]*CELL_SIZE;
|
||||
float terrainHeight = terrain->getExactGroundLevel(vertX, vertZ);
|
||||
float vertX = (x + DX[j]) * CELL_SIZE;
|
||||
float vertZ = (z + DZ[j]) * CELL_SIZE;
|
||||
float terrainHeight = terrain->getVertexGroundLevel(x + DX[j], z + DZ[j]);
|
||||
float alpha = clamp((m_WaterHeight - terrainHeight) / m_WaterFullDepth + m_WaterAlphaOffset,
|
||||
-100.0f, m_WaterMaxAlpha);
|
||||
glColor4f(m_WaterColor.r, m_WaterColor.g, m_WaterColor.b, alpha);
|
||||
@ -964,40 +968,6 @@ void CRenderer::RenderWater()
|
||||
|
||||
glEnd();
|
||||
|
||||
/*
|
||||
//Don't add of we don't need to
|
||||
if (m_WaterScroll == true)
|
||||
{
|
||||
m_SWaterScrollCounter+=get_time();
|
||||
m_TWaterScrollCounter+=get_time();
|
||||
|
||||
if(m_SWaterScrollCounter >=.02)
|
||||
{
|
||||
m_SWaterScrollCounter=0;
|
||||
m_SWaterTrans+=m_SWaterSpeed;
|
||||
}
|
||||
|
||||
if(m_TWaterScrollCounter >=.02)
|
||||
{
|
||||
m_TWaterScrollCounter=0;
|
||||
m_TWaterTrans+=m_TWaterSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
//--------Reset counters--------
|
||||
//will someone play this long though?
|
||||
|
||||
if(m_SWaterTrans >= 4)
|
||||
{
|
||||
m_SWaterTrans=0;
|
||||
}
|
||||
|
||||
if(m_TWaterTrans >= 4)
|
||||
{
|
||||
m_TWaterTrans=0;
|
||||
}*/
|
||||
|
||||
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
@ -1006,6 +976,76 @@ void CRenderer::RenderWater()
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void CRenderer::RenderLOS()
|
||||
{
|
||||
PROFILE(" render los ");
|
||||
|
||||
const int DX[] = {1,1,0,0};
|
||||
const int DZ[] = {0,1,1,0};
|
||||
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
||||
|
||||
int mapSize = terrain->GetVerticesPerSide();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
|
||||
for(size_t i=0; i<m_VisiblePatches.size(); i++)
|
||||
{
|
||||
CPatch* patch = m_VisiblePatches[i];
|
||||
|
||||
for(int dx=0; dx<PATCH_SIZE; dx++)
|
||||
{
|
||||
for(int dz=0; dz<PATCH_SIZE; dz++)
|
||||
{
|
||||
int x = patch->m_X*PATCH_SIZE + dx;
|
||||
int z = patch->m_Z*PATCH_SIZE + dz;
|
||||
|
||||
// UGLY: This assumes that quads are always split up into triangles in this particular order;
|
||||
// this happens to be true on Matei's GeforceFX 5200, but it's undefined by OpenGL; using
|
||||
// GL_QUADS *didn't* work even though the terrain renderer uses GL_QUADS so there's something
|
||||
// wierd going on.
|
||||
const int INDICES[6] = {0,1,3, 1,2,3};
|
||||
|
||||
for(int j=0; j<6; j++)
|
||||
{
|
||||
int vx = x + DX[INDICES[j]];
|
||||
int vz = z + DZ[INDICES[j]];
|
||||
|
||||
float terrainHeight = terrain->getVertexGroundLevel(vx, vz);
|
||||
|
||||
float alpha = 0.0f;
|
||||
|
||||
for(int k=0; k<4; k++)
|
||||
{
|
||||
int tx = vx - DX[k];
|
||||
int tz = vz - DZ[k];
|
||||
|
||||
if(tx >= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2)
|
||||
{
|
||||
ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer());
|
||||
if(s==LOS_EXPLORED && alpha < 0.3f)
|
||||
alpha = 0.25f;
|
||||
else if(s==LOS_UNEXPLORED && alpha < 1.0f)
|
||||
alpha = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
glColor4f(0, 0, 0, alpha);
|
||||
glVertex3f(vx*CELL_SIZE, terrainHeight, vz*CELL_SIZE);
|
||||
}
|
||||
} //end of x loop
|
||||
} //end of z loop
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void CRenderer::RenderModelSubmissions()
|
||||
{
|
||||
@ -1148,13 +1188,18 @@ void CRenderer::FlushFrame()
|
||||
RenderWater();
|
||||
oglCheck();
|
||||
|
||||
// render darkness/fog due to LOS, above the actual terrain
|
||||
MICROLOG(L"render los");
|
||||
RenderLOS();
|
||||
oglCheck();
|
||||
|
||||
// empty lists
|
||||
MICROLOG(L"empty lists");
|
||||
g_TransparencyRenderer.Clear();
|
||||
g_PlayerRenderer.Clear();
|
||||
CPatchRData::ClearSubmissions();
|
||||
CModelRData::ClearSubmissions();
|
||||
m_WaterPatches.clear();
|
||||
m_VisiblePatches.clear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1203,11 +1248,7 @@ void CRenderer::SetViewport(const SViewPort &vp)
|
||||
void CRenderer::Submit(CPatch* patch)
|
||||
{
|
||||
CPatchRData::Submit(patch);
|
||||
}
|
||||
|
||||
void CRenderer::SubmitWater(CPatch* patch)
|
||||
{
|
||||
m_WaterPatches.push_back(patch);
|
||||
m_VisiblePatches.push_back(patch);
|
||||
}
|
||||
|
||||
void CRenderer::Submit(CModel* model)
|
||||
|
@ -76,7 +76,7 @@ struct SVertex2D
|
||||
class CRenderer : public Singleton<CRenderer>
|
||||
{
|
||||
private:
|
||||
std::vector<CPatch*> m_WaterPatches;
|
||||
std::vector<CPatch*> m_VisiblePatches;
|
||||
|
||||
public:
|
||||
Handle m_WaterTexture[60];
|
||||
@ -198,7 +198,6 @@ public:
|
||||
// submission of objects for rendering; the passed matrix indicating the transform must be scoped such that it is valid beyond
|
||||
// the call to frame end, as must the object itself
|
||||
void Submit(CPatch* patch);
|
||||
void SubmitWater(CPatch* patch);
|
||||
void Submit(CModel* model);
|
||||
void Submit(CSprite* sprite);
|
||||
void Submit(CParticleSys* psys);
|
||||
@ -266,7 +265,8 @@ protected:
|
||||
// patch rendering stuff
|
||||
void RenderPatchSubmissions();
|
||||
void RenderPatches();
|
||||
void RenderWater();
|
||||
void RenderWater(); // should this and RenderLOS be moved into the terrain renderer?
|
||||
void RenderLOS();
|
||||
|
||||
// model rendering stuff
|
||||
void RenderModelSubmissions();
|
||||
|
@ -13,10 +13,14 @@ IEventTarget::~IEventTarget()
|
||||
|
||||
bool IEventTarget::_DispatchEvent( CScriptEvent* evt, IEventTarget* target )
|
||||
{
|
||||
PROFILE_START( "_DispatchEvent" );
|
||||
|
||||
// TODO: Deal correctly with multiple handlers
|
||||
|
||||
if( before && before->_DispatchEvent( evt, target ) )
|
||||
{
|
||||
return( true ); // Stop propagation.
|
||||
}
|
||||
|
||||
evt->m_CurrentTarget = this;
|
||||
|
||||
@ -25,7 +29,9 @@ bool IEventTarget::_DispatchEvent( CScriptEvent* evt, IEventTarget* target )
|
||||
{
|
||||
DOMEventHandler id = *it;
|
||||
if( id && id->DispatchEvent( GetScriptExecContext( target ), evt ) )
|
||||
{
|
||||
return( true );
|
||||
}
|
||||
}
|
||||
|
||||
HandlerRange range = m_Handlers_name.equal_range( evt->m_Type );
|
||||
@ -34,20 +40,29 @@ bool IEventTarget::_DispatchEvent( CScriptEvent* evt, IEventTarget* target )
|
||||
{
|
||||
DOMEventHandler id = itm->second;
|
||||
if( id && id->DispatchEvent( GetScriptExecContext( target ), evt ) )
|
||||
{
|
||||
return( true );
|
||||
}
|
||||
}
|
||||
|
||||
if( after && after->_DispatchEvent( evt, target ) )
|
||||
{
|
||||
return( true ); // Stop propagation.
|
||||
}
|
||||
|
||||
return( false );
|
||||
|
||||
PROFILE_END( "_DispatchEvent" );
|
||||
}
|
||||
|
||||
// Dispatch an event to its handler.
|
||||
// returns: whether the event arrived (i.e. wasn't cancelled) [bool]
|
||||
bool IEventTarget::DispatchEvent( CScriptEvent* evt )
|
||||
{
|
||||
const char* data = g_Profiler.InternString( "script: " + (CStr8)evt->m_Type );
|
||||
char* data;
|
||||
PROFILE_START( "intern string" );
|
||||
data = (char*) g_Profiler.InternString( "script: " + (CStr8)evt->m_Type );
|
||||
PROFILE_END( "intern string" );
|
||||
g_Profiler.StartScript( data );
|
||||
evt->m_Target = this;
|
||||
_DispatchEvent( evt, this );
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include "GameEvents.h"
|
||||
#include "Interact.h"
|
||||
#include "Renderer.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "LOSManager.h"
|
||||
#include "Network/Server.h"
|
||||
#include "Network/Client.h"
|
||||
#include "gui/CGUI.h"
|
||||
@ -864,6 +864,29 @@ JSBool setWaterAlphaOffset( JSContext* cx, JSObject* UNUSED(globalObject), uint
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
// Reveal map
|
||||
JSBool revealMap( JSContext* cx, JSObject* UNUSED(globalObject), uint argc, jsval* argv, jsval* rval )
|
||||
{
|
||||
REQUIRE_MIN_PARAMS( 0, revealMap );
|
||||
REQUIRE_MAX_PARAMS( 1, revealMap );
|
||||
|
||||
bool newValue;
|
||||
if(argc == 0)
|
||||
{
|
||||
newValue = true;
|
||||
}
|
||||
else if(!ToPrimitive( g_ScriptingHost.GetContext(), argv[0], newValue ))
|
||||
{
|
||||
JS_ReportError( cx, "Invalid boolean argument" );
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_FALSE );
|
||||
}
|
||||
|
||||
g_Game->GetWorld()->GetLOSManager()->m_MapRevealed = newValue;
|
||||
*rval = JSVAL_VOID;
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// function table
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -938,6 +961,7 @@ JSFunctionSpec ScriptFunctionTable[] =
|
||||
// Debug
|
||||
JS_FUNC(crash, crash, 0)
|
||||
JS_FUNC(forceGC, forceGC, 0)
|
||||
JS_FUNC(revealMap, revealMap, 1)
|
||||
|
||||
// Misc. Engine Interface
|
||||
JS_FUNC(writeLog, WriteLog, 1)
|
||||
|
@ -34,6 +34,8 @@ CBaseEntity::CBaseEntity()
|
||||
AddProperty( L"traits.minimap.green", &m_minimapG );
|
||||
AddProperty( L"traits.minimap.blue", &m_minimapB );
|
||||
AddProperty( L"traits.anchor.type", &m_anchorType );
|
||||
AddProperty( L"traits.vision.los", &m_los );
|
||||
AddProperty( L"traits.vision.permanent", &m_permanent );
|
||||
|
||||
for( int t = 0; t < EVENT_LAST; t++ )
|
||||
{
|
||||
|
@ -70,6 +70,10 @@ public:
|
||||
// Y anchor
|
||||
CStrW m_anchorType;
|
||||
|
||||
// LOS
|
||||
int m_los;
|
||||
bool m_permanent;
|
||||
|
||||
float m_speed;
|
||||
SEntityAction m_melee;
|
||||
SEntityAction m_gather;
|
||||
|
@ -60,6 +60,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
AddProperty( L"traits.minimap.green", &m_minimapG );
|
||||
AddProperty( L"traits.minimap.blue", &m_minimapB );
|
||||
AddProperty( L"traits.anchor.type", &m_anchorType );
|
||||
AddProperty( L"traits.vision.los", &m_los );
|
||||
AddProperty( L"traits.vision.permanent", &m_permanent );
|
||||
|
||||
for( int t = 0; t < EVENT_LAST; t++ )
|
||||
{
|
||||
@ -799,9 +801,10 @@ void CEntity::renderHealthBar()
|
||||
CCamera &g_Camera=*g_Game->GetView()->GetCamera();
|
||||
|
||||
float sx, sy;
|
||||
CVector3D pos = m_graphics_position;
|
||||
CVector3D above = pos;
|
||||
above.Y += m_healthBarHeight;
|
||||
CVector3D above;
|
||||
above.X = m_position.X;
|
||||
above.Z = m_position.Z;
|
||||
above.Y = getAnchorLevel(m_position.X, m_position.Z) + m_healthBarHeight;
|
||||
g_Camera.GetScreenCoordinates(above, sx, sy);
|
||||
float fraction = clamp(m_healthCurr / m_healthMax, 0.0f, 1.0f);
|
||||
|
||||
|
@ -92,6 +92,10 @@ public:
|
||||
// Y anchor
|
||||
CStrW m_anchorType;
|
||||
|
||||
// LOS
|
||||
int m_los;
|
||||
bool m_permanent;
|
||||
|
||||
//-- Interpolated property
|
||||
CVector3D m_position;
|
||||
CVector3D m_position_previous;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "EntityManager.h"
|
||||
#include "BaseEntityCollection.h"
|
||||
#include "ConfigDB.h"
|
||||
#include "Profile.h"
|
||||
|
||||
int SELECTION_CIRCLE_POINTS;
|
||||
int SELECTION_BOX_POINTS;
|
||||
@ -135,16 +136,23 @@ void CEntityManager::TickAll()
|
||||
|
||||
void CEntityManager::updateAll( size_t timestep )
|
||||
{
|
||||
PROFILE_START( "reaper" );
|
||||
std::vector<CEntity*>::iterator it;
|
||||
for( it = m_reaper.begin(); it < m_reaper.end(); it++ )
|
||||
delete( *it );
|
||||
m_reaper.clear();
|
||||
PROFILE_END( "reaper" );
|
||||
|
||||
PROFILE_START( "tick all" );
|
||||
TickAll();
|
||||
PROFILE_END( "tick all" );
|
||||
|
||||
|
||||
PROFILE_START( "update all" );
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
m_entities[i].m_entity->update( timestep );
|
||||
PROFILE_END( "update all" );
|
||||
}
|
||||
|
||||
void CEntityManager::interpolateAll( float relativeoffset )
|
||||
|
169
source/simulation/LOSManager.cpp
Normal file
169
source/simulation/LOSManager.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "LOSManager.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Player.h"
|
||||
#include "Terrain.h"
|
||||
#include "Entity.h"
|
||||
#include "EntityManager.h"
|
||||
#include "Unit.h"
|
||||
#include "Bound.h"
|
||||
#include "Model.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLOSManager::CLOSManager()
|
||||
{
|
||||
m_MapRevealed = false;
|
||||
}
|
||||
|
||||
CLOSManager::~CLOSManager()
|
||||
{
|
||||
}
|
||||
|
||||
void CLOSManager::Initialize()
|
||||
{
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
int tilesPerSide = terrain->GetVerticesPerSide() - 1;
|
||||
|
||||
// Create the LOS data arrays
|
||||
|
||||
m_Explored = new int*[tilesPerSide];
|
||||
for(int i=0; i<tilesPerSide; i++)
|
||||
{
|
||||
m_Explored[i] = new int[tilesPerSide];
|
||||
}
|
||||
|
||||
m_Visible = new int*[tilesPerSide];
|
||||
for(int i=0; i<tilesPerSide; i++)
|
||||
{
|
||||
m_Visible[i] = new int[tilesPerSide];
|
||||
}
|
||||
|
||||
// TODO: This memory should be freed somewhere when the engine supports
|
||||
// multiple sessions without restarting the program.
|
||||
|
||||
// Clear everything to unexplored
|
||||
for(int x=0; x<tilesPerSide; x++)
|
||||
{
|
||||
memset(m_Explored[x], 0, tilesPerSide*sizeof(int));
|
||||
}
|
||||
|
||||
// Just Update() to set the visible array and also mark currently visible tiles as explored.
|
||||
// NOTE: this will have to be changed if we decide to use incremental LOS
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
// NOTE: this will have to be changed if we decide to use incremental LOS
|
||||
void CLOSManager::Update()
|
||||
{
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
int tilesPerSide = terrain->GetVerticesPerSide() - 1;
|
||||
|
||||
// Clear the visible array
|
||||
for(int x=0; x<tilesPerSide; x++)
|
||||
{
|
||||
memset(m_Visible[x], 0, tilesPerSide*sizeof(int));
|
||||
}
|
||||
|
||||
// Set visibility for each entity
|
||||
vector<CEntity*> extant;
|
||||
g_Game->GetWorld()->GetEntityManager()->GetExtant(extant);
|
||||
for(size_t i=0; i<extant.size(); i++)
|
||||
{
|
||||
CEntity* e = extant[i];
|
||||
|
||||
int los = e->m_los;
|
||||
if(los == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int mask = (1 << e->GetPlayer()->GetPlayerID());
|
||||
|
||||
int cx = min(int(e->m_position.X/CELL_SIZE), tilesPerSide-1);
|
||||
int cz = min(int(e->m_position.Z/CELL_SIZE), tilesPerSide-1);
|
||||
|
||||
int minX = max(cx-los, 0);
|
||||
int minZ = max(cz-los, 0);
|
||||
int maxX = min(cx+los, tilesPerSide-1);
|
||||
int maxZ = min(cz+los, tilesPerSide-1);
|
||||
|
||||
for(int x=minX; x<=maxX; x++)
|
||||
{
|
||||
for(int z=minZ; z<=maxZ; z++)
|
||||
{
|
||||
if((x-cx)*(x-cx) + (z-cz)*(z-cz) <= los*los)
|
||||
{
|
||||
m_Visible[x][z] |= mask;
|
||||
m_Explored[x][z] |= mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ELOSStatus CLOSManager::GetStatus(int tx, int tz, CPlayer* player)
|
||||
{
|
||||
int mask = (1 << player->GetPlayerID());
|
||||
|
||||
if(m_MapRevealed)
|
||||
{
|
||||
return LOS_VISIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_Visible[tx][tz] & mask)
|
||||
{
|
||||
return LOS_VISIBLE;
|
||||
}
|
||||
else if(m_Explored[tx][tz] & mask)
|
||||
{
|
||||
return LOS_EXPLORED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return LOS_UNEXPLORED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ELOSStatus CLOSManager::GetStatus(float fx, float fz, CPlayer* player)
|
||||
{
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
int tilesPerSide = terrain->GetVerticesPerSide() - 1;
|
||||
|
||||
int ix = min(int(fx/CELL_SIZE), tilesPerSide-1);
|
||||
int iz = min(int(fz/CELL_SIZE), tilesPerSide-1);
|
||||
return GetStatus(ix, iz, player);
|
||||
}
|
||||
|
||||
EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player)
|
||||
{
|
||||
CVector3D centre;
|
||||
unit->GetModel()->GetBounds().GetCentre(centre);
|
||||
ELOSStatus status = GetStatus(centre.X, centre.Z, player);
|
||||
if(status == LOS_VISIBLE)
|
||||
{
|
||||
return UNIT_VISIBLE;
|
||||
}
|
||||
else if(status == LOS_EXPLORED)
|
||||
{
|
||||
if(unit->GetEntity() != 0 && unit->GetEntity()->m_permanent)
|
||||
{
|
||||
return UNIT_REMEMBERED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return UNIT_HIDDEN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return UNIT_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
|
63
source/simulation/LOSManager.h
Normal file
63
source/simulation/LOSManager.h
Normal file
@ -0,0 +1,63 @@
|
||||
// LOSManager.h
|
||||
//
|
||||
// Matei Zaharia matei@sprint.ca / matei@wildfiregames.com
|
||||
//
|
||||
// Maintains and updates line of sight data (including Shroud of Darkness
|
||||
// and Fog of War).
|
||||
//
|
||||
// Usage: Doesn't do anything useful right now.
|
||||
|
||||
|
||||
#ifndef LOS_MANAGER_INCLUDED
|
||||
#define LOS_MANAGER_INCLUDED
|
||||
|
||||
#include "Singleton.h"
|
||||
#include "Game.h"
|
||||
#include "World.h"
|
||||
#include "Player.h"
|
||||
|
||||
class CUnit;
|
||||
class CPlayer;
|
||||
|
||||
enum ELOSStatus
|
||||
{
|
||||
LOS_VISIBLE = 2, // tile is currently in LOS of one of the player's units
|
||||
LOS_EXPLORED = 1, // tile was explored before but is now in Fog of War
|
||||
LOS_UNEXPLORED = 0 // tile is unexplored and therefore in Shroud of Darkness
|
||||
};
|
||||
|
||||
enum EUnitLOSStatus
|
||||
{
|
||||
UNIT_VISIBLE = 2, // unit is in LOS of one of the player's units
|
||||
UNIT_REMEMBERED = 1, // unit was seen before and is permanent but is no longer in LOS
|
||||
UNIT_HIDDEN = 0 // unit is either not permanent or was never seen before
|
||||
};
|
||||
|
||||
class CLOSManager : public Singleton<CLOSManager>
|
||||
{
|
||||
int** m_Explored; // (m_Explored[x][z] & (1<<p) says whether player p has explored tile (x,z),
|
||||
// i.e. has removed Shroud of Darkness from it.
|
||||
int** m_Visible; // (m_Visible[x][z] & (1<<p)) says whether player p currently sees tile (x,z).
|
||||
// NOTE: This will have to be changed to a 3D array where each element stores the number of units
|
||||
// of a certain player that can see a certain tile if we want to use incremental LOS.
|
||||
|
||||
public:
|
||||
bool m_MapRevealed; // Set to true to ignore LOS
|
||||
|
||||
CLOSManager();
|
||||
~CLOSManager();
|
||||
|
||||
void Initialize();
|
||||
void Update();
|
||||
|
||||
// Get LOS status for a tile (in tile coordinates)
|
||||
ELOSStatus GetStatus(int tx, int tz, CPlayer* player);
|
||||
|
||||
// Get LOS status for a point (in game coordinates)
|
||||
ELOSStatus GetStatus(float fx, float fz, CPlayer* player);
|
||||
|
||||
// Returns whether a given entity is visible to the given player
|
||||
EUnitLOSStatus GetUnitStatus(CUnit* unit, CPlayer* player);
|
||||
};
|
||||
|
||||
#endif
|
@ -16,6 +16,7 @@
|
||||
#include "CConsole.h"
|
||||
#include "Unit.h"
|
||||
#include "Model.h"
|
||||
#include "LOSManager.h"
|
||||
#include "Loader.h"
|
||||
#include "LoaderThunks.h"
|
||||
|
||||
@ -43,6 +44,9 @@ int CSimulation::Initialize(CGameAttributes* UNUSED(pAttribs))
|
||||
m_pTurnManager->Initialize(m_pGame->GetNumPlayers());
|
||||
|
||||
g_EntityManager.InitializeAll();
|
||||
|
||||
m_pWorld->GetLOSManager()->Initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -117,6 +121,10 @@ void CSimulation::Simulate()
|
||||
g_ProjectileManager.UpdateAll( m_pTurnManager->GetTurnLength() );
|
||||
PROFILE_END( "projectile updates" );
|
||||
|
||||
PROFILE_START( "los update" );
|
||||
m_pWorld->GetLOSManager()->Update();
|
||||
PROFILE_END( "los update" );
|
||||
|
||||
PROFILE_START( "turn manager update" );
|
||||
m_pTurnManager->NewTurn();
|
||||
m_pTurnManager->IterateBatch(0, TranslateMessage, this);
|
||||
|
Loading…
Reference in New Issue
Block a user