engine.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <iostream>
00024 #include <algorithm>
00025 
00026 // 3rd party library includes
00027 #include <SDL.h>
00028 #include <SDL_ttf.h>
00029 
00030 // FIFE includes
00031 // These includes are split up in two parts, separated by one empty line
00032 // First block: files included from the FIFE root src directory
00033 // Second block: files included from the same folder
00034 #include "util/base/exception.h"
00035 #include "util/log/logger.h"
00036 #include "util/time/timemanager.h"
00037 #include "audio/soundmanager.h"
00038 #include "gui/guimanager.h"
00039 #include "vfs/vfs.h"
00040 #include "vfs/vfsdirectory.h"
00041 #include "vfs/directoryprovider.h"
00042 #ifdef HAVE_ZIP
00043 #include "vfs/zip/zipprovider.h"
00044 #endif
00045 #include "eventchannel/eventmanager.h"
00046 #include "video/imagemanager.h"
00047 #include "audio/soundclipmanager.h"
00048 #include "video/renderbackend.h"
00049 #include "video/cursor.h"
00050 #include "video/devicecaps.h"
00051 #ifdef HAVE_OPENGL
00052 #include "video/opengl/fife_opengl.h"
00053 #include "video/opengl/renderbackendopengl.h"
00054 #include "video/opengle/renderbackendopengle.h"
00055 #endif
00056 #include "video/sdl/renderbackendsdl.h"
00057 #include "loaders/native/video/imageloader.h"
00058 #include "loaders/native/audio/ogg_loader.h"
00059 #include "model/model.h"
00060 #include "pathfinder/routepather/routepather.h"
00061 #include "model/metamodel/grids/hexgrid.h"
00062 #include "model/metamodel/grids/squaregrid.h"
00063 #include "view/renderers/quadtreerenderer.h"
00064 #include "view/renderers/gridrenderer.h"
00065 #include "view/renderers/instancerenderer.h"
00066 #include "view/renderers/coordinaterenderer.h"
00067 #include "view/renderers/floatingtextrenderer.h"
00068 #include "view/renderers/cellselectionrenderer.h"
00069 #include "view/renderers/blockinginforenderer.h"
00070 #include "view/renderers/genericrenderer.h"
00071 #include "view/renderers/targetrenderer.h"
00072 #include "view/renderers/lightrenderer.h"
00073 #include "view/renderers/offrenderer.h"
00074 #include "video/image.h"
00075 #include "engine.h"
00076 
00077 #ifdef USE_COCOA
00078 
00079 #include <objc/message.h>
00080 #include <dlfcn.h>
00081 
00082 int32_t main(int32_t argc, char **argv)
00083 {
00084     return 0;
00085 }
00086 #endif
00087 
00088 namespace FIFE {
00089     static Logger _log(LM_CONTROLLER);
00090 
00091     Engine::Engine():
00092         m_renderbackend(0),
00093         m_guimanager(0),
00094         m_eventmanager(0),
00095         m_soundmanager(0),
00096         m_timemanager(0),
00097         m_imagemanager(0),
00098         m_soundclipmanager(0),
00099         m_vfs(0),
00100         m_model(0),
00101         m_logmanager(0),
00102         m_cursor(0),
00103         m_settings(),
00104         m_devcaps(),
00105         m_offrenderer(0),
00106         m_changelisteners() {
00107 #ifdef USE_COCOA
00108         // The next lines ensure that Cocoa is initialzed correctly.
00109         // This is needed for SDL to function properly on MAC OS X.
00110         void* cocoa_lib;
00111         cocoa_lib = dlopen( "/System/Library/Frameworks/Cocoa.framework/Cocoa", RTLD_LAZY );
00112         void (*nsappload)(void);
00113         nsappload = (void(*)()) dlsym( cocoa_lib, "NSApplicationLoad");
00114         nsappload();
00115 
00116         // Create an autorelease pool, so autoreleased SDL objects don't leak.
00117         objc_object *NSAutoreleasePool = objc_getClass("NSAutoreleasePool");
00118         m_autoreleasePool =
00119             objc_msgSend(NSAutoreleasePool, sel_registerName("new"));
00120 #endif
00121         m_logmanager = LogManager::instance();
00122     }
00123 
00124     EngineSettings& Engine::getSettings() {
00125         return m_settings;
00126     }
00127 
00128     const DeviceCaps& Engine::getDeviceCaps() const {
00129         return m_devcaps;
00130     }
00131 
00132     void Engine::changeScreenMode(const ScreenMode& mode){
00133         m_cursor->invalidate();
00134 
00135         m_imagemanager->invalidateAll();
00136 
00137         m_renderbackend->setScreenMode(mode);
00138 
00139         if (m_guimanager) {
00140             m_guimanager->resizeTopContainer(0,0,mode.getWidth(), mode.getHeight());
00141         }
00142 
00143         std::vector<IEngineChangeListener*>::iterator i = m_changelisteners.begin();
00144         while (i != m_changelisteners.end()) {
00145             (*i)->onScreenModeChanged(mode);
00146             ++i;
00147         }
00148     }
00149 
00150     void Engine::init() {
00151         m_destroyed = false;
00152 
00153         FL_LOG(_log, "================== Engine initialize start =================");
00154         m_timemanager = new TimeManager();
00155         FL_LOG(_log, "Time manager created");
00156 
00157         FL_LOG(_log, "Creating VFS");
00158         m_vfs = new VFS();
00159 
00160         FL_LOG(_log, "Adding root directory to VFS");
00161         m_vfs->addSource( new VFSDirectory(m_vfs) );
00162         m_vfs->addProvider( new DirectoryProvider() );
00163 #ifdef HAVE_ZIP
00164         FL_LOG(_log, "Adding zip provider to VFS");
00165         m_vfs->addProvider( new ZipProvider() );
00166 #endif
00167         //m_vfs->addProvider(ProviderDAT2());
00168         //m_vfs->addProvider(ProviderDAT1());
00169         FL_LOG(_log, "Engine pre-init done");
00170 
00171         // If failed to init SDL throw exception.
00172         if (SDL_Init(SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER) < 0) {
00173             throw SDLException(SDL_GetError());
00174         }
00175 
00176         SDL_EnableUNICODE(1);
00177         SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
00178         TTF_Init();
00179 
00180         FL_LOG(_log, "Creating event manager");
00181         m_eventmanager = new EventManager();
00182         m_eventmanager->setMouseSensitivity(m_settings.getMouseSensitivity());
00183         m_eventmanager->setMouseAcceleration(m_settings.getMouseAcceleration());
00184 
00185         FL_LOG(_log, "Creating resource managers");
00186 
00187         m_imagemanager = new ImageManager();
00188         m_soundclipmanager = new SoundClipManager();
00189 
00190         FL_LOG(_log, "Creating render backend");
00191         std::string rbackend(m_settings.getRenderBackend());
00192         if (rbackend == "SDL") {
00193             m_renderbackend = new RenderBackendSDL(m_settings.getColorKey());
00194             FL_LOG(_log, "SDL Render backend created");
00195         } else {
00196 #ifdef HAVE_OPENGL
00197             if (rbackend == "OpenGLe") {
00198                 m_renderbackend = new RenderBackendOpenGLe(m_settings.getColorKey());
00199                 FL_LOG(_log, "OpenGLe Render backend created");
00200                 FL_LOG(_log, "This is highly experimental so bear in mind some features may not work/work correctly.");
00201             } else {
00202                 m_renderbackend = new RenderBackendOpenGL(m_settings.getColorKey());
00203                 FL_LOG(_log, "OpenGL Render backend created");
00204             }
00205 #else
00206             m_renderbackend = new RenderBackendSDL(m_settings.getColorKey());
00207             // Remember  the choice so we pick the right graphics class.
00208             rbackend = "SDL";
00209             FL_WARN(_log, "Tried to select OpenGL, even though it is not compiled into the engine. Falling back to SDL Render backend");
00210 #endif
00211         }
00212         FL_LOG(_log, "Initializing render backend");
00213         m_renderbackend->setColorKeyEnabled(m_settings.isColorKeyEnabled());
00214         // we always set this to false
00215         //m_renderbackend->setAlphaOptimizerEnabled(false);
00216         m_renderbackend->setImageCompressingEnabled(m_settings.isGLCompressImages());
00217         m_renderbackend->setFramebufferEnabled(m_settings.isGLUseFramebuffer());
00218         m_renderbackend->setNPOTEnabled(m_settings.isGLUseNPOT());
00219 
00220         if (m_settings.isFrameLimitEnabled()) {
00221             m_renderbackend->setFrameLimitEnabled(true);
00222             m_renderbackend->setFrameLimit(m_settings.getFrameLimit());
00223         }
00224 
00225         std::string driver = m_settings.getVideoDriver();
00226         std::vector<std::string> drivers = m_devcaps.getAvailableDrivers();
00227 
00228         if (driver != ""){
00229             if (std::find (drivers.begin(), drivers.end(), driver) == drivers.end()) {
00230                 FL_WARN(_log, "Selected driver is not supported for your Operating System!  Reverting to default driver.");
00231                 driver = "";
00232             }
00233         }
00234 
00235         m_renderbackend->init(driver);
00236 
00237         FL_LOG(_log, "Querying device capabilities");
00238         m_devcaps.fillDeviceCaps();
00239 
00240         uint16_t bpp = m_settings.getBitsPerPixel();
00241 
00242         m_screenMode = m_devcaps.getNearestScreenMode(
00243             m_settings.getScreenWidth(),
00244             m_settings.getScreenHeight(),
00245             bpp,
00246             rbackend,
00247             m_settings.isFullScreen());
00248 
00249         FL_LOG(_log, "Creating main screen");
00250         m_renderbackend->createMainScreen(
00251             m_screenMode,
00252             m_settings.getWindowTitle(),
00253             m_settings.getWindowIcon());
00254         FL_LOG(_log, "Main screen created");
00255 
00256 #ifdef HAVE_OPENGL
00257         if (m_settings.getLightingModel() != 0) {
00258             m_renderbackend->setLightingModel(m_settings.getLightingModel());
00259         }
00260 
00261 #endif
00262         SDL_EnableUNICODE(1);
00263 
00264         FL_LOG(_log, "Creating sound manager");
00265         m_soundmanager = new SoundManager();
00266         m_soundmanager->setVolume(static_cast<float>(m_settings.getInitialVolume()) / 10);
00267 
00268         FL_LOG(_log, "Creating renderers");
00269         m_offrenderer = new OffRenderer(m_renderbackend);
00270         m_targetrenderer = new TargetRenderer(m_renderbackend);
00271         m_renderers.push_back(new InstanceRenderer(m_renderbackend, 10));
00272         m_renderers.push_back(new GridRenderer(m_renderbackend, 20));
00273         m_renderers.push_back(new CellSelectionRenderer(m_renderbackend, 30));
00274         m_renderers.push_back(new BlockingInfoRenderer(m_renderbackend, 40));
00275         m_renderers.push_back(new FloatingTextRenderer(m_renderbackend, 50));
00276         m_renderers.push_back(new QuadTreeRenderer(m_renderbackend, 60));
00277         m_renderers.push_back(new CoordinateRenderer(m_renderbackend, 70));
00278         m_renderers.push_back(new GenericRenderer(m_renderbackend, 80));
00279         m_renderers.push_back(new LightRenderer(m_renderbackend, 90));
00280 
00281         FL_LOG(_log, "Creating model");
00282         m_model = new Model(m_renderbackend, m_renderers);
00283         FL_LOG(_log, "Adding pathers to model");
00284         m_model->adoptPather(new RoutePather());
00285         FL_LOG(_log, "Adding grid prototypes to model");
00286         m_model->adoptCellGrid(new SquareGrid());
00287         m_model->adoptCellGrid(new HexGrid());
00288 
00289         m_cursor = new Cursor(m_renderbackend);
00290         FL_LOG(_log, "Engine intialized");
00291     }
00292 
00293     Engine::~Engine() {
00294         if( !m_destroyed ) {
00295             destroy();
00296         }
00297     }
00298 
00299     void Engine::destroy() {
00300         FL_LOG(_log, "Destructing engine");
00301         delete m_cursor;
00302         delete m_model;
00303         delete m_soundmanager;
00304         delete m_guimanager;
00305 
00306         delete m_imagemanager;
00307         delete m_soundclipmanager;
00308 //      delete m_eventmanager;
00309 
00310         // properly remove all the renderers created during init
00311         delete m_offrenderer;
00312         delete m_targetrenderer;
00313         std::vector<RendererBase*>::iterator rendererIter = m_renderers.begin();
00314         for ( ; rendererIter != m_renderers.end(); ++rendererIter)
00315         {
00316             delete *rendererIter;
00317         }
00318         m_renderers.clear();
00319 
00320         delete m_renderbackend;
00321         delete m_vfs;
00322         delete m_timemanager;
00323 
00324         TTF_Quit();
00325         SDL_Quit();
00326 
00327 #ifdef USE_COCOA
00328         objc_msgSend(m_autoreleasePool, sel_registerName("release"));
00329 #endif
00330 
00331         FL_LOG(_log, "================== Engine destructed ==================");
00332         m_destroyed = true;
00333         //delete m_logmanager;
00334     }
00335     void Engine::initializePumping() {
00336         m_eventmanager->processEvents();
00337     }
00338 
00339     void Engine::pump() {
00340         m_renderbackend->startFrame();
00341         m_eventmanager->processEvents();
00342         m_timemanager->update();
00343         
00344         m_targetrenderer->render();
00345         if (m_model->getMapCount() == 0) {
00346             m_renderbackend->clearBackBuffer();
00347             m_offrenderer->render();
00348         } else {
00349             m_model->update();
00350         }
00351 
00352         if (m_guimanager) {
00353             m_guimanager->turn();
00354         }
00355 
00356         m_cursor->draw();
00357         m_renderbackend->endFrame();
00358     }
00359 
00360     void Engine::finalizePumping() {
00361         // nothing here at the moment..
00362     }
00363 
00364     void Engine::addChangeListener(IEngineChangeListener* listener) {
00365         m_changelisteners.push_back(listener);
00366     }
00367 
00368     void Engine::removeChangeListener(IEngineChangeListener* listener) {
00369         std::vector<IEngineChangeListener*>::iterator i = m_changelisteners.begin();
00370         while (i != m_changelisteners.end()) {
00371             if ((*i) == listener) {
00372                 m_changelisteners.erase(i);
00373                 return;
00374             }
00375             ++i;
00376         }
00377     }
00378 }//FIFE
00379 
00380 /* vim: set noexpandtab: set shiftwidth=2: set tabstop=2: */