mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-17 13:53:57 -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>
558 lines
15 KiB
C++
558 lines
15 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 "MessageHandler.h"
|
|
|
|
#include "graphics/Camera.h"
|
|
#include "graphics/CinemaManager.h"
|
|
#include "graphics/GameView.h"
|
|
#include "lib/debug.h"
|
|
#include "maths/Fixed.h"
|
|
#include "maths/FixedVector3D.h"
|
|
#include "maths/MathUtil.h"
|
|
#include "maths/Matrix3D.h"
|
|
#include "maths/NUSpline.h"
|
|
#include "maths/Quaternion.h"
|
|
#include "maths/Vector2D.h"
|
|
#include "maths/Vector3D.h"
|
|
#include "ps/CStr.h"
|
|
#include "ps/Game.h"
|
|
#include "simulation2/components/ICmpCinemaManager.h"
|
|
#include "simulation2/helpers/CinemaPath.h"
|
|
#include "simulation2/system/Component.h"
|
|
#include "simulation2/system/Entity.h"
|
|
#include "tools/atlas/GameInterface/CommandProc.h"
|
|
#include "tools/atlas/GameInterface/GameLoop.h"
|
|
#include "tools/atlas/GameInterface/Messages.h"
|
|
#include "tools/atlas/GameInterface/Shareable.h"
|
|
#include "tools/atlas/GameInterface/SharedTypes.h"
|
|
#include "tools/atlas/GameInterface/View.h"
|
|
|
|
#include <cstddef>
|
|
#include <map>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace AtlasMessage { struct cAddPathNode; }
|
|
namespace AtlasMessage { struct cDeletePathNode; }
|
|
namespace AtlasMessage { struct cMovePathNode; }
|
|
|
|
namespace AtlasMessage
|
|
{
|
|
|
|
const float MINIMAL_SCREEN_DISTANCE = 5.f;
|
|
|
|
sCinemaPath ConstructCinemaPath(const CCinemaPath* source)
|
|
{
|
|
sCinemaPath path;
|
|
const CCinemaData* data = source->GetData();
|
|
//path.mode = data->m_Mode;
|
|
//path.style = data->m_Style;
|
|
path.growth = data->m_Growth;
|
|
path.timescale = data->m_Timescale.ToFloat();
|
|
path.change = data->m_Switch;
|
|
|
|
return path;
|
|
}
|
|
CCinemaData ConstructCinemaData(const sCinemaPath& path)
|
|
{
|
|
CCinemaData data;
|
|
data.m_Growth = data.m_GrowthCount = path.growth;
|
|
data.m_Switch = path.change;
|
|
//data.m_Mode = path.mode;
|
|
//data.m_Style = path.style;
|
|
|
|
return data;
|
|
}
|
|
sCinemaSplineNode ConstructCinemaNode(const SplineData& data)
|
|
{
|
|
sCinemaSplineNode node;
|
|
node.px = data.Position.X.ToFloat();
|
|
node.py = data.Position.Y.ToFloat();
|
|
node.pz = data.Position.Z.ToFloat();
|
|
|
|
node.rx = data.Rotation.X.ToFloat();
|
|
node.ry = data.Rotation.Y.ToFloat();
|
|
node.rz = data.Rotation.Z.ToFloat();
|
|
node.t = data.Distance.ToFloat();
|
|
|
|
return node;
|
|
}
|
|
|
|
std::vector<sCinemaPath> GetCurrentPaths()
|
|
{
|
|
std::vector<sCinemaPath> atlasPaths;
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
|
if (!cmpCinemaManager)
|
|
return atlasPaths;
|
|
const std::map<CStrW, CCinemaPath>& paths = cmpCinemaManager->GetPaths();
|
|
|
|
for ( std::map<CStrW, CCinemaPath>::const_iterator it=paths.begin(); it!=paths.end(); ++it )
|
|
{
|
|
sCinemaPath path = ConstructCinemaPath(&it->second);
|
|
path.name = it->first;
|
|
|
|
const std::vector<SplineData>& nodes = it->second.GetAllNodes();
|
|
std::vector<sCinemaSplineNode> atlasNodes;
|
|
|
|
for ( size_t i=0; i<nodes.size(); ++i )
|
|
atlasNodes.push_back( ConstructCinemaNode(nodes[i]) );
|
|
|
|
if ( !atlasNodes.empty() )
|
|
{
|
|
float back = atlasNodes.back().t;
|
|
if ( atlasNodes.size() > 2 )
|
|
{
|
|
for ( size_t i=atlasNodes.size()-2; i>0; --i )
|
|
atlasNodes[i].t = atlasNodes[i-1].t;
|
|
}
|
|
atlasNodes.back().t = atlasNodes.front().t;
|
|
atlasNodes.front().t = back;
|
|
}
|
|
path.nodes = atlasNodes;
|
|
atlasPaths.push_back(path);
|
|
}
|
|
return atlasPaths;
|
|
}
|
|
|
|
void SetCurrentPaths(const std::vector<sCinemaPath>& atlasPaths)
|
|
{
|
|
std::map<CStrW, CCinemaPath> paths;
|
|
|
|
for ( std::vector<sCinemaPath>::const_iterator it=atlasPaths.begin(); it!=atlasPaths.end(); ++it )
|
|
{
|
|
CStrW pathName(*it->name);
|
|
paths[pathName] = CCinemaPath();
|
|
paths[pathName].SetTimescale(fixed::FromFloat(it->timescale));
|
|
|
|
const sCinemaPath& atlasPath = *it;
|
|
const std::vector<sCinemaSplineNode> nodes = *atlasPath.nodes;
|
|
TNSpline spline;
|
|
CCinemaData data = ConstructCinemaData(atlasPath);
|
|
|
|
for ( size_t j=0; j<nodes.size(); ++j )
|
|
{
|
|
spline.AddNode(CFixedVector3D(fixed::FromFloat(nodes[j].px), fixed::FromFloat(nodes[j].py), fixed::FromFloat(nodes[j].pz)),
|
|
CFixedVector3D(fixed::FromFloat(nodes[j].rx), fixed::FromFloat(nodes[j].ry), fixed::FromFloat(nodes[j].rz)), fixed::FromFloat(nodes[j].t));
|
|
}
|
|
paths[pathName] = CCinemaPath(data, spline, TNSpline());
|
|
}
|
|
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
|
if (cmpCinemaManager)
|
|
cmpCinemaManager->SetPaths(paths);
|
|
}
|
|
QUERYHANDLER(GetCameraInfo)
|
|
{
|
|
sCameraInfo info;
|
|
const CMatrix3D& cameraOrientation = g_Game->GetView()->GetCamera()->GetOrientation();
|
|
|
|
CQuaternion quatRot = cameraOrientation.GetRotation();
|
|
quatRot.Normalize();
|
|
CVector3D rotation = quatRot.ToEulerAngles();
|
|
rotation.X = RADTODEG(rotation.X);
|
|
rotation.Y = RADTODEG(rotation.Y);
|
|
rotation.Z = RADTODEG(rotation.Z);
|
|
CVector3D translation = cameraOrientation.GetTranslation();
|
|
|
|
info.pX = translation.X;
|
|
info.pY = translation.Y;
|
|
info.pZ = translation.Z;
|
|
info.rX = rotation.X;
|
|
info.rY = rotation.Y;
|
|
info.rZ = rotation.Z;
|
|
msg->info = info;
|
|
}
|
|
|
|
MESSAGEHANDLER(CinemaEvent)
|
|
{
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
|
if (!cmpCinemaManager)
|
|
return;
|
|
|
|
if (msg->mode == eCinemaEventMode::SMOOTH)
|
|
{
|
|
cmpCinemaManager->AddCinemaPathToQueue(*msg->path);
|
|
}
|
|
else if ( msg->mode == eCinemaEventMode::RESET )
|
|
{
|
|
// g_Game->GetView()->ResetCamera();
|
|
}
|
|
else
|
|
ENSURE(false);
|
|
}
|
|
|
|
BEGIN_COMMAND(AddCinemaPath)
|
|
{
|
|
void Do()
|
|
{
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
|
if (!cmpCinemaManager)
|
|
return;
|
|
|
|
CCinemaData pathData;
|
|
pathData.m_Name = *msg->pathName;
|
|
pathData.m_Timescale = fixed::FromInt(1);
|
|
pathData.m_Orientation = L"target";
|
|
pathData.m_Mode = L"ease_inout";
|
|
pathData.m_Style = L"default";
|
|
|
|
CVector3D focus = g_Game->GetView()->GetCamera()->GetFocus();
|
|
CFixedVector3D target(
|
|
fixed::FromFloat(focus.X),
|
|
fixed::FromFloat(focus.Y),
|
|
fixed::FromFloat(focus.Z)
|
|
);
|
|
|
|
CVector3D camera = g_Game->GetView()->GetCamera()->GetOrientation().GetTranslation();
|
|
CFixedVector3D position(
|
|
fixed::FromFloat(camera.X),
|
|
fixed::FromFloat(camera.Y),
|
|
fixed::FromFloat(camera.Z)
|
|
);
|
|
|
|
TNSpline positionSpline;
|
|
positionSpline.AddNode(position, CFixedVector3D(), fixed::FromInt(0));
|
|
|
|
TNSpline targetSpline;
|
|
targetSpline.AddNode(target, CFixedVector3D(), fixed::FromInt(0));
|
|
|
|
cmpCinemaManager->AddPath(CCinemaPath(pathData, positionSpline, targetSpline));
|
|
}
|
|
void Redo()
|
|
{
|
|
}
|
|
void Undo()
|
|
{
|
|
}
|
|
};
|
|
END_COMMAND(AddCinemaPath)
|
|
|
|
BEGIN_COMMAND(DeleteCinemaPath)
|
|
{
|
|
void Do()
|
|
{
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
|
if (!cmpCinemaManager)
|
|
return;
|
|
|
|
cmpCinemaManager->DeletePath(*msg->pathName);
|
|
}
|
|
void Redo()
|
|
{
|
|
}
|
|
void Undo()
|
|
{
|
|
}
|
|
};
|
|
END_COMMAND(DeleteCinemaPath)
|
|
|
|
BEGIN_COMMAND(SetCinemaPaths)
|
|
{
|
|
std::vector<sCinemaPath> m_oldPaths, m_newPaths;
|
|
void Do()
|
|
{
|
|
m_oldPaths = GetCurrentPaths();
|
|
m_newPaths = *msg->paths;
|
|
Redo();
|
|
}
|
|
void Redo()
|
|
{
|
|
SetCurrentPaths(m_newPaths);
|
|
}
|
|
void Undo()
|
|
{
|
|
SetCurrentPaths(m_oldPaths);
|
|
}
|
|
};
|
|
END_COMMAND(SetCinemaPaths)
|
|
|
|
BEGIN_COMMAND(SetCinemaPathsDrawing)
|
|
{
|
|
void Do()
|
|
{
|
|
if (g_Game && g_Game->GetView() && g_Game->GetView()->GetCinema())
|
|
g_Game->GetView()->GetCinema()->SetPathsDrawing(msg->drawPaths);
|
|
}
|
|
|
|
void Redo()
|
|
{
|
|
}
|
|
|
|
void Undo()
|
|
{
|
|
}
|
|
};
|
|
END_COMMAND(SetCinemaPathsDrawing)
|
|
|
|
static CVector3D GetNearestPointToScreenCoords(const CVector3D& base, const CVector3D& dir, const CVector2D& screen, float lower = -1e5, float upper = 1e5)
|
|
{
|
|
// It uses a ternary search, because an intersection of cylinders is the complex task
|
|
for (int i = 0; i < 64; ++i)
|
|
{
|
|
float delta = (upper - lower) / 3.0;
|
|
float middle1 = lower + delta, middle2 = lower + 2.0f * delta;
|
|
CVector3D p1 = base + dir * middle1, p2 = base + dir * middle2;
|
|
const CVector2D s1{g_Game->GetView()->GetCamera()->GetScreenCoordinates(p1)};
|
|
const CVector2D s2{g_Game->GetView()->GetCamera()->GetScreenCoordinates(p2)};
|
|
if ((s1 - screen).Length() < (s2 - screen).Length())
|
|
upper = middle2;
|
|
else
|
|
lower = middle1;
|
|
}
|
|
return base + dir * upper;
|
|
}
|
|
|
|
#define GET_PATH_NODE_WITH_VALIDATION() \
|
|
int index = msg->node->index; \
|
|
if (index < 0) \
|
|
return; \
|
|
CStrW name = *msg->node->name; \
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); \
|
|
if (!cmpCinemaManager || !cmpCinemaManager->HasPath(name)) \
|
|
return; \
|
|
const CCinemaPath& path = cmpCinemaManager->GetPaths().find(name)->second; \
|
|
if (!msg->node->targetNode) \
|
|
{ \
|
|
if (index >= (int)path.GetAllNodes().size()) \
|
|
return; \
|
|
} \
|
|
else \
|
|
{ \
|
|
if (index >= (int)path.GetTargetSpline().GetAllNodes().size()) \
|
|
return; \
|
|
}
|
|
|
|
BEGIN_COMMAND(AddPathNode)
|
|
{
|
|
void Do()
|
|
{
|
|
GET_PATH_NODE_WITH_VALIDATION();
|
|
|
|
CCinemaData data = *path.GetData();
|
|
TNSpline positionSpline = path;
|
|
TNSpline targetSpline = path.GetTargetSpline();
|
|
TNSpline& spline = msg->node->targetNode ? targetSpline : positionSpline;
|
|
|
|
CVector3D focus = g_Game->GetView()->GetCamera()->GetFocus();
|
|
CFixedVector3D target(
|
|
fixed::FromFloat(focus.X),
|
|
fixed::FromFloat(focus.Y),
|
|
fixed::FromFloat(focus.Z)
|
|
);
|
|
spline.InsertNode(index + 1, target, CFixedVector3D(), fixed::FromInt(1));
|
|
|
|
spline.BuildSpline();
|
|
cmpCinemaManager->DeletePath(name);
|
|
cmpCinemaManager->AddPath(CCinemaPath(data, positionSpline, targetSpline));
|
|
}
|
|
|
|
void Redo()
|
|
{
|
|
}
|
|
|
|
void Undo()
|
|
{
|
|
}
|
|
};
|
|
END_COMMAND(AddPathNode)
|
|
|
|
BEGIN_COMMAND(DeletePathNode)
|
|
{
|
|
void Do()
|
|
{
|
|
GET_PATH_NODE_WITH_VALIDATION();
|
|
|
|
CCinemaData data = *path.GetData();
|
|
TNSpline positionSpline = path;
|
|
TNSpline targetSpline = path.GetTargetSpline();
|
|
TNSpline& spline = msg->node->targetNode ? targetSpline : positionSpline;
|
|
if (spline.GetAllNodes().size() <= 1)
|
|
return;
|
|
|
|
spline.RemoveNode(index);
|
|
spline.BuildSpline();
|
|
cmpCinemaManager->DeletePath(name);
|
|
cmpCinemaManager->AddPath(CCinemaPath(data, positionSpline, targetSpline));
|
|
|
|
g_AtlasGameLoop->view->SetParam(L"movetool", false);
|
|
}
|
|
|
|
void Redo()
|
|
{
|
|
}
|
|
|
|
void Undo()
|
|
{
|
|
}
|
|
};
|
|
END_COMMAND(DeletePathNode)
|
|
|
|
BEGIN_COMMAND(MovePathNode)
|
|
{
|
|
void Do()
|
|
{
|
|
int axis = msg->axis;
|
|
if (axis == AXIS_INVALID)
|
|
return;
|
|
|
|
GET_PATH_NODE_WITH_VALIDATION();
|
|
|
|
CCinemaData data = *path.GetData();
|
|
TNSpline positionSpline = path;
|
|
TNSpline targetSpline = path.GetTargetSpline();
|
|
TNSpline& spline = msg->node->targetNode ? targetSpline : positionSpline;
|
|
|
|
// Get shift of the tool by the cursor movement
|
|
CFixedVector3D pos = spline.GetAllNodes()[index].Position;
|
|
CVector3D position(
|
|
pos.X.ToFloat(),
|
|
pos.Y.ToFloat(),
|
|
pos.Z.ToFloat()
|
|
);
|
|
CVector3D axisDirection(axis & AXIS_X, axis & AXIS_Y, axis & AXIS_Z);
|
|
CVector2D from, to;
|
|
msg->from->GetScreenSpace(from.X, from.Y);
|
|
msg->to->GetScreenSpace(to.X, to.Y);
|
|
CVector3D shift(
|
|
GetNearestPointToScreenCoords(position, axisDirection, to) -
|
|
GetNearestPointToScreenCoords(position, axisDirection, from)
|
|
);
|
|
|
|
// Change, rebuild and update the path
|
|
position += shift;
|
|
pos += CFixedVector3D(
|
|
fixed::FromFloat(shift.X),
|
|
fixed::FromFloat(shift.Y),
|
|
fixed::FromFloat(shift.Z)
|
|
);
|
|
spline.UpdateNodePos(index, pos);
|
|
spline.BuildSpline();
|
|
cmpCinemaManager->DeletePath(name);
|
|
cmpCinemaManager->AddPath(CCinemaPath(data, positionSpline, targetSpline));
|
|
|
|
// Update visual tool coordinates
|
|
g_AtlasGameLoop->view->SetParam(L"movetool_x", position.X);
|
|
g_AtlasGameLoop->view->SetParam(L"movetool_y", position.Y);
|
|
g_AtlasGameLoop->view->SetParam(L"movetool_z", position.Z);
|
|
}
|
|
|
|
void Redo()
|
|
{
|
|
}
|
|
|
|
void Undo()
|
|
{
|
|
}
|
|
};
|
|
END_COMMAND(MovePathNode)
|
|
|
|
QUERYHANDLER(GetCinemaPaths)
|
|
{
|
|
msg->paths = GetCurrentPaths();
|
|
}
|
|
|
|
static bool isPathNodePicked(const TNSpline& spline, const CVector2D& cursor, AtlasMessage::sCinemaPathNode& node, bool targetNode)
|
|
{
|
|
for (size_t i = 0; i < spline.GetAllNodes().size(); ++i)
|
|
{
|
|
const SplineData& data = spline.GetAllNodes()[i];
|
|
CVector3D position(
|
|
data.Position.X.ToFloat(),
|
|
data.Position.Y.ToFloat(),
|
|
data.Position.Z.ToFloat()
|
|
);
|
|
const CVector2D screenPos{g_Game->GetView()->GetCamera()->GetScreenCoordinates(position)};
|
|
if ((screenPos - cursor).Length() < MINIMAL_SCREEN_DISTANCE)
|
|
{
|
|
node.index = i;
|
|
node.targetNode = targetNode;
|
|
g_AtlasGameLoop->view->SetParam(L"movetool", true);
|
|
g_AtlasGameLoop->view->SetParam(L"movetool_x", position.X);
|
|
g_AtlasGameLoop->view->SetParam(L"movetool_y", position.Y);
|
|
g_AtlasGameLoop->view->SetParam(L"movetool_z", position.Z);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QUERYHANDLER(PickPathNode)
|
|
{
|
|
AtlasMessage::sCinemaPathNode node;
|
|
CmpPtr<ICmpCinemaManager> cmpCinemaManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
|
if (!cmpCinemaManager)
|
|
{
|
|
msg->node = node;
|
|
return;
|
|
}
|
|
|
|
CVector2D cursor;
|
|
msg->pos->GetScreenSpace(cursor.X, cursor.Y);
|
|
|
|
for (const std::pair<const CStrW, CCinemaPath>& p : cmpCinemaManager->GetPaths())
|
|
{
|
|
const CCinemaPath& path = p.second;
|
|
if (isPathNodePicked(path, cursor, node, false) || isPathNodePicked(path.GetTargetSpline(), cursor, node, true))
|
|
{
|
|
node.name = path.GetName();
|
|
msg->node = node;
|
|
return;
|
|
}
|
|
}
|
|
msg->node = node;
|
|
g_AtlasGameLoop->view->SetParam(L"movetool", false);
|
|
}
|
|
|
|
static bool isAxisPicked(const CVector3D& base, const CVector3D& direction, float length, const CVector2D& cursor)
|
|
{
|
|
CVector3D position = GetNearestPointToScreenCoords(base, direction, cursor, 0, length);
|
|
const CVector2D screenPos{g_Game->GetView()->GetCamera()->GetScreenCoordinates(position)};
|
|
return (cursor - screenPos).Length() < MINIMAL_SCREEN_DISTANCE;
|
|
}
|
|
|
|
QUERYHANDLER(PickAxis)
|
|
{
|
|
msg->axis = AXIS_INVALID;
|
|
|
|
GET_PATH_NODE_WITH_VALIDATION();
|
|
|
|
const TNSpline& spline = msg->node->targetNode ? path.GetTargetSpline() : path;
|
|
CFixedVector3D pos = spline.GetAllNodes()[index].Position;
|
|
CVector3D position(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat());
|
|
CVector3D camera = g_Game->GetView()->GetCamera()->GetOrientation().GetTranslation();
|
|
float scale = (position - camera).Length() / 10.0;
|
|
|
|
CVector2D cursor;
|
|
msg->pos->GetScreenSpace(cursor.X, cursor.Y);
|
|
if (isAxisPicked(position, CVector3D(1, 0, 0), scale, cursor))
|
|
msg->axis = AXIS_X;
|
|
else if (isAxisPicked(position, CVector3D(0, 1, 0), scale, cursor))
|
|
msg->axis = AXIS_Y;
|
|
else if (isAxisPicked(position, CVector3D(0, 0, 1), scale, cursor))
|
|
msg->axis = AXIS_Z;
|
|
}
|
|
|
|
MESSAGEHANDLER(ClearPathNodePreview)
|
|
{
|
|
g_AtlasGameLoop->view->SetParam(L"movetool", false);
|
|
}
|
|
|
|
} // namespace AtlasMessage
|