1
0
forked from 0ad/0ad

Partial experimental version of circular maps

This was SVN commit r8470.
This commit is contained in:
Ykkrosh 2010-10-25 21:59:52 +00:00
parent 09b2a4ade8
commit 02aa8499ed
10 changed files with 179 additions and 63 deletions

Binary file not shown.

View File

@ -402,11 +402,13 @@
<object name="minimap"
type="minimap"
size="10 10 100%-10 100%-10"
circular="true"
>
<action on="WorldClick">handleMinimapEvent(arguments[0]);</action>
</object>
<object size="10 10 100%-10 100%-10" type="image" sprite="glassSquareMap" ghost="true"/>
<!-- <object size="10 10 100%-10 100%-10" type="image" sprite="glassSquareMap" ghost="true"/>-->
<object size="10 10 100%-10 100%-10" type="image" sprite="stretched:session/minimap_circle.png" ghost="true"/>
</object>
<!-- ================================ ================================ -->

Binary file not shown.

View File

@ -19,10 +19,17 @@ function LoadMapSettings(settings)
if (cmpRangeManager)
cmpRangeManager.SetLosRevealAll(true);
}
if (settings.CircularMap)
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpRangeManager)
cmpRangeManager.SetLosCircular(true);
}
var cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
if (settings.GameType)
{
{
cmpEndGameManager.SetGameType(settings.GameType);
}
cmpEndGameManager.Start();

View File

@ -56,6 +56,7 @@ CMiniMap::CMiniMap()
m_LOSTexture(0), m_TerrainDirty(true)
{
AddSetting(GUIST_CColor, "fov_wedge_color");
AddSetting(GUIST_bool, "circular");
AddSetting(GUIST_CStr, "tooltip");
AddSetting(GUIST_CStr, "tooltip_style");
m_Clicking = false;
@ -125,26 +126,51 @@ void CMiniMap::HandleMessage(const SGUIMessage &Message)
} // switch
}
void CMiniMap::GetMouseWorldCoordinates(float& x, float& z)
{
// Determine X and Z according to proportion of mouse position and minimap
CPos mousePos = GetMousePos();
float px = (mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth();
float py = (m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight();
float angle = GetAngle();
x = CELL_SIZE * m_MapSize * (cos(angle)*(px-0.5) - sin(angle)*(py-0.5) + 0.5);
z = CELL_SIZE * m_MapSize * (cos(angle)*(py-0.5) + sin(angle)*(px-0.5) + 0.5);
}
void CMiniMap::SetCameraPos()
{
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
CVector3D target;
CPos mousePos = GetMousePos();
target.X = CELL_SIZE * m_MapSize * ((mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth());
target.Z = CELL_SIZE * m_MapSize * ((m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight());
GetMouseWorldCoordinates(target.X, target.Z);
target.Y = terrain->GetExactGroundLevel(target.X, target.Z);
g_Game->GetView()->MoveCameraTarget(target);
}
float CMiniMap::GetAngle()
{
bool circular;
GUI<bool>::GetSetting(this, "circular", circular);
// If this is a circular map, rotate it to match the camera angle
if (circular)
{
CVector3D cameraIn = m_Camera->m_Orientation.GetIn();
return -atan2(cameraIn.X, cameraIn.Z);
}
// Otherwise there's no rotation
return 0.f;
}
void CMiniMap::FireWorldClickEvent(int button, int clicks)
{
// Determine X and Z according to proportion of mouse position and minimap
CPos MousePos = GetMousePos();
float x = CELL_SIZE * m_MapSize *
((MousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth());
float z = CELL_SIZE * m_MapSize *
((m_CachedActualSize.bottom - MousePos.y) / m_CachedActualSize.GetHeight());
float x, z;
GetMouseWorldCoordinates(x, z);
CScriptValRooted coords;
g_ScriptingHost.GetScriptInterface().Eval("({})", coords);
@ -194,10 +220,10 @@ void CMiniMap::DrawViewRect()
// Draw the viewing rectangle with the ScEd's conversion algorithm
glBegin(GL_LINE_LOOP);
glVertex2f(x+ViewRect[0][0], y-ViewRect[0][1]);
glVertex2f(x+ViewRect[1][0], y-ViewRect[1][1]);
glVertex2f(x+ViewRect[2][0], y-ViewRect[2][1]);
glVertex2f(x+ViewRect[3][0], y-ViewRect[3][1]);
glVertex2f(ViewRect[0][0], -ViewRect[0][1]);
glVertex2f(ViewRect[1][0], -ViewRect[1][1]);
glVertex2f(ViewRect[2][0], -ViewRect[2][1]);
glVertex2f(ViewRect[3][0], -ViewRect[3][1]);
glEnd();
// restore state
@ -212,6 +238,25 @@ struct MinimapUnitVertex
float x, y;
};
void CMiniMap::DrawTexture(float coordMax, float angle, float x, float y, float x2, float y2, float z)
{
// Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m)
const float s = sin(angle);
const float c = cos(angle);
const float m = coordMax / 2.f;
glBegin(GL_QUADS);
glTexCoord2f(m*(-c + s + 1.f), m*(-c + -s + 1.f));
glVertex3f(x, y, z);
glTexCoord2f(m*(c + s + 1.f), m*(-c + s + 1.f));
glVertex3f(x2, y, z);
glTexCoord2f(m*(c + -s + 1.f), m*(c + s + 1.f));
glVertex3f(x2, y2, z);
glTexCoord2f(m*(-c + -s + 1.f), m*(c + -s + 1.f));
glVertex3f(x, y2, z);
glEnd();
}
void CMiniMap::Draw()
{
PROFILE("minimap");
@ -220,7 +265,7 @@ void CMiniMap::Draw()
// happens when the game is started, so abort until then.
if(!(GetGUI() && g_Game && g_Game->IsGameStarted()))
return;
glDisable(GL_DEPTH_TEST);
// Set our globals in case they hadn't been set before
@ -252,27 +297,20 @@ void CMiniMap::Draw()
RebuildLOSTexture();
}
const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize;
const float losTexCoordMax = (float)(m_LOSMapSize - 1) / (float)m_LOSTextureSize;
const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
const float z = GetBufferedZ();
const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize;
const float losTexCoordMax = (float)(m_LOSMapSize - 1) / (float)m_LOSTextureSize;
const float angle = GetAngle();
// Draw the main textured quad
g_Renderer.BindTexture(0, m_TerrainTexture);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(x, y, z);
glTexCoord2f(texCoordMax, 0.0f);
glVertex3f(x2, y, z);
glTexCoord2f(texCoordMax, texCoordMax);
glVertex3f(x2, y2, z);
glTexCoord2f(0.0f, texCoordMax);
glVertex3f(x, y2, z);
glEnd();
DrawTexture(texCoordMax, angle, x, y, x2, y2, z);
/* // TODO: reimplement with new sim system
// Shade territories by player
@ -340,19 +378,18 @@ void CMiniMap::Draw()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
glColor3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(x, y, z);
glTexCoord2f(losTexCoordMax, 0.0f);
glVertex3f(x2, y, z);
glTexCoord2f(losTexCoordMax, losTexCoordMax);
glVertex3f(x2, y2, z);
glTexCoord2f(0.0f, losTexCoordMax);
glVertex3f(x, y2, z);
glEnd();
DrawTexture(losTexCoordMax, angle, x, y, x2, y2, z);
glDisable(GL_BLEND);
// Set up the matrix for drawing points and lines
glPushMatrix();
glTranslatef(x, y, z);
// Rotate around the center of the map
glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f);
glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f);
glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f);
PROFILE_START("minimap units");
// Don't enable GL_POINT_SMOOTH because it's far too slow
@ -382,8 +419,8 @@ void CMiniMap::Draw()
if (vis != ICmpRangeManager::VIS_HIDDEN)
{
v.a = 255;
v.x = x + posX.ToFloat()*sx;
v.y = y - posZ.ToFloat()*sy;
v.x = posX.ToFloat()*sx;
v.y = -posZ.ToFloat()*sy;
vertexArray.push_back(v);
}
}
@ -391,22 +428,19 @@ void CMiniMap::Draw()
if (!vertexArray.empty())
{
glPushMatrix();
glTranslatef(0, 0, z);
glInterleavedArrays(GL_C4UB_V2F, sizeof(MinimapUnitVertex), &vertexArray[0]);
glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
PROFILE_END("minimap units");
DrawViewRect();
glPopMatrix();
// Reset everything back to normal
glPointSize(1.0f);
glEnable(GL_TEXTURE_2D);

View File

@ -82,7 +82,13 @@ protected:
GLsizei m_TextureSize;
GLsizei m_LOSTextureSize;
void DrawViewRect(); // split out of Draw
void DrawTexture(float coordMax, float angle, float x, float y, float x2, float y2, float z);
void DrawViewRect();
void GetMouseWorldCoordinates(float& x, float& z);
float GetAngle();
};
#endif

View File

@ -436,7 +436,7 @@ void CPatchRData::Update()
SColor4ub baseColour = terrain->GetBaseColour();
CmpPtr<ICmpRangeManager> cmpRangeManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (cmpRangeManager.null() || cmpRangeManager->GetLosRevealAll(g_Game->GetPlayerID()))
if (cmpRangeManager.null())
{
for (ssize_t j = 0; j < vsize; ++j)
{

View File

@ -184,6 +184,7 @@ public:
// LOS state:
bool m_LosRevealAll;
bool m_LosCircular;
i32 m_TerrainVerticesPerSide;
// Counts of units seeing vertex, per vertex, per player (starting with player 0).
@ -197,6 +198,10 @@ public:
std::vector<u32> m_LosState;
static const int MAX_LOS_PLAYER_ID = 16;
// Special static visibility data for the "reveal whole map" mode
// (TODO: this is usually a waste of memory)
std::vector<u32> m_LosStateRevealed;
static std::string GetSchema()
{
return "<a:component type='system'/><empty/>";
@ -216,6 +221,7 @@ public:
ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1));
m_LosRevealAll = false;
m_LosCircular = false;
m_TerrainVerticesPerSide = 0;
}
@ -236,6 +242,7 @@ public:
SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData);
serialize.Bool("los reveal all", m_LosRevealAll);
serialize.Bool("los circular", m_LosCircular);
serialize.NumberI32_Unbounded("terrain verts per side", m_TerrainVerticesPerSide);
// We don't serialize m_Subdivision, m_LosPlayerCounts, m_LosState
@ -254,7 +261,7 @@ public:
SerializeCommon(deserialize);
// Reinitialise subdivisions and LOS data
SetBounds(m_WorldX0, m_WorldZ0, m_WorldX1, m_WorldZ1, m_TerrainVerticesPerSide);
ResetDerivedData();
}
virtual void HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool UNUSED(global))
@ -403,16 +410,28 @@ public:
m_WorldZ1 = z1;
m_TerrainVerticesPerSide = vertices;
debug_assert(x0.IsZero() && z0.IsZero()); // don't bother implementing non-zero offsets yet
ResetSubdivisions(x1, z1);
ResetDerivedData();
}
// Reinitialise subdivisions and LOS data, based on entity data
void ResetDerivedData()
{
debug_assert(m_WorldX0.IsZero() && m_WorldZ0.IsZero()); // don't bother implementing non-zero offsets yet
ResetSubdivisions(m_WorldX1, m_WorldZ1);
m_LosPlayerCounts.clear();
m_LosPlayerCounts.resize(MAX_LOS_PLAYER_ID+1);
m_LosState.clear();
m_LosState.resize(vertices*vertices);
m_LosState.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
m_LosStateRevealed.clear();
m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
for (std::map<u32, EntityData>::iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
for (ssize_t j = 0; j < m_TerrainVerticesPerSide; ++j)
for (ssize_t i = 0; i < m_TerrainVerticesPerSide; ++i)
m_LosStateRevealed[i + j*m_TerrainVerticesPerSide] = LosIsOffWorld(i, j) ? 0 : 0xFFFFFFFFu;
}
void ResetSubdivisions(entity_pos_t x1, entity_pos_t z1)
@ -728,7 +747,10 @@ private:
virtual CLosQuerier GetLosQuerier(int player)
{
return CLosQuerier(player, m_LosState, m_TerrainVerticesPerSide);
if (m_LosRevealAll)
return CLosQuerier(player, m_LosStateRevealed, m_TerrainVerticesPerSide);
else
return CLosQuerier(player, m_LosState, m_TerrainVerticesPerSide);
}
virtual ELosVisibility GetLosVisibility(entity_id_t ent, int player)
@ -740,19 +762,24 @@ private:
if (cmpPosition.null() || !cmpPosition->IsInWorld())
return VIS_HIDDEN;
// Global flag makes all positioned entities visible
if (m_LosRevealAll)
return VIS_VISIBLE;
// Visible if within a visible region
CFixedVector2D pos = cmpPosition->GetPosition2D();
CLosQuerier los(player, m_LosState, m_TerrainVerticesPerSide);
int i = (pos.X / (int)CELL_SIZE).ToInt_RoundToNearest();
int j = (pos.Y / (int)CELL_SIZE).ToInt_RoundToNearest();
// Global flag makes all positioned entities visible
if (m_LosRevealAll)
{
if (LosIsOffWorld(i, j))
return VIS_HIDDEN;
else
return VIS_VISIBLE;
}
// Visible if within a visible region
CLosQuerier los(player, m_LosState, m_TerrainVerticesPerSide);
if (los.IsVisible(i, j))
return VIS_VISIBLE;
@ -782,6 +809,35 @@ private:
return m_LosRevealAll;
}
virtual void SetLosCircular(bool enabled)
{
m_LosCircular = enabled;
ResetDerivedData();
}
/**
* Returns whether the given vertex is outside the normal bounds of the world
* (i.e. outside the range of a circular map)
*/
inline bool LosIsOffWorld(ssize_t i, ssize_t j)
{
if (m_LosCircular)
{
// With a circular map, vertex is off-world if hypot(i - size/2, j - size/2) > size/2:
ssize_t dist2 = (i - m_TerrainVerticesPerSide/2)*(i - m_TerrainVerticesPerSide/2)
+ (j - m_TerrainVerticesPerSide/2)*(j - m_TerrainVerticesPerSide/2);
if (dist2 >= m_TerrainVerticesPerSide*m_TerrainVerticesPerSide/4)
return true;
}
// With a square map, nothing is off-world
return false;
}
/**
* Update the LOS state of tiles within a given horizontal strip (i0,j) to (i1,j) (inclusive).
* amount is +1 or -1.
@ -795,7 +851,8 @@ private:
// Increasing from zero to non-zero - move from unexplored/explored to visible+explored
if (counts[idx] == 0 && amount > 0)
{
m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1)));
if (!LosIsOffWorld(i, j))
m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1)));
}
counts[idx] += amount;
@ -803,6 +860,7 @@ private:
// Decreasing from non-zero to zero - move from visible+explored to explored
if (counts[idx] == 0 && amount < 0)
{
// (If LosIsOffWorld then this is a no-op, so don't bother doing the check)
m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1)));
}
}

View File

@ -44,4 +44,5 @@ DEFINE_INTERFACE_METHOD_1("GetEntitiesByPlayer", std::vector<entity_id_t>, ICmpR
DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpRangeManager, SetDebugOverlay, bool)
DEFINE_INTERFACE_METHOD_1("SetLosRevealAll", void, ICmpRangeManager, SetLosRevealAll, bool)
DEFINE_INTERFACE_METHOD_2("GetLosVisibility", std::string, ICmpRangeManager, GetLosVisibility_wrapper, entity_id_t, int)
DEFINE_INTERFACE_METHOD_1("SetLosCircular", void, ICmpRangeManager, SetLosCircular, bool)
END_INTERFACE_WRAPPER(RangeManager)

View File

@ -244,6 +244,11 @@ public:
*/
virtual bool GetLosRevealAll(int player) = 0;
/**
* Set the LOS to be restricted to a circular map.
*/
virtual void SetLosCircular(bool enabled) = 0;
DECLARE_INTERFACE_TYPE(RangeManager)
};