diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg
index 5824892984..793792ae84 100644
--- a/binaries/data/config/default.cfg
+++ b/binaries/data/config/default.cfg
@@ -449,6 +449,10 @@ howtoshownames = 0 ; Whether the specific names are show as default, as opposed
selectformationasone = "true" ; Whether to select formations as a whole by default.
[gui.session.minimap]
+; Icons that are displayed for some entities on a minimap.
+icons.enabled = "true"
+icons.opacity = 1.0
+icons.sizescale = 1.0
blinkduration = 1.7 ; The blink duration while pinging
pingduration = 50.0 ; The duration for which an entity will be pinged after an attack notification
diff --git a/binaries/data/mods/public/art/textures/ui/session/icons/minimap/civil_centre.png b/binaries/data/mods/public/art/textures/ui/session/icons/minimap/civil_centre.png
new file mode 100644
index 0000000000..b86712dc7c
--- /dev/null
+++ b/binaries/data/mods/public/art/textures/ui/session/icons/minimap/civil_centre.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5b8318553b62de53680dbd1ad39d61ffa6409a901951de4ed03c9f31d7e6bc9f
+size 792
diff --git a/binaries/data/mods/public/gui/options/options.json b/binaries/data/mods/public/gui/options/options.json
index 377140745a..9b7115ea7a 100644
--- a/binaries/data/mods/public/gui/options/options.json
+++ b/binaries/data/mods/public/gui/options/options.json
@@ -608,6 +608,12 @@
"min": 0,
"max": 60
},
+ {
+ "type": "boolean",
+ "label": "Minimap icons",
+ "tooltip": "Show special icons for some entities on the minimap.",
+ "config": "gui.session.minimap.icons.enabled"
+ },
{
"type": "boolean",
"label": "Chat notification attack",
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml b/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
index 620fae3e43..661191aa22 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
@@ -84,6 +84,10 @@
100
100
+
+ structure
+ civil_centre.png
+
diff --git a/source/graphics/MiniMapTexture.cpp b/source/graphics/MiniMapTexture.cpp
index 0376599a54..46f35cfc59 100644
--- a/source/graphics/MiniMapTexture.cpp
+++ b/source/graphics/MiniMapTexture.cpp
@@ -58,6 +58,8 @@ namespace
// f.e. use instancing.
const size_t MAX_ENTITIES_DRAWN = 65536 / 4;
+const size_t MAX_ICON_COUNT = 128;
+
const size_t FINAL_TEXTURE_SIZE = 512;
unsigned int ScaleColor(unsigned int color, float x)
@@ -444,10 +446,12 @@ void CMiniMapTexture::RenderFinalTexture(
unitMatrix.Translate(CVector3D(-1.0f, -1.0f, 0.0f));
shader->Uniform(str_transform, unitMatrix);
- CSimulation2::InterfaceList ents = m_Simulation.GetEntitiesWithInterface(IID_Minimap);
-
if (doUpdate)
{
+ m_Icons.clear();
+
+ CSimulation2::InterfaceList ents = m_Simulation.GetEntitiesWithInterface(IID_Minimap);
+
VertexArrayIterator attrPos = m_AttributePos.GetIterator();
VertexArrayIterator attrColor = m_AttributeColor.GetIterator();
@@ -467,6 +471,15 @@ void CMiniMapTexture::RenderFinalTexture(
m_NextBlinkTime = currentTime + m_HalfBlinkDuration;
}
+ bool iconsEnabled = false;
+ CFG_GET_VAL("gui.session.minimap.icons.enabled", iconsEnabled);
+ float iconsOpacity = 1.0f;
+ CFG_GET_VAL("gui.session.minimap.icons.opacity", iconsOpacity);
+ float iconsSizeScale = 1.0f;
+ CFG_GET_VAL("gui.session.minimap.icons.sizescale", iconsSizeScale);
+
+ bool iconsCountOverflow = false;
+
entity_pos_t posX, posZ;
for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
{
@@ -493,10 +506,29 @@ void CMiniMapTexture::RenderFinalTexture(
AddEntity(v, attrColor, attrPos, entityRadius);
++m_EntitiesDrawn;
}
+
+ if (!iconsEnabled || !cmpMinimap->HasIcon())
+ continue;
+
+ if (m_Icons.size() < MAX_ICON_COUNT)
+ {
+ CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(
+ CTextureProperties(cmpMinimap->GetIconPath()));
+ const CColor color(v.r / 255.0f, v.g / 255.0f, v.b / 255.0f, iconsOpacity);
+ m_Icons.emplace_back(Icon{
+ std::move(texture), color, v.position, cmpMinimap->GetIconSize() * iconsSizeScale * 0.5f});
+ }
+ else
+ {
+ iconsCountOverflow = true;
+ }
}
}
}
+ if (iconsCountOverflow)
+ LOGWARNING("Too many minimap icons to draw: %zu/%zu", m_Icons.size(), MAX_ICON_COUNT);
+
// Add the pinged vertices at the end, so they are drawn on top
for (const MinimapUnitVertex& vertex : pingingVertices)
{
diff --git a/source/graphics/MiniMapTexture.h b/source/graphics/MiniMapTexture.h
index 29b4733d89..9c4b31e1c8 100644
--- a/source/graphics/MiniMapTexture.h
+++ b/source/graphics/MiniMapTexture.h
@@ -18,11 +18,15 @@
#ifndef INCLUDED_MINIMAPTEXTURE
#define INCLUDED_MINIMAPTEXTURE
+#include "graphics/Color.h"
+#include "graphics/Texture.h"
+#include "maths/Vector2D.h"
#include "renderer/backend/gl/DeviceCommandContext.h"
#include "renderer/backend/gl/Texture.h"
#include "renderer/VertexArray.h"
#include
+#include
class CSimulation2;
class CTerrain;
@@ -51,6 +55,16 @@ public:
*/
static float GetShallowPassageHeight();
+ struct Icon
+ {
+ CTexturePtr texture;
+ CColor color;
+ CVector2D worldPosition;
+ float halfSize;
+ };
+ // Returns icons for corresponding entities on the minimap texture.
+ const std::vector& GetIcons() { return m_Icons; }
+
private:
void CreateTextures(
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
@@ -96,6 +110,8 @@ private:
double m_HalfBlinkDuration = 0.0;
double m_NextBlinkTime = 0.0;
bool m_BlinkState = false;
+
+ std::vector m_Icons;
};
#endif // INCLUDED_MINIMAPTEXTURE
diff --git a/source/gui/ObjectTypes/CMiniMap.cpp b/source/gui/ObjectTypes/CMiniMap.cpp
index 5310687637..648fa9eeea 100644
--- a/source/gui/ObjectTypes/CMiniMap.cpp
+++ b/source/gui/ObjectTypes/CMiniMap.cpp
@@ -444,6 +444,19 @@ void CMiniMap::Draw(CCanvas2D& canvas)
tech->EndPass();
}
+ for (const CMiniMapTexture::Icon& icon : miniMapTexture.GetIcons())
+ {
+ const CVector2D center = WorldSpaceToMiniMapSpace(
+ CVector3D(icon.worldPosition.X, 0.0f, icon.worldPosition.Y));
+ const CRect destination(
+ center.X - icon.halfSize, center.Y - icon.halfSize,
+ center.X + icon.halfSize, center.Y + icon.halfSize);
+ const CRect source(0, 0, icon.texture->GetWidth(), icon.texture->GetHeight());
+ canvas.DrawTexture(
+ icon.texture, destination, source,
+ icon.color, CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f);
+ }
+
PROFILE_START("minimap flares");
DrawViewRect(canvas);
diff --git a/source/simulation2/components/CCmpMinimap.cpp b/source/simulation2/components/CCmpMinimap.cpp
index 0ef77d64af..1fe5358214 100644
--- a/source/simulation2/components/CCmpMinimap.cpp
+++ b/source/simulation2/components/CCmpMinimap.cpp
@@ -57,6 +57,10 @@ public:
double m_PingEndTime;
bool m_IsPinging;
+ bool m_HasIcon = false;
+ std::string m_IconPath;
+ float m_IconSize = 16.0f;
+
static std::string GetSchema()
{
return
@@ -84,6 +88,14 @@ public:
"0255"
""
""
+ ""
+ ""
+ ""
+ ""
+ "0"
+ ""
+ ""
+ ""
"";
}
@@ -92,6 +104,7 @@ public:
m_Active = true;
m_IsPinging = false;
m_PingEndTime = 0.0;
+ m_HasIcon = false;
const CParamNode& color = paramNode.GetChild("Color");
if (color.IsOk())
@@ -109,6 +122,18 @@ public:
m_G = 0;
m_B = 255;
}
+
+ const CParamNode& iconNode = paramNode.GetChild("Icon");
+ if (iconNode.IsOk())
+ {
+ const CParamNode& iconSizeNode = iconNode.GetChild("@size");
+ if (iconSizeNode.IsOk())
+ {
+ m_HasIcon = true;
+ m_IconPath = "art/textures/ui/session/icons/minimap/" + iconNode.ToString();
+ m_IconSize = iconSizeNode.ToFloat();
+ }
+ }
}
virtual void Deinit()
@@ -238,6 +263,21 @@ public:
m_G = (u8) (color.g * 255);
m_B = (u8) (color.b * 255);
}
+
+ bool HasIcon() override
+ {
+ return m_HasIcon;
+ }
+
+ std::string GetIconPath() override
+ {
+ return m_IconPath;
+ }
+
+ float GetIconSize() override
+ {
+ return m_IconSize;
+ }
};
REGISTER_COMPONENT_TYPE(Minimap)
diff --git a/source/simulation2/components/ICmpMinimap.h b/source/simulation2/components/ICmpMinimap.h
index 71effeb0ff..b508805c54 100644
--- a/source/simulation2/components/ICmpMinimap.h
+++ b/source/simulation2/components/ICmpMinimap.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018 Wildfire Games.
+/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -22,6 +22,8 @@
#include "simulation2/helpers/Position.h"
+#include
+
/**
* Per-unit minimap data.
*/
@@ -45,6 +47,18 @@ public:
*/
virtual void UpdateColor() = 0;
+ /**
+ * Returns true if a minimap should have icon of this entity.
+ */
+ virtual bool HasIcon() = 0;
+
+ /**
+ * Returns a path to icon of this entity.
+ */
+ virtual std::string GetIconPath() = 0;
+
+ virtual float GetIconSize() = 0;
+
DECLARE_INTERFACE_TYPE(Minimap)
};