1
0
forked from 0ad/0ad
0ad/source/simulation/LOSManager.cpp
Matei 0ed2815c8b 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.
2005-10-09 03:43:03 +00:00

170 lines
3.5 KiB
C++

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