Index: ps/trunk/source/graphics/GameView.cpp
===================================================================
--- ps/trunk/source/graphics/GameView.cpp (revision 25627)
+++ ps/trunk/source/graphics/GameView.cpp (revision 25628)
@@ -1,413 +1,423 @@
/* Copyright (C) 2021 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 "GameView.h"
#include "graphics/CameraController.h"
#include "graphics/CinemaManager.h"
#include "graphics/ColladaManager.h"
#include "graphics/HFTracer.h"
#include "graphics/LOSTexture.h"
#include "graphics/LightEnv.h"
+#include "graphics/MiniMapTexture.h"
#include "graphics/Model.h"
#include "graphics/ObjectManager.h"
#include "graphics/Patch.h"
#include "graphics/SkeletonAnimManager.h"
#include "graphics/SmoothedValue.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureManager.h"
#include "graphics/TerritoryTexture.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "lib/input.h"
#include "lib/timer.h"
#include "lobby/IXmppClient.h"
#include "maths/BoundingBoxAligned.h"
#include "maths/MathUtil.h"
#include "maths/Matrix3D.h"
#include "maths/Quaternion.h"
#include "ps/ConfigDB.h"
#include "ps/Filesystem.h"
#include "ps/Game.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Loader.h"
#include "ps/LoaderThunks.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h"
#include "ps/TouchInput.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpRangeManager.h"
#include
class CGameViewImpl
{
NONCOPYABLE(CGameViewImpl);
public:
CGameViewImpl(CGame* game)
: Game(game),
ColladaManager(g_VFS), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
ObjectManager(MeshManager, SkeletonAnimManager, *game->GetSimulation2()),
LOSTexture(*game->GetSimulation2()),
TerritoryTexture(*game->GetSimulation2()),
+ MiniMapTexture(*game->GetSimulation2()),
ViewCamera(),
CullCamera(),
LockCullCamera(false),
Culling(true),
CameraController(new CCameraController(ViewCamera))
{
}
CGame* Game;
CColladaManager ColladaManager;
CMeshManager MeshManager;
CSkeletonAnimManager SkeletonAnimManager;
CObjectManager ObjectManager;
CLOSTexture LOSTexture;
CTerritoryTexture TerritoryTexture;
+ CMiniMapTexture MiniMapTexture;
/**
* this camera controls the eye position when rendering
*/
CCamera ViewCamera;
/**
* this camera controls the frustum that is used for culling
* and shadow calculations
*
* Note that all code that works with camera movements should only change
* m_ViewCamera. The render functions automatically sync the cull camera to
* the view camera depending on the value of m_LockCullCamera.
*/
CCamera CullCamera;
/**
* When @c true, the cull camera is locked in place.
* When @c false, the cull camera follows the view camera.
*
* Exposed to JS as gameView.lockCullCamera
*/
bool LockCullCamera;
/**
* When @c true, culling is enabled so that only models that have a chance of
* being visible are sent to the renderer.
* Otherwise, the entire world is sent to the renderer.
*
* Exposed to JS as gameView.culling
*/
bool Culling;
/**
* Cache global lighting environment. This is used to check whether the
* environment has changed during the last frame, so that vertex data can be updated etc.
*/
CLightEnv CachedLightEnv;
CCinemaManager CinemaManager;
/**
* Controller of the view's camera. We use a std::unique_ptr for an easy
* on the fly replacement. It's guaranteed that the pointer is never nulllptr.
*/
std::unique_ptr CameraController;
};
#define IMPLEMENT_BOOLEAN_SETTING(NAME) \
bool CGameView::Get##NAME##Enabled() const \
{ \
return m->NAME; \
} \
\
void CGameView::Set##NAME##Enabled(bool Enabled) \
{ \
m->NAME = Enabled; \
}
IMPLEMENT_BOOLEAN_SETTING(Culling);
IMPLEMENT_BOOLEAN_SETTING(LockCullCamera);
bool CGameView::GetConstrainCameraEnabled() const
{
return m->CameraController->GetConstrainCamera();
}
void CGameView::SetConstrainCameraEnabled(bool enabled)
{
m->CameraController->SetConstrainCamera(enabled);
}
#undef IMPLEMENT_BOOLEAN_SETTING
CGameView::CGameView(CGame *pGame):
m(new CGameViewImpl(pGame))
{
m->CullCamera = m->ViewCamera;
g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera);
}
CGameView::~CGameView()
{
UnloadResources();
delete m;
}
void CGameView::SetViewport(const SViewPort& vp)
{
m->CameraController->SetViewport(vp);
}
CObjectManager& CGameView::GetObjectManager()
{
return m->ObjectManager;
}
CCamera* CGameView::GetCamera()
{
return &m->ViewCamera;
}
CCinemaManager* CGameView::GetCinema()
{
return &m->CinemaManager;
-};
+}
CLOSTexture& CGameView::GetLOSTexture()
{
return m->LOSTexture;
}
CTerritoryTexture& CGameView::GetTerritoryTexture()
{
return m->TerritoryTexture;
}
+CMiniMapTexture& CGameView::GetMiniMapTexture()
+{
+ return m->MiniMapTexture;
+}
+
int CGameView::Initialize()
{
m->CameraController->LoadConfig();
return 0;
}
void CGameView::RegisterInit()
{
// CGameView init
RegMemFun(this, &CGameView::Initialize, L"CGameView init", 1);
RegMemFun(g_TexMan.GetSingletonPtr(), &CTerrainTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 60);
RegMemFun(g_Renderer.GetSingletonPtr(), &CRenderer::LoadAlphaMaps, L"LoadAlphaMaps", 5);
}
void CGameView::BeginFrame()
{
if (m->LockCullCamera == false)
{
// Set up cull camera
m->CullCamera = m->ViewCamera;
}
g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera);
CheckLightEnv();
m->Game->CachePlayerColors();
}
void CGameView::Render()
{
g_Renderer.RenderScene(*this);
}
///////////////////////////////////////////////////////////
// This callback is part of the Scene interface
// Submit all objects visible in the given frustum
void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
{
{
PROFILE3("submit terrain");
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f;
const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide();
// find out which patches will be drawn
for (ssize_t j=0; jGetPatch(i,j); // can't fail
// If the patch is underwater, calculate a bounding box that also contains the water plane
CBoundingBoxAligned bounds = patch->GetWorldBounds();
if(bounds[1].Y < waterHeight)
bounds[1].Y = waterHeight;
if (!m->Culling || frustum.IsBoxVisible(bounds))
c->Submit(patch);
}
}
}
m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
}
void CGameView::CheckLightEnv()
{
if (m->CachedLightEnv == g_LightEnv)
return;
m->CachedLightEnv = g_LightEnv;
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
if (!pTerrain)
return;
PROFILE("update light env");
pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR);
const std::vector& units = m->Game->GetWorld()->GetUnitManager().GetUnits();
for (size_t i = 0; i < units.size(); ++i)
units[i]->GetModel().SetDirtyRec(RENDERDATA_UPDATE_COLOR);
}
void CGameView::UnloadResources()
{
g_TexMan.UnloadTerrainTextures();
g_Renderer.UnloadAlphaMaps();
g_Renderer.GetWaterManager()->UnloadWaterTextures();
}
void CGameView::Update(const float deltaRealTime)
{
+ m->MiniMapTexture.Update(deltaRealTime);
+
// If camera movement is being handled by the touch-input system,
// then we should stop to avoid conflicting with it
if (g_TouchInput.IsEnabled())
return;
if (!g_app_has_focus)
return;
m->CinemaManager.Update(deltaRealTime);
if (m->CinemaManager.IsEnabled())
return;
m->CameraController->Update(deltaRealTime);
}
CVector3D CGameView::GetCameraPivot() const
{
return m->CameraController->GetCameraPivot();
}
CVector3D CGameView::GetCameraPosition() const
{
return m->CameraController->GetCameraPosition();
}
CVector3D CGameView::GetCameraRotation() const
{
return m->CameraController->GetCameraRotation();
}
float CGameView::GetCameraZoom() const
{
return m->CameraController->GetCameraZoom();
}
void CGameView::SetCamera(const CVector3D& pos, float rotX, float rotY, float zoom)
{
m->CameraController->SetCamera(pos, rotX, rotY, zoom);
}
void CGameView::MoveCameraTarget(const CVector3D& target)
{
m->CameraController->MoveCameraTarget(target);
}
void CGameView::ResetCameraTarget(const CVector3D& target)
{
m->CameraController->ResetCameraTarget(target);
}
void CGameView::FollowEntity(entity_id_t entity, bool firstPerson)
{
m->CameraController->FollowEntity(entity, firstPerson);
}
entity_id_t CGameView::GetFollowedEntity()
{
return m->CameraController->GetFollowedEntity();
}
InReaction game_view_handler(const SDL_Event_* ev)
{
// put any events that must be processed even if inactive here
if (!g_app_has_focus || !g_Game || !g_Game->IsGameStarted() || g_Game->GetView()->GetCinema()->IsEnabled())
return IN_PASS;
CGameView *pView=g_Game->GetView();
return pView->HandleEvent(ev);
}
InReaction CGameView::HandleEvent(const SDL_Event_* ev)
{
switch(ev->ev.type)
{
case SDL_HOTKEYPRESS:
{
std::string hotkey = static_cast(ev->ev.user.data1);
if (hotkey == "wireframe")
{
if (g_XmppClient && g_rankedGame == true)
break;
else if (g_Renderer.GetModelRenderMode() == SOLID)
{
g_Renderer.SetTerrainRenderMode(EDGED_FACES);
g_Renderer.SetWaterRenderMode(EDGED_FACES);
g_Renderer.SetModelRenderMode(EDGED_FACES);
g_Renderer.SetOverlayRenderMode(EDGED_FACES);
}
else if (g_Renderer.GetModelRenderMode() == EDGED_FACES)
{
g_Renderer.SetTerrainRenderMode(WIREFRAME);
g_Renderer.SetWaterRenderMode(WIREFRAME);
g_Renderer.SetModelRenderMode(WIREFRAME);
g_Renderer.SetOverlayRenderMode(WIREFRAME);
}
else
{
g_Renderer.SetTerrainRenderMode(SOLID);
g_Renderer.SetWaterRenderMode(SOLID);
g_Renderer.SetModelRenderMode(SOLID);
g_Renderer.SetOverlayRenderMode(SOLID);
}
return IN_HANDLED;
}
}
}
return m->CameraController->HandleEvent(ev);
}
Index: ps/trunk/source/graphics/GameView.h
===================================================================
--- ps/trunk/source/graphics/GameView.h (revision 25627)
+++ ps/trunk/source/graphics/GameView.h (revision 25628)
@@ -1,102 +1,103 @@
-/* Copyright (C) 2019 Wildfire Games.
+/* Copyright (C) 2021 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_GAMEVIEW
#define INCLUDED_GAMEVIEW
#include "renderer/Scene.h"
#include "simulation2/system/Entity.h"
#include "lib/input.h" // InReaction - can't forward-declare enum
-class CGame;
-class CObjectManager;
class CCamera;
class CCinemaManager;
+class CGame;
+class CObjectManager;
class CVector3D;
struct SViewPort;
class CGameViewImpl;
class CGameView : private Scene
{
NONCOPYABLE(CGameView);
public:
CGameView(CGame *pGame);
~CGameView();
void SetViewport(const SViewPort& vp);
void RegisterInit();
int Initialize();
/**
* Updates all the view information (i.e. rotate camera, scroll, whatever). This will *not* change any
* World information - only the *presentation*.
*
* @param deltaRealTime Elapsed real time since the last frame.
*/
void Update(const float deltaRealTime);
void BeginFrame();
void Render();
InReaction HandleEvent(const SDL_Event_* ev);
CVector3D GetCameraPivot() const;
CVector3D GetCameraPosition() const;
CVector3D GetCameraRotation() const;
float GetCameraZoom() const;
void SetCamera(const CVector3D& pos, float rotX, float rotY, float zoom);
void MoveCameraTarget(const CVector3D& target);
void ResetCameraTarget(const CVector3D& target);
void FollowEntity(entity_id_t entity, bool firstPerson);
entity_id_t GetFollowedEntity();
#define DECLARE_BOOLEAN_SETTING(NAME) \
bool Get##NAME##Enabled() const; \
void Set##NAME##Enabled(bool Enabled);
DECLARE_BOOLEAN_SETTING(Culling);
DECLARE_BOOLEAN_SETTING(LockCullCamera);
DECLARE_BOOLEAN_SETTING(ConstrainCamera);
#undef DECLARE_BOOLEAN_SETTING
CCamera* GetCamera();
CCinemaManager* GetCinema();
CObjectManager& GetObjectManager();
// Implementations of Scene
void EnumerateObjects(const CFrustum& frustum, SceneCollector* c) override;
CLOSTexture& GetLOSTexture() override;
CTerritoryTexture& GetTerritoryTexture() override;
+ CMiniMapTexture& GetMiniMapTexture() override;
private:
// Unloads all graphics resources loaded by RegisterInit.
void UnloadResources();
// Checks whether lighting environment has changed and update vertex data if necessary.
void CheckLightEnv();
CGameViewImpl* m;
};
extern InReaction game_view_handler(const SDL_Event_* ev);
#endif // INCLUDED_GAMEVIEW
Index: ps/trunk/source/graphics/MiniMapTexture.cpp
===================================================================
--- ps/trunk/source/graphics/MiniMapTexture.cpp (nonexistent)
+++ ps/trunk/source/graphics/MiniMapTexture.cpp (revision 25628)
@@ -0,0 +1,205 @@
+/* Copyright (C) 2021 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 "MiniMapTexture.h"
+
+#include "graphics/MiniPatch.h"
+#include "graphics/ShaderManager.h"
+#include "graphics/Terrain.h"
+#include "graphics/TerrainTextureEntry.h"
+#include "graphics/TerrainTextureManager.h"
+#include "graphics/TerritoryTexture.h"
+#include "lib/bits.h"
+#include "ps/CStrInternStatic.h"
+#include "ps/Filesystem.h"
+#include "ps/Game.h"
+#include "ps/World.h"
+#include "ps/XML/Xeromyces.h"
+#include "renderer/Renderer.h"
+#include "renderer/RenderingOptions.h"
+#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
+{
+
+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);
+}
+
+} // anonymous namespace
+
+CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation)
+ : m_Simulation(simulation)
+{
+ // Register Relax NG validator.
+ CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng");
+
+ m_ShallowPassageHeight = GetShallowPassageHeight();
+}
+
+CMiniMapTexture::~CMiniMapTexture()
+{
+ DestroyTextures();
+}
+
+void CMiniMapTexture::Update(const float UNUSED(deltaRealTime))
+{
+ if (m_WaterHeight != g_Renderer.GetWaterManager()->m_WaterHeight)
+ m_Dirty = true;
+}
+
+void CMiniMapTexture::Render()
+{
+ if (!m_Dirty)
+ return;
+
+ const CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
+ if (!terrain)
+ return;
+
+ CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY);
+ ENSURE(cmpRangeManager);
+
+ m_MapSize = terrain->GetVerticesPerSide();
+ m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize);
+
+ if (!m_TerrainTexture)
+ CreateTextures(terrain);
+
+ RebuildTerrainTexture(terrain);
+}
+
+void CMiniMapTexture::CreateTextures()
+{
+ DestroyTextures();
+
+ // 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);
+}
+
+void CMiniMapTexture::DestroyTextures()
+{
+ if (m_TerrainTexture)
+ {
+ glDeleteTextures(1, &m_TerrainTexture);
+ m_TerrainTexture = 0;
+ }
+
+ SAFE_ARRAY_DELETE(m_TerrainData);
+}
+
+void CMiniMapTexture::RebuildTerrainTexture(const CTerrain* terrain)
+{
+ u32 x = 0;
+ u32 y = 0;
+ u32 w = m_MapSize - 1;
+ u32 h = m_MapSize - 1;
+ m_WaterHeight = g_Renderer.GetWaterManager()->m_WaterHeight;
+
+ m_Dirty = 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 = ( terrain->GetVertexGroundLevel((int)i, (int)j)
+ + 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())
+ m_Dirty = 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);
+ g_Renderer.BindTexture(0, 0);
+}
+
+// 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;
+}
Property changes on: ps/trunk/source/graphics/MiniMapTexture.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/graphics/MiniMapTexture.h
===================================================================
--- ps/trunk/source/graphics/MiniMapTexture.h (nonexistent)
+++ ps/trunk/source/graphics/MiniMapTexture.h (revision 25628)
@@ -0,0 +1,79 @@
+/* Copyright (C) 2021 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_MINIMAPTEXTURE
+#define INCLUDED_MINIMAPTEXTURE
+
+#include "graphics/ShaderTechniquePtr.h"
+#include "lib/ogl.h"
+
+class CSimulation2;
+class CTerrain;
+
+class CMiniMapTexture
+{
+ NONCOPYABLE(CMiniMapTexture);
+public:
+ CMiniMapTexture(CSimulation2& simulation);
+ ~CMiniMapTexture();
+
+ /**
+ * Marks the texture as dirty if it's old enough to redraw it on Render.
+ */
+ void Update(const float deltaRealTime);
+
+ /**
+ * Redraws the texture if it's dirty.
+ */
+ void Render();
+
+ GLuint GetTerrainTexture() const { return m_TerrainTexture; }
+
+ GLsizei GetTerrainTextureSize() const { return m_TextureSize; }
+
+ /**
+ * @return The maximum height for unit passage in water.
+ */
+ static float GetShallowPassageHeight();
+
+private:
+ void CreateTextures();
+ void DestroyTextures();
+ void RebuildTerrainTexture(const CTerrain* terrain);
+
+ CSimulation2& m_Simulation;
+
+ bool m_Dirty = true;
+
+ // minimap texture handles
+ GLuint m_TerrainTexture = 0;
+
+ // texture data
+ u32* m_TerrainData = nullptr;
+
+ // map size
+ ssize_t m_MapSize = 0;
+
+ // texture size
+ GLsizei m_TextureSize = 0;
+
+ // Maximal water height to allow the passage of a unit (for underwater shallows).
+ float m_ShallowPassageHeight = 0.0f;
+ float m_WaterHeight = 0.0f;
+};
+
+#endif // INCLUDED_MINIMAPTEXTURE
Property changes on: ps/trunk/source/graphics/MiniMapTexture.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: ps/trunk/source/gui/ObjectTypes/CChart.h
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CChart.h (revision 25627)
+++ ps/trunk/source/gui/ObjectTypes/CChart.h (revision 25628)
@@ -1,102 +1,101 @@
/* Copyright (C) 2021 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_CCHART
#define INCLUDED_CCHART
-#include "graphics/ShaderProgramPtr.h"
#include "gui/ObjectBases/IGUIObject.h"
#include "gui/ObjectBases/IGUITextOwner.h"
#include "gui/SettingTypes/CGUIColor.h"
#include "gui/SettingTypes/CGUIList.h"
#include "gui/SettingTypes/CGUISeries.h"
#include "maths/Size2D.h"
#include "maths/Vector2D.h"
#include
struct CChartData
{
// Avoid copying the container.
NONCOPYABLE(CChartData);
MOVABLE(CChartData);
CChartData() = default;
CGUIColor m_Color;
std::vector m_Points;
};
/**
* Chart for a data visualization as lines or points
*/
class CChart : public IGUIObject, public IGUITextOwner
{
GUI_OBJECT(CChart)
public:
CChart(CGUI& pGUI);
virtual ~CChart();
protected:
/**
* @see IGUIObject#UpdateCachedSize()
*/
void UpdateCachedSize();
/**
* @see IGUIObject#HandleMessage()
*/
virtual void HandleMessage(SGUIMessage& Message);
/**
* Draws the Chart
*/
virtual void Draw(CCanvas2D& canvas);
virtual CRect GetChartRect() const;
void UpdateSeries();
void SetupText();
std::vector m_Series;
CVector2D m_LeftBottom, m_RightTop;
std::vector m_TextPositions;
bool m_EqualX, m_EqualY;
// Settings
CGUISimpleSetting m_AxisColor;
CGUISimpleSetting m_AxisWidth;
CGUISimpleSetting m_BufferZone;
CGUISimpleSetting m_Font;
CGUISimpleSetting m_FormatX;
CGUISimpleSetting m_FormatY;
CGUISimpleSetting m_SeriesColor;
CGUISimpleSetting m_SeriesSetting;
private:
void DrawAxes(CCanvas2D& canvas) const;
CSize2D AddFormattedValue(const CStrW& format, const float value, const CStrW& font, const float buffer_zone);
void UpdateBounds();
};
#endif // INCLUDED_CCHART
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 25627)
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 25628)
@@ -1,789 +1,654 @@
/* Copyright (C) 2021 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/Canvas2D.h"
#include "graphics/GameView.h"
#include "graphics/LOSTexture.h"
+#include "graphics/MiniMapTexture.h"
#include "graphics/MiniPatch.h"
#include "graphics/ShaderManager.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/CStrInternStatic.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/Object.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpMinimap.h"
#include "simulation2/components/ICmpRangeManager.h"
#include "simulation2/helpers/Los.h"
#include "simulation2/system/ParamNode.h"
#include
#include
#include
extern bool g_GameRestarted;
namespace
{
// 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;
-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);
-}
-
// Adds segments pieces lying inside the circle to lines.
void CropPointsByCircle(const std::array& points, const CVector3D& center, const float radius, std::vector* lines)
{
constexpr float EPS = 1e-3f;
lines->reserve(points.size() * 2);
for (size_t idx = 0; idx < points.size(); ++idx)
{
const CVector3D& currentPoint = points[idx];
const CVector3D& nextPoint = points[(idx + 1) % points.size()];
const CVector3D direction = (nextPoint - currentPoint).Normalized();
const CVector3D normal(direction.Z, 0.0f, -direction.X);
const float offset = normal.Dot(currentPoint) - normal.Dot(center);
// We need to have lines only inside the circle.
if (std::abs(offset) + EPS >= radius)
continue;
const CVector3D closestPoint = center + normal * offset;
const float halfChordLength = sqrt(radius * radius - offset * offset);
const CVector3D intersectionA = closestPoint - direction * halfChordLength;
const CVector3D intersectionB = closestPoint + direction * halfChordLength;
// We have no intersection if the segment is lying outside of the circle.
if (direction.Dot(currentPoint) + EPS > direction.Dot(intersectionB) ||
direction.Dot(nextPoint) - EPS < direction.Dot(intersectionA))
continue;
lines->emplace_back(
direction.Dot(currentPoint) > direction.Dot(intersectionA) ? currentPoint : intersectionA);
lines->emplace_back(
direction.Dot(nextPoint) < direction.Dot(intersectionB) ? nextPoint : intersectionB);
}
}
} // anonymous namespace
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_MapSize(0), m_MapScale(1.f),
m_EntitiesDrawn(0), m_IndexArray(GL_STATIC_DRAW), m_VertexArray(GL_DYNAMIC_DRAW), m_Mask(this, "mask", false),
- m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false), m_WaterHeight(0.0)
+ m_NextBlinkTime(0.0), m_PingDuration(25.0), m_BlinkState(false)
{
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();
-}
+CMiniMap::~CMiniMap() = default;
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 CVector2D& mousePos = m_pGUI.GetMousePos();
// Get the position of the center of the minimap.
CVector2D minimapCenter = CVector2D(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 CVector2D& 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))
{
ScriptRequest rq(g_GUI->GetActiveGUI()->GetScriptInterface());
float x, z;
GetMouseWorldCoordinates(x, z);
JS::RootedValue coords(rq.cx);
Script::CreateObject(rq, &coords, "x", x, "z", z);
JS::RootedValue buttonJs(rq.cx);
Script::ToJSVal(rq, &buttonJs, button);
JS::RootedValueVector paramData(rq.cx);
ignore_result(paramData.append(coords));
ignore_result(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(const 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);
const std::array hitPoints = {
m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h),
m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h),
m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h),
m_Camera->GetWorldCoordinates(0, 0, h)
};
std::vector lines;
// We need to prevent drawing view bounds out of the map.
const float halfMapSize = static_cast((m_MapSize - 1) * TERRAIN_TILE_SIZE) * 0.5f;
CropPointsByCircle(hitPoints, CVector3D(halfMapSize, 0.0f, halfMapSize), halfMapSize * m_MapScale, &lines);
if (lines.empty())
return;
std::vector vertices;
vertices.reserve(lines.size() * 2);
for (const CVector3D& point : lines)
{
// Convert to minimap space.
vertices.emplace_back(width * point.X * invTileMapSize);
vertices.emplace_back(-(height * point.Z * invTileMapSize));
}
// 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, vertices.data());
shader->AssertPointersBound();
if (!g_Renderer.DoSkipSubmit())
glDrawArrays(GL_LINES, 0, vertices.size() / 2);
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) 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, 0.0f,
x2, y, 0.0f,
x2, y2, 0.0f,
x2, y2, 0.0f,
x, y2, 0.0f,
x, y, 0.0f
};
shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex);
shader->VertexPointer(3, GL_FLOAT, 0, quadVerts);
shader->AssertPointersBound();
if (!g_Renderer.DoSkipSubmit())
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(CCanvas2D& canvas)
{
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;
canvas.Flush();
CSimulation2* sim = g_Game->GetSimulation2();
CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY);
ENSURE(cmpRangeManager);
+ CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
+ CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture();
+
// Set our globals in case they hadn't been set before
m_Camera = g_Game->GetView()->GetCamera();
- m_Terrain = g_Game->GetWorld()->GetTerrain();
+ const CTerrain* 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_MapSize = terrain->GetVerticesPerSide();
+ m_TextureSize = miniMapTexture.GetTerrainTextureSize();
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 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();
-
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 (miniMapTexture.GetTerrainTexture())
+ shader->BindTexture(str_baseTex, miniMapTexture.GetTerrainTexture());
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);
+ if (miniMapTexture.GetTerrainTexture())
+ DrawTexture(shader, texCoordMax, angle, x, y, x2, y2);
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);
tech->EndPass();
// Draw the LOS quad in black, using alpha values from the LOS texture
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);
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, 0.0f);
// 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 (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)
{
#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();
if (!g_Renderer.DoSkipSubmit())
glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase);
g_Renderer.GetStats().m_DrawCalls++;
CVertexBuffer::Unbind();
#if !CONFIG2_GLES
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
}
tech->EndPass();
DrawViewRect(unitMatrix);
PROFILE_END("minimap units");
}
-
-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 25627)
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.h (revision 25628)
@@ -1,126 +1,96 @@
/* Copyright (C) 2021 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(CCanvas2D& canvas);
/**
* @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();
-
+private:
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.
CGUISimpleSetting 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) const;
void DrawViewRect(const 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/renderer/Renderer.cpp
===================================================================
--- ps/trunk/source/renderer/Renderer.cpp (revision 25627)
+++ ps/trunk/source/renderer/Renderer.cpp (revision 25628)
@@ -1,1941 +1,1944 @@
/* Copyright (C) 2021 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 .
*/
/*
* higher level interface on top of OpenGL to render basic objects:
* terrain, models, sprites, particles etc.
*/
#include "precompiled.h"
#include "Renderer.h"
#include "lib/bits.h" // is_pow2
#include "lib/res/graphics/ogl_tex.h"
#include "lib/allocators/shared_ptr.h"
#include "maths/Matrix3D.h"
#include "maths/MathUtil.h"
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
#include "ps/CStrInternStatic.h"
#include "ps/Game.h"
#include "ps/Profile.h"
#include "ps/Filesystem.h"
#include "ps/World.h"
#include "ps/Loader.h"
#include "ps/ProfileViewer.h"
#include "graphics/Camera.h"
#include "graphics/Decal.h"
#include "graphics/FontManager.h"
#include "graphics/GameView.h"
#include "graphics/LightEnv.h"
#include "graphics/LOSTexture.h"
#include "graphics/MaterialManager.h"
+#include "graphics/MiniMapTexture.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "graphics/ParticleManager.h"
#include "graphics/Patch.h"
#include "graphics/ShaderManager.h"
#include "graphics/Terrain.h"
#include "graphics/Texture.h"
#include "graphics/TextureManager.h"
#include "renderer/DebugRenderer.h"
#include "renderer/HWLightingModelRenderer.h"
#include "renderer/InstancingModelRenderer.h"
#include "renderer/ModelRenderer.h"
#include "renderer/OverlayRenderer.h"
#include "renderer/ParticleRenderer.h"
#include "renderer/PostprocManager.h"
#include "renderer/RenderingOptions.h"
#include "renderer/RenderModifiers.h"
#include "renderer/ShadowMap.h"
#include "renderer/SilhouetteRenderer.h"
#include "renderer/SkyManager.h"
#include "renderer/TerrainOverlay.h"
#include "renderer/TerrainRenderer.h"
#include "renderer/TimeManager.h"
#include "renderer/VertexBufferManager.h"
#include "renderer/WaterManager.h"
#include
#include
#include