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"
20 #include "MessageHandler.h"
21 #include "../GameLoop.h"
22 #include "../CommandProc.h"
23 #include "../ActorViewer.h"
25 #include "../InputProcessor.h"
27 #include "graphics/GameView.h"
28 #include "graphics/ObjectManager.h"
29 #include "gui/GUIManager.h"
30 #include "lib/external_libraries/libsdl.h"
31 #include "lib/timer.h"
32 #include "maths/MathUtil.h"
33 #include "ps/CConsole.h"
34 #include "ps/CLogger.h"
35 #include "ps/Filesystem.h"
36 #include "ps/Profile.h"
37 #include "ps/Profiler2.h"
39 #include "ps/VideoMode.h"
40 #include "ps/GameSetup/Config.h"
41 #include "ps/GameSetup/GameSetup.h"
42 #include "renderer/backend/IDevice.h"
43 #include "renderer/Renderer.h"
44 #include "renderer/SceneRenderer.h"
47 // We don't include wutil header directly to prevent including Windows headers.
48 extern void wutil_SetAppWindow(void* hwnd
);
51 namespace AtlasMessage
54 InputProcessor g_Input
;
56 // This keeps track of the last in-game user input.
57 // It is used to throttle FPS to save CPU & GPU.
58 double last_user_activity
;
60 // see comment in GameLoop.cpp about ah_display_error before using INIT_HAVE_DISPLAY_ERROR
61 const int g_InitFlags
= INIT_HAVE_VMODE
| INIT_NO_GUI
;
69 // Mount mods if there are any specified as command line parameters
70 if (!Init(g_AtlasGameLoop
->args
, g_InitFlags
| INIT_MODS
| INIT_MODS_PUBLIC
))
72 // There are no mods specified on the command line,
73 // but there are in the config file, so mount those.
74 Shutdown(SHUTDOWN_FROM_CONFIG
);
75 ENSURE(Init(g_AtlasGameLoop
->args
, g_InitFlags
));
78 // Initialise some graphics state for Atlas.
79 // (This must be done after Init loads the config DB,
80 // but before the UI constructs its GL canvases.)
81 g_VideoMode
.InitNonSDL();
84 MESSAGEHANDLER(InitAppWindow
)
87 wutil_SetAppWindow(msg
->handle
);
93 MESSAGEHANDLER(InitSDL
)
97 // When using GLX (Linux), SDL has to load the GL library to find
98 // glXGetProcAddressARB before it can load any extensions.
99 // When running in Atlas, we skip the SDL video initialisation code
100 // which loads the library, and so SDL_GL_GetProcAddress fails (in
101 // ogl.cpp importExtensionFunctions).
102 // So, make sure it's loaded:
103 SDL_InitSubSystem(SDL_INIT_VIDEO
);
104 // wxWidgets doesn't use a proper approach to dynamically load functions and
105 // doesn't provide GetProcAddr-like function. Technically we need to call
106 // SDL_GL_LoadLibrary inside GL device creation, but that might lead to a
107 // crash on Windows because of a wrong order of initialization between SDL
108 // and wxWidgets context management. So leave the call as is while it works.
110 // http://trac.wxwidgets.org/ticket/9213
111 // http://trac.wxwidgets.org/ticket/9215
112 if (SDL_GL_LoadLibrary(nullptr) && g_Logger
)
113 LOGERROR("SDL failed to load GL library: '%s'", SDL_GetError());
116 MESSAGEHANDLER(InitGraphics
)
120 g_VideoMode
.CreateBackendDevice(false);
122 g_VideoMode
.GetBackendDevice()->OnWindowResize(g_xres
, g_yres
);
124 InitGraphics(g_AtlasGameLoop
->args
, g_InitFlags
, {});
128 MESSAGEHANDLER(Shutdown
)
132 // Empty the CommandProc, to get rid of its references to entities before
133 // we kill the EntityManager
134 GetCommandProc().Destroy();
136 AtlasView::DestroyViews();
137 g_AtlasGameLoop
->view
= AtlasView::GetView_None();
147 g_AtlasGameLoop
->running
= false;
151 MESSAGEHANDLER(RenderEnable
)
153 g_AtlasGameLoop
->view
->SetEnabled(false);
154 g_AtlasGameLoop
->view
= AtlasView::GetView(msg
->view
);
155 g_AtlasGameLoop
->view
->SetEnabled(true);
158 MESSAGEHANDLER(SetViewParamB
)
160 AtlasView
* view
= AtlasView::GetView(msg
->view
);
161 view
->SetParam(*msg
->name
, msg
->value
);
164 MESSAGEHANDLER(SetViewParamI
)
166 AtlasView
* view
= AtlasView::GetView(msg
->view
);
167 view
->SetParam(*msg
->name
, msg
->value
);
170 MESSAGEHANDLER(SetViewParamC
)
172 AtlasView
* view
= AtlasView::GetView(msg
->view
);
173 view
->SetParam(*msg
->name
, msg
->value
);
176 MESSAGEHANDLER(SetViewParamS
)
178 AtlasView
* view
= AtlasView::GetView(msg
->view
);
179 view
->SetParam(*msg
->name
, *msg
->value
);
182 MESSAGEHANDLER(SetActorViewer
)
186 // TODO EXTREME DANGER: this'll break horribly if any units remain
187 // in existence and use their actors after we've deleted all the actors.
188 // (The actor viewer currently only has one unit at a time, so it's
190 // Should replace this with proper actor hot-loading system, or something.
192 AtlasView::GetView_Actor()->GetActorViewer().SetActor(L
"", "", -1);
193 AtlasView::GetView_Actor()->GetActorViewer().UnloadObjects();
194 // vfs_reload_changed_files();
196 AtlasView::GetView_Actor()->SetSpeedMultiplier(msg
->speed
);
197 AtlasView::GetView_Actor()->GetActorViewer().SetActor(*msg
->id
, *msg
->animation
, msg
->playerID
);
200 //////////////////////////////////////////////////////////////////////////
202 MESSAGEHANDLER(SetCanvas
)
204 // Need to set the canvas size before possibly doing any rendering,
205 // else we'll get GL errors when trying to render to 0x0
206 CVideoMode::UpdateRenderer(msg
->width
, msg
->height
);
208 g_AtlasGameLoop
->glCanvas
= msg
->canvas
;
209 Atlas_GLSetCurrent(const_cast<void*>(g_AtlasGameLoop
->glCanvas
));
213 MESSAGEHANDLER(ResizeScreen
)
215 CVideoMode::UpdateRenderer(msg
->width
, msg
->height
);
218 // OS X seems to require this to update the GL canvas
219 Atlas_GLSetCurrent(const_cast<void*>(g_AtlasGameLoop
->glCanvas
));
223 QUERYHANDLER(RenderLoop
)
226 const double time
= timer_Time();
227 static double last_time
= time
;
228 const double realFrameLength
= time
-last_time
;
230 ENSURE(realFrameLength
>= 0.0);
231 // TODO: filter out big jumps, e.g. when having done a lot of slow
232 // processing in the last frame
233 g_AtlasGameLoop
->realFrameLength
= realFrameLength
;
236 if (g_Input
.ProcessInput(g_AtlasGameLoop
))
237 last_user_activity
= timer_Time();
239 msg
->timeSinceActivity
= timer_Time() - last_user_activity
;
241 ReloadChangedFiles();
243 RendererIncrementalLoad();
245 // Pump SDL events (e.g. hotkeys)
247 while (in_poll_priority_event(&ev
))
248 in_dispatch_event(&ev
);
251 g_GUI
->TickObjects();
253 g_AtlasGameLoop
->view
->Update(g_AtlasGameLoop
->realFrameLength
);
255 g_AtlasGameLoop
->view
->Render();
257 if (CProfileManager::IsInitialised())
260 msg
->wantHighFPS
= g_AtlasGameLoop
->view
->WantsHighFramerate();
263 //////////////////////////////////////////////////////////////////////////
265 MESSAGEHANDLER(RenderStyle
)
267 g_Renderer
.GetSceneRenderer().SetTerrainRenderMode(msg
->wireframe
? EDGED_FACES
: SOLID
);
268 g_Renderer
.GetSceneRenderer().SetWaterRenderMode(msg
->wireframe
? EDGED_FACES
: SOLID
);
269 g_Renderer
.GetSceneRenderer().SetModelRenderMode(msg
->wireframe
? EDGED_FACES
: SOLID
);
270 g_Renderer
.GetSceneRenderer().SetOverlayRenderMode(msg
->wireframe
? EDGED_FACES
: SOLID
);
273 } // namespace AtlasMessage