Index: ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml
+++ ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml
@@ -4,8 +4,6 @@
sprite="mapPanel"
type="image"
>
-
-
+
+
+
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.h
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.h
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.h
@@ -104,7 +104,7 @@
void DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const;
- void DrawViewRect(CMatrix3D transform) const;
+ void DrawViewRect(const CMatrix3D& transform) const;
void GetMouseWorldCoordinates(float& x, float& z) const;
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp
@@ -50,15 +50,20 @@
#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;
-static unsigned int ScaleColor(unsigned int color, float x)
+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);
@@ -66,6 +71,40 @@
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;
+ const float radiusSquared = radius * radius;
+ 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) :
@@ -259,7 +298,7 @@
// This sets up and draws the rectangle on the minimap
// which represents the view of the camera in the world.
-void CMiniMap::DrawViewRect(CMatrix3D transform) const
+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
@@ -268,27 +307,29 @@
const float height = m_CachedActualSize.GetHeight();
const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize);
- CVector3D hitPt[4];
- hitPt[0] = m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h);
- hitPt[1] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), h);
- hitPt[2] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h);
- hitPt[3] = m_Camera->GetWorldCoordinates(0, 0, h);
-
- float ViewRect[4][2];
- for (int i = 0; i < 4; ++i)
- {
- // convert to minimap space
- ViewRect[i][0] = (width * hitPt[i].X * invTileMapSize);
- ViewRect[i][1] = (height * hitPt[i].Z * invTileMapSize);
- }
-
- float viewVerts[] = {
- ViewRect[0][0], -ViewRect[0][1],
- ViewRect[1][0], -ViewRect[1][1],
- ViewRect[2][0], -ViewRect[2][1],
- ViewRect[3][0], -ViewRect[3][1]
+ 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, &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,
@@ -306,11 +347,11 @@
shader->Uniform(str_transform, transform);
shader->Uniform(str_color, 1.0f, 0.3f, 0.3f, 1.0f);
- shader->VertexPointer(2, GL_FLOAT, 0, viewVerts);
+ shader->VertexPointer(2, GL_FLOAT, 0, vertices.data());
shader->AssertPointersBound();
if (!g_Renderer.m_SkipSubmit)
- glDrawArrays(GL_LINE_LOOP, 0, 4);
+ glDrawArrays(GL_LINES, 0, vertices.size() / 2);
tech->EndPass();