mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Make include-what-you-use happy with some files in source/tools/atlas and fix what needs to be fixed. Add "source" to include path for AtlasUI target to allow for absolute includes. In the future all but one should be removed. Drop check for at least boost 1.40. Ref: #8086 Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
469 lines
12 KiB
C++
469 lines
12 KiB
C++
/* Copyright (C) 2025 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
|
|
#include "View.h"
|
|
|
|
#include "graphics/Canvas2D.h"
|
|
#include "graphics/CinemaManager.h"
|
|
#include "graphics/Color.h"
|
|
#include "graphics/GameView.h"
|
|
#include "lib/debug.h"
|
|
#include "lib/utf8.h"
|
|
#include "maths/MathUtil.h"
|
|
#include "maths/Matrix3D.h"
|
|
#include "maths/Vector2D.h"
|
|
#include "ps/CStr.h"
|
|
#include "ps/ConfigDB.h"
|
|
#include "ps/Game.h"
|
|
#include "ps/VideoMode.h"
|
|
#include "renderer/DebugRenderer.h"
|
|
#include "renderer/Renderer.h"
|
|
#include "renderer/SceneRenderer.h"
|
|
#include "renderer/backend/IDevice.h"
|
|
#include "simulation2/Simulation2.h"
|
|
#include "simulation2/components/ICmpParticleManager.h"
|
|
#include "simulation2/components/ICmpPathfinder.h"
|
|
#include "simulation2/system/Component.h"
|
|
#include "soundmanager/ISoundManager.h"
|
|
#include "tools/atlas/GameInterface/ActorViewer.h"
|
|
#include "tools/atlas/GameInterface/GameLoop.h"
|
|
#include "tools/atlas/GameInterface/Messages.h"
|
|
#include "tools/atlas/GameInterface/SimState.h"
|
|
|
|
#include <sstream>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
extern void (*Atlas_GLSwapBuffers)(void* context);
|
|
|
|
extern int g_xres, g_yres;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void AtlasView::SetParam(const std::wstring& /*name*/, bool /*value*/)
|
|
{
|
|
}
|
|
|
|
void AtlasView::SetParam(const std::wstring& /*name*/, const AtlasMessage::Color& /*value*/)
|
|
{
|
|
}
|
|
|
|
void AtlasView::SetParam(const std::wstring& /*name*/, const std::wstring& /*value*/)
|
|
{
|
|
}
|
|
|
|
void AtlasView::SetParam(const std::wstring& /*name*/, int /*value*/)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
AtlasViewActor::AtlasViewActor()
|
|
: m_SpeedMultiplier(1.f), m_ActorViewer(new ActorViewer())
|
|
{
|
|
}
|
|
|
|
AtlasViewActor::~AtlasViewActor()
|
|
{
|
|
delete m_ActorViewer;
|
|
}
|
|
|
|
void AtlasViewActor::Update(float realFrameLength)
|
|
{
|
|
m_ActorViewer->Update(realFrameLength * m_SpeedMultiplier, realFrameLength);
|
|
}
|
|
|
|
void AtlasViewActor::Render()
|
|
{
|
|
SViewPort vp = { 0, 0, g_xres, g_yres };
|
|
CCamera& camera = GetCamera();
|
|
camera.SetViewPort(vp);
|
|
camera.SetPerspectiveProjection(2.f, 512.f, DEGTORAD(20.f));
|
|
camera.UpdateFrustum();
|
|
|
|
m_ActorViewer->Render();
|
|
Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas);
|
|
}
|
|
|
|
CCamera& AtlasViewActor::GetCamera()
|
|
{
|
|
return m_Camera;
|
|
}
|
|
|
|
CSimulation2* AtlasViewActor::GetSimulation2()
|
|
{
|
|
return m_ActorViewer->GetSimulation2();
|
|
}
|
|
|
|
entity_id_t AtlasViewActor::GetEntityId(AtlasMessage::ObjectID)
|
|
{
|
|
return m_ActorViewer->GetEntity();
|
|
}
|
|
|
|
bool AtlasViewActor::WantsHighFramerate()
|
|
{
|
|
if (m_SpeedMultiplier != 0.f)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void AtlasViewActor::SetEnabled(bool enabled)
|
|
{
|
|
m_ActorViewer->SetEnabled(enabled);
|
|
}
|
|
|
|
void AtlasViewActor::SetSpeedMultiplier(float speedMultiplier)
|
|
{
|
|
m_SpeedMultiplier = speedMultiplier;
|
|
}
|
|
|
|
ActorViewer& AtlasViewActor::GetActorViewer()
|
|
{
|
|
return *m_ActorViewer;
|
|
}
|
|
|
|
void AtlasViewActor::SetParam(const std::wstring& name, bool value)
|
|
{
|
|
if (name == L"wireframe")
|
|
g_Renderer.GetSceneRenderer().SetModelRenderMode(value ? WIREFRAME : SOLID);
|
|
else if (name == L"walk")
|
|
m_ActorViewer->SetWalkEnabled(value);
|
|
else if (name == L"ground")
|
|
m_ActorViewer->SetGroundEnabled(value);
|
|
// TODO: this causes corruption of WaterManager's global state
|
|
// which should be asociated with terrain or simulation instead
|
|
// see https://gitea.wildfiregames.com/0ad/0ad/issues/2692
|
|
//else if (name == L"water")
|
|
//m_ActorViewer->SetWaterEnabled(value);
|
|
else if (name == L"shadows")
|
|
m_ActorViewer->ToggleShadows();
|
|
else if (name == L"stats")
|
|
m_ActorViewer->SetStatsEnabled(value);
|
|
else if (name == L"bounding_box")
|
|
m_ActorViewer->SetBoundingBoxesEnabled(value);
|
|
else if (name == L"axes_marker")
|
|
m_ActorViewer->SetAxesMarkerEnabled(value);
|
|
}
|
|
|
|
void AtlasViewActor::SetParam(const std::wstring& name, int value)
|
|
{
|
|
if (name == L"prop_points")
|
|
m_ActorViewer->SetPropPointsMode(value);
|
|
}
|
|
|
|
void AtlasViewActor::SetParam(const std::wstring& /*name*/, const AtlasMessage::Color& /*value*/)
|
|
{
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
AtlasViewGame::AtlasViewGame()
|
|
: m_SpeedMultiplier(0.f), m_IsTesting(false), m_DrawMoveTool(false)
|
|
{
|
|
ENSURE(g_Game);
|
|
}
|
|
|
|
AtlasViewGame::~AtlasViewGame()
|
|
{
|
|
for (const std::pair<const std::wstring, SimState*>& p : m_SavedStates)
|
|
delete p.second;
|
|
}
|
|
|
|
CSimulation2* AtlasViewGame::GetSimulation2()
|
|
{
|
|
return g_Game->GetSimulation2();
|
|
}
|
|
|
|
void AtlasViewGame::Update(float realFrameLength)
|
|
{
|
|
const float actualFrameLength = realFrameLength * m_SpeedMultiplier;
|
|
|
|
// Clean up any entities destroyed during UI message processing
|
|
g_Game->GetSimulation2()->FlushDestroyedEntities();
|
|
|
|
if (m_SpeedMultiplier == 0.f)
|
|
{
|
|
// Update unit interpolation
|
|
g_Game->Interpolate(0.0, realFrameLength);
|
|
}
|
|
else
|
|
{
|
|
// Update the whole world
|
|
// (Tell the game update not to interpolate graphics - we'll do that
|
|
// ourselves)
|
|
g_Game->Update(actualFrameLength, false);
|
|
|
|
// Interpolate the graphics - we only want to do this once per visual frame,
|
|
// not in every call to g_Game->Update
|
|
g_Game->Interpolate(actualFrameLength, realFrameLength);
|
|
}
|
|
|
|
// Run sound idle tasks every frame.
|
|
if (g_SoundManager)
|
|
g_SoundManager->IdleTask();
|
|
|
|
// Cinematic motion should be independent of simulation update, so we can
|
|
// preview the cinematics by themselves
|
|
g_Game->GetView()->GetCinema()->Update(realFrameLength);
|
|
}
|
|
|
|
void AtlasViewGame::Render()
|
|
{
|
|
if (!g_VideoMode.GetBackendDevice()->AcquireNextBackbuffer())
|
|
return;
|
|
|
|
SViewPort vp = { 0, 0, g_xres, g_yres };
|
|
CCamera& camera = GetCamera();
|
|
camera.SetViewPort(vp);
|
|
camera.SetProjectionFromCamera(*g_Game->GetView()->GetCamera());
|
|
camera.UpdateFrustum();
|
|
|
|
g_Renderer.RenderFrame(false);
|
|
Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas);
|
|
// In case of atlas the device's present will do only internal stuff
|
|
// without calling a real backbuffer swap.
|
|
g_VideoMode.GetBackendDevice()->Present();
|
|
}
|
|
|
|
void AtlasViewGame::DrawCinemaPathTool()
|
|
{
|
|
if (!m_DrawMoveTool)
|
|
return;
|
|
|
|
const CVector3D focus = m_MoveTool;
|
|
const CVector3D camera = GetCamera().GetOrientation().GetTranslation();
|
|
const float scale = (focus - camera).Length();
|
|
const float axisLength = scale / 10.0f;
|
|
const float lineWidth = scale / 1e3f;
|
|
|
|
g_Renderer.GetDebugRenderer().DrawLine(
|
|
focus, focus + CVector3D(axisLength, 0, 0),
|
|
CColor(1.0f, 0.0f, 0.0f, 1.0f), lineWidth, false);
|
|
g_Renderer.GetDebugRenderer().DrawLine(
|
|
focus, focus + CVector3D(0, axisLength, 0),
|
|
CColor(0.0f, 1.0f, 0.0f, 1.0f), lineWidth, false);
|
|
g_Renderer.GetDebugRenderer().DrawLine(
|
|
focus, focus + CVector3D(0, 0, axisLength),
|
|
CColor(0.0f, 0.0f, 1.0f, 1.0f), lineWidth, false);
|
|
}
|
|
|
|
void AtlasViewGame::DrawOverlays(CCanvas2D& canvas)
|
|
{
|
|
if (m_Bandbox.left >= m_Bandbox.right || m_Bandbox.top >= m_Bandbox.bottom)
|
|
return;
|
|
|
|
const std::vector<CVector2D> outerPoints = {
|
|
m_Bandbox.TopLeft() + CVector2D(-1.0f, -1.0f),
|
|
m_Bandbox.TopRight() + CVector2D(1.0f, -1.0f),
|
|
m_Bandbox.BottomRight() + CVector2D(1.0f, 1.0f),
|
|
m_Bandbox.BottomLeft() + CVector2D(-1.0f, 1.0f),
|
|
m_Bandbox.TopLeft() + CVector2D(-1.0f, -1.0f)
|
|
};
|
|
canvas.DrawLine(outerPoints, 1.5f, CColor(0.0f, 0.0f, 0.0f, 1.0f));
|
|
|
|
const std::vector<CVector2D> innerPoints = {
|
|
m_Bandbox.TopLeft(),
|
|
m_Bandbox.TopRight(),
|
|
m_Bandbox.BottomRight(),
|
|
m_Bandbox.BottomLeft(),
|
|
m_Bandbox.TopLeft()
|
|
};
|
|
canvas.DrawLine(innerPoints, 1.5f, CColor(1.0f, 1.0f, 1.0f, 1.0f));
|
|
}
|
|
|
|
void AtlasViewGame::SetParam(const std::wstring& name, bool value)
|
|
{
|
|
if (name == L"priorities")
|
|
g_Renderer.GetSceneRenderer().SetDisplayTerrainPriorities(value);
|
|
else if (name == L"movetool")
|
|
m_DrawMoveTool = value;
|
|
}
|
|
|
|
void AtlasViewGame::SetParam(const std::wstring& name, float value)
|
|
{
|
|
if (name == L"movetool_x")
|
|
m_MoveTool.X = value;
|
|
else if (name == L"movetool_y")
|
|
m_MoveTool.Y = value;
|
|
else if (name == L"movetool_z")
|
|
m_MoveTool.Z = value;
|
|
}
|
|
|
|
void AtlasViewGame::SetParam(const std::wstring& name, const std::wstring& value)
|
|
{
|
|
if (name == L"passability")
|
|
{
|
|
m_DisplayPassability = CStrW(value).ToUTF8();
|
|
|
|
CmpPtr<ICmpPathfinder> cmpPathfinder(*GetSimulation2(), SYSTEM_ENTITY);
|
|
if (cmpPathfinder)
|
|
{
|
|
if (!value.empty())
|
|
cmpPathfinder->SetAtlasOverlay(true, cmpPathfinder->GetPassabilityClass(m_DisplayPassability));
|
|
else
|
|
cmpPathfinder->SetAtlasOverlay(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
CCamera& AtlasViewGame::GetCamera()
|
|
{
|
|
return *g_Game->GetView()->GetCamera();
|
|
}
|
|
|
|
bool AtlasViewGame::WantsHighFramerate()
|
|
{
|
|
if (g_Game->GetView()->GetCinema()->IsPlaying())
|
|
return true;
|
|
|
|
if (m_SpeedMultiplier != 0.f)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void AtlasViewGame::SetSpeedMultiplier(float speed)
|
|
{
|
|
m_SpeedMultiplier = speed;
|
|
}
|
|
|
|
void AtlasViewGame::SetTesting(bool testing)
|
|
{
|
|
m_IsTesting = testing;
|
|
// If we're testing, particles should freeze on pause (like in-game), otherwise they keep going
|
|
CmpPtr<ICmpParticleManager> cmpParticleManager(*GetSimulation2(), SYSTEM_ENTITY);
|
|
if (cmpParticleManager)
|
|
cmpParticleManager->SetUseSimTime(m_IsTesting);
|
|
}
|
|
|
|
void AtlasViewGame::SaveState(const std::wstring& label)
|
|
{
|
|
delete m_SavedStates[label]; // in case it already exists
|
|
m_SavedStates[label] = SimState::Freeze();
|
|
}
|
|
|
|
void AtlasViewGame::RestoreState(const std::wstring& label)
|
|
{
|
|
SimState* simState = m_SavedStates[label];
|
|
if (! simState)
|
|
return;
|
|
|
|
simState->Thaw();
|
|
}
|
|
|
|
std::wstring AtlasViewGame::DumpState(bool binary)
|
|
{
|
|
std::stringstream stream;
|
|
if (binary)
|
|
{
|
|
if (! g_Game->GetSimulation2()->SerializeState(stream))
|
|
return L"(internal error)";
|
|
// We can't return raw binary data, because we want to handle it with wxJS which
|
|
// doesn't like \0 bytes in strings, so return it as hex
|
|
static const char digits[] = "0123456789abcdef";
|
|
std::string str = stream.str();
|
|
std::wstring ret;
|
|
ret.reserve(str.length()*3);
|
|
for (size_t i = 0; i < str.length(); ++i)
|
|
{
|
|
ret += digits[(unsigned char)str[i] >> 4];
|
|
ret += digits[(unsigned char)str[i] & 0x0f];
|
|
ret += ' ';
|
|
}
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
if (! g_Game->GetSimulation2()->DumpDebugState(stream))
|
|
return L"(internal error)";
|
|
return wstring_from_utf8(stream.str());
|
|
}
|
|
}
|
|
|
|
void AtlasViewGame::SetBandbox(bool visible, float x0, float y0, float x1, float y1)
|
|
{
|
|
if (visible)
|
|
{
|
|
// Make sure corners are arranged in correct order
|
|
if (x0 > x1)
|
|
std::swap(x0, x1);
|
|
if (y0 > y1)
|
|
std::swap(y0, y1);
|
|
|
|
const float scale{g_ConfigDB.Get("gui.scale", 0.0f)};
|
|
m_Bandbox = CRect(x0 / scale, y0 / scale, x1 / scale, y1 / scale);
|
|
}
|
|
else
|
|
{
|
|
m_Bandbox = CRect{};
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
AtlasViewNone* view_None = NULL;
|
|
AtlasViewGame* view_Game = NULL;
|
|
AtlasViewActor* view_Actor = NULL;
|
|
|
|
AtlasView::~AtlasView()
|
|
{
|
|
}
|
|
|
|
AtlasView* AtlasView::GetView(int /*eRenderView*/ view)
|
|
{
|
|
switch (view)
|
|
{
|
|
case AtlasMessage::eRenderView::NONE: return AtlasView::GetView_None();
|
|
case AtlasMessage::eRenderView::GAME: return AtlasView::GetView_Game();
|
|
case AtlasMessage::eRenderView::ACTOR: return AtlasView::GetView_Actor();
|
|
default:
|
|
debug_warn(L"Invalid view type");
|
|
return AtlasView::GetView_None();
|
|
}
|
|
}
|
|
|
|
AtlasView* AtlasView::GetView_None()
|
|
{
|
|
if (! view_None)
|
|
view_None = new AtlasViewNone();
|
|
return view_None;
|
|
}
|
|
|
|
AtlasViewGame* AtlasView::GetView_Game()
|
|
{
|
|
if (! view_Game)
|
|
view_Game = new AtlasViewGame();
|
|
return view_Game;
|
|
}
|
|
|
|
AtlasViewActor* AtlasView::GetView_Actor()
|
|
{
|
|
if (! view_Actor)
|
|
view_Actor = new AtlasViewActor();
|
|
return view_Actor;
|
|
}
|
|
|
|
void AtlasView::DestroyViews()
|
|
{
|
|
delete view_None; view_None = NULL;
|
|
delete view_Game; view_Game = NULL;
|
|
delete view_Actor; view_Actor = NULL;
|
|
}
|