1
0
forked from 0ad/0ad
0ad/source/simulation/LOSManager.cpp
janwas a1cddc4ac3 gameview, renderer: LoadWaterTextures is now a coroutine because it takes friggin forever (3 seconds). VFS performance is down by a factor of ten! investigating is on todo.
dyn_array.h -> allocators.h
ogl_tex: reenable performance warning
tex: comments
h_mgr: debug_printf if long filename is passed in (so we notice)
wsdl: squelch DestroyWindow warning. will look into the cause.
sysdep: slightly simplify "restrict" determination

This was SVN commit r2916.
2005-10-12 17:19:07 +00:00

167 lines
4.1 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"
#include "lib/allocators.h"
using namespace std;
CLOSManager::CLOSManager() : m_LOSSetting(0), m_Explored(0), m_Visible(0)
{
}
CLOSManager::~CLOSManager()
{
matrix_free((void**)m_Explored);
m_Explored = 0;
matrix_free((void**)m_Visible);
m_Visible = 0;
}
void CLOSManager::Initialize(uint losSetting)
{
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
int tilesPerSide = terrain->GetVerticesPerSide() - 1;
// Create the LOS data arrays
m_Explored = (int**)matrix_alloc(tilesPerSide, tilesPerSide, sizeof(int));
m_Visible = (int**)matrix_alloc(tilesPerSide, tilesPerSide, sizeof(int));
// TODO: This memory should be freed somewhere when the engine supports
// multiple sessions without restarting the program.
// JW: currently free it in the dtor
// 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();
// Set special LOS setting
m_LOSSetting = losSetting;
}
// 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)
{
// TODO: Make the mask depend on the player's diplomacy (just OR all his allies' masks)
int mask = (1 << player->GetPlayerID());
if((m_Visible[tx][tz] & mask) || m_LOSSetting == ALL_VISIBLE)
{
return LOS_VISIBLE;
}
else if((m_Explored[tx][tz] & mask) || m_LOSSetting == EXPLORED)
{
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)
{
// both actors (which are usually for decoration) and units with the
// permanent flag should be remembered
return UNIT_REMEMBERED;
// TODO: the unit status system will have to be replaced with a "ghost actor"
// system so that we can't remember units that we haven't seen and so we can
// see permanent units that have died but that we haven't been near lately
}
else
{
return UNIT_HIDDEN;
}
}
else
{
return UNIT_HIDDEN;
}
}