Line data Source code
1 : /* Copyright (C) 2022 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
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.
8 : *
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.
13 : *
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/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "View.h"
21 :
22 : #include "ActorViewer.h"
23 : #include "GameLoop.h"
24 : #include "Messages.h"
25 : #include "SimState.h"
26 :
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"
33 : #include "lib/utf8.h"
34 : #include "maths/MathUtil.h"
35 : #include "ps/Game.h"
36 : #include "ps/GameSetup/GameSetup.h"
37 : #include "ps/VideoMode.h"
38 : #include "ps/World.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"
48 :
49 : extern void (*Atlas_GLSwapBuffers)(void* context);
50 :
51 : extern int g_xres, g_yres;
52 :
53 : //////////////////////////////////////////////////////////////////////////
54 :
55 0 : void AtlasView::SetParam(const std::wstring& UNUSED(name), bool UNUSED(value))
56 : {
57 0 : }
58 :
59 0 : void AtlasView::SetParam(const std::wstring& UNUSED(name), const AtlasMessage::Color& UNUSED(value))
60 : {
61 0 : }
62 :
63 0 : void AtlasView::SetParam(const std::wstring& UNUSED(name), const std::wstring& UNUSED(value))
64 : {
65 0 : }
66 :
67 0 : void AtlasView::SetParam(const std::wstring& UNUSED(name), int UNUSED(value))
68 : {
69 0 : }
70 :
71 : //////////////////////////////////////////////////////////////////////////
72 :
73 0 : AtlasViewActor::AtlasViewActor()
74 0 : : m_SpeedMultiplier(1.f), m_ActorViewer(new ActorViewer())
75 : {
76 0 : }
77 :
78 0 : AtlasViewActor::~AtlasViewActor()
79 : {
80 0 : delete m_ActorViewer;
81 0 : }
82 :
83 0 : void AtlasViewActor::Update(float realFrameLength)
84 : {
85 0 : m_ActorViewer->Update(realFrameLength * m_SpeedMultiplier, realFrameLength);
86 0 : }
87 :
88 0 : void AtlasViewActor::Render()
89 : {
90 0 : SViewPort vp = { 0, 0, g_xres, g_yres };
91 0 : CCamera& camera = GetCamera();
92 0 : camera.SetViewPort(vp);
93 0 : camera.SetPerspectiveProjection(2.f, 512.f, DEGTORAD(20.f));
94 0 : camera.UpdateFrustum();
95 :
96 0 : m_ActorViewer->Render();
97 0 : Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas);
98 0 : }
99 :
100 0 : CCamera& AtlasViewActor::GetCamera()
101 : {
102 0 : return m_Camera;
103 : }
104 :
105 0 : CSimulation2* AtlasViewActor::GetSimulation2()
106 : {
107 0 : return m_ActorViewer->GetSimulation2();
108 : }
109 :
110 0 : entity_id_t AtlasViewActor::GetEntityId(AtlasMessage::ObjectID UNUSED(obj))
111 : {
112 0 : return m_ActorViewer->GetEntity();
113 : }
114 :
115 0 : bool AtlasViewActor::WantsHighFramerate()
116 : {
117 0 : if (m_SpeedMultiplier != 0.f)
118 0 : return true;
119 :
120 0 : return false;
121 : }
122 :
123 0 : void AtlasViewActor::SetEnabled(bool enabled)
124 : {
125 0 : m_ActorViewer->SetEnabled(enabled);
126 0 : }
127 :
128 0 : void AtlasViewActor::SetSpeedMultiplier(float speedMultiplier)
129 : {
130 0 : m_SpeedMultiplier = speedMultiplier;
131 0 : }
132 :
133 0 : ActorViewer& AtlasViewActor::GetActorViewer()
134 : {
135 0 : return *m_ActorViewer;
136 : }
137 :
138 0 : void AtlasViewActor::SetParam(const std::wstring& name, bool value)
139 : {
140 0 : if (name == L"wireframe")
141 0 : g_Renderer.GetSceneRenderer().SetModelRenderMode(value ? WIREFRAME : SOLID);
142 0 : else if (name == L"walk")
143 0 : m_ActorViewer->SetWalkEnabled(value);
144 0 : else if (name == L"ground")
145 0 : 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 0 : else if (name == L"shadows")
152 0 : m_ActorViewer->ToggleShadows();
153 0 : else if (name == L"stats")
154 0 : m_ActorViewer->SetStatsEnabled(value);
155 0 : else if (name == L"bounding_box")
156 0 : m_ActorViewer->SetBoundingBoxesEnabled(value);
157 0 : else if (name == L"axes_marker")
158 0 : m_ActorViewer->SetAxesMarkerEnabled(value);
159 0 : }
160 :
161 0 : void AtlasViewActor::SetParam(const std::wstring& name, int value)
162 : {
163 0 : if (name == L"prop_points")
164 0 : m_ActorViewer->SetPropPointsMode(value);
165 0 : }
166 :
167 0 : void AtlasViewActor::SetParam(const std::wstring& UNUSED(name), const AtlasMessage::Color& UNUSED(value))
168 : {
169 0 : }
170 :
171 :
172 : //////////////////////////////////////////////////////////////////////////
173 :
174 0 : AtlasViewGame::AtlasViewGame()
175 0 : : m_SpeedMultiplier(0.f), m_IsTesting(false), m_DrawMoveTool(false)
176 : {
177 0 : ENSURE(g_Game);
178 0 : }
179 :
180 0 : AtlasViewGame::~AtlasViewGame()
181 : {
182 0 : for (const std::pair<const std::wstring, SimState*>& p : m_SavedStates)
183 0 : delete p.second;
184 0 : }
185 :
186 0 : CSimulation2* AtlasViewGame::GetSimulation2()
187 : {
188 0 : return g_Game->GetSimulation2();
189 : }
190 :
191 0 : void AtlasViewGame::Update(float realFrameLength)
192 : {
193 0 : const float actualFrameLength = realFrameLength * m_SpeedMultiplier;
194 :
195 : // Clean up any entities destroyed during UI message processing
196 0 : g_Game->GetSimulation2()->FlushDestroyedEntities();
197 :
198 0 : if (m_SpeedMultiplier == 0.f)
199 : {
200 : // Update unit interpolation
201 0 : g_Game->Interpolate(0.0, realFrameLength);
202 : }
203 : else
204 : {
205 : // Update the whole world
206 : // (Tell the game update not to interpolate graphics - we'll do that
207 : // ourselves)
208 0 : g_Game->Update(actualFrameLength, false);
209 :
210 : // Interpolate the graphics - we only want to do this once per visual frame,
211 : // not in every call to g_Game->Update
212 0 : g_Game->Interpolate(actualFrameLength, realFrameLength);
213 : }
214 :
215 : // Run sound idle tasks every frame.
216 0 : if (g_SoundManager)
217 0 : g_SoundManager->IdleTask();
218 :
219 : // Cinematic motion should be independent of simulation update, so we can
220 : // preview the cinematics by themselves
221 0 : g_Game->GetView()->GetCinema()->Update(realFrameLength);
222 0 : }
223 :
224 0 : void AtlasViewGame::Render()
225 : {
226 0 : if (!g_VideoMode.GetBackendDevice()->AcquireNextBackbuffer())
227 0 : return;
228 :
229 0 : SViewPort vp = { 0, 0, g_xres, g_yres };
230 0 : CCamera& camera = GetCamera();
231 0 : camera.SetViewPort(vp);
232 0 : camera.SetProjectionFromCamera(*g_Game->GetView()->GetCamera());
233 0 : camera.UpdateFrustum();
234 :
235 0 : g_Renderer.RenderFrame(false);
236 0 : Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas);
237 : // In case of atlas the device's present will do only internal stuff
238 : // without calling a real backbuffer swap.
239 0 : g_VideoMode.GetBackendDevice()->Present();
240 : }
241 :
242 0 : void AtlasViewGame::DrawCinemaPathTool()
243 : {
244 0 : if (!m_DrawMoveTool)
245 0 : return;
246 :
247 0 : const CVector3D focus = m_MoveTool;
248 0 : const CVector3D camera = GetCamera().GetOrientation().GetTranslation();
249 0 : const float scale = (focus - camera).Length();
250 0 : const float axisLength = scale / 10.0f;
251 0 : const float lineWidth = scale / 1e3f;
252 :
253 0 : g_Renderer.GetDebugRenderer().DrawLine(
254 0 : focus, focus + CVector3D(axisLength, 0, 0),
255 0 : CColor(1.0f, 0.0f, 0.0f, 1.0f), lineWidth, false);
256 0 : g_Renderer.GetDebugRenderer().DrawLine(
257 0 : focus, focus + CVector3D(0, axisLength, 0),
258 0 : CColor(0.0f, 1.0f, 0.0f, 1.0f), lineWidth, false);
259 0 : g_Renderer.GetDebugRenderer().DrawLine(
260 0 : focus, focus + CVector3D(0, 0, axisLength),
261 0 : CColor(0.0f, 0.0f, 1.0f, 1.0f), lineWidth, false);
262 : }
263 :
264 0 : void AtlasViewGame::DrawOverlays(CCanvas2D& canvas)
265 : {
266 0 : if (m_Bandbox.left >= m_Bandbox.right || m_Bandbox.top >= m_Bandbox.bottom)
267 0 : return;
268 :
269 : const std::vector<CVector2D> outerPoints = {
270 0 : m_Bandbox.TopLeft() + CVector2D(-1.0f, -1.0f),
271 0 : m_Bandbox.TopRight() + CVector2D(1.0f, -1.0f),
272 0 : m_Bandbox.BottomRight() + CVector2D(1.0f, 1.0f),
273 0 : m_Bandbox.BottomLeft() + CVector2D(-1.0f, 1.0f),
274 0 : m_Bandbox.TopLeft() + CVector2D(-1.0f, -1.0f)
275 0 : };
276 0 : canvas.DrawLine(outerPoints, 1.5f, CColor(0.0f, 0.0f, 0.0f, 1.0f));
277 :
278 : const std::vector<CVector2D> innerPoints = {
279 0 : m_Bandbox.TopLeft(),
280 0 : m_Bandbox.TopRight(),
281 0 : m_Bandbox.BottomRight(),
282 0 : m_Bandbox.BottomLeft(),
283 0 : m_Bandbox.TopLeft()
284 0 : };
285 0 : canvas.DrawLine(innerPoints, 1.5f, CColor(1.0f, 1.0f, 1.0f, 1.0f));
286 : }
287 :
288 0 : void AtlasViewGame::SetParam(const std::wstring& name, bool value)
289 : {
290 0 : if (name == L"priorities")
291 0 : g_Renderer.GetSceneRenderer().SetDisplayTerrainPriorities(value);
292 0 : else if (name == L"movetool")
293 0 : m_DrawMoveTool = value;
294 0 : }
295 :
296 0 : void AtlasViewGame::SetParam(const std::wstring& name, float value)
297 : {
298 0 : if (name == L"movetool_x")
299 0 : m_MoveTool.X = value;
300 0 : else if (name == L"movetool_y")
301 0 : m_MoveTool.Y = value;
302 0 : else if (name == L"movetool_z")
303 0 : m_MoveTool.Z = value;
304 0 : }
305 :
306 0 : void AtlasViewGame::SetParam(const std::wstring& name, const std::wstring& value)
307 : {
308 0 : if (name == L"passability")
309 : {
310 0 : m_DisplayPassability = CStrW(value).ToUTF8();
311 :
312 0 : CmpPtr<ICmpPathfinder> cmpPathfinder(*GetSimulation2(), SYSTEM_ENTITY);
313 0 : if (cmpPathfinder)
314 : {
315 0 : if (!value.empty())
316 0 : cmpPathfinder->SetAtlasOverlay(true, cmpPathfinder->GetPassabilityClass(m_DisplayPassability));
317 : else
318 0 : cmpPathfinder->SetAtlasOverlay(false);
319 : }
320 : }
321 0 : }
322 :
323 0 : CCamera& AtlasViewGame::GetCamera()
324 : {
325 0 : return *g_Game->GetView()->GetCamera();
326 : }
327 :
328 0 : bool AtlasViewGame::WantsHighFramerate()
329 : {
330 0 : if (g_Game->GetView()->GetCinema()->IsPlaying())
331 0 : return true;
332 :
333 0 : if (m_SpeedMultiplier != 0.f)
334 0 : return true;
335 :
336 0 : return false;
337 : }
338 :
339 0 : void AtlasViewGame::SetSpeedMultiplier(float speed)
340 : {
341 0 : m_SpeedMultiplier = speed;
342 0 : }
343 :
344 0 : void AtlasViewGame::SetTesting(bool testing)
345 : {
346 0 : m_IsTesting = testing;
347 : // If we're testing, particles should freeze on pause (like in-game), otherwise they keep going
348 0 : CmpPtr<ICmpParticleManager> cmpParticleManager(*GetSimulation2(), SYSTEM_ENTITY);
349 0 : if (cmpParticleManager)
350 0 : cmpParticleManager->SetUseSimTime(m_IsTesting);
351 0 : }
352 :
353 0 : void AtlasViewGame::SaveState(const std::wstring& label)
354 : {
355 0 : delete m_SavedStates[label]; // in case it already exists
356 0 : m_SavedStates[label] = SimState::Freeze();
357 0 : }
358 :
359 0 : void AtlasViewGame::RestoreState(const std::wstring& label)
360 : {
361 0 : SimState* simState = m_SavedStates[label];
362 0 : if (! simState)
363 0 : return;
364 :
365 0 : simState->Thaw();
366 : }
367 :
368 0 : std::wstring AtlasViewGame::DumpState(bool binary)
369 : {
370 0 : std::stringstream stream;
371 0 : if (binary)
372 : {
373 0 : if (! g_Game->GetSimulation2()->SerializeState(stream))
374 0 : return L"(internal error)";
375 : // We can't return raw binary data, because we want to handle it with wxJS which
376 : // doesn't like \0 bytes in strings, so return it as hex
377 : static const char digits[] = "0123456789abcdef";
378 0 : std::string str = stream.str();
379 0 : std::wstring ret;
380 0 : ret.reserve(str.length()*3);
381 0 : for (size_t i = 0; i < str.length(); ++i)
382 : {
383 0 : ret += digits[(unsigned char)str[i] >> 4];
384 0 : ret += digits[(unsigned char)str[i] & 0x0f];
385 0 : ret += ' ';
386 : }
387 0 : return ret;
388 : }
389 : else
390 : {
391 0 : if (! g_Game->GetSimulation2()->DumpDebugState(stream))
392 0 : return L"(internal error)";
393 0 : return wstring_from_utf8(stream.str());
394 : }
395 : }
396 :
397 0 : void AtlasViewGame::SetBandbox(bool visible, float x0, float y0, float x1, float y1)
398 : {
399 0 : if (visible)
400 : {
401 : // Make sure corners are arranged in correct order
402 0 : if (x0 > x1)
403 0 : std::swap(x0, x1);
404 0 : if (y0 > y1)
405 0 : std::swap(y0, y1);
406 :
407 0 : m_Bandbox = CRect(x0, y0, x1, y1);
408 : }
409 : else
410 : {
411 0 : m_Bandbox = CRect{};
412 : }
413 0 : }
414 :
415 : //////////////////////////////////////////////////////////////////////////
416 :
417 : AtlasViewNone* view_None = NULL;
418 : AtlasViewGame* view_Game = NULL;
419 : AtlasViewActor* view_Actor = NULL;
420 :
421 0 : AtlasView::~AtlasView()
422 : {
423 0 : }
424 :
425 0 : AtlasView* AtlasView::GetView(int /*eRenderView*/ view)
426 : {
427 0 : switch (view)
428 : {
429 0 : case AtlasMessage::eRenderView::NONE: return AtlasView::GetView_None();
430 0 : case AtlasMessage::eRenderView::GAME: return AtlasView::GetView_Game();
431 0 : case AtlasMessage::eRenderView::ACTOR: return AtlasView::GetView_Actor();
432 0 : default:
433 0 : debug_warn(L"Invalid view type");
434 0 : return AtlasView::GetView_None();
435 : }
436 : }
437 :
438 0 : AtlasView* AtlasView::GetView_None()
439 : {
440 0 : if (! view_None)
441 0 : view_None = new AtlasViewNone();
442 0 : return view_None;
443 : }
444 :
445 0 : AtlasViewGame* AtlasView::GetView_Game()
446 : {
447 0 : if (! view_Game)
448 0 : view_Game = new AtlasViewGame();
449 0 : return view_Game;
450 : }
451 :
452 0 : AtlasViewActor* AtlasView::GetView_Actor()
453 : {
454 0 : if (! view_Actor)
455 0 : view_Actor = new AtlasViewActor();
456 0 : return view_Actor;
457 : }
458 :
459 0 : void AtlasView::DestroyViews()
460 : {
461 0 : delete view_None; view_None = NULL;
462 0 : delete view_Game; view_Game = NULL;
463 0 : delete view_Actor; view_Actor = NULL;
464 0 : }
|