1
0
forked from 0ad/0ad

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:
Matei 2005-10-09 03:43:03 +00:00
parent 7ebdefec4b
commit 0ed2815c8b
20 changed files with 525 additions and 103 deletions

View File

@ -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());
}

View File

@ -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

View File

@ -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;

View File

@ -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 ) ); }

View File

@ -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;

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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();

View File

@ -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 );

View File

@ -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)

View File

@ -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++ )
{

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 )

View 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;
}
}

View 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

View File

@ -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);