Index: ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml (revision 24140)
+++ ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml (revision 24141)
@@ -1,36 +1,36 @@
Index: ps/trunk/binaries/data/mods/public/shaders/arb/minimap.fp
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/arb/minimap.fp (revision 24140)
+++ ps/trunk/binaries/data/mods/public/shaders/arb/minimap.fp (revision 24141)
@@ -1,29 +1,42 @@
!!ARBfp1.0
+#if MINIMAP_MASK
+ ATTRIB v_maskUV = fragment.texcoord[1];
+ TEMP mask;
+ TEX mask, v_maskUV, texture[2], 2D;
+#endif
+
#if MINIMAP_BASE
+#if MINIMAP_MASK
+ TEMP color;
+ TEX color, fragment.texcoord[0], texture[0], 2D;
+ MUL color.a, color.a, mask.a;
+ MOV result.color, color;
+#else
TEX result.color, fragment.texcoord[0], texture[0], 2D;
#endif
+#endif
#if MINIMAP_LOS
TEMP tex;
TEX tex, fragment.texcoord[0], texture[0], 2D;
SUB tex.a, 1.0, tex.a;
MOV result.color.r, 0.0;
MOV result.color.g, 0.0;
MOV result.color.b, 0.0;
MOV result.color.a, tex.a;
#endif
#if MINIMAP_POINT
MOV result.color, fragment.color;
MOV result.color.a, 1.0;
#endif
#if MINIMAP_LINE
PARAM color = program.local[1];
MOV result.color, color;
#endif
END
Index: ps/trunk/binaries/data/mods/public/shaders/arb/minimap.vp
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/arb/minimap.vp (revision 24140)
+++ ps/trunk/binaries/data/mods/public/shaders/arb/minimap.vp (revision 24141)
@@ -1,30 +1,49 @@
!!ARBvp1.0
+PARAM transform[4] = { program.local[0..3] };
+PARAM textureTransform[4] = { program.local[4..7] };
+#if MINIMAP_MASK
+ PARAM maskTextureTransform[4] = { program.local[12..15] };
+#endif
+OUTPUT v_tex = result.texcoord[0];
+
TEMP position;
MOV position, vertex.position;
#if MINIMAP_POINT || MINIMAP_LINE
MOV position.z, 0.0;
#endif
MOV position.w, 1.0;
-DP4 result.position.x, program.local[0], position;
-DP4 result.position.y, program.local[1], position;
-DP4 result.position.z, program.local[2], position;
-DP4 result.position.w, program.local[3], position;
+DP4 result.position.x, transform[0], position;
+DP4 result.position.y, transform[1], position;
+DP4 result.position.z, transform[2], position;
+DP4 result.position.w, transform[3], position;
-#if MINIMAP_BASE || MINIMAP_LOS
+#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_MASK
TEMP tex;
MOV tex, vertex.texcoord;
+#endif
- DP4 result.texcoord.x, program.local[4], tex;
- DP4 result.texcoord.y, program.local[5], tex;
- DP4 result.texcoord.z, program.local[6], tex;
- DP4 result.texcoord.w, program.local[7], tex;
+#if MINIMAP_BASE || MINIMAP_LOS
+ DP4 v_tex.x, textureTransform[0], tex;
+ DP4 v_tex.y, textureTransform[1], tex;
+ DP4 v_tex.z, textureTransform[2], tex;
+ DP4 v_tex.w, textureTransform[3], tex;
#endif
#if MINIMAP_POINT
MOV result.color, vertex.color;
MOV result.pointsize, program.local[8];
#endif
+#if MINIMAP_MASK
+ OUTPUT v_maskUV = result.texcoord[1];
+ MOV v_maskUV.x, tex.x;
+ MOV v_maskUV.y, tex.y;
+ DP4 v_maskUV.x, maskTextureTransform[0], tex;
+ DP4 v_maskUV.y, maskTextureTransform[1], tex;
+ DP4 v_maskUV.z, maskTextureTransform[2], tex;
+ DP4 v_maskUV.w, maskTextureTransform[3], tex;
+#endif
+
END
Index: ps/trunk/binaries/data/mods/public/shaders/arb/minimap.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/arb/minimap.xml (revision 24140)
+++ ps/trunk/binaries/data/mods/public/shaders/arb/minimap.xml (revision 24141)
@@ -1,18 +1,20 @@
-
+
+
+
Index: ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.fs
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.fs (revision 24140)
+++ ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.fs (revision 24141)
@@ -1,33 +1,48 @@
#version 110
#if MINIMAP_BASE || MINIMAP_LOS
uniform sampler2D baseTex;
varying vec2 v_tex;
#endif
+#if MINIMAP_MASK
+ uniform sampler2D maskTex;
+ varying vec2 v_maskUV;
+#endif
+
#if MINIMAP_POINT
varying vec3 color;
#endif
#if MINIMAP_LINE
uniform vec4 color;
#endif
void main()
{
+ #if MINIMAP_MASK
+ float mask = texture2D(maskTex, v_maskUV).a;
+ #endif
+
#if MINIMAP_BASE
+ #if MINIMAP_MASK
+ vec4 color = texture2D(baseTex, v_tex);
+ gl_FragColor.rgb = color.rgb;
+ gl_FragColor.a = color.a * mask;
+ #else
gl_FragColor = texture2D(baseTex, v_tex);
#endif
+ #endif
#if MINIMAP_LOS
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0 - texture2D(baseTex, v_tex).a);
#endif
#if MINIMAP_POINT
gl_FragColor = vec4(color, 1.0);
#endif
#if MINIMAP_LINE
gl_FragColor = color;
#endif
}
Index: ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.vs
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.vs (revision 24140)
+++ ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.vs (revision 24141)
@@ -1,39 +1,51 @@
#version 110
uniform mat4 transform;
uniform mat4 textureTransform;
uniform float pointSize;
-#if MINIMAP_BASE || MINIMAP_LOS
+#if MINIMAP_MASK
+ uniform mat4 maskTextureTransform;
+ varying vec2 v_maskUV;
+#endif
+
+#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_MASK
attribute vec3 a_vertex;
attribute vec2 a_uv0;
+#endif
+
+#if MINIMAP_BASE || MINIMAP_LOS
varying vec2 v_tex;
#endif
#if MINIMAP_POINT
attribute vec2 a_vertex;
attribute vec3 a_color;
varying vec3 color;
#endif
#if MINIMAP_LINE
attribute vec2 a_vertex;
#endif
void main()
{
#if MINIMAP_BASE || MINIMAP_LOS
gl_Position = transform * vec4(a_vertex, 1.0);
v_tex = (textureTransform * vec4(a_uv0, 0.0, 1.0)).xy;
#endif
+ #if MINIMAP_MASK
+ v_maskUV = (maskTextureTransform * vec4(a_uv0, 0.0, 1.0)).xy;
+ #endif
+
#if MINIMAP_POINT
gl_PointSize = pointSize;
gl_Position = transform * vec4(a_vertex, 0.0, 1.0);
color = a_color;
#endif
#if MINIMAP_LINE
gl_Position = transform * vec4(a_vertex, 0.0, 1.0);
#endif
}
Index: ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.xml (revision 24140)
+++ ps/trunk/binaries/data/mods/public/shaders/glsl/minimap.xml (revision 24141)
@@ -1,15 +1,15 @@
-
+
-
+
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 24140)
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 24141)
@@ -1,726 +1,755 @@
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#include "precompiled.h"
#include "CMiniMap.h"
#include "graphics/GameView.h"
#include "graphics/LOSTexture.h"
#include "graphics/MiniPatch.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureEntry.h"
#include "graphics/TerrainTextureManager.h"
#include "graphics/TerritoryTexture.h"
#include "gui/CGUI.h"
#include "gui/GUIManager.h"
#include "gui/GUIMatrix.h"
#include "lib/bits.h"
#include "lib/external_libraries/libsdl.h"
#include "lib/ogl.h"
#include "lib/timer.h"
#include "ps/ConfigDB.h"
#include "ps/Filesystem.h"
#include "ps/Game.h"
#include "ps/GameSetup/Config.h"
#include "ps/Profile.h"
#include "ps/World.h"
#include "ps/XML/Xeromyces.h"
#include "renderer/Renderer.h"
#include "renderer/RenderingOptions.h"
#include "renderer/WaterManager.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpMinimap.h"
#include "simulation2/helpers/Los.h"
#include "simulation2/system/ParamNode.h"
#include
extern bool g_GameRestarted;
// Set max drawn entities to UINT16_MAX for now, which is more than enough
// TODO: we should be cleverer about drawing them to reduce clutter
const u16 MAX_ENTITIES_DRAWN = 65535;
static unsigned int ScaleColor(unsigned int color, float x)
{
unsigned int r = unsigned(float(color & 0xff) * x);
unsigned int g = unsigned(float((color>>8) & 0xff) * x);
unsigned int b = unsigned(float((color>>16) & 0xff) * x);
return (0xff000000 | b | g<<8 | r<<16);
}
const CStr CMiniMap::EventNameWorldClick = "WorldClick";
CMiniMap::CMiniMap(CGUI& pGUI) :
IGUIObject(pGUI),
m_TerrainTexture(0), m_TerrainData(0), m_MapSize(0), m_Terrain(0), m_TerrainDirty(true), m_MapScale(1.f),
- m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW),
+ m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), m_Mask(false),
m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), m_WaterHeight(0.0)
{
+ RegisterSetting("mask", m_Mask);
+
m_Clicking = false;
m_MouseHovering = false;
// Register Relax NG validator
CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng");
m_ShallowPassageHeight = GetShallowPassageHeight();
m_AttributePos.type = GL_FLOAT;
m_AttributePos.elems = 2;
m_VertexArray.AddAttribute(&m_AttributePos);
m_AttributeColor.type = GL_UNSIGNED_BYTE;
m_AttributeColor.elems = 4;
m_VertexArray.AddAttribute(&m_AttributeColor);
m_VertexArray.SetNumVertices(MAX_ENTITIES_DRAWN);
m_VertexArray.Layout();
m_IndexArray.SetNumVertices(MAX_ENTITIES_DRAWN);
m_IndexArray.Layout();
VertexArrayIterator index = m_IndexArray.GetIterator();
for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i)
*index++ = i;
m_IndexArray.Upload();
m_IndexArray.FreeBackingStore();
VertexArrayIterator attrPos = m_AttributePos.GetIterator();
VertexArrayIterator attrColor = m_AttributeColor.GetIterator();
for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i)
{
(*attrColor)[0] = 0;
(*attrColor)[1] = 0;
(*attrColor)[2] = 0;
(*attrColor)[3] = 0;
++attrColor;
(*attrPos)[0] = -10000.0f;
(*attrPos)[1] = -10000.0f;
++attrPos;
}
m_VertexArray.Upload();
double blinkDuration = 1.0;
// Tests won't have config initialised
if (CConfigDB::IsInitialised())
{
CFG_GET_VAL("gui.session.minimap.pingduration", m_PingDuration);
CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration);
}
m_HalfBlinkDuration = blinkDuration/2;
}
CMiniMap::~CMiniMap()
{
Destroy();
}
void CMiniMap::HandleMessage(SGUIMessage& Message)
{
IGUIObject::HandleMessage(Message);
switch (Message.type)
{
case GUIM_MOUSE_PRESS_LEFT:
if (m_MouseHovering)
{
if (!CMiniMap::FireWorldClickEvent(SDL_BUTTON_LEFT, 1))
{
SetCameraPos();
m_Clicking = true;
}
}
break;
case GUIM_MOUSE_RELEASE_LEFT:
if (m_MouseHovering && m_Clicking)
SetCameraPos();
m_Clicking = false;
break;
case GUIM_MOUSE_DBLCLICK_LEFT:
if (m_MouseHovering && m_Clicking)
SetCameraPos();
m_Clicking = false;
break;
case GUIM_MOUSE_ENTER:
m_MouseHovering = true;
break;
case GUIM_MOUSE_LEAVE:
m_Clicking = false;
m_MouseHovering = 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_MouseHovering && m_Clicking)
SetCameraPos();
break;
case GUIM_MOUSE_WHEEL_DOWN:
case GUIM_MOUSE_WHEEL_UP:
Message.Skip();
break;
default:
break;
}
}
bool CMiniMap::IsMouseOver() const
{
// Get the mouse position.
const CPos& mousePos = m_pGUI.GetMousePos();
// Get the position of the center of the minimap.
CPos minimapCenter = CPos(m_CachedActualSize.left + m_CachedActualSize.GetWidth() / 2.0, m_CachedActualSize.bottom - m_CachedActualSize.GetHeight() / 2.0);
// Take the magnitude of the difference of the mouse position and minimap center.
double distFromCenter = sqrt(pow((mousePos.x - minimapCenter.x), 2) + pow((mousePos.y - minimapCenter.y), 2));
// If the distance is less then the radius of the minimap (half the width) the mouse is over the minimap.
if (distFromCenter < m_CachedActualSize.GetWidth() / 2.0)
return true;
else
return false;
}
void CMiniMap::GetMouseWorldCoordinates(float& x, float& z) const
{
// Determine X and Z according to proportion of mouse position and minimap
const CPos& mousePos = m_pGUI.GetMousePos();
float px = (mousePos.x - m_CachedActualSize.left) / m_CachedActualSize.GetWidth();
float py = (m_CachedActualSize.bottom - mousePos.y) / m_CachedActualSize.GetHeight();
float angle = GetAngle();
// Scale world coordinates for shrunken square map
x = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(px-0.5) - sin(angle)*(py-0.5)) + 0.5);
z = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(py-0.5) + sin(angle)*(px-0.5)) + 0.5);
}
void CMiniMap::SetCameraPos()
{
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
CVector3D target;
GetMouseWorldCoordinates(target.X, target.Z);
target.Y = terrain->GetExactGroundLevel(target.X, target.Z);
g_Game->GetView()->MoveCameraTarget(target);
}
float CMiniMap::GetAngle() const
{
CVector3D cameraIn = m_Camera->GetOrientation().GetIn();
return -atan2(cameraIn.X, cameraIn.Z);
}
bool CMiniMap::FireWorldClickEvent(int button, int UNUSED(clicks))
{
JSContext* cx = g_GUI->GetActiveGUI()->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
float x, z;
GetMouseWorldCoordinates(x, z);
JS::RootedValue coords(cx);
ScriptInterface::CreateObject(cx, &coords, "x", x, "z", z);
JS::RootedValue buttonJs(cx);
ScriptInterface::ToJSVal(cx, &buttonJs, button);
JS::AutoValueVector paramData(cx);
paramData.append(coords);
paramData.append(buttonJs);
return ScriptEventWithReturn(EventNameWorldClick, paramData);
}
// This sets up and draws the rectangle on the minimap
// which represents the view of the camera in the world.
void CMiniMap::DrawViewRect(CMatrix3D transform) const
{
// Compute the camera frustum intersected with a fixed-height plane.
// Use the water height as a fixed base height, which should be the lowest we can go
float h = g_Renderer.GetWaterManager()->m_WaterHeight;
const float width = m_CachedActualSize.GetWidth();
const float height = m_CachedActualSize.GetHeight();
const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize);
CVector3D hitPt[4];
hitPt[0] = m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h);
hitPt[1] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h);
hitPt[2] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h);
hitPt[3] = m_Camera->GetWorldCoordinates(0, 0, h);
float ViewRect[4][2];
for (int i = 0; i < 4; ++i)
{
// convert to minimap space
ViewRect[i][0] = (width * hitPt[i].X * invTileMapSize);
ViewRect[i][1] = (height * hitPt[i].Z * invTileMapSize);
}
float viewVerts[] = {
ViewRect[0][0], -ViewRect[0][1],
ViewRect[1][0], -ViewRect[1][1],
ViewRect[2][0], -ViewRect[2][1],
ViewRect[3][0], -ViewRect[3][1]
};
// Enable Scissoring to restrict the rectangle to only the minimap.
glScissor(
m_CachedActualSize.left * g_GuiScale,
g_Renderer.GetHeight() - m_CachedActualSize.bottom * g_GuiScale,
width * g_GuiScale,
height * g_GuiScale);
glEnable(GL_SCISSOR_TEST);
glLineWidth(2.0f);
CShaderDefines lineDefines;
lineDefines.Add(str_MINIMAP_LINE, str_1);
CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), lineDefines);
tech->BeginPass();
CShaderProgramPtr shader = tech->GetShader();
shader->Uniform(str_transform, transform);
shader->Uniform(str_color, 1.0f, 0.3f, 0.3f, 1.0f);
shader->VertexPointer(2, GL_FLOAT, 0, viewVerts);
shader->AssertPointersBound();
if (!g_Renderer.m_SkipSubmit)
glDrawArrays(GL_LINE_LOOP, 0, 4);
tech->EndPass();
glLineWidth(1.0f);
glDisable(GL_SCISSOR_TEST);
}
struct MinimapUnitVertex
{
// This struct is copyable for convenience and because to move is to copy for primitives.
u8 r, g, b, a;
float x, y;
};
// Adds a vertex to the passed VertexArray
static void inline addVertex(const MinimapUnitVertex& v,
VertexArrayIterator& attrColor,
VertexArrayIterator& attrPos)
{
(*attrColor)[0] = v.r;
(*attrColor)[1] = v.g;
(*attrColor)[2] = v.b;
(*attrColor)[3] = v.a;
++attrColor;
(*attrPos)[0] = v.x;
(*attrPos)[1] = v.y;
++attrPos;
}
void CMiniMap::DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const
{
// Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m)
// Scale square maps to fit in circular minimap area
const float s = sin(angle) * m_MapScale;
const float c = cos(angle) * m_MapScale;
const float m = coordMax / 2.f;
float quadTex[] = {
m*(-c + s + 1.f), m*(-c + -s + 1.f),
m*(c + s + 1.f), m*(-c + s + 1.f),
m*(c + -s + 1.f), m*(c + s + 1.f),
m*(c + -s + 1.f), m*(c + s + 1.f),
m*(-c + -s + 1.f), m*(c + -s + 1.f),
m*(-c + s + 1.f), m*(-c + -s + 1.f)
};
float quadVerts[] = {
x, y, z,
x2, y, z,
x2, y2, z,
x2, y2, z,
x, y2, z,
x, y, z
};
shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex);
shader->VertexPointer(3, GL_FLOAT, 0, quadVerts);
shader->AssertPointersBound();
if (!g_Renderer.m_SkipSubmit)
glDrawArrays(GL_TRIANGLES, 0, 6);
}
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture
// most of the time, updating the framebuffer twice a frame.
// Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling
// (those operations cause a gpu sync, which slows down the way gpu works)
void CMiniMap::Draw()
{
PROFILE3("render minimap");
// The terrain isn't actually initialized until the map is loaded, which
// happens when the game is started, so abort until then.
if (!g_Game || !g_Game->IsGameStarted())
return;
CSimulation2* sim = g_Game->GetSimulation2();
CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY);
ENSURE(cmpRangeManager);
// Set our globals in case they hadn't been set before
m_Camera = g_Game->GetView()->GetCamera();
m_Terrain = g_Game->GetWorld()->GetTerrain();
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 = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f);
if (!m_TerrainTexture || g_GameRestarted)
CreateTextures();
// only update 2x / second
// (note: since units only move a few pixels per second on the minimap,
// we can get away with infrequent updates; this is slow)
// TODO: Update all but camera at same speed as simulation
static double last_time;
const double cur_time = timer_Time();
const bool doUpdate = cur_time - last_time > 0.5;
if (doUpdate)
{
last_time = cur_time;
if (m_TerrainDirty || m_WaterHeight != g_Renderer.GetWaterManager()->m_WaterHeight)
RebuildTerrainTexture();
}
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 angle = GetAngle();
const float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f);
+ CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
// Disable depth updates to prevent apparent z-fighting-related issues
// with some drivers causing units to get drawn behind the texture.
glDepthMask(0);
CShaderProgramPtr shader;
CShaderTechniquePtr tech;
CShaderDefines baseDefines;
baseDefines.Add(str_MINIMAP_BASE, str_1);
+ if (m_Mask)
+ baseDefines.Add(str_MINIMAP_MASK, str_1);
+
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines);
tech->BeginPass();
shader = tech->GetShader();
// Draw the main textured quad
shader->BindTexture(str_baseTex, m_TerrainTexture);
+ if (m_Mask)
+ {
+ shader->BindTexture(str_maskTex, losTexture.GetTexture());
+ CMatrix3D maskTextureTransform = *losTexture.GetMinimapTextureMatrix();
+ // We need to have texture coordinates in the same coordinate space.
+ const float scale = 1.0f / texCoordMax;
+ maskTextureTransform.Scale(scale, scale, 1.0f);
+ shader->Uniform(str_maskTextureTransform, maskTextureTransform);
+ }
const CMatrix3D baseTransform = GetDefaultGuiMatrix();
CMatrix3D baseTextureTransform;
baseTextureTransform.SetIdentity();
shader->Uniform(str_transform, baseTransform);
shader->Uniform(str_textureTransform, baseTextureTransform);
+ if (m_Mask)
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z);
- // Draw territory boundaries
- glEnable(GL_BLEND);
+ if (!m_Mask)
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ // Draw territory boundaries
CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture();
shader->BindTexture(str_baseTex, territoryTexture.GetTexture());
+ if (m_Mask)
+ {
+ shader->BindTexture(str_maskTex, losTexture.GetTexture());
+ shader->Uniform(str_maskTextureTransform, *losTexture.GetMinimapTextureMatrix());
+ }
const CMatrix3D* territoryTransform = territoryTexture.GetMinimapTextureMatrix();
shader->Uniform(str_transform, baseTransform);
shader->Uniform(str_textureTransform, *territoryTransform);
DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);
tech->EndPass();
// Draw the LOS quad in black, using alpha values from the LOS texture
- CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
-
- CShaderDefines losDefines;
- losDefines.Add(str_MINIMAP_LOS, str_1);
- tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines);
- tech->BeginPass();
- shader = tech->GetShader();
- shader->BindTexture(str_baseTex, losTexture.GetTexture());
-
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix();
- shader->Uniform(str_transform, baseTransform);
- shader->Uniform(str_textureTransform, *losTransform);
+ if (!m_Mask)
+ {
+ CShaderDefines losDefines;
+ losDefines.Add(str_MINIMAP_LOS, str_1);
+ tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), losDefines);
+ tech->BeginPass();
+ shader = tech->GetShader();
+ shader->BindTexture(str_baseTex, losTexture.GetTexture());
+
+ const CMatrix3D* losTransform = losTexture.GetMinimapTextureMatrix();
+ shader->Uniform(str_transform, baseTransform);
+ shader->Uniform(str_textureTransform, *losTransform);
- DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);
- tech->EndPass();
+ DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z);
+ tech->EndPass();
+ }
glDisable(GL_BLEND);
PROFILE_START("minimap units");
CShaderDefines pointDefines;
pointDefines.Add(str_MINIMAP_POINT, str_1);
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), pointDefines);
tech->BeginPass();
shader = tech->GetShader();
shader->Uniform(str_transform, baseTransform);
shader->Uniform(str_pointSize, 3.f);
CMatrix3D unitMatrix;
unitMatrix.SetIdentity();
// Center the minimap on the origin of the axis of rotation.
unitMatrix.Translate(-(x2 - x) / 2.f, -(y2 - y) / 2.f, 0.f);
// Rotate the map.
unitMatrix.RotateZ(angle);
// Scale square maps to fit.
unitMatrix.Scale(unitScale, unitScale, 1.f);
// Move the minimap back to it's starting position.
unitMatrix.Translate((x2 - x) / 2.f, (y2 - y) / 2.f, 0.f);
// Move the minimap to it's final location.
unitMatrix.Translate(x, y, z);
// Apply the gui matrix.
unitMatrix *= GetDefaultGuiMatrix();
// Load the transform into the shader.
shader->Uniform(str_transform, unitMatrix);
const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);
CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);
if (doUpdate)
{
VertexArrayIterator attrPos = m_AttributePos.GetIterator();
VertexArrayIterator attrColor = m_AttributeColor.GetIterator();
m_EntitiesDrawn = 0;
MinimapUnitVertex v;
std::vector pingingVertices;
pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2);
if (cur_time > m_NextBlinkTime)
{
m_BlinkState = !m_BlinkState;
m_NextBlinkTime = cur_time + m_HalfBlinkDuration;
}
entity_pos_t posX, posZ;
for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
{
ICmpMinimap* cmpMinimap = static_cast(it->second);
if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
{
LosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer());
if (vis != LosVisibility::HIDDEN)
{
v.a = 255;
v.x = posX.ToFloat() * sx;
v.y = -posZ.ToFloat() * sy;
// Check minimap pinging to indicate something
if (m_BlinkState && cmpMinimap->CheckPing(cur_time, m_PingDuration))
{
v.r = 255; // ping color is white
v.g = 255;
v.b = 255;
pingingVertices.push_back(v);
}
else
{
addVertex(v, attrColor, attrPos);
++m_EntitiesDrawn;
}
}
}
}
// Add the pinged vertices at the end, so they are drawn on top
for (size_t v = 0; v < pingingVertices.size(); ++v)
{
addVertex(pingingVertices[v], attrColor, attrPos);
++m_EntitiesDrawn;
}
ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN);
m_VertexArray.Upload();
}
m_VertexArray.PrepareForRendering();
if (m_EntitiesDrawn > 0)
{
#if !CONFIG2_GLES
if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER)
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
u8* indexBase = m_IndexArray.Bind();
u8* base = m_VertexArray.Bind();
const GLsizei stride = (GLsizei)m_VertexArray.GetStride();
shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset);
shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset);
shader->AssertPointersBound();
if (!g_Renderer.m_SkipSubmit)
glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase);
g_Renderer.GetStats().m_DrawCalls++;
CVertexBuffer::Unbind();
#if !CONFIG2_GLES
if (g_RenderingOptions.GetRenderPath() == RenderPath::SHADER)
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
}
tech->EndPass();
DrawViewRect(unitMatrix);
PROFILE_END("minimap units");
// Reset depth mask
glDepthMask(1);
}
void CMiniMap::CreateTextures()
{
Destroy();
// Create terrain texture
glGenTextures(1, &m_TerrainTexture);
g_Renderer.BindTexture(0, m_TerrainTexture);
// Initialise texture with solid black, for the areas we don't
// overwrite with glTexSubImage2D later
u32* texData = new u32[m_TextureSize * m_TextureSize];
for (ssize_t i = 0; i < m_TextureSize * m_TextureSize; ++i)
texData[i] = 0xFF000000;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
delete[] texData;
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_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Rebuild and upload both of them
RebuildTerrainTexture();
}
void CMiniMap::RebuildTerrainTexture()
{
u32 x = 0;
u32 y = 0;
u32 w = m_MapSize - 1;
u32 h = m_MapSize - 1;
m_WaterHeight = g_Renderer.GetWaterManager()->m_WaterHeight;
m_TerrainDirty = false;
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 < m_WaterHeight && avgHeight > m_WaterHeight - m_ShallowPassageHeight)
{
// shallow water
*dataPtr++ = 0xffc09870;
}
else if (avgHeight < m_WaterHeight)
{
// Set water as constant color for consistency on different maps
*dataPtr++ = 0xffa07850;
}
else
{
int hmap = ((int)m_Terrain->GetHeightMap()[(y + j) * m_MapSize + x + i]) >> 8;
int val = (hmap / 3) + 170;
u32 color = 0xFFFFFFFF;
CMiniPatch* mp = m_Terrain->GetTile(x + i, y + j);
if (mp)
{
CTerrainTextureEntry* tex = mp->GetTextureEntry();
if (tex)
{
// If the texture can't be loaded yet, set the dirty flags
// so we'll try regenerating the terrain texture again soon
if(!tex->GetTexture()->TryLoad())
m_TerrainDirty = true;
color = tex->GetBaseColor();
}
}
*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_RGBA, GL_UNSIGNED_BYTE, m_TerrainData);
}
void CMiniMap::Destroy()
{
if (m_TerrainTexture)
{
glDeleteTextures(1, &m_TerrainTexture);
m_TerrainTexture = 0;
}
SAFE_ARRAY_DELETE(m_TerrainData);
}
// static
float CMiniMap::GetShallowPassageHeight()
{
float shallowPassageHeight = 0.0f;
CParamNode externalParamNode;
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses");
if (pathingSettings.GetChild("default").IsOk() && pathingSettings.GetChild("default").GetChild("MaxWaterDepth").IsOk())
shallowPassageHeight = pathingSettings.GetChild("default").GetChild("MaxWaterDepth").ToFloat();
return shallowPassageHeight;
}
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.h
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.h (revision 24140)
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.h (revision 24141)
@@ -1,123 +1,126 @@
-/* Copyright (C) 2019 Wildfire Games.
+/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
#ifndef INCLUDED_MINIMAP
#define INCLUDED_MINIMAP
#include "graphics/ShaderProgramPtr.h"
#include "gui/ObjectBases/IGUIObject.h"
#include "renderer/VertexArray.h"
class CCamera;
class CMatrix3D;
class CTerrain;
class CMiniMap : public IGUIObject
{
GUI_OBJECT(CMiniMap)
public:
CMiniMap(CGUI& pGUI);
virtual ~CMiniMap();
/**
* @return The maximum height for unit passage in water.
*/
static float GetShallowPassageHeight();
protected:
virtual void Draw();
/**
* @see IGUIObject#HandleMessage()
*/
virtual void HandleMessage(SGUIMessage& Message);
/**
* @see IGUIObject#IsMouseOver()
*/
virtual bool IsMouseOver() const;
// create the minimap textures
void CreateTextures();
// rebuild the terrain texture map
void RebuildTerrainTexture();
// destroy and free any memory and textures
void Destroy();
void SetCameraPos();
bool FireWorldClickEvent(int button, int clicks);
static const CStr EventNameWorldClick;
// the terrain we are mini-mapping
const CTerrain* m_Terrain;
const CCamera* m_Camera;
//Whether or not the mouse is currently down
bool m_Clicking;
// minimap texture handles
GLuint m_TerrainTexture;
// texture data
u32* m_TerrainData;
// whether we need to regenerate the terrain texture
bool m_TerrainDirty;
+ // Whether to draw a black square around and under the minimap.
+ bool m_Mask;
+
ssize_t m_Width, m_Height;
// map size
ssize_t m_MapSize;
// texture size
GLsizei m_TextureSize;
// 1.f if map is circular or 1.414f if square (to shrink it inside the circle)
float m_MapScale;
// maximal water height to allow the passage of a unit (for underwater shallows).
float m_ShallowPassageHeight;
float m_WaterHeight;
void DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const;
void DrawViewRect(CMatrix3D transform) const;
void GetMouseWorldCoordinates(float& x, float& z) const;
float GetAngle() const;
VertexIndexArray m_IndexArray;
VertexArray m_VertexArray;
VertexArray::Attribute m_AttributePos;
VertexArray::Attribute m_AttributeColor;
size_t m_EntitiesDrawn;
double m_PingDuration;
double m_HalfBlinkDuration;
double m_NextBlinkTime;
bool m_BlinkState;
};
#endif // INCLUDED_MINIMAP
Index: ps/trunk/source/ps/CStrInternStatic.h
===================================================================
--- ps/trunk/source/ps/CStrInternStatic.h (revision 24140)
+++ ps/trunk/source/ps/CStrInternStatic.h (revision 24141)
@@ -1,162 +1,164 @@
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see .
*/
// This file defines global CStrIntern variables, to avoid the cost of
// constructing CStrInterns frequently at runtime.
//
// A line like
// X(foo)
// defines a variable str_foo with value "foo".
//
// A line like
// X2(foo_0, "foo[0]")
// defines a variable str_foo_0 with value "foo[0]".
X(0)
X(1)
X(2)
X(ALPHABLEND_PASS_BLEND)
X(ALPHABLEND_PASS_OPAQUE)
X(BLEND)
X(BLOOM_NOP)
X(BLOOM_PASS_H)
X(BLOOM_PASS_V)
X(DECAL)
X(DISABLE_RECEIVE_SHADOWS)
X(IGNORE_LOS)
X(MINIMAP_BASE)
X(MINIMAP_LINE)
X(MINIMAP_LOS)
+X(MINIMAP_MASK)
X(MINIMAP_POINT)
X(MODE_SHADOWCAST)
X(MODE_SILHOUETTEDISPLAY)
X(MODE_SILHOUETTEOCCLUDER)
X(MODE_WIREFRAME)
X(SYS_HAS_ARB)
X(SYS_HAS_GLSL)
X(SYS_PREFER_GLSL)
X(USE_FANCY_EFFECTS)
X(USE_FP_SHADOW)
X(USE_GPU_SKINNING)
X(USE_INSTANCING)
X(USE_NORMALS)
X(USE_OBJECTCOLOR)
X(USE_REAL_DEPTH)
X(USE_REFLECTION)
X(USE_REFRACTION)
X(USE_SHADOW)
X(USE_SHADOW_PCF)
X(USE_SHADOW_SAMPLER)
X(USE_SHADOWS_ON_WATER)
X(USE_FOG)
X(WATERTYPE_CLAP)
X(WATERTYPE_LAKE)
X2(_emptystring, "")
X(a_apexPosition)
X(a_otherPosition)
X(a_retreatPosition)
X(a_skinJoints)
X(a_skinWeights)
X(a_splashPosition)
X(a_tangent)
X(a_waterInfo)
X(ambient)
X(baseTex)
X(blendTex)
X(bloom)
X(blurTex2)
X(blurTex4)
X(blurTex8)
X(brightness)
X(cameraPos)
X(color)
X(colorAdd)
X(colorMul)
X(delta)
X(depthTex)
X(foamTex)
X(fogColor)
X(fogParams)
X(foreground_overlay)
X(gui_add)
X(gui_basic)
X(gui_grayscale)
X(gui_solid)
X(gui_solid_mask)
X(gui_text)
X(hdr)
X(height)
X(instancingTransform)
X(losMatrix)
X(losTex)
X(losTex1)
X(losTex2)
X(losTransform)
X(los_interp)
X(mapSize)
X(maskTex)
+X(maskTextureTransform)
X(minimap)
X(modelViewMatrix)
X(murkiness)
X(normalMap)
X(normalMap2)
X(objectColor)
X(overlay_solid)
X(particle)
X(particle_solid)
X(playerColor)
X(pointSize)
X(qualityLevel)
X(reflectionMap)
X(reflectionMatrix)
X(refractionMap)
X(refractionMatrix)
X(renderedTex)
X(repeatScale)
X2(sans_10, "sans-10");
X(saturation)
X(screenSize)
X(shadingColor)
X(shadowScale)
X(shadowTex)
X(shadowTransform)
X(sharpness)
X(skinBlendMatrices)
X2(skinBlendMatrices_0, "skinBlendMatrices[0]")
X(skyBoxRot)
X(skyCube)
X(sky_simple)
X(sunColor)
X(sunDir)
X(tex)
X(texSize)
X(textureTransform)
X(time)
X(tint)
X(transform)
X(translation)
X(water_simple)
X(waterEffectsTex)
X(waterTex)
X(waveTex)
X(waviness)
X(waveParams1)
X(waveParams2)
X(width)
X(windAngle)
X(zFar)
X(zNear)