1
0
forked from 0ad/0ad

Sped up territory border rendering by caching each edge segment's terrain-conformed coordinates so they don't have to be recalculated each frame.

This was SVN commit r4308.
This commit is contained in:
Matei 2006-09-08 16:03:18 +00:00
parent 6db054f7dd
commit f8bff91a38
2 changed files with 82 additions and 51 deletions

View File

@ -234,36 +234,11 @@ void CTerritoryManager::renderTerritories()
glLineWidth(1.5f);
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
const CTerrain* pTerrain = g_Game->GetWorld()->GetTerrain();
CFrustum frustum = g_Game->GetView()->GetCamera()->GetFrustum();
std::vector<CTerritory*>::iterator terr=m_Territories.begin();
for ( ; terr != m_Territories.end(); ++terr )
{
if ((*terr)->boundary.empty())
continue;
// Tweak the boundary to shift all edges "inwards" by 0.3 units towards the territory's centre,
// so that boundaries for adjacent territories don't overlap
std::vector<CVector2D> boundary = (*terr)->boundary;
for ( size_t i=0; i<boundary.size(); i++ )
{
size_t prevI = (i+boundary.size()-1) % boundary.size();
size_t nextI = (i+1) % boundary.size();
// Figure out the direction perpendicular to each of the two edges that meet at this point.
CVector2D dir1 = ((*terr)->boundary[i]-(*terr)->boundary[prevI]).beta().normalize();
CVector2D dir2 = ((*terr)->boundary[nextI]-(*terr)->boundary[i]).beta().normalize();
// If you draw a picture of what our point looks like and what the two lines 0.3 units
// away from it look like, and draw a line between our point and that one as well as
// drop perpendicular lines from it to the original edges, you get this formula for the
// length and direction we have to be moved.
float angle = acosf(dir1.dot(dir2));
boundary[i] += (dir1 + dir2).normalize() * 0.3f / cosf(angle/2);
}
float r, g, b;
if ( (*terr)->owner->GetPlayerID() == 0 )
@ -282,39 +257,27 @@ void CTerritoryManager::renderTerritories()
b = col.b;
}
for ( std::vector<CVector2D>::iterator it = boundary.begin(); it != boundary.end(); it++ )
for ( size_t edge=0; edge < (*terr)->boundary.size(); edge++ )
{
std::vector<CVector2D>::iterator it2 = it + 1;
if( it2 == boundary.end() ) // loop around if we are at the last vertex
it2 = boundary.begin();
CVector3D start(it->x, pTerrain->getExactGroundLevel(it->x, it->y), it->y);
CVector3D end(it2->x, pTerrain->getExactGroundLevel(it2->x, it2->y), it2->y);
const std::vector<CVector3D>& coords = (*terr)->GetEdgeCoords(edge);
CVector3D start = coords[0];
CVector3D end = coords[coords.size() - 1];
if ( !frustum.DoesSegmentIntersect(start, end) )
continue;
glBegin(GL_LINE_STRIP);
glBegin( GL_LINE_STRIP );
float iterf = (end - start).GetLength() / TERRITORY_PRECISION_STEP;
for ( float i=0; i < iterf; i += TERRITORY_PRECISION_STEP )
for( size_t i=0; i<coords.size(); i++ )
{
CVector2D pos( Interpolate(start, end, i/iterf) );
ELOSStatus los = losMgr->GetStatus(pos.x, pos.y, g_Game->GetLocalPlayer());
float m = 1.0f;
if(los == LOS_UNEXPLORED) m = 0.0f;
else if(los == LOS_EXPLORED) m = 0.7f;
glColor3f(m*r, m*g, m*b);
glVertex3f(pos.x, pTerrain->getExactGroundLevel(pos)+.25f, pos.y);
float losScale = 0.0f;
ELOSStatus los = losMgr->GetStatus(coords[i].X, coords[i].Z, g_Game->GetLocalPlayer());
if( los & LOS_VISIBLE ) losScale = 1.0f;
else if( los & LOS_EXPLORED ) losScale = 0.7f;
glColor3f( r*losScale, g*losScale, b*losScale );
glVertex3f( coords[i].X, coords[i].Y, coords[i].Z );
}
ELOSStatus los = losMgr->GetStatus(end.X, end.Z, g_Game->GetLocalPlayer());
float m = 1.0f;
if(los == LOS_UNEXPLORED) m = 0.0f;
else if(los == LOS_EXPLORED) m = 0.7f;
glColor3f(m*r, m*g, m*b);
glVertex3f(end.X, pTerrain->getExactGroundLevel(end.X, end.Z)+.25f, end.Z);
glEnd();
}
}
@ -324,4 +287,62 @@ void CTerritoryManager::renderTerritories()
glDisable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
glColor4f(1,1,1,1);
}
}
const std::vector<CVector3D>& CTerritory::GetEdgeCoords(size_t edge)
{
if ( edgeCoords.size() == 0 )
{
// Edge coords have not been calculated - calculate them now
edgeCoords.resize( boundary.size() );
const CTerrain* pTerrain = g_Game->GetWorld()->GetTerrain();
// Tweak the boundary to shift all edges "inwards" by 0.3 units towards the territory's centre,
// so that boundaries for adjacent territories don't overlap
std::vector<CVector2D> tweakedBoundary = boundary;
for ( size_t i=0; i<boundary.size(); i++ )
{
size_t prevI = (i+boundary.size()-1) % boundary.size();
size_t nextI = (i+1) % boundary.size();
// Figure out the direction perpendicular to each of the two edges that meet at this point.
CVector2D dir1 = (boundary[i]-boundary[prevI]).beta().normalize();
CVector2D dir2 = (boundary[nextI]-boundary[i]).beta().normalize();
// If you draw a picture of what our point looks like and what the two lines 0.3 units
// away from it look like, and draw a line between our point and that one as well as
// drop perpendicular lines from it to the original edges, you get this formula for the
// length and direction we have to be moved.
float angle = acosf(dir1.dot(dir2));
tweakedBoundary[i] += (dir1 + dir2).normalize() * 0.3f / cosf(angle/2);
}
// Calculate the heights at points TERRITORY_PRECISION_STEP apart on our edges
// and store the final vertices in edgeCoords.
for ( size_t e=0; e<boundary.size(); e++ )
{
std::vector<CVector3D>& coords = edgeCoords[e];
CVector2D start = tweakedBoundary[e];
CVector2D end = tweakedBoundary[(e+1) % boundary.size()];
float iterf = (end - start).length() / TERRITORY_PRECISION_STEP;
for ( float i=0; i < iterf; i += TERRITORY_PRECISION_STEP )
{
CVector2D pos = Interpolate( start, end, i/iterf );
coords.push_back( CVector3D( pos.x, pTerrain->getExactGroundLevel(pos)+0.25f, pos.y ) );
}
coords.push_back( CVector3D( end.x, pTerrain->getExactGroundLevel(end)+0.25f, end.y ) );
}
}
return edgeCoords[edge];
}
void CTerritory::ClearEdgeCache()
{
edgeCoords.clear();
edgeCoords.resize( boundary.size() );
}

View File

@ -11,6 +11,7 @@
#define TERRITORY_MANAGER_INCLUDED
#include "ps/Vector2D.h"
#include "maths/Vector3D.h"
#include "EntityHandles.h"
class CUnit;
@ -23,10 +24,19 @@ class CTerritory
public:
CPlayer* owner; // owner of the territory, or Gaia for none
HEntity centre; // centre object of this territory
std::vector<CVector2D> boundary; // boundary polygon, in map coordinates
std::vector<CVector2D> boundary; // boundary polygon, in map coordinates
private:
// cached coordinates for the polygon's edge segments (conformed to the terrain)
std::vector<std::vector<CVector3D> > edgeCoords;
public:
CTerritory(CPlayer* owner_, HEntity centre_, std::vector<CVector2D> boundary_)
: owner(owner_), centre(centre_), boundary(boundary_) {}
const std::vector<CVector3D>& GetEdgeCoords(size_t edge);
void ClearEdgeCache();
};
class CTerritoryManager