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 "MessageHandler.h"
21 : #include "../GameLoop.h"
22 : #include "../CommandProc.h"
23 : #include "../ActorViewer.h"
24 : #include "../View.h"
25 : #include "../InputProcessor.h"
26 :
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"
38 : #include "ps/Game.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"
45 :
46 : #if OS_WIN
47 : // We don't include wutil header directly to prevent including Windows headers.
48 : extern void wutil_SetAppWindow(void* hwnd);
49 : #endif
50 :
51 : namespace AtlasMessage
52 : {
53 :
54 : InputProcessor g_Input;
55 :
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;
59 :
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;
62 :
63 0 : MESSAGEHANDLER(Init)
64 : {
65 : UNUSED2(msg);
66 :
67 0 : g_Quickstart = true;
68 :
69 : // Mount mods if there are any specified as command line parameters
70 0 : if (!Init(g_AtlasGameLoop->args, g_InitFlags | INIT_MODS| INIT_MODS_PUBLIC))
71 : {
72 : // There are no mods specified on the command line,
73 : // but there are in the config file, so mount those.
74 0 : Shutdown(SHUTDOWN_FROM_CONFIG);
75 0 : ENSURE(Init(g_AtlasGameLoop->args, g_InitFlags));
76 : }
77 :
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 0 : g_VideoMode.InitNonSDL();
82 0 : }
83 :
84 0 : MESSAGEHANDLER(InitAppWindow)
85 : {
86 : #if OS_WIN
87 : wutil_SetAppWindow(msg->handle);
88 : #else
89 : UNUSED2(msg);
90 : #endif
91 0 : }
92 :
93 0 : MESSAGEHANDLER(InitSDL)
94 : {
95 : UNUSED2(msg);
96 :
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 0 : 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.
109 : // Refs:
110 : // http://trac.wxwidgets.org/ticket/9213
111 : // http://trac.wxwidgets.org/ticket/9215
112 0 : if (SDL_GL_LoadLibrary(nullptr) && g_Logger)
113 0 : LOGERROR("SDL failed to load GL library: '%s'", SDL_GetError());
114 0 : }
115 :
116 0 : MESSAGEHANDLER(InitGraphics)
117 : {
118 : UNUSED2(msg);
119 :
120 0 : g_VideoMode.CreateBackendDevice(false);
121 :
122 0 : g_VideoMode.GetBackendDevice()->OnWindowResize(g_xres, g_yres);
123 :
124 0 : InitGraphics(g_AtlasGameLoop->args, g_InitFlags, {});
125 0 : }
126 :
127 :
128 0 : MESSAGEHANDLER(Shutdown)
129 : {
130 : UNUSED2(msg);
131 :
132 : // Empty the CommandProc, to get rid of its references to entities before
133 : // we kill the EntityManager
134 0 : GetCommandProc().Destroy();
135 :
136 0 : AtlasView::DestroyViews();
137 0 : g_AtlasGameLoop->view = AtlasView::GetView_None();
138 :
139 0 : int flags = 0;
140 0 : Shutdown(flags);
141 0 : }
142 :
143 :
144 0 : QUERYHANDLER(Exit)
145 : {
146 : UNUSED2(msg);
147 0 : g_AtlasGameLoop->running = false;
148 0 : }
149 :
150 :
151 0 : MESSAGEHANDLER(RenderEnable)
152 : {
153 0 : g_AtlasGameLoop->view->SetEnabled(false);
154 0 : g_AtlasGameLoop->view = AtlasView::GetView(msg->view);
155 0 : g_AtlasGameLoop->view->SetEnabled(true);
156 0 : }
157 :
158 0 : MESSAGEHANDLER(SetViewParamB)
159 : {
160 0 : AtlasView* view = AtlasView::GetView(msg->view);
161 0 : view->SetParam(*msg->name, msg->value);
162 0 : }
163 :
164 0 : MESSAGEHANDLER(SetViewParamI)
165 : {
166 0 : AtlasView* view = AtlasView::GetView(msg->view);
167 0 : view->SetParam(*msg->name, msg->value);
168 0 : }
169 :
170 0 : MESSAGEHANDLER(SetViewParamC)
171 : {
172 0 : AtlasView* view = AtlasView::GetView(msg->view);
173 0 : view->SetParam(*msg->name, msg->value);
174 0 : }
175 :
176 0 : MESSAGEHANDLER(SetViewParamS)
177 : {
178 0 : AtlasView* view = AtlasView::GetView(msg->view);
179 0 : view->SetParam(*msg->name, *msg->value);
180 0 : }
181 :
182 0 : MESSAGEHANDLER(SetActorViewer)
183 : {
184 0 : if (msg->flushcache)
185 : {
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
189 : // alright.)
190 : // Should replace this with proper actor hot-loading system, or something.
191 :
192 0 : AtlasView::GetView_Actor()->GetActorViewer().SetActor(L"", "", -1);
193 0 : AtlasView::GetView_Actor()->GetActorViewer().UnloadObjects();
194 : // vfs_reload_changed_files();
195 : }
196 0 : AtlasView::GetView_Actor()->SetSpeedMultiplier(msg->speed);
197 0 : AtlasView::GetView_Actor()->GetActorViewer().SetActor(*msg->id, *msg->animation, msg->playerID);
198 0 : }
199 :
200 : //////////////////////////////////////////////////////////////////////////
201 :
202 0 : MESSAGEHANDLER(SetCanvas)
203 : {
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 0 : CVideoMode::UpdateRenderer(msg->width, msg->height);
207 :
208 0 : g_AtlasGameLoop->glCanvas = msg->canvas;
209 0 : Atlas_GLSetCurrent(const_cast<void*>(g_AtlasGameLoop->glCanvas));
210 0 : }
211 :
212 :
213 0 : MESSAGEHANDLER(ResizeScreen)
214 : {
215 0 : CVideoMode::UpdateRenderer(msg->width, msg->height);
216 :
217 : #if OS_MACOSX
218 : // OS X seems to require this to update the GL canvas
219 : Atlas_GLSetCurrent(const_cast<void*>(g_AtlasGameLoop->glCanvas));
220 : #endif
221 0 : }
222 :
223 0 : QUERYHANDLER(RenderLoop)
224 : {
225 : {
226 0 : const double time = timer_Time();
227 0 : static double last_time = time;
228 0 : const double realFrameLength = time-last_time;
229 0 : last_time = time;
230 0 : 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 0 : g_AtlasGameLoop->realFrameLength = realFrameLength;
234 : }
235 :
236 0 : if (g_Input.ProcessInput(g_AtlasGameLoop))
237 0 : last_user_activity = timer_Time();
238 :
239 0 : msg->timeSinceActivity = timer_Time() - last_user_activity;
240 :
241 0 : ReloadChangedFiles();
242 :
243 0 : RendererIncrementalLoad();
244 :
245 : // Pump SDL events (e.g. hotkeys)
246 : SDL_Event_ ev;
247 0 : while (in_poll_priority_event(&ev))
248 0 : in_dispatch_event(&ev);
249 :
250 0 : if (g_GUI)
251 0 : g_GUI->TickObjects();
252 :
253 0 : g_AtlasGameLoop->view->Update(g_AtlasGameLoop->realFrameLength);
254 :
255 0 : g_AtlasGameLoop->view->Render();
256 :
257 0 : if (CProfileManager::IsInitialised())
258 0 : g_Profiler.Frame();
259 :
260 0 : msg->wantHighFPS = g_AtlasGameLoop->view->WantsHighFramerate();
261 0 : }
262 :
263 : //////////////////////////////////////////////////////////////////////////
264 :
265 0 : MESSAGEHANDLER(RenderStyle)
266 : {
267 0 : g_Renderer.GetSceneRenderer().SetTerrainRenderMode(msg->wireframe ? EDGED_FACES : SOLID);
268 0 : g_Renderer.GetSceneRenderer().SetWaterRenderMode(msg->wireframe ? EDGED_FACES : SOLID);
269 0 : g_Renderer.GetSceneRenderer().SetModelRenderMode(msg->wireframe ? EDGED_FACES : SOLID);
270 0 : g_Renderer.GetSceneRenderer().SetOverlayRenderMode(msg->wireframe ? EDGED_FACES : SOLID);
271 0 : }
272 :
273 : } // namespace AtlasMessage
|