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 "GameView.h"
21 :
22 : #include "graphics/CameraController.h"
23 : #include "graphics/CinemaManager.h"
24 : #include "graphics/ColladaManager.h"
25 : #include "graphics/HFTracer.h"
26 : #include "graphics/LOSTexture.h"
27 : #include "graphics/LightEnv.h"
28 : #include "graphics/MiniMapTexture.h"
29 : #include "graphics/Model.h"
30 : #include "graphics/ObjectManager.h"
31 : #include "graphics/Patch.h"
32 : #include "graphics/SkeletonAnimManager.h"
33 : #include "graphics/SmoothedValue.h"
34 : #include "graphics/Terrain.h"
35 : #include "graphics/TerrainTextureManager.h"
36 : #include "graphics/TerritoryTexture.h"
37 : #include "graphics/Unit.h"
38 : #include "graphics/UnitManager.h"
39 : #include "lib/input.h"
40 : #include "lib/timer.h"
41 : #include "lobby/IXmppClient.h"
42 : #include "maths/BoundingBoxAligned.h"
43 : #include "maths/MathUtil.h"
44 : #include "maths/Matrix3D.h"
45 : #include "maths/Quaternion.h"
46 : #include "ps/ConfigDB.h"
47 : #include "ps/Filesystem.h"
48 : #include "ps/Game.h"
49 : #include "ps/Globals.h"
50 : #include "ps/Hotkey.h"
51 : #include "ps/Loader.h"
52 : #include "ps/LoaderThunks.h"
53 : #include "ps/Profile.h"
54 : #include "ps/Pyrogenesis.h"
55 : #include "ps/TouchInput.h"
56 : #include "ps/World.h"
57 : #include "renderer/Renderer.h"
58 : #include "renderer/SceneRenderer.h"
59 : #include "renderer/WaterManager.h"
60 : #include "simulation2/Simulation2.h"
61 : #include "simulation2/components/ICmpPosition.h"
62 : #include "simulation2/components/ICmpRangeManager.h"
63 :
64 : #include <memory>
65 :
66 0 : class CGameViewImpl
67 : {
68 : NONCOPYABLE(CGameViewImpl);
69 : public:
70 0 : CGameViewImpl(CGame* game)
71 0 : : Game(game),
72 : ColladaManager(g_VFS), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
73 0 : ObjectManager(MeshManager, SkeletonAnimManager, *game->GetSimulation2()),
74 0 : LOSTexture(*game->GetSimulation2()),
75 0 : TerritoryTexture(*game->GetSimulation2()),
76 0 : MiniMapTexture(*game->GetSimulation2()),
77 : ViewCamera(),
78 : CullCamera(),
79 : LockCullCamera(false),
80 : Culling(true),
81 0 : CameraController(new CCameraController(ViewCamera))
82 : {
83 0 : }
84 :
85 : CGame* Game;
86 : CColladaManager ColladaManager;
87 : CMeshManager MeshManager;
88 : CSkeletonAnimManager SkeletonAnimManager;
89 : CObjectManager ObjectManager;
90 : CLOSTexture LOSTexture;
91 : CTerritoryTexture TerritoryTexture;
92 : CMiniMapTexture MiniMapTexture;
93 :
94 : /**
95 : * this camera controls the eye position when rendering
96 : */
97 : CCamera ViewCamera;
98 :
99 : /**
100 : * this camera controls the frustum that is used for culling
101 : * and shadow calculations
102 : *
103 : * Note that all code that works with camera movements should only change
104 : * m_ViewCamera. The render functions automatically sync the cull camera to
105 : * the view camera depending on the value of m_LockCullCamera.
106 : */
107 : CCamera CullCamera;
108 :
109 : /**
110 : * When @c true, the cull camera is locked in place.
111 : * When @c false, the cull camera follows the view camera.
112 : *
113 : * Exposed to JS as gameView.lockCullCamera
114 : */
115 : bool LockCullCamera;
116 :
117 : /**
118 : * When @c true, culling is enabled so that only models that have a chance of
119 : * being visible are sent to the renderer.
120 : * Otherwise, the entire world is sent to the renderer.
121 : *
122 : * Exposed to JS as gameView.culling
123 : */
124 : bool Culling;
125 :
126 : CCinemaManager CinemaManager;
127 :
128 : /**
129 : * Controller of the view's camera. We use a std::unique_ptr for an easy
130 : * on the fly replacement. It's guaranteed that the pointer is never nulllptr.
131 : */
132 : std::unique_ptr<ICameraController> CameraController;
133 : };
134 :
135 : #define IMPLEMENT_BOOLEAN_SETTING(NAME) \
136 : bool CGameView::Get##NAME##Enabled() const \
137 : { \
138 : return m->NAME; \
139 : } \
140 : \
141 : void CGameView::Set##NAME##Enabled(bool Enabled) \
142 : { \
143 : m->NAME = Enabled; \
144 : }
145 :
146 0 : IMPLEMENT_BOOLEAN_SETTING(Culling);
147 0 : IMPLEMENT_BOOLEAN_SETTING(LockCullCamera);
148 :
149 0 : bool CGameView::GetConstrainCameraEnabled() const
150 : {
151 0 : return m->CameraController->GetConstrainCamera();
152 : }
153 :
154 0 : void CGameView::SetConstrainCameraEnabled(bool enabled)
155 : {
156 0 : m->CameraController->SetConstrainCamera(enabled);
157 0 : }
158 :
159 : #undef IMPLEMENT_BOOLEAN_SETTING
160 :
161 0 : CGameView::CGameView(CGame *pGame):
162 0 : m(new CGameViewImpl(pGame))
163 : {
164 0 : m->CullCamera = m->ViewCamera;
165 0 : g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera);
166 0 : }
167 :
168 0 : CGameView::~CGameView()
169 : {
170 0 : UnloadResources();
171 :
172 0 : delete m;
173 0 : }
174 :
175 0 : void CGameView::SetViewport(const SViewPort& vp)
176 : {
177 0 : m->CameraController->SetViewport(vp);
178 0 : }
179 :
180 0 : CObjectManager& CGameView::GetObjectManager()
181 : {
182 0 : return m->ObjectManager;
183 : }
184 :
185 0 : CCamera* CGameView::GetCamera()
186 : {
187 0 : return &m->ViewCamera;
188 : }
189 :
190 0 : CCinemaManager* CGameView::GetCinema()
191 : {
192 0 : return &m->CinemaManager;
193 : }
194 :
195 0 : CLOSTexture& CGameView::GetLOSTexture()
196 : {
197 0 : return m->LOSTexture;
198 : }
199 :
200 0 : CTerritoryTexture& CGameView::GetTerritoryTexture()
201 : {
202 0 : return m->TerritoryTexture;
203 : }
204 :
205 0 : CMiniMapTexture& CGameView::GetMiniMapTexture()
206 : {
207 0 : return m->MiniMapTexture;
208 : }
209 :
210 0 : int CGameView::Initialize()
211 : {
212 0 : m->CameraController->LoadConfig();
213 0 : return 0;
214 : }
215 :
216 0 : void CGameView::RegisterInit()
217 : {
218 : // CGameView init
219 0 : RegMemFun(this, &CGameView::Initialize, L"CGameView init", 1);
220 :
221 0 : RegMemFun(g_TexMan.GetSingletonPtr(), &CTerrainTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 60);
222 0 : }
223 :
224 0 : void CGameView::BeginFrame()
225 : {
226 0 : if (m->LockCullCamera == false)
227 : {
228 : // Set up cull camera
229 0 : m->CullCamera = m->ViewCamera;
230 : }
231 0 : g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera);
232 :
233 0 : m->Game->CachePlayerColors();
234 0 : }
235 :
236 0 : void CGameView::Prepare(
237 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
238 : {
239 0 : g_Renderer.GetSceneRenderer().PrepareScene(deviceCommandContext, *this);
240 0 : }
241 :
242 0 : void CGameView::Render(
243 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
244 : {
245 0 : g_Renderer.GetSceneRenderer().RenderScene(deviceCommandContext);
246 0 : }
247 :
248 0 : void CGameView::RenderOverlays(
249 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
250 : {
251 0 : g_Renderer.GetSceneRenderer().RenderSceneOverlays(deviceCommandContext);
252 0 : }
253 :
254 : ///////////////////////////////////////////////////////////
255 : // This callback is part of the Scene interface
256 : // Submit all objects visible in the given frustum
257 0 : void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
258 : {
259 : {
260 0 : PROFILE3("submit terrain");
261 :
262 0 : CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
263 0 : float waterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight + 0.001f;
264 0 : const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide();
265 :
266 : // find out which patches will be drawn
267 0 : for (ssize_t j=0; j<patchesPerSide; ++j)
268 : {
269 0 : for (ssize_t i=0; i<patchesPerSide; ++i)
270 : {
271 0 : CPatch* patch=pTerrain->GetPatch(i,j); // can't fail
272 :
273 : // If the patch is underwater, calculate a bounding box that also contains the water plane
274 0 : CBoundingBoxAligned bounds = patch->GetWorldBounds();
275 0 : if(bounds[1].Y < waterHeight)
276 0 : bounds[1].Y = waterHeight;
277 :
278 0 : if (!m->Culling || frustum.IsBoxVisible(bounds))
279 0 : c->Submit(patch);
280 : }
281 : }
282 : }
283 :
284 0 : m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
285 0 : }
286 :
287 0 : void CGameView::UnloadResources()
288 : {
289 0 : g_TexMan.UnloadTerrainTextures();
290 0 : g_Renderer.GetSceneRenderer().GetWaterManager().UnloadWaterTextures();
291 0 : }
292 :
293 0 : void CGameView::Update(const float deltaRealTime)
294 : {
295 0 : m->MiniMapTexture.Update(deltaRealTime);
296 :
297 : // If camera movement is being handled by the touch-input system,
298 : // then we should stop to avoid conflicting with it
299 0 : if (g_TouchInput.IsEnabled())
300 0 : return;
301 :
302 0 : if (!g_app_has_focus)
303 0 : return;
304 :
305 0 : m->CinemaManager.Update(deltaRealTime);
306 0 : if (m->CinemaManager.IsEnabled())
307 0 : return;
308 :
309 0 : m->CameraController->Update(deltaRealTime);
310 : }
311 :
312 0 : CVector3D CGameView::GetCameraPivot() const
313 : {
314 0 : return m->CameraController->GetCameraPivot();
315 : }
316 :
317 0 : CVector3D CGameView::GetCameraPosition() const
318 : {
319 0 : return m->CameraController->GetCameraPosition();
320 : }
321 :
322 0 : CVector3D CGameView::GetCameraRotation() const
323 : {
324 0 : return m->CameraController->GetCameraRotation();
325 : }
326 :
327 0 : float CGameView::GetCameraZoom() const
328 : {
329 0 : return m->CameraController->GetCameraZoom();
330 : }
331 :
332 0 : void CGameView::SetCamera(const CVector3D& pos, float rotX, float rotY, float zoom)
333 : {
334 0 : m->CameraController->SetCamera(pos, rotX, rotY, zoom);
335 0 : }
336 :
337 0 : void CGameView::MoveCameraTarget(const CVector3D& target)
338 : {
339 0 : m->CameraController->MoveCameraTarget(target);
340 0 : }
341 :
342 0 : void CGameView::ResetCameraTarget(const CVector3D& target)
343 : {
344 0 : m->CameraController->ResetCameraTarget(target);
345 0 : }
346 :
347 0 : void CGameView::FollowEntity(entity_id_t entity, bool firstPerson)
348 : {
349 0 : m->CameraController->FollowEntity(entity, firstPerson);
350 0 : }
351 :
352 0 : entity_id_t CGameView::GetFollowedEntity()
353 : {
354 0 : return m->CameraController->GetFollowedEntity();
355 : }
356 :
357 7 : InReaction game_view_handler(const SDL_Event_* ev)
358 : {
359 : // put any events that must be processed even if inactive here
360 7 : if (!g_app_has_focus || !g_Game || !g_Game->IsGameStarted() || g_Game->GetView()->GetCinema()->IsEnabled())
361 7 : return IN_PASS;
362 :
363 0 : CGameView *pView=g_Game->GetView();
364 :
365 0 : return pView->HandleEvent(ev);
366 : }
367 :
368 0 : InReaction CGameView::HandleEvent(const SDL_Event_* ev)
369 : {
370 0 : switch(ev->ev.type)
371 : {
372 0 : case SDL_HOTKEYPRESS:
373 : {
374 0 : std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
375 0 : CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
376 0 : if (hotkey == "wireframe")
377 : {
378 0 : if (g_XmppClient && g_rankedGame == true)
379 : break;
380 0 : else if (sceneRenderer.GetModelRenderMode() == SOLID)
381 : {
382 0 : sceneRenderer.SetTerrainRenderMode(EDGED_FACES);
383 0 : sceneRenderer.SetWaterRenderMode(EDGED_FACES);
384 0 : sceneRenderer.SetModelRenderMode(EDGED_FACES);
385 0 : sceneRenderer.SetOverlayRenderMode(EDGED_FACES);
386 : }
387 0 : else if (sceneRenderer.GetModelRenderMode() == EDGED_FACES)
388 : {
389 0 : sceneRenderer.SetTerrainRenderMode(WIREFRAME);
390 0 : sceneRenderer.SetWaterRenderMode(WIREFRAME);
391 0 : sceneRenderer.SetModelRenderMode(WIREFRAME);
392 0 : sceneRenderer.SetOverlayRenderMode(WIREFRAME);
393 : }
394 : else
395 : {
396 0 : sceneRenderer.SetTerrainRenderMode(SOLID);
397 0 : sceneRenderer.SetWaterRenderMode(SOLID);
398 0 : sceneRenderer.SetModelRenderMode(SOLID);
399 0 : sceneRenderer.SetOverlayRenderMode(SOLID);
400 : }
401 0 : return IN_HANDLED;
402 0 : }
403 : }
404 : }
405 :
406 0 : return m->CameraController->HandleEvent(ev);
407 3 : }
|