1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
22 #include "ActorViewer.h"
27 #include "graphics/Canvas2D.h"
28 #include "graphics/CinemaManager.h"
29 #include "graphics/GameView.h"
30 #include "graphics/ParticleManager.h"
31 #include "graphics/UnitManager.h"
32 #include "lib/timer.h"
34 #include "maths/MathUtil.h"
36 #include "ps/GameSetup/GameSetup.h"
37 #include "ps/VideoMode.h"
39 #include "renderer/backend/IDevice.h"
40 #include "renderer/DebugRenderer.h"
41 #include "renderer/Renderer.h"
42 #include "renderer/SceneRenderer.h"
43 #include "simulation2/components/ICmpObstructionManager.h"
44 #include "simulation2/components/ICmpParticleManager.h"
45 #include "simulation2/components/ICmpPathfinder.h"
46 #include "simulation2/Simulation2.h"
47 #include "soundmanager/ISoundManager.h"
49 extern void (*Atlas_GLSwapBuffers
)(void* context
);
51 extern int g_xres
, g_yres
;
53 //////////////////////////////////////////////////////////////////////////
55 void AtlasView::SetParam(const std::wstring
& UNUSED(name
), bool UNUSED(value
))
59 void AtlasView::SetParam(const std::wstring
& UNUSED(name
), const AtlasMessage::Color
& UNUSED(value
))
63 void AtlasView::SetParam(const std::wstring
& UNUSED(name
), const std::wstring
& UNUSED(value
))
67 void AtlasView::SetParam(const std::wstring
& UNUSED(name
), int UNUSED(value
))
71 //////////////////////////////////////////////////////////////////////////
73 AtlasViewActor::AtlasViewActor()
74 : m_SpeedMultiplier(1.f
), m_ActorViewer(new ActorViewer())
78 AtlasViewActor::~AtlasViewActor()
83 void AtlasViewActor::Update(float realFrameLength
)
85 m_ActorViewer
->Update(realFrameLength
* m_SpeedMultiplier
, realFrameLength
);
88 void AtlasViewActor::Render()
90 SViewPort vp
= { 0, 0, g_xres
, g_yres
};
91 CCamera
& camera
= GetCamera();
92 camera
.SetViewPort(vp
);
93 camera
.SetPerspectiveProjection(2.f
, 512.f
, DEGTORAD(20.f
));
94 camera
.UpdateFrustum();
96 m_ActorViewer
->Render();
97 Atlas_GLSwapBuffers((void*)g_AtlasGameLoop
->glCanvas
);
100 CCamera
& AtlasViewActor::GetCamera()
105 CSimulation2
* AtlasViewActor::GetSimulation2()
107 return m_ActorViewer
->GetSimulation2();
110 entity_id_t
AtlasViewActor::GetEntityId(AtlasMessage::ObjectID
UNUSED(obj
))
112 return m_ActorViewer
->GetEntity();
115 bool AtlasViewActor::WantsHighFramerate()
117 if (m_SpeedMultiplier
!= 0.f
)
123 void AtlasViewActor::SetEnabled(bool enabled
)
125 m_ActorViewer
->SetEnabled(enabled
);
128 void AtlasViewActor::SetSpeedMultiplier(float speedMultiplier
)
130 m_SpeedMultiplier
= speedMultiplier
;
133 ActorViewer
& AtlasViewActor::GetActorViewer()
135 return *m_ActorViewer
;
138 void AtlasViewActor::SetParam(const std::wstring
& name
, bool value
)
140 if (name
== L
"wireframe")
141 g_Renderer
.GetSceneRenderer().SetModelRenderMode(value
? WIREFRAME
: SOLID
);
142 else if (name
== L
"walk")
143 m_ActorViewer
->SetWalkEnabled(value
);
144 else if (name
== L
"ground")
145 m_ActorViewer
->SetGroundEnabled(value
);
146 // TODO: this causes corruption of WaterManager's global state
147 // which should be asociated with terrain or simulation instead
148 // see http://trac.wildfiregames.com/ticket/2692
149 //else if (name == L"water")
150 //m_ActorViewer->SetWaterEnabled(value);
151 else if (name
== L
"shadows")
152 m_ActorViewer
->ToggleShadows();
153 else if (name
== L
"stats")
154 m_ActorViewer
->SetStatsEnabled(value
);
155 else if (name
== L
"bounding_box")
156 m_ActorViewer
->SetBoundingBoxesEnabled(value
);
157 else if (name
== L
"axes_marker")
158 m_ActorViewer
->SetAxesMarkerEnabled(value
);
161 void AtlasViewActor::SetParam(const std::wstring
& name
, int value
)
163 if (name
== L
"prop_points")
164 m_ActorViewer
->SetPropPointsMode(value
);
167 void AtlasViewActor::SetParam(const std::wstring
& UNUSED(name
), const AtlasMessage::Color
& UNUSED(value
))
172 //////////////////////////////////////////////////////////////////////////
174 AtlasViewGame::AtlasViewGame()
175 : m_SpeedMultiplier(0.f
), m_IsTesting(false), m_DrawMoveTool(false)
180 AtlasViewGame::~AtlasViewGame()
182 for (const std::pair
<const std::wstring
, SimState
*>& p
: m_SavedStates
)
186 CSimulation2
* AtlasViewGame::GetSimulation2()
188 return g_Game
->GetSimulation2();
191 void AtlasViewGame::Update(float realFrameLength
)
193 const float actualFrameLength
= realFrameLength
* m_SpeedMultiplier
;
195 // Clean up any entities destroyed during UI message processing
196 g_Game
->GetSimulation2()->FlushDestroyedEntities();
198 if (m_SpeedMultiplier
== 0.f
)
200 // Update unit interpolation
201 g_Game
->Interpolate(0.0, realFrameLength
);
205 // Update the whole world
206 // (Tell the game update not to interpolate graphics - we'll do that
208 g_Game
->Update(actualFrameLength
, false);
210 // Interpolate the graphics - we only want to do this once per visual frame,
211 // not in every call to g_Game->Update
212 g_Game
->Interpolate(actualFrameLength
, realFrameLength
);
215 // Run sound idle tasks every frame.
217 g_SoundManager
->IdleTask();
219 // Cinematic motion should be independent of simulation update, so we can
220 // preview the cinematics by themselves
221 g_Game
->GetView()->GetCinema()->Update(realFrameLength
);
224 void AtlasViewGame::Render()
226 SViewPort vp
= { 0, 0, g_xres
, g_yres
};
227 CCamera
& camera
= GetCamera();
228 camera
.SetViewPort(vp
);
229 camera
.SetProjectionFromCamera(*g_Game
->GetView()->GetCamera());
230 camera
.UpdateFrustum();
232 g_Renderer
.RenderFrame(false);
233 Atlas_GLSwapBuffers((void*)g_AtlasGameLoop
->glCanvas
);
234 // In case of atlas the device's present will do only internal stuff
235 // without calling a real backbuffer swap.
236 g_VideoMode
.GetBackendDevice()->Present();
239 void AtlasViewGame::DrawCinemaPathTool()
244 const CVector3D focus
= m_MoveTool
;
245 const CVector3D camera
= GetCamera().GetOrientation().GetTranslation();
246 const float scale
= (focus
- camera
).Length();
247 const float axisLength
= scale
/ 10.0f
;
248 const float lineWidth
= scale
/ 1e3f
;
250 g_Renderer
.GetDebugRenderer().DrawLine(
251 focus
, focus
+ CVector3D(axisLength
, 0, 0),
252 CColor(1.0f
, 0.0f
, 0.0f
, 1.0f
), lineWidth
, false);
253 g_Renderer
.GetDebugRenderer().DrawLine(
254 focus
, focus
+ CVector3D(0, axisLength
, 0),
255 CColor(0.0f
, 1.0f
, 0.0f
, 1.0f
), lineWidth
, false);
256 g_Renderer
.GetDebugRenderer().DrawLine(
257 focus
, focus
+ CVector3D(0, 0, axisLength
),
258 CColor(0.0f
, 0.0f
, 1.0f
, 1.0f
), lineWidth
, false);
261 void AtlasViewGame::DrawOverlays(CCanvas2D
& canvas
)
263 if (m_Bandbox
.left
>= m_Bandbox
.right
|| m_Bandbox
.top
>= m_Bandbox
.bottom
)
266 const std::vector
<CVector2D
> outerPoints
= {
267 m_Bandbox
.TopLeft() + CVector2D(-1.0f
, -1.0f
),
268 m_Bandbox
.TopRight() + CVector2D(1.0f
, -1.0f
),
269 m_Bandbox
.BottomRight() + CVector2D(1.0f
, 1.0f
),
270 m_Bandbox
.BottomLeft() + CVector2D(-1.0f
, 1.0f
),
271 m_Bandbox
.TopLeft() + CVector2D(-1.0f
, -1.0f
)
273 canvas
.DrawLine(outerPoints
, 1.5f
, CColor(0.0f
, 0.0f
, 0.0f
, 1.0f
));
275 const std::vector
<CVector2D
> innerPoints
= {
277 m_Bandbox
.TopRight(),
278 m_Bandbox
.BottomRight(),
279 m_Bandbox
.BottomLeft(),
282 canvas
.DrawLine(innerPoints
, 1.5f
, CColor(1.0f
, 1.0f
, 1.0f
, 1.0f
));
285 void AtlasViewGame::SetParam(const std::wstring
& name
, bool value
)
287 if (name
== L
"priorities")
288 g_Renderer
.GetSceneRenderer().SetDisplayTerrainPriorities(value
);
289 else if (name
== L
"movetool")
290 m_DrawMoveTool
= value
;
293 void AtlasViewGame::SetParam(const std::wstring
& name
, float value
)
295 if (name
== L
"movetool_x")
296 m_MoveTool
.X
= value
;
297 else if (name
== L
"movetool_y")
298 m_MoveTool
.Y
= value
;
299 else if (name
== L
"movetool_z")
300 m_MoveTool
.Z
= value
;
303 void AtlasViewGame::SetParam(const std::wstring
& name
, const std::wstring
& value
)
305 if (name
== L
"passability")
307 m_DisplayPassability
= CStrW(value
).ToUTF8();
309 CmpPtr
<ICmpPathfinder
> cmpPathfinder(*GetSimulation2(), SYSTEM_ENTITY
);
313 cmpPathfinder
->SetAtlasOverlay(true, cmpPathfinder
->GetPassabilityClass(m_DisplayPassability
));
315 cmpPathfinder
->SetAtlasOverlay(false);
320 CCamera
& AtlasViewGame::GetCamera()
322 return *g_Game
->GetView()->GetCamera();
325 bool AtlasViewGame::WantsHighFramerate()
327 if (g_Game
->GetView()->GetCinema()->IsPlaying())
330 if (m_SpeedMultiplier
!= 0.f
)
336 void AtlasViewGame::SetSpeedMultiplier(float speed
)
338 m_SpeedMultiplier
= speed
;
341 void AtlasViewGame::SetTesting(bool testing
)
343 m_IsTesting
= testing
;
344 // If we're testing, particles should freeze on pause (like in-game), otherwise they keep going
345 CmpPtr
<ICmpParticleManager
> cmpParticleManager(*GetSimulation2(), SYSTEM_ENTITY
);
346 if (cmpParticleManager
)
347 cmpParticleManager
->SetUseSimTime(m_IsTesting
);
350 void AtlasViewGame::SaveState(const std::wstring
& label
)
352 delete m_SavedStates
[label
]; // in case it already exists
353 m_SavedStates
[label
] = SimState::Freeze();
356 void AtlasViewGame::RestoreState(const std::wstring
& label
)
358 SimState
* simState
= m_SavedStates
[label
];
365 std::wstring
AtlasViewGame::DumpState(bool binary
)
367 std::stringstream stream
;
370 if (! g_Game
->GetSimulation2()->SerializeState(stream
))
371 return L
"(internal error)";
372 // We can't return raw binary data, because we want to handle it with wxJS which
373 // doesn't like \0 bytes in strings, so return it as hex
374 static const char digits
[] = "0123456789abcdef";
375 std::string str
= stream
.str();
377 ret
.reserve(str
.length()*3);
378 for (size_t i
= 0; i
< str
.length(); ++i
)
380 ret
+= digits
[(unsigned char)str
[i
] >> 4];
381 ret
+= digits
[(unsigned char)str
[i
] & 0x0f];
388 if (! g_Game
->GetSimulation2()->DumpDebugState(stream
))
389 return L
"(internal error)";
390 return wstring_from_utf8(stream
.str());
394 void AtlasViewGame::SetBandbox(bool visible
, float x0
, float y0
, float x1
, float y1
)
398 // Make sure corners are arranged in correct order
404 m_Bandbox
= CRect(x0
, y0
, x1
, y1
);
412 //////////////////////////////////////////////////////////////////////////
414 AtlasViewNone
* view_None
= NULL
;
415 AtlasViewGame
* view_Game
= NULL
;
416 AtlasViewActor
* view_Actor
= NULL
;
418 AtlasView::~AtlasView()
422 AtlasView
* AtlasView::GetView(int /*eRenderView*/ view
)
426 case AtlasMessage::eRenderView::NONE
: return AtlasView::GetView_None();
427 case AtlasMessage::eRenderView::GAME
: return AtlasView::GetView_Game();
428 case AtlasMessage::eRenderView::ACTOR
: return AtlasView::GetView_Actor();
430 debug_warn(L
"Invalid view type");
431 return AtlasView::GetView_None();
435 AtlasView
* AtlasView::GetView_None()
438 view_None
= new AtlasViewNone();
442 AtlasViewGame
* AtlasView::GetView_Game()
445 view_Game
= new AtlasViewGame();
449 AtlasViewActor
* AtlasView::GetView_Actor()
452 view_Actor
= new AtlasViewActor();
456 void AtlasView::DestroyViews()
458 delete view_None
; view_None
= NULL
;
459 delete view_Game
; view_Game
= NULL
;
460 delete view_Actor
; view_Actor
= NULL
;