2022-01-03 11:49:12 +01:00
|
|
|
/* Copyright (C) 2022 Wildfire Games.
|
2021-06-01 20:55:35 +02:00
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
|
|
#include "MiniMapTexture.h"
|
|
|
|
|
2021-11-12 20:15:48 +01:00
|
|
|
#include "graphics/GameView.h"
|
|
|
|
#include "graphics/LOSTexture.h"
|
2021-06-01 20:55:35 +02:00
|
|
|
#include "graphics/MiniPatch.h"
|
2021-11-12 20:15:48 +01:00
|
|
|
#include "graphics/ShaderManager.h"
|
|
|
|
#include "graphics/ShaderProgramPtr.h"
|
2021-06-01 20:55:35 +02:00
|
|
|
#include "graphics/Terrain.h"
|
|
|
|
#include "graphics/TerrainTextureEntry.h"
|
|
|
|
#include "graphics/TerrainTextureManager.h"
|
|
|
|
#include "graphics/TerritoryTexture.h"
|
2022-01-07 15:33:54 +01:00
|
|
|
#include "graphics/TextureManager.h"
|
2021-06-01 20:55:35 +02:00
|
|
|
#include "lib/bits.h"
|
2021-11-12 20:15:48 +01:00
|
|
|
#include "lib/timer.h"
|
|
|
|
#include "ps/ConfigDB.h"
|
2021-06-01 20:55:35 +02:00
|
|
|
#include "ps/CStrInternStatic.h"
|
|
|
|
#include "ps/Filesystem.h"
|
|
|
|
#include "ps/Game.h"
|
|
|
|
#include "ps/World.h"
|
|
|
|
#include "ps/XML/Xeromyces.h"
|
2022-02-05 17:59:23 +01:00
|
|
|
#include "renderer/backend/gl/Device.h"
|
2021-06-01 20:55:35 +02:00
|
|
|
#include "renderer/Renderer.h"
|
|
|
|
#include "renderer/RenderingOptions.h"
|
2022-01-04 14:29:01 +01:00
|
|
|
#include "renderer/SceneRenderer.h"
|
2021-06-01 20:55:35 +02:00
|
|
|
#include "renderer/WaterManager.h"
|
|
|
|
#include "scriptinterface/Object.h"
|
|
|
|
#include "simulation2/Simulation2.h"
|
|
|
|
#include "simulation2/components/ICmpMinimap.h"
|
|
|
|
#include "simulation2/components/ICmpRangeManager.h"
|
|
|
|
#include "simulation2/system/ParamNode.h"
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
2021-11-12 20:15:48 +01:00
|
|
|
// 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;
|
|
|
|
|
|
|
|
const size_t FINAL_TEXTURE_SIZE = 512;
|
|
|
|
|
2021-06-01 20:55:35 +02:00
|
|
|
unsigned int ScaleColor(unsigned int color, float x)
|
|
|
|
{
|
|
|
|
unsigned int r = unsigned(float(color & 0xff) * x);
|
2021-11-12 20:15:48 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DrawTexture(CShaderProgramPtr shader)
|
|
|
|
{
|
|
|
|
const float quadUVs[] =
|
|
|
|
{
|
|
|
|
0.0f, 0.0f,
|
|
|
|
1.0f, 0.0f,
|
|
|
|
1.0f, 1.0f,
|
|
|
|
|
|
|
|
1.0f, 1.0f,
|
|
|
|
0.0f, 1.0f,
|
|
|
|
0.0f, 0.0f
|
|
|
|
};
|
|
|
|
const float quadVertices[] =
|
|
|
|
{
|
|
|
|
-1.0f, -1.0f, 0.0f,
|
|
|
|
1.0f, -1.0f, 0.0f,
|
|
|
|
1.0f, 1.0f, 0.0f,
|
|
|
|
|
|
|
|
1.0f, 1.0f, 0.0f,
|
|
|
|
-1.0f, 1.0f, 0.0f,
|
|
|
|
-1.0f, -1.0f, 0.0f
|
|
|
|
};
|
|
|
|
|
|
|
|
shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadUVs);
|
|
|
|
shader->VertexPointer(3, GL_FLOAT, 0, quadVertices);
|
|
|
|
shader->AssertPointersBound();
|
|
|
|
|
2022-01-03 13:16:16 +01:00
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
2021-11-12 20:15:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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<u8[4]>& attrColor,
|
|
|
|
VertexArrayIterator<float[2]>& 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;
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation)
|
2021-11-12 20:15:48 +01:00
|
|
|
: m_Simulation(simulation), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW)
|
2021-06-01 20:55:35 +02:00
|
|
|
{
|
|
|
|
// Register Relax NG validator.
|
|
|
|
CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng");
|
|
|
|
|
|
|
|
m_ShallowPassageHeight = GetShallowPassageHeight();
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
double blinkDuration = 1.0;
|
|
|
|
// Tests won't have config initialised
|
|
|
|
if (CConfigDB::IsInitialised())
|
|
|
|
{
|
|
|
|
CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration);
|
|
|
|
CFG_GET_VAL("gui.session.minimap.pingduration", m_PingDuration);
|
|
|
|
}
|
|
|
|
m_HalfBlinkDuration = blinkDuration / 2.0;
|
|
|
|
|
|
|
|
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<u16> index = m_IndexArray.GetIterator();
|
|
|
|
for (u16 i = 0; i < MAX_ENTITIES_DRAWN; ++i)
|
|
|
|
*index++ = i;
|
|
|
|
m_IndexArray.Upload();
|
|
|
|
m_IndexArray.FreeBackingStore();
|
|
|
|
|
|
|
|
VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>();
|
|
|
|
VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>();
|
|
|
|
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();
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CMiniMapTexture::~CMiniMapTexture()
|
|
|
|
{
|
|
|
|
DestroyTextures();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMiniMapTexture::Update(const float UNUSED(deltaRealTime))
|
|
|
|
{
|
2022-01-04 14:29:01 +01:00
|
|
|
if (m_WaterHeight != g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight)
|
2021-11-12 20:15:48 +01:00
|
|
|
{
|
|
|
|
m_TerrainTextureDirty = true;
|
|
|
|
m_FinalTextureDirty = true;
|
|
|
|
}
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
2022-01-05 15:49:54 +01:00
|
|
|
void CMiniMapTexture::Render(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
|
2021-06-01 20:55:35 +02:00
|
|
|
{
|
|
|
|
const CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
|
|
|
if (!terrain)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!m_TerrainTexture)
|
2022-01-05 15:49:54 +01:00
|
|
|
CreateTextures(deviceCommandContext, terrain);
|
2021-06-01 20:55:35 +02:00
|
|
|
|
2021-11-12 20:15:48 +01:00
|
|
|
if (m_TerrainTextureDirty)
|
2022-01-05 15:49:54 +01:00
|
|
|
RebuildTerrainTexture(deviceCommandContext, terrain);
|
2021-11-12 20:15:48 +01:00
|
|
|
|
2022-01-19 18:28:47 +01:00
|
|
|
RenderFinalTexture(deviceCommandContext);
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
2022-01-05 15:49:54 +01:00
|
|
|
void CMiniMapTexture::CreateTextures(
|
|
|
|
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, const CTerrain* terrain)
|
2021-06-01 20:55:35 +02:00
|
|
|
{
|
|
|
|
DestroyTextures();
|
|
|
|
|
2021-11-12 20:15:48 +01:00
|
|
|
m_MapSize = terrain->GetVerticesPerSide();
|
2022-01-05 15:49:54 +01:00
|
|
|
const size_t textureSize = round_up_to_pow2(static_cast<size_t>(m_MapSize));
|
2021-11-12 20:15:48 +01:00
|
|
|
|
2021-12-25 01:26:10 +01:00
|
|
|
const Renderer::Backend::Sampler::Desc defaultSamplerDesc =
|
|
|
|
Renderer::Backend::Sampler::MakeDefaultSampler(
|
|
|
|
Renderer::Backend::Sampler::Filter::LINEAR,
|
|
|
|
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
|
|
|
|
2021-06-01 20:55:35 +02:00
|
|
|
// Create terrain texture
|
2022-02-13 20:30:28 +01:00
|
|
|
m_TerrainTexture = deviceCommandContext->GetDevice()->CreateTexture2D("MiniMapTerrainTexture",
|
2022-01-05 15:49:54 +01:00
|
|
|
Renderer::Backend::Format::R8G8B8A8, textureSize, textureSize, defaultSamplerDesc);
|
2021-06-01 20:55:35 +02:00
|
|
|
|
|
|
|
// Initialise texture with solid black, for the areas we don't
|
2022-01-05 15:49:54 +01:00
|
|
|
// overwrite with uploading later.
|
|
|
|
std::unique_ptr<u32[]> texData = std::make_unique<u32[]>(textureSize * textureSize);
|
|
|
|
for (size_t i = 0; i < textureSize * textureSize; ++i)
|
2021-06-01 20:55:35 +02:00
|
|
|
texData[i] = 0xFF000000;
|
2022-01-05 15:49:54 +01:00
|
|
|
deviceCommandContext->UploadTexture(
|
|
|
|
m_TerrainTexture.get(), Renderer::Backend::Format::R8G8B8A8,
|
|
|
|
texData.get(), textureSize * textureSize * 4);
|
|
|
|
texData.reset();
|
2021-06-01 20:55:35 +02:00
|
|
|
|
2022-01-05 15:49:54 +01:00
|
|
|
m_TerrainData = std::make_unique<u32[]>((m_MapSize - 1) * (m_MapSize - 1));
|
2021-11-12 20:15:48 +01:00
|
|
|
|
2022-02-13 20:30:28 +01:00
|
|
|
m_FinalTexture = deviceCommandContext->GetDevice()->CreateTexture2D("MiniMapFinalTexture",
|
2021-12-25 01:26:10 +01:00
|
|
|
Renderer::Backend::Format::R8G8B8A8, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE, defaultSamplerDesc);
|
2021-11-12 20:15:48 +01:00
|
|
|
|
2022-02-05 17:59:23 +01:00
|
|
|
m_FinalTextureFramebuffer = Renderer::Backend::GL::CFramebuffer::Create(
|
|
|
|
m_FinalTexture.get(), nullptr);
|
|
|
|
ENSURE(m_FinalTextureFramebuffer);
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CMiniMapTexture::DestroyTextures()
|
|
|
|
{
|
2021-12-25 01:26:10 +01:00
|
|
|
m_TerrainTexture.reset();
|
|
|
|
m_FinalTexture.reset();
|
2022-01-05 15:49:54 +01:00
|
|
|
m_TerrainData.reset();
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
2022-01-05 15:49:54 +01:00
|
|
|
void CMiniMapTexture::RebuildTerrainTexture(
|
|
|
|
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
|
|
|
const CTerrain* terrain)
|
2021-06-01 20:55:35 +02:00
|
|
|
{
|
2021-06-01 21:50:15 +02:00
|
|
|
const u32 x = 0;
|
|
|
|
const u32 y = 0;
|
|
|
|
const u32 width = m_MapSize - 1;
|
|
|
|
const u32 height = m_MapSize - 1;
|
2021-06-01 20:55:35 +02:00
|
|
|
|
2022-01-04 14:29:01 +01:00
|
|
|
m_WaterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight;
|
2021-11-12 20:15:48 +01:00
|
|
|
m_TerrainTextureDirty = false;
|
2021-06-01 20:55:35 +02:00
|
|
|
|
2021-06-01 21:50:15 +02:00
|
|
|
for (u32 j = 0; j < height; ++j)
|
2021-06-01 20:55:35 +02:00
|
|
|
{
|
2022-01-05 15:49:54 +01:00
|
|
|
u32* dataPtr = m_TerrainData.get() + ((y + j) * width) + x;
|
2021-06-01 21:50:15 +02:00
|
|
|
for (u32 i = 0; i < width; ++i)
|
2021-06-01 20:55:35 +02:00
|
|
|
{
|
2021-06-01 21:50:15 +02:00
|
|
|
const float avgHeight = ( terrain->GetVertexGroundLevel((int)i, (int)j)
|
2021-06-01 20:55:35 +02:00
|
|
|
+ terrain->GetVertexGroundLevel((int)i+1, (int)j)
|
|
|
|
+ terrain->GetVertexGroundLevel((int)i, (int)j+1)
|
|
|
|
+ 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)terrain->GetHeightMap()[(y + j) * m_MapSize + x + i]) >> 8;
|
|
|
|
int val = (hmap / 3) + 170;
|
|
|
|
|
|
|
|
u32 color = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
CMiniPatch* mp = 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())
|
2021-11-12 20:15:48 +01:00
|
|
|
m_TerrainTextureDirty = true;
|
2021-06-01 20:55:35 +02:00
|
|
|
|
|
|
|
color = tex->GetBaseColor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*dataPtr++ = ScaleColor(color, float(val) / 255.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upload the texture
|
2022-01-05 15:49:54 +01:00
|
|
|
deviceCommandContext->UploadTextureRegion(
|
|
|
|
m_TerrainTexture.get(), Renderer::Backend::Format::R8G8B8A8,
|
|
|
|
m_TerrainData.get(), width * height * 4, 0, 0, width, height);
|
2021-06-01 20:55:35 +02:00
|
|
|
}
|
|
|
|
|
2022-01-19 18:28:47 +01:00
|
|
|
void CMiniMapTexture::RenderFinalTexture(
|
|
|
|
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
|
2021-11-12 20:15:48 +01:00
|
|
|
{
|
|
|
|
// 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
|
|
|
|
const double currentTime = timer_Time();
|
|
|
|
const bool doUpdate = (currentTime - m_LastFinalTextureUpdate > 0.5) || m_FinalTextureDirty;
|
|
|
|
if (doUpdate)
|
|
|
|
m_LastFinalTextureUpdate = currentTime;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
m_FinalTextureDirty = false;
|
|
|
|
|
2022-02-05 17:59:23 +01:00
|
|
|
deviceCommandContext->SetFramebuffer(m_FinalTextureFramebuffer.get());
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
const SViewPort oldViewPort = g_Renderer.GetViewport();
|
|
|
|
const SViewPort viewPort = { 0, 0, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE };
|
|
|
|
g_Renderer.SetViewport(viewPort);
|
|
|
|
|
2021-12-09 19:07:10 +01:00
|
|
|
CmpPtr<ICmpRangeManager> cmpRangeManager(m_Simulation, SYSTEM_ENTITY);
|
2021-11-12 20:15:48 +01:00
|
|
|
ENSURE(cmpRangeManager);
|
|
|
|
CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
|
|
|
|
|
|
|
|
const float invTileMapSize = 1.0f / static_cast<float>(TERRAIN_TILE_SIZE * m_MapSize);
|
2022-01-05 15:49:54 +01:00
|
|
|
const float texCoordMax = m_TerrainTexture ? static_cast<float>(m_MapSize - 1) / m_TerrainTexture->GetWidth() : 1.0f;
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
CShaderProgramPtr shader;
|
|
|
|
CShaderTechniquePtr tech;
|
|
|
|
|
|
|
|
CShaderDefines baseDefines;
|
|
|
|
baseDefines.Add(str_MINIMAP_BASE, str_1);
|
|
|
|
|
2021-12-14 07:34:02 +01:00
|
|
|
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines);
|
2022-01-19 18:28:47 +01:00
|
|
|
Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc =
|
|
|
|
tech->GetGraphicsPipelineStateDesc();
|
2021-11-12 20:15:48 +01:00
|
|
|
tech->BeginPass();
|
2022-01-19 18:28:47 +01:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc);
|
2021-11-12 20:15:48 +01:00
|
|
|
shader = tech->GetShader();
|
|
|
|
|
|
|
|
if (m_TerrainTexture)
|
2021-12-30 17:37:51 +01:00
|
|
|
shader->BindTexture(str_baseTex, m_TerrainTexture.get());
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
CMatrix3D baseTransform;
|
|
|
|
baseTransform.SetIdentity();
|
|
|
|
CMatrix3D baseTextureTransform;
|
|
|
|
baseTextureTransform.SetIdentity();
|
|
|
|
|
|
|
|
CMatrix3D terrainTransform;
|
|
|
|
terrainTransform.SetIdentity();
|
|
|
|
terrainTransform.Scale(texCoordMax, texCoordMax, 1.0f);
|
|
|
|
shader->Uniform(str_transform, baseTransform);
|
|
|
|
shader->Uniform(str_textureTransform, terrainTransform);
|
|
|
|
|
|
|
|
if (m_TerrainTexture)
|
|
|
|
DrawTexture(shader);
|
|
|
|
|
2022-01-19 18:28:47 +01:00
|
|
|
pipelineStateDesc.blendState.enabled = true;
|
|
|
|
pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor =
|
|
|
|
Renderer::Backend::BlendFactor::SRC_ALPHA;
|
|
|
|
pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor =
|
|
|
|
Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA;
|
|
|
|
pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp =
|
|
|
|
Renderer::Backend::BlendOp::ADD;
|
2022-01-31 21:10:06 +01:00
|
|
|
pipelineStateDesc.blendState.colorWriteMask =
|
|
|
|
Renderer::Backend::ColorWriteMask::RED |
|
|
|
|
Renderer::Backend::ColorWriteMask::GREEN |
|
|
|
|
Renderer::Backend::ColorWriteMask::BLUE;
|
2022-01-19 18:28:47 +01:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc);
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
// Draw territory boundaries
|
|
|
|
CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture();
|
|
|
|
|
|
|
|
shader->BindTexture(str_baseTex, territoryTexture.GetTexture());
|
|
|
|
shader->Uniform(str_transform, baseTransform);
|
2022-01-05 15:49:54 +01:00
|
|
|
shader->Uniform(str_textureTransform, territoryTexture.GetMinimapTextureMatrix());
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
DrawTexture(shader);
|
|
|
|
|
2022-01-19 18:28:47 +01:00
|
|
|
pipelineStateDesc.blendState.enabled = false;
|
2022-01-31 21:10:06 +01:00
|
|
|
pipelineStateDesc.blendState.colorWriteMask =
|
|
|
|
Renderer::Backend::ColorWriteMask::ALPHA;
|
2022-01-19 18:28:47 +01:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc);
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
shader->BindTexture(str_baseTex, losTexture.GetTexture());
|
|
|
|
shader->Uniform(str_transform, baseTransform);
|
2022-01-05 15:49:54 +01:00
|
|
|
shader->Uniform(str_textureTransform, losTexture.GetMinimapTextureMatrix());
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
DrawTexture(shader);
|
|
|
|
|
|
|
|
tech->EndPass();
|
|
|
|
|
|
|
|
CShaderDefines pointDefines;
|
|
|
|
pointDefines.Add(str_MINIMAP_POINT, str_1);
|
2021-12-14 07:34:02 +01:00
|
|
|
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, pointDefines);
|
2021-11-12 20:15:48 +01:00
|
|
|
tech->BeginPass();
|
2022-01-19 18:28:47 +01:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
|
|
|
tech->GetGraphicsPipelineStateDesc());
|
2021-11-12 20:15:48 +01:00
|
|
|
shader = tech->GetShader();
|
|
|
|
shader->Uniform(str_transform, baseTransform);
|
|
|
|
shader->Uniform(str_pointSize, 9.0f);
|
|
|
|
|
|
|
|
CMatrix3D unitMatrix;
|
|
|
|
unitMatrix.SetIdentity();
|
|
|
|
// Convert world space coordinates into [0, 2].
|
|
|
|
const float unitScale = invTileMapSize;
|
|
|
|
unitMatrix.Scale(unitScale * 2.0f, unitScale * 2.0f, 1.0f);
|
|
|
|
// Offset the coordinates to [-1, 1].
|
|
|
|
unitMatrix.Translate(CVector3D(-1.0f, -1.0f, 0.0f));
|
|
|
|
shader->Uniform(str_transform, unitMatrix);
|
|
|
|
|
2021-12-09 19:07:10 +01:00
|
|
|
CSimulation2::InterfaceList ents = m_Simulation.GetEntitiesWithInterface(IID_Minimap);
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
if (doUpdate)
|
|
|
|
{
|
|
|
|
VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>();
|
|
|
|
VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>();
|
|
|
|
|
|
|
|
m_EntitiesDrawn = 0;
|
|
|
|
MinimapUnitVertex v;
|
|
|
|
std::vector<MinimapUnitVertex> pingingVertices;
|
|
|
|
pingingVertices.reserve(MAX_ENTITIES_DRAWN / 2);
|
|
|
|
|
|
|
|
if (currentTime > m_NextBlinkTime)
|
|
|
|
{
|
|
|
|
m_BlinkState = !m_BlinkState;
|
|
|
|
m_NextBlinkTime = currentTime + m_HalfBlinkDuration;
|
|
|
|
}
|
|
|
|
|
|
|
|
entity_pos_t posX, posZ;
|
|
|
|
for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
|
|
|
|
{
|
|
|
|
ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second);
|
|
|
|
if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ))
|
|
|
|
{
|
2021-12-09 19:07:10 +01:00
|
|
|
LosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, m_Simulation.GetSimContext().GetCurrentDisplayedPlayer());
|
2021-11-12 20:15:48 +01:00
|
|
|
if (vis != LosVisibility::HIDDEN)
|
|
|
|
{
|
|
|
|
v.a = 255;
|
|
|
|
v.x = posX.ToFloat();
|
|
|
|
v.y = posZ.ToFloat();
|
|
|
|
|
|
|
|
// Check minimap pinging to indicate something
|
|
|
|
if (m_BlinkState && cmpMinimap->CheckPing(currentTime, 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 (const MinimapUnitVertex& vertex : pingingVertices)
|
|
|
|
{
|
|
|
|
addVertex(vertex, attrColor, attrPos);
|
|
|
|
++m_EntitiesDrawn;
|
|
|
|
}
|
|
|
|
|
|
|
|
ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN);
|
|
|
|
m_VertexArray.Upload();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_VertexArray.PrepareForRendering();
|
|
|
|
|
|
|
|
if (m_EntitiesDrawn > 0)
|
|
|
|
{
|
2022-02-01 18:58:21 +01:00
|
|
|
Renderer::Backend::GL::CDeviceCommandContext::ScissorRect scissorRect;
|
|
|
|
scissorRect.x = scissorRect.y = 1;
|
|
|
|
scissorRect.width = scissorRect.height = FINAL_TEXTURE_SIZE - 2;
|
|
|
|
deviceCommandContext->SetScissors(1, &scissorRect);
|
2021-11-12 20:15:48 +01:00
|
|
|
#if !CONFIG2_GLES
|
|
|
|
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();
|
|
|
|
|
2022-01-03 13:16:16 +01:00
|
|
|
glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase);
|
2021-11-12 20:15:48 +01:00
|
|
|
|
|
|
|
g_Renderer.GetStats().m_DrawCalls++;
|
|
|
|
CVertexBuffer::Unbind();
|
|
|
|
|
|
|
|
#if !CONFIG2_GLES
|
|
|
|
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
|
|
|
#endif
|
2022-02-01 18:58:21 +01:00
|
|
|
deviceCommandContext->SetScissors(0, nullptr);
|
2021-11-12 20:15:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
tech->EndPass();
|
2022-02-05 17:59:23 +01:00
|
|
|
deviceCommandContext->SetFramebuffer(
|
|
|
|
deviceCommandContext->GetDevice()->GetCurrentBackbuffer());
|
2021-11-12 20:15:48 +01:00
|
|
|
g_Renderer.SetViewport(oldViewPort);
|
|
|
|
}
|
|
|
|
|
2021-06-01 20:55:35 +02:00
|
|
|
// static
|
|
|
|
float CMiniMapTexture::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;
|
|
|
|
}
|