Matei
603401dc09
- Fixed a crash that was happening in pathfinding on maps where some tiles had invalid texture names (from earlier versions of the game). - Releasing the mouse over the minimap while dragging a selection band will no longer cause the view to move there. Unfortunately, the bandbox still won't properly "release". The bandbox input routine should ideally be placed at a higher priority than the GUI, separate from the other Interact.cpp routines. This was SVN commit r4711.
589 lines
17 KiB
C++
589 lines
17 KiB
C++
#include "precompiled.h"
|
|
|
|
#include <math.h>
|
|
|
|
#include "MiniMap.h"
|
|
|
|
#include "graphics/GameView.h"
|
|
#include "graphics/MiniPatch.h"
|
|
#include "graphics/Terrain.h"
|
|
#include "graphics/TextureEntry.h"
|
|
#include "graphics/TextureManager.h"
|
|
#include "graphics/Unit.h"
|
|
#include "graphics/UnitManager.h"
|
|
#include "lib/ogl.h"
|
|
#include "lib/sdl.h"
|
|
#include "ps/Game.h"
|
|
#include "ps/Interact.h"
|
|
#include "network/NetMessage.h"
|
|
#include "ps/Profile.h"
|
|
#include "renderer/Renderer.h"
|
|
#include "renderer/WaterManager.h"
|
|
#include "scripting/GameEvents.h"
|
|
#include "simulation/Entity.h"
|
|
#include "simulation/EntityTemplate.h"
|
|
#include "simulation/LOSManager.h"
|
|
#include "simulation/TerritoryManager.h"
|
|
|
|
|
|
bool g_TerrainModified = false;
|
|
bool g_GameRestarted = false;
|
|
|
|
// used by GetMapSpaceCoords (precalculated as an optimization).
|
|
// this was formerly access via inline asm, which required it to be
|
|
// static data instead of a class member. that is no longer the case,
|
|
// but we leave it because this is slightly more efficient.
|
|
static float m_scaleX, m_scaleY;
|
|
|
|
|
|
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);
|
|
return (0xff000000 | r | g<<8 | b<<16);
|
|
}
|
|
|
|
CMiniMap::CMiniMap()
|
|
: m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0),
|
|
m_LOSTexture(0), m_LOSData(0), m_UnitManager(0)
|
|
{
|
|
AddSetting(GUIST_CColor, "fov_wedge_color");
|
|
AddSetting(GUIST_CStr, "tooltip");
|
|
AddSetting(GUIST_CStr, "tooltip_style");
|
|
m_Clicking = false;
|
|
}
|
|
|
|
CMiniMap::~CMiniMap()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
void CMiniMap::HandleMessage(const SGUIMessage &Message)
|
|
{
|
|
switch(Message.type)
|
|
{
|
|
case GUIM_MOUSE_PRESS_LEFT:
|
|
{
|
|
SetCameraPos();
|
|
m_Clicking = true;
|
|
break;
|
|
}
|
|
case GUIM_MOUSE_RELEASE_LEFT:
|
|
{
|
|
if(m_Clicking)
|
|
SetCameraPos();
|
|
m_Clicking = false;
|
|
break;
|
|
}
|
|
case GUIM_MOUSE_ENTER:
|
|
{
|
|
g_Selection.m_mouseOverMM = true;
|
|
break;
|
|
}
|
|
case GUIM_MOUSE_LEAVE:
|
|
{
|
|
g_Selection.m_mouseOverMM = false;
|
|
break;
|
|
}
|
|
|
|
case GUIM_MOUSE_RELEASE_RIGHT:
|
|
{
|
|
CMiniMap::FireWorldClickEvent(SDL_BUTTON_RIGHT, 1);
|
|
break;
|
|
}
|
|
case GUIM_MOUSE_DBLCLICK_RIGHT:
|
|
{
|
|
CMiniMap::FireWorldClickEvent(SDL_BUTTON_RIGHT, 2);
|
|
break;
|
|
}
|
|
case GUIM_MOUSE_MOTION:
|
|
{
|
|
if (m_Clicking)
|
|
SetCameraPos();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
} // switch
|
|
}
|
|
|
|
void CMiniMap::SetCameraPos()
|
|
{
|
|
CTerrain *MMTerrain=g_Game->GetWorld()->GetTerrain();
|
|
CVector3D CamOrient=m_Camera->m_Orientation.GetTranslation();
|
|
|
|
//get center point of screen
|
|
int x = g_Renderer.GetWidth()/2;
|
|
int y = g_Renderer.GetHeight()/2;
|
|
CVector3D ScreenMiddle=m_Camera->GetWorldCoordinates(x,y);
|
|
|
|
//Get Vector required to go from camera position to ScreenMiddle
|
|
CVector3D TransVector;
|
|
TransVector.X=CamOrient.X-ScreenMiddle.X;
|
|
TransVector.Z=CamOrient.Z-ScreenMiddle.Z;
|
|
//world position of where mouse clicked
|
|
CVector3D Destination;
|
|
CPos MousePos = GetMousePos();
|
|
//X and Z according to proportion of mouse position and minimap
|
|
Destination.X = CELL_SIZE * m_MapSize *
|
|
( (MousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth() );
|
|
Destination.Z = CELL_SIZE * m_MapSize * ( (m_CachedActualSize.bottom - MousePos.y) /
|
|
m_CachedActualSize.GetHeight() );
|
|
|
|
m_Camera->m_Orientation._14=Destination.X;
|
|
m_Camera->m_Orientation._34=Destination.Z;
|
|
m_Camera->m_Orientation._14+=TransVector.X;
|
|
m_Camera->m_Orientation._34+=TransVector.Z;
|
|
|
|
//Lock Y coord. No risk of zoom exceeding limit-Y does not increase
|
|
float Height=MMTerrain->getExactGroundLevel(
|
|
m_Camera->m_Orientation._14, m_Camera->m_Orientation._34) + g_YMinOffset;
|
|
|
|
if (m_Camera->m_Orientation._24 < Height)
|
|
{
|
|
m_Camera->m_Orientation._24=Height;
|
|
}
|
|
m_Camera->UpdateFrustum();
|
|
}
|
|
void CMiniMap::FireWorldClickEvent(uint button, int clicks)
|
|
{
|
|
//debug_printf("FireWorldClickEvent: button %d, clicks %d\n", button, clicks);
|
|
|
|
CPos MousePos = GetMousePos();
|
|
CVector2D Destination;
|
|
//X and Z according to proportion of mouse position and minimap
|
|
Destination.x = CELL_SIZE * m_MapSize *
|
|
( (MousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth() );
|
|
Destination.y = CELL_SIZE * m_MapSize * ( (m_CachedActualSize.bottom - MousePos.y) /
|
|
m_CachedActualSize.GetHeight() );
|
|
|
|
g_JSGameEvents.FireWorldClick(
|
|
button,
|
|
clicks,
|
|
NMT_Goto,
|
|
-1,
|
|
NMT_Run,
|
|
-1,
|
|
NULL,
|
|
(int)Destination.x,
|
|
(int)Destination.y);
|
|
}
|
|
|
|
// render view rect : John M. Mena
|
|
// This sets up and draws the rectangle on the mini-map
|
|
// which represents the view of the camera in the world.
|
|
void CMiniMap::DrawViewRect()
|
|
{
|
|
// Get correct world coordinates based off corner of screen start
|
|
// at Bottom Left and going CW
|
|
CVector3D hitPt[4];
|
|
hitPt[0]=m_Camera->GetWorldCoordinates(0,g_Renderer.GetHeight());
|
|
hitPt[1]=m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(),g_Renderer.GetHeight());
|
|
hitPt[2]=m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(),0);
|
|
hitPt[3]=m_Camera->GetWorldCoordinates(0,0);
|
|
|
|
float ViewRect[4][2];
|
|
for (int i=0;i<4;i++) {
|
|
// convert to minimap space
|
|
float px=hitPt[i].X;
|
|
float pz=hitPt[i].Z;
|
|
ViewRect[i][0]=(m_CachedActualSize.GetWidth()*px/float(CELL_SIZE*m_MapSize));
|
|
ViewRect[i][1]=(m_CachedActualSize.GetHeight()*pz/float(CELL_SIZE*m_MapSize));
|
|
}
|
|
|
|
// Enable Scissoring as to restrict the rectangle
|
|
// to only the mini-map below by retrieving the mini-maps
|
|
// screen coords.
|
|
glScissor((int)m_CachedActualSize.left, 0, (int)m_CachedActualSize.right, (int)m_CachedActualSize.GetHeight());
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glLineWidth(2.0f);
|
|
glColor3f(1.0f, 0.3f, 0.3f);
|
|
|
|
// Draw the viewing rectangle with the ScEd's conversion algorithm
|
|
const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
|
|
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]);
|
|
glEnd();
|
|
|
|
// restore state
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_LINE_SMOOTH);
|
|
glLineWidth(1.0f);
|
|
}
|
|
|
|
struct MinimapUnitVertex
|
|
{
|
|
u8 r, g, b, a;
|
|
float x, y;
|
|
};
|
|
|
|
void CMiniMap::Draw()
|
|
{
|
|
PROFILE("minimap");
|
|
|
|
// The terrain isn't actually initialized until the map is loaded, which
|
|
// 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
|
|
m_Camera = g_Game->GetView()->GetCamera();
|
|
m_Terrain = g_Game->GetWorld()->GetTerrain();
|
|
m_UnitManager = g_Game->GetWorld()->GetUnitManager();
|
|
m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left);
|
|
m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top);
|
|
m_MapSize = m_Terrain->GetVerticesPerSide();
|
|
m_TextureSize = round_up_to_pow2(m_MapSize);
|
|
|
|
m_scaleX = float(m_Width) / float(m_MapSize - 1);
|
|
m_scaleY = float(m_Height) / float(m_MapSize - 1);
|
|
|
|
if(!m_TerrainTexture || g_GameRestarted)
|
|
CreateTextures();
|
|
|
|
// do not limit this as with LOS updates below - we must update
|
|
// immediately after changes are reported because this flag will be
|
|
// reset at the end of the frame.
|
|
if(g_TerrainModified)
|
|
RebuildTerrainTexture();
|
|
|
|
// only update 10x / second
|
|
// (note: since units only move a few pixels per second on the minimap,
|
|
// we can get away with infrequent updates; this is slow, ~20ms)
|
|
static double last_time;
|
|
const double cur_time = get_time();
|
|
if(cur_time - last_time > 100e-3) // 10 updates/sec
|
|
{
|
|
last_time = cur_time;
|
|
|
|
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
|
if(losMgr->m_LOSSetting != CLOSManager::ALL_VISIBLE)
|
|
RebuildLOSTexture();
|
|
}
|
|
|
|
const float texCoordMax = ((float)m_MapSize - 1) / ((float)m_TextureSize);
|
|
const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
|
|
const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
|
|
const float z = GetBufferedZ();
|
|
|
|
// 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();
|
|
|
|
// Shade territories by player
|
|
CTerritoryManager* territoryMgr = g_Game->GetWorld()->GetTerritoryManager();
|
|
std::vector<CTerritory*>& territories = territoryMgr->GetTerritories();
|
|
|
|
PROFILE_START("minimap territory shade");
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
for( size_t i=0; i<territories.size(); i++ )
|
|
{
|
|
if( territories[i]->owner->GetPlayerID() == 0 )
|
|
continue;
|
|
std::vector<CVector2D>& boundary = territories[i]->boundary;
|
|
SPlayerColour col = territories[i]->owner->GetColour();
|
|
glColor4f(col.r, col.g, col.b, 0.25f);
|
|
glBegin(GL_POLYGON);
|
|
for( size_t j=0; j<boundary.size(); j++ )
|
|
{
|
|
float fx = boundary[j].x / (m_Terrain->GetTilesPerSide() * CELL_SIZE);
|
|
float fy = boundary[j].y / (m_Terrain->GetTilesPerSide() * CELL_SIZE);
|
|
glVertex3f( x*(1-fx) + x2*fx, y*(1-fy) + y2*fy, z );
|
|
}
|
|
glEnd();
|
|
}
|
|
glDisable(GL_BLEND);
|
|
|
|
PROFILE_END("minimap territory shade");
|
|
|
|
// Draw territory boundaries
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glLineWidth(1.0f);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glColor4f(0.8f, 0.8f, 0.8f, 0.8f);
|
|
for( size_t i=0; i<territories.size(); i++ )
|
|
{
|
|
std::vector<CVector2D>& boundary = territories[i]->boundary;
|
|
glBegin(GL_LINE_LOOP);
|
|
for( size_t j=0; j<boundary.size(); j++ )
|
|
{
|
|
float fx = boundary[j].x / (m_Terrain->GetTilesPerSide() * CELL_SIZE);
|
|
float fy = boundary[j].y / (m_Terrain->GetTilesPerSide() * CELL_SIZE);
|
|
glVertex3f( x*(1-fx) + x2*fx, y*(1-fy) + y2*fy, z );
|
|
}
|
|
glEnd();
|
|
}
|
|
glLineWidth(1.0f);
|
|
glDisable(GL_LINE_SMOOTH);
|
|
glDisable(GL_BLEND);
|
|
|
|
// Draw the LOS quad in black, using alpha values from the LOS texture
|
|
g_Renderer.BindTexture(0, m_LOSTexture);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
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(texCoordMax, 0.0f);
|
|
glVertex3f(x2, y, z);
|
|
glTexCoord2f(texCoordMax, texCoordMax);
|
|
glVertex3f(x2, y2, z);
|
|
glTexCoord2f(0.0f, texCoordMax);
|
|
glVertex3f(x, y2, z);
|
|
glEnd();
|
|
glDisable(GL_BLEND);
|
|
|
|
PROFILE_START("minimap units");
|
|
|
|
// Draw unit points
|
|
const std::vector<CUnit *> &units = m_UnitManager->GetUnits();
|
|
std::vector<CUnit *>::const_iterator iter = units.begin();
|
|
CUnit *unit = 0;
|
|
CVector2D pos;
|
|
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
|
|
|
std::vector<MinimapUnitVertex> vertexArray;
|
|
// TODO: don't reallocate this after every frame (but don't waste memory
|
|
// after the number of units decreases substantially)
|
|
|
|
// Don't enable GL_POINT_SMOOTH because it's far too slow
|
|
// (~70msec/frame on a GF4 rendering a thousand points)
|
|
glPointSize(3.f);
|
|
|
|
for(; iter != units.end(); ++iter)
|
|
{
|
|
unit = (CUnit *)(*iter);
|
|
if(unit && unit->GetEntity() && losMgr->GetUnitStatus(unit, g_Game->GetLocalPlayer()) != UNIT_HIDDEN)
|
|
{
|
|
CEntity* entity = unit->GetEntity();
|
|
CStrW& type = entity->m_base->m_minimapType;
|
|
|
|
MinimapUnitVertex v;
|
|
|
|
if(type==L"Unit" || type==L"Structure" || type==L"Hero") {
|
|
// Use the player colour
|
|
const SPlayerColour& colour = entity->GetPlayer()->GetColour();
|
|
v.r = i32_from_float(colour.r*255.f);
|
|
v.g = i32_from_float(colour.g*255.f);
|
|
v.b = i32_from_float(colour.b*255.f);
|
|
v.a = 255;
|
|
}
|
|
else {
|
|
CEntityTemplate* base = entity->m_base;
|
|
v.r = base->m_minimapR;
|
|
v.g = base->m_minimapG;
|
|
v.b = base->m_minimapB;
|
|
v.a = 255;
|
|
}
|
|
|
|
pos = GetMapSpaceCoords(entity->m_position);
|
|
|
|
v.x = x + pos.x;
|
|
v.y = y - pos.y;
|
|
vertexArray.push_back(v);
|
|
}
|
|
}
|
|
|
|
if (vertexArray.size())
|
|
{
|
|
glPushMatrix();
|
|
glTranslatef(0, 0, z);
|
|
|
|
pglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
|
|
|
|
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();
|
|
|
|
// Reset everything back to normal
|
|
glPointSize(1.0f);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
void CMiniMap::CreateTextures()
|
|
{
|
|
Destroy();
|
|
|
|
// Create terrain texture
|
|
glGenTextures(1, (GLuint *)&m_TerrainTexture);
|
|
g_Renderer.BindTexture(0, m_TerrainTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_TextureSize, m_TextureSize, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0);
|
|
m_TerrainData = new u32[(m_MapSize - 1) * (m_MapSize - 1)];
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
|
|
|
|
// Create LOS texture
|
|
glGenTextures(1, (GLuint *)&m_LOSTexture);
|
|
g_Renderer.BindTexture(0, m_LOSTexture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
|
|
m_LOSData = new u8[(m_MapSize - 1) * (m_MapSize - 1)];
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
|
|
|
|
// Rebuild and upload both of them
|
|
RebuildTerrainTexture();
|
|
RebuildLOSTexture();
|
|
}
|
|
|
|
|
|
void CMiniMap::RebuildTerrainTexture()
|
|
{
|
|
u32 x = 0;
|
|
u32 y = 0;
|
|
u32 w = m_MapSize - 1;
|
|
u32 h = m_MapSize - 1;
|
|
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight;
|
|
|
|
for(u32 j = 0; j < h; j++)
|
|
{
|
|
u32 *dataPtr = m_TerrainData + ((y + j) * (m_MapSize - 1)) + x;
|
|
for(u32 i = 0; i < w; i++)
|
|
{
|
|
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 < waterHeight)
|
|
{
|
|
*dataPtr++ = 0xff304080; // TODO: perhaps use the renderer's water color?
|
|
}
|
|
else
|
|
{
|
|
int hmap = ((int)m_Terrain->GetHeightMap()[(y + j) * m_MapSize + x + i]) >> 8;
|
|
int val = (hmap / 3) + 170;
|
|
|
|
u32 color = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
*dataPtr++ = ScaleColor(color, float(val) / 255.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Upload the texture
|
|
g_Renderer.BindTexture(0, m_TerrainTexture);
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize - 1, m_MapSize - 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, m_TerrainData);
|
|
}
|
|
|
|
|
|
void CMiniMap::RebuildLOSTexture()
|
|
{
|
|
PROFILE_START("rebuild minimap: los");
|
|
|
|
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
|
|
CPlayer* player = g_Game->GetLocalPlayer();
|
|
|
|
u32 x = 0;
|
|
u32 y = 0;
|
|
u32 w = m_MapSize - 1;
|
|
u32 h = m_MapSize - 1;
|
|
|
|
for(u32 j = 0; j < h; j++)
|
|
{
|
|
u8 *dataPtr = m_LOSData + ((y + j) * (m_MapSize - 1)) + x;
|
|
for(u32 i = 0; i < w; i++)
|
|
{
|
|
ELOSStatus status = losMgr->GetStatus((int) i, (int) j, player);
|
|
if(status == LOS_UNEXPLORED)
|
|
{
|
|
*dataPtr++ = 0xff;
|
|
}
|
|
else if(status == LOS_EXPLORED)
|
|
{
|
|
*dataPtr++ = (u8) (0xff * 0.3f);
|
|
}
|
|
else {
|
|
*dataPtr++ = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Upload the texture
|
|
g_Renderer.BindTexture(0, m_LOSTexture);
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize - 1, m_MapSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, m_LOSData);
|
|
|
|
PROFILE_END("rebuild minimap: los");
|
|
}
|
|
|
|
void CMiniMap::Destroy()
|
|
{
|
|
if(m_TerrainTexture)
|
|
glDeleteTextures(1, (GLuint *)&m_TerrainTexture);
|
|
|
|
if(m_LOSTexture)
|
|
glDeleteTextures(1, (GLuint *)&m_LOSTexture);
|
|
|
|
delete[] m_TerrainData; m_TerrainData = 0;
|
|
delete[] m_LOSData; m_LOSData = 0;
|
|
}
|
|
|
|
CVector2D CMiniMap::GetMapSpaceCoords(CVector3D worldPos)
|
|
{
|
|
float x = rintf(worldPos.X / CELL_SIZE);
|
|
float y = rintf(worldPos.Z / CELL_SIZE);
|
|
// Entity's Z coordinate is really its longitudinal coordinate on the terrain
|
|
|
|
// Calculate map space scale
|
|
return CVector2D(x * m_scaleX, y * m_scaleY);
|
|
}
|