1 /***************************************************************************
2 * Copyright (C) 2005-2019 by the FIFE team *
3 * http://www.fifengine.net *
4 * This file is part of FIFE. *
5 * *
6 * FIFE is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU Lesser General Public *
8 * License as published by the Free Software Foundation; either *
9 * version 2.1 of the License, or (at your option) any later version. *
10 * *
11 * This library is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * Lesser General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with this library; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20 ***************************************************************************/
21
22 // Standard C++ library includes
23 #include <iostream>
24 #include <algorithm>
25
26 // 3rd party library includes
27 #include <SDL.h>
28 #include <SDL_ttf.h>
29
30 // FIFE includes
31 // These includes are split up in two parts, separated by one empty line
32 // First block: files included from the FIFE root src directory
33 // Second block: files included from the same folder
34 #include "util/base/exception.h"
35 #include "util/log/logger.h"
36 #include "util/time/timemanager.h"
37 #include "audio/soundmanager.h"
38 #include "gui/guimanager.h"
39 #include "vfs/vfs.h"
40 #include "vfs/vfsdirectory.h"
41 #include "vfs/directoryprovider.h"
42 #include "vfs/zip/zipprovider.h"
43 #include "eventchannel/eventmanager.h"
44 #include "video/imagemanager.h"
45 #include "video/animationmanager.h"
46 #include "audio/soundclipmanager.h"
47 #include "video/renderbackend.h"
48 #include "video/cursor.h"
49 #include "video/devicecaps.h"
50 #ifdef HAVE_OPENGL
51 #include "video/opengl/fife_opengl.h"
52 #include "video/opengl/renderbackendopengl.h"
53 #endif
54 #include "video/sdl/renderbackendsdl.h"
55 #include "loaders/native/video/imageloader.h"
56 #include "loaders/native/audio/ogg_loader.h"
57 #include "model/model.h"
58 #include "pathfinder/routepather/routepather.h"
59 #include "model/metamodel/grids/hexgrid.h"
60 #include "model/metamodel/grids/squaregrid.h"
61 #include "view/renderers/quadtreerenderer.h"
62 #include "view/renderers/gridrenderer.h"
63 #include "view/renderers/instancerenderer.h"
64 #include "view/renderers/coordinaterenderer.h"
65 #include "view/renderers/floatingtextrenderer.h"
66 #include "view/renderers/cellselectionrenderer.h"
67 #include "view/renderers/blockinginforenderer.h"
68 #include "view/renderers/genericrenderer.h"
69 #include "view/renderers/targetrenderer.h"
70 #include "view/renderers/lightrenderer.h"
71 #include "view/renderers/offrenderer.h"
72 #include "view/renderers/cellrenderer.h"
73 #include "video/image.h"
74 #include "engine.h"
75 #include "version.h"
76
77 #ifdef USE_COCOA
78
79 #include <objc/message.h>
80 #include <dlfcn.h>
81
main(int32_t argc,char ** argv)82 int32_t main(int32_t argc, char **argv)
83 {
84 return 0;
85 }
86 #endif
87
88 namespace FIFE {
89 static Logger _log(LM_CONTROLLER);
90
Engine()91 Engine::Engine():
92 m_renderbackend(0),
93 m_guimanager(0),
94 m_eventmanager(0),
95 m_soundmanager(0),
96 m_timemanager(0),
97 m_imagemanager(0),
98 m_animationmanager(0),
99 m_soundclipmanager(0),
100 m_vfs(0),
101 m_model(0),
102 m_logmanager(0),
103 m_cursor(0),
104 m_destroyed(false),
105 m_settings(),
106 m_devcaps(),
107 m_offrenderer(0),
108 m_targetrenderer(0),
109 m_changelisteners() {
110 #ifdef USE_COCOA
111 // The next lines ensure that Cocoa is initialzed correctly.
112 // This is needed for SDL to function properly on MAC OS X.
113 void* cocoa_lib;
114 cocoa_lib = dlopen( "/System/Library/Frameworks/Cocoa.framework/Cocoa", RTLD_LAZY );
115 void (*nsappload)(void);
116 nsappload = (void(*)()) dlsym( cocoa_lib, "NSApplicationLoad");
117 nsappload();
118
119 // Create an autorelease pool, so autoreleased SDL objects don't leak.
120 #ifdef OSX_109
121 Class NSAutoreleasePool = objc_getClass("NSAutoreleasePool");
122 m_autoreleasePool = class_createInstance(NSAutoreleasePool, 0);
123 #else
124 objc_object *NSAutoreleasePool = objc_getClass("NSAutoreleasePool");
125 m_autoreleasePool =
126 objc_msgSend(NSAutoreleasePool, sel_registerName("new"));
127 #endif
128 #endif
129 m_logmanager = LogManager::instance();
130 }
131
getSettings()132 EngineSettings& Engine::getSettings() {
133 return m_settings;
134 }
135
getDeviceCaps() const136 const DeviceCaps& Engine::getDeviceCaps() const {
137 return m_devcaps;
138 }
139
changeScreenMode(const ScreenMode & mode)140 void Engine::changeScreenMode(const ScreenMode& mode){
141 m_cursor->invalidate();
142
143 m_imagemanager->invalidateAll();
144
145 // recreate main screen
146 m_renderbackend->createMainScreen(mode, m_settings.getWindowTitle(), m_settings.getWindowIcon());
147
148 if (m_guimanager) {
149 m_guimanager->resizeTopContainer(0,0,mode.getWidth(), mode.getHeight());
150 }
151
152 std::vector<IEngineChangeListener*>::iterator i = m_changelisteners.begin();
153 while (i != m_changelisteners.end()) {
154 (*i)->onScreenModeChanged(mode);
155 ++i;
156 }
157 }
158
init()159 void Engine::init() {
160 m_destroyed = false;
161
162 FL_LOG(_log, LMsg("Fifengine v") << FIFE::getVersion());
163 FL_LOG(_log, "================== Engine initialize start =================");
164 m_timemanager = new TimeManager();
165 FL_LOG(_log, "Time manager created");
166
167 FL_LOG(_log, "Creating VFS");
168 m_vfs = new VFS();
169
170 FL_LOG(_log, "Adding root directory to VFS");
171 m_vfs->addSource( new VFSDirectory(m_vfs) );
172 m_vfs->addProvider( new DirectoryProvider() );
173
174 FL_LOG(_log, "Adding zip provider to VFS");
175 m_vfs->addProvider( new ZipProvider() );
176
177 //m_vfs->addProvider(ProviderDAT2());
178 //m_vfs->addProvider(ProviderDAT1());
179 FL_LOG(_log, "Engine pre-init done");
180
181 // If failed to init SDL throw exception.
182 if (SDL_Init(SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER) < 0) {
183 throw SDLException(SDL_GetError());
184 }
185
186 TTF_Init();
187
188 FL_LOG(_log, "Creating event manager");
189 m_eventmanager = new EventManager();
190 m_eventmanager->setMouseSensitivity(m_settings.getMouseSensitivity());
191 m_eventmanager->setMouseAccelerationEnabled(m_settings.isMouseAccelerationEnabled());
192 m_eventmanager->setJoystickSupport(m_settings.isJoystickSupport());
193
194 FL_LOG(_log, "Creating resource managers");
195
196 m_imagemanager = new ImageManager();
197 m_animationmanager = new AnimationManager();
198 m_soundclipmanager = new SoundClipManager();
199
200 FL_LOG(_log, "Creating render backend");
201 std::string rbackend(m_settings.getRenderBackend());
202 if (rbackend == "SDL") {
203 m_renderbackend = new RenderBackendSDL(m_settings.getColorKey());
204 FL_LOG(_log, "SDL Render backend created");
205 } else {
206 #ifdef HAVE_OPENGL
207 m_renderbackend = new RenderBackendOpenGL(m_settings.getColorKey());
208 FL_LOG(_log, "OpenGL Render backend created");
209 #else
210 m_renderbackend = new RenderBackendSDL(m_settings.getColorKey());
211 // Remember the choice so we pick the right graphics class.
212 rbackend = "SDL";
213 FL_WARN(_log, "Tried to select OpenGL, even though it is not compiled into the engine. Falling back to SDL Render backend");
214 #endif
215 }
216 FL_LOG(_log, "Initializing render backend");
217 m_renderbackend->setColorKeyEnabled(m_settings.isColorKeyEnabled());
218 // we always set this to false
219 //m_renderbackend->setAlphaOptimizerEnabled(false);
220 m_renderbackend->setImageCompressingEnabled(m_settings.isGLCompressImages());
221 m_renderbackend->setFramebufferEnabled(m_settings.isGLUseFramebuffer());
222 m_renderbackend->setNPOTEnabled(m_settings.isGLUseNPOT());
223 m_renderbackend->setTextureFiltering(m_settings.getGLTextureFiltering());
224 m_renderbackend->setMipmappingEnabled(m_settings.isGLUseMipmapping());
225 m_renderbackend->setMonochromeEnabled(m_settings.isGLUseMonochrome());
226 m_renderbackend->setDepthBufferEnabled(m_settings.isGLUseDepthBuffer());
227 m_renderbackend->setAlphaTestValue(m_settings.getGLAlphaTestValue());
228 m_renderbackend->setVSyncEnabled(m_settings.isVSync());
229 if (m_settings.isFrameLimitEnabled()) {
230 m_renderbackend->setFrameLimitEnabled(true);
231 m_renderbackend->setFrameLimit(m_settings.getFrameLimit());
232 }
233
234 std::string driver = m_settings.getVideoDriver();
235 if (driver != ""){
236 std::vector<std::string> drivers = m_devcaps.getAvailableVideoDrivers();
237 if (std::find (drivers.begin(), drivers.end(), driver) == drivers.end()) {
238 FL_WARN(_log, "Selected video driver is not supported for your Operating System! Reverting to default driver.");
239 driver = "";
240 }
241 m_devcaps.setVideoDriverName(driver);
242 }
243 // init backend with selected video driver or default
244 m_renderbackend->init(driver);
245
246 // in case of SDL we use this to create the SDL_Renderer
247 driver = m_settings.getSDLDriver();
248 if (driver != ""){
249 std::vector<std::string> drivers = m_devcaps.getAvailableRenderDrivers();
250 if (std::find (drivers.begin(), drivers.end(), driver) == drivers.end()) {
251 FL_WARN(_log, "Selected render driver is not supported for your Operating System! Reverting to default driver.");
252 driver = "";
253 }
254 m_devcaps.setRenderDriverName(driver);
255 }
256
257 FL_LOG(_log, "Querying device capabilities");
258 m_devcaps.fillDeviceCaps();
259
260 uint16_t bpp = m_settings.getBitsPerPixel();
261
262 m_screenMode = m_devcaps.getNearestScreenMode(
263 m_settings.getScreenWidth(),
264 m_settings.getScreenHeight(),
265 bpp,
266 rbackend,
267 m_settings.isFullScreen(),
268 m_settings.getRefreshRate(),
269 m_settings.getDisplay());
270
271 FL_LOG(_log, "Creating main screen");
272 m_renderbackend->createMainScreen(
273 m_screenMode,
274 m_settings.getWindowTitle(),
275 m_settings.getWindowIcon());
276 FL_LOG(_log, "Main screen created");
277
278 #ifdef HAVE_OPENGL
279 if (m_settings.getLightingModel() != 0) {
280 m_renderbackend->setLightingModel(m_settings.getLightingModel());
281 }
282
283 #endif
284 FL_LOG(_log, "Creating sound manager");
285 m_soundmanager = new SoundManager();
286 m_soundmanager->setVolume(static_cast<float>(m_settings.getInitialVolume()) / 10);
287
288 FL_LOG(_log, "Creating renderers");
289 m_offrenderer = new OffRenderer(m_renderbackend);
290 m_targetrenderer = new TargetRenderer(m_renderbackend);
291 m_renderers.push_back(new InstanceRenderer(m_renderbackend, 10));
292 m_renderers.push_back(new GridRenderer(m_renderbackend, 20));
293 m_renderers.push_back(new CellSelectionRenderer(m_renderbackend, 30));
294 m_renderers.push_back(new BlockingInfoRenderer(m_renderbackend, 40));
295 m_renderers.push_back(new FloatingTextRenderer(m_renderbackend, 50));
296 m_renderers.push_back(new QuadTreeRenderer(m_renderbackend, 60));
297 m_renderers.push_back(new CoordinateRenderer(m_renderbackend, 70));
298 m_renderers.push_back(new GenericRenderer(m_renderbackend, 80));
299 m_renderers.push_back(new LightRenderer(m_renderbackend, 90));
300 m_renderers.push_back(new CellRenderer(m_renderbackend, 100));
301
302 FL_LOG(_log, "Creating model");
303 m_model = new Model(m_renderbackend, m_renderers);
304 FL_LOG(_log, "Adding pathers to model");
305 m_model->adoptPather(new RoutePather());
306 FL_LOG(_log, "Adding grid prototypes to model");
307 m_model->adoptCellGrid(new SquareGrid());
308 m_model->adoptCellGrid(new HexGrid(false));
309 m_model->adoptCellGrid(new HexGrid(true));
310
311 m_cursor = new Cursor(m_renderbackend);
312 m_cursor->setNativeImageCursorEnabled(m_settings.isNativeImageCursorEnabled());
313 FL_LOG(_log, "Engine initialized");
314 }
315
~Engine()316 Engine::~Engine() {
317 if( !m_destroyed ) {
318 destroy();
319 }
320 }
321
destroy()322 void Engine::destroy() {
323 FL_LOG(_log, "Destructing engine");
324 delete m_cursor;
325 delete m_model;
326 delete m_soundmanager;
327 delete m_guimanager;
328
329 delete m_animationmanager;
330 delete m_imagemanager;
331 delete m_soundclipmanager;
332 delete m_eventmanager;
333
334 // properly remove all the renderers created during init
335 delete m_offrenderer;
336 delete m_targetrenderer;
337 std::vector<RendererBase*>::iterator rendererIter = m_renderers.begin();
338 for ( ; rendererIter != m_renderers.end(); ++rendererIter)
339 {
340 delete *rendererIter;
341 }
342 m_renderers.clear();
343
344 delete m_renderbackend;
345 delete m_vfs;
346 delete m_timemanager;
347
348 TTF_Quit();
349 SDL_Quit();
350
351 #ifdef USE_COCOA
352 objc_msgSend(m_autoreleasePool, sel_registerName("release"));
353 #endif
354
355 FL_LOG(_log, "================== Engine destructed ==================");
356 m_destroyed = true;
357 //delete m_logmanager;
358 }
initializePumping()359 void Engine::initializePumping() {
360 m_eventmanager->processEvents();
361 }
362
pump()363 void Engine::pump() {
364 m_renderbackend->startFrame();
365 m_eventmanager->processEvents();
366 m_timemanager->update();
367 m_soundmanager->update();
368
369 m_targetrenderer->render();
370 if (m_model->getActiveCameraCount() == 0) {
371 m_renderbackend->clearBackBuffer();
372 m_offrenderer->render();
373 } else {
374 m_model->update();
375 }
376
377 if (m_guimanager) {
378 m_guimanager->turn();
379 }
380
381 m_cursor->draw();
382 m_renderbackend->endFrame();
383 }
384
finalizePumping()385 void Engine::finalizePumping() {
386 // nothing here at the moment..
387 }
388
addChangeListener(IEngineChangeListener * listener)389 void Engine::addChangeListener(IEngineChangeListener* listener) {
390 m_changelisteners.push_back(listener);
391 }
392
removeChangeListener(IEngineChangeListener * listener)393 void Engine::removeChangeListener(IEngineChangeListener* listener) {
394 std::vector<IEngineChangeListener*>::iterator i = m_changelisteners.begin();
395 while (i != m_changelisteners.end()) {
396 if ((*i) == listener) {
397 m_changelisteners.erase(i);
398 return;
399 }
400 ++i;
401 }
402 }
403 }
404