Index: ps/trunk/binaries/data/mods/mod/gui/gui.rng
===================================================================
--- ps/trunk/binaries/data/mods/mod/gui/gui.rng (revision 26000)
+++ ps/trunk/binaries/data/mods/mod/gui/gui.rng (revision 26001)
@@ -1,899 +1,909 @@
true
false
left
center
right
top
center
bottom
repeat
mirrored_repeat
clamp_to_edge
-?\d*\.?\d+%?([\+\-]\d*\.?\d+%?)*
0
255
0
255
0
255
0
255
[A-Za-z]+
0
-
+
-
+
+
+
+
+
+
+
+
+
+
+
1
1
Index: ps/trunk/binaries/data/mods/public/art/textures/animated/minimap-flare/frame00.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: ps/trunk/binaries/data/mods/public/art/textures/animated/minimap-flare/frame01.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: ps/trunk/binaries/data/mods/public/art/textures/animated/minimap-flare/frame02.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: ps/trunk/binaries/data/mods/public/art/textures/animated/minimap-flare/frame13.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: ps/trunk/binaries/data/mods/public/art/textures/animated/minimap-flare/frame14.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: ps/trunk/binaries/data/mods/public/art/textures/animated/minimap-flare/frame15.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml (revision 26000)
+++ ps/trunk/binaries/data/mods/public/gui/session/minimap/MiniMap.xml (revision 26001)
@@ -1,70 +1,72 @@
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 26000)
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.cpp (revision 26001)
@@ -1,440 +1,460 @@
/* 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/ShaderProgramPtr.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureEntry.h"
#include "graphics/TerrainTextureManager.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 "maths/MathUtil.h"
#include "ps/CLogger.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 "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
namespace
{
// 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);
}
}
void DrawTexture(CShaderProgramPtr shader, float angle, float x, float y, float x2, float y2, float mapScale)
{
// 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) * mapScale;
const float c = cos(angle) * mapScale;
const float m = 0.5f;
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);
}
} // anonymous namespace
const CStr CMiniMap::EventNameWorldClick = "WorldClick";
CMiniMap::CMiniMap(CGUI& pGUI) :
IGUIObject(pGUI),
m_MapSize(0), m_MapScale(1.f), m_Mask(this, "mask", false),
m_FlareTextureCount(this, "flare_texture_count", 0), m_FlareRenderSize(this, "flare_render_size", 0),
m_FlareInterleave(this, "flare_interleave", false), m_FlareAnimationSpeed(this, "flare_animation_speed", 0.0f),
- m_FlareLifetimeSeconds(this, "flare_lifetime_seconds", 0.0f)
+ m_FlareLifetimeSeconds(this, "flare_lifetime_seconds", 0.0f),
+ m_FlareStartFadeSeconds(this, "flare_start_fade_seconds", 0.0f),
+ m_FlareStopFadeSeconds(this, "flare_stop_fade_seconds", 0.0f)
{
m_Clicking = false;
m_MouseHovering = false;
}
CMiniMap::~CMiniMap() = default;
void CMiniMap::HandleMessage(SGUIMessage& Message)
{
IGUIObject::HandleMessage(Message);
switch (Message.type)
{
case GUIM_LOAD:
RecreateFlareTextures();
break;
case GUIM_SETTINGS_UPDATED:
if (Message.value == "flare_texture_count")
RecreateFlareTextures();
break;
case GUIM_MOUSE_PRESS_LEFT:
if (m_MouseHovering)
{
if (!CMiniMap::FireWorldClickEvent(SDL_BUTTON_LEFT, 1))
{
SetCameraPositionFromMousePosition();
m_Clicking = true;
}
}
break;
case GUIM_MOUSE_RELEASE_LEFT:
if (m_MouseHovering && m_Clicking)
SetCameraPositionFromMousePosition();
m_Clicking = false;
break;
case GUIM_MOUSE_DBLCLICK_LEFT:
if (m_MouseHovering && m_Clicking)
SetCameraPositionFromMousePosition();
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)
SetCameraPositionFromMousePosition();
break;
case GUIM_MOUSE_WHEEL_DOWN:
case GUIM_MOUSE_WHEEL_UP:
Message.Skip();
break;
default:
break;
}
}
void CMiniMap::RecreateFlareTextures()
{
// Catch invalid values.
if (m_FlareTextureCount > 99)
{
LOGERROR("Invalid value for flare texture count. Valid range is 0-99.");
return;
}
const CStr textureNumberingFormat = "art/textures/animated/minimap-flare/frame%02u.png";
m_FlareTextures.clear();
m_FlareTextures.reserve(m_FlareTextureCount);
for (u32 i = 0; i < m_FlareTextureCount; ++i)
{
const CTextureProperties textureProps(fmt::sprintf(textureNumberingFormat, i).c_str());
m_FlareTextures.emplace_back(g_Renderer.GetTextureManager().CreateTexture(textureProps));
}
}
bool CMiniMap::IsMouseOver() const
{
const CVector2D& mousePos = m_pGUI.GetMousePos();
// Take the magnitude of the difference of the mouse position and minimap center.
const float distanceFromCenter = (mousePos - m_CachedActualSize.CenterPoint()).Length();
// If the distance is less then the radius of the minimap (half the width) the mouse is over the minimap.
return distanceFromCenter < m_CachedActualSize.GetWidth() / 2.0;
}
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::SetCameraPositionFromMousePosition()
{
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 = g_Game->GetView()->GetCamera()->GetOrientation().GetIn();
return -atan2(cameraIn.X, cameraIn.Z);
}
CVector2D CMiniMap::WorldSpaceToMiniMapSpace(const CVector3D& worldPosition) const
{
// Coordinates with 0,0 in the middle of the minimap and +-0.5 as max.
const float invTileMapSize = 1.0f / static_cast(TERRAIN_TILE_SIZE * m_MapSize);
const float relativeX = (worldPosition.X * invTileMapSize - 0.5) / m_MapScale;
const float relativeY = (worldPosition.Z * invTileMapSize - 0.5) / m_MapScale;
// Rotate coordinates.
const float angle = GetAngle();
const float rotatedX = cos(angle) * relativeX + sin(angle) * relativeY;
const float rotatedY = -sin(angle) * relativeX + cos(angle) * relativeY;
// Calculate coordinates in GUI space.
return CVector2D(
m_CachedActualSize.left + (0.5f + rotatedX) * m_CachedActualSize.GetWidth(),
m_CachedActualSize.bottom - (0.5f + rotatedY) * m_CachedActualSize.GetHeight());
}
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(CCanvas2D& canvas) 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
const float sampleHeight = g_Renderer.GetWaterManager()->m_WaterHeight;
const CCamera* camera = g_Game->GetView()->GetCamera();
const std::array hitPoints = {
camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), sampleHeight),
camera->GetWorldCoordinates(g_Renderer.GetWidth(), g_Renderer.GetHeight(), sampleHeight),
camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, sampleHeight),
camera->GetWorldCoordinates(0, 0, sampleHeight)
};
std::vector worldSpaceLines;
// 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, &worldSpaceLines);
if (worldSpaceLines.empty())
return;
for (size_t index = 0; index < worldSpaceLines.size() && index + 1 < worldSpaceLines.size(); index += 2)
{
const CVector2D from = WorldSpaceToMiniMapSpace(worldSpaceLines[index]);
const CVector2D to = WorldSpaceToMiniMapSpace(worldSpaceLines[index + 1]);
canvas.DrawLine({from, to}, 2.0f, CColor(1.0f, 0.3f, 0.3f, 1.0f));
}
}
void CMiniMap::DrawFlare(CCanvas2D& canvas, const MapFlare& flare, double currentTime) const
{
if (m_FlareTextures.empty())
return;
const CVector2D flareCenter = WorldSpaceToMiniMapSpace(CVector3D(flare.pos.X, 0.0f, flare.pos.Y));
const CRect destination(
flareCenter.X - m_FlareRenderSize, flareCenter.Y - m_FlareRenderSize,
flareCenter.X + m_FlareRenderSize, flareCenter.Y + m_FlareRenderSize);
- const u32 flooredStep = floor((currentTime - flare.time) * m_FlareAnimationSpeed);
+ const double deltaTime = currentTime - flare.time;
+ const double remainingTime = m_FlareLifetimeSeconds - deltaTime;
+ const u32 flooredStep = floor(deltaTime * m_FlareAnimationSpeed);
+
+ const float startFadeAlpha = m_FlareStartFadeSeconds > 0.0f ? deltaTime / m_FlareStartFadeSeconds : 1.0f;
+ const float stopFadeAlpha = m_FlareStopFadeSeconds > 0.0f ? remainingTime / m_FlareStopFadeSeconds : 1.0f;
+ const float alpha = Clamp(std::min(
+ SmoothStep(0.0f, 1.0f, startFadeAlpha), SmoothStep(0.0f, 1.0f, stopFadeAlpha)),
+ 0.0f, 1.0f);
- CTexturePtr texture = m_FlareTextures[flooredStep % m_FlareTextures.size()];
- // TODO: Only draw inside the minimap circle.
- canvas.DrawTexture(texture, destination, CRect(0, 0, texture->GetWidth(), texture->GetHeight()), flare.color, CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f);
+ DrawFlareFrame(canvas, flooredStep % m_FlareTextures.size(), destination, flare.color, alpha);
- // Draw a second circle if the first has reached half of the animation
+ // Draw a second circle if the first has reached half of the animation.
if (m_FlareInterleave && flooredStep >= m_FlareTextures.size() / 2)
{
- texture = m_FlareTextures[(flooredStep - m_FlareTextures.size() / 2) % m_FlareTextures.size()];
- // TODO: Only draw inside the minimap circle.
- canvas.DrawTexture(texture, destination, CRect(0, 0, texture->GetWidth(), texture->GetHeight()), flare.color, CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f);
+ DrawFlareFrame(canvas, (flooredStep - m_FlareTextures.size() / 2) % m_FlareTextures.size(),
+ destination, flare.color, alpha);
}
}
+void CMiniMap::DrawFlareFrame(CCanvas2D& canvas, const u32 frameIndex,
+ const CRect& destination, const CColor& color, float alpha) const
+{
+ // TODO: Only draw inside the minimap circle.
+ CTexturePtr texture = m_FlareTextures[frameIndex % m_FlareTextures.size()];
+ CColor finalColor = color;
+ finalColor.a *= alpha;
+ canvas.DrawTexture(texture, destination,
+ CRect(0, 0, texture->GetWidth(), texture->GetHeight()), finalColor,
+ CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f);
+}
+
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;
if (!m_Mask)
canvas.DrawRect(m_CachedActualSize, CColor(0.0f, 0.0f, 0.0f, 1.0f));
canvas.Flush();
CSimulation2* sim = g_Game->GetSimulation2();
CmpPtr cmpRangeManager(*sim, SYSTEM_ENTITY);
ENSURE(cmpRangeManager);
// Set our globals in case they hadn't been set before
const CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
m_MapSize = terrain->GetVerticesPerSide();
m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f);
// Draw the main textured quad
CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture();
if (miniMapTexture.GetTexture())
{
CShaderProgramPtr shader;
CShaderTechniquePtr tech;
CShaderDefines baseDefines;
baseDefines.Add(str_MINIMAP_BASE, str_1);
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), baseDefines);
tech->BeginPass();
shader = tech->GetShader();
shader->BindTexture(str_baseTex, miniMapTexture.GetTexture());
const CMatrix3D baseTransform = GetDefaultGuiMatrix();
CMatrix3D baseTextureTransform;
baseTextureTransform.SetIdentity();
shader->Uniform(str_transform, baseTransform);
shader->Uniform(str_textureTransform, baseTextureTransform);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
const float angle = GetAngle();
DrawTexture(shader, angle, x, y, x2, y2, m_MapScale);
tech->EndPass();
glDisable(GL_BLEND);
}
PROFILE_START("minimap flares");
DrawViewRect(canvas);
const double currentTime = timer_Time();
while (!m_MapFlares.empty() && m_FlareLifetimeSeconds + m_MapFlares.front().time < currentTime)
m_MapFlares.pop_front();
for (const MapFlare& flare : m_MapFlares)
DrawFlare(canvas, flare, currentTime);
PROFILE_END("minimap flares");
}
bool CMiniMap::Flare(const CVector2D& pos, const CStr& colorStr)
{
CColor color;
if (!color.ParseString(colorStr))
{
LOGERROR("CMiniMap::Flare: Couldn't parse color string");
return false;
}
m_MapFlares.push_back({ pos, color, timer_Time() });
return true;
}
Index: ps/trunk/source/gui/ObjectTypes/CMiniMap.h
===================================================================
--- ps/trunk/source/gui/ObjectTypes/CMiniMap.h (revision 26000)
+++ ps/trunk/source/gui/ObjectTypes/CMiniMap.h (revision 26001)
@@ -1,105 +1,108 @@
/* 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/Color.h"
#include "graphics/Texture.h"
#include "gui/ObjectBases/IGUIObject.h"
#include "maths/Vector2D.h"
#include "renderer/VertexArray.h"
#include
#include
class CMatrix3D;
class CMiniMap : public IGUIObject
{
GUI_OBJECT(CMiniMap)
public:
CMiniMap(CGUI& pGUI);
virtual ~CMiniMap();
bool Flare(const CVector2D& pos, const CStr& colorStr);
protected:
struct MapFlare
{
CVector2D pos;
CColor color;
double time;
};
virtual void Draw(CCanvas2D& canvas);
virtual void CreateJSObject();
/**
* @see IGUIObject#HandleMessage()
*/
virtual void HandleMessage(SGUIMessage& Message);
/**
* @see IGUIObject#IsMouseOver()
*/
virtual bool IsMouseOver() const;
private:
void SetCameraPositionFromMousePosition();
bool FireWorldClickEvent(int button, int clicks);
static const CStr EventNameWorldClick;
// Whether or not the mouse is currently down
bool m_Clicking;
std::deque m_MapFlares;
std::vector m_FlareTextures;
CGUISimpleSetting m_FlareTextureCount;
CGUISimpleSetting m_FlareRenderSize;
CGUISimpleSetting m_FlareInterleave;
CGUISimpleSetting m_FlareAnimationSpeed;
CGUISimpleSetting m_FlareLifetimeSeconds;
+ CGUISimpleSetting m_FlareStartFadeSeconds;
+ CGUISimpleSetting m_FlareStopFadeSeconds;
// Whether to draw a black square around and under the minimap.
CGUISimpleSetting m_Mask;
// map size
ssize_t m_MapSize;
// 1.f if map is circular or 1.414f if square (to shrink it inside the circle)
float m_MapScale;
void RecreateFlareTextures();
void DrawViewRect(CCanvas2D& canvas) const;
- void DrawFlare(CCanvas2D& canvas, const MapFlare& flare, double curentTime) const;
+ void DrawFlare(CCanvas2D& canvas, const MapFlare& flare, double currentTime) const;
+ void DrawFlareFrame(CCanvas2D& canvas, const u32 frameIndex, const CRect& destination, const CColor& color, float alpha) const;
void GetMouseWorldCoordinates(float& x, float& z) const;
float GetAngle() const;
CVector2D WorldSpaceToMiniMapSpace(const CVector3D& worldPosition) const;
};
#endif // INCLUDED_MINIMAP
Index: ps/trunk/source/maths/MathUtil.h
===================================================================
--- ps/trunk/source/maths/MathUtil.h (revision 26000)
+++ ps/trunk/source/maths/MathUtil.h (revision 26001)
@@ -1,50 +1,57 @@
/* 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_MATHUTIL
#define INCLUDED_MATHUTIL
#define DEGTORAD(a) ((a) * ((float)M_PI/180.0f))
#define RADTODEG(a) ((a) * (180.0f/(float)M_PI))
#define SQR(x) ((x) * (x))
-template
+template
inline T Interpolate(const T& a, const T& b, float t)
{
return a + (b - a) * t;
}
-template
+template
inline T Clamp(T value, T min, T max)
{
if (value <= min)
return min;
else if (value >= max)
return max;
return value;
}
+template
+inline T SmoothStep(T edge0, T edge1, T value)
+{
+ value = Clamp((value - edge0) / (edge1 - edge0), 0, 1);
+ return value * value * (3 - 2 * value);
+}
+
inline float sgn(float a)
{
if (a > 0.0f)
return 1.0f;
if (a < 0.0f)
return -1.0f;
return 0.0f;
}
#endif // INCLUDED_MATHUTIL