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) };