Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/Core.cc @ 8351

Last change on this file since 8351 was 8351, checked in by rgrieder, 13 years ago

Merged kicklib2 branch back to trunk (includes former branches ois_update, mac_osx and kicklib).

Notes for updating

Linux:
You don't need an extra package for CEGUILua and Tolua, it's already shipped with CEGUI.
However you do need to make sure that the OgreRenderer is installed too with CEGUI 0.7 (may be a separate package).
Also, Orxonox now recognises if you install the CgProgramManager (a separate package available on newer Ubuntu on Debian systems).

Windows:
Download the new dependency packages versioned 6.0 and use these. If you have problems with that or if you don't like the in game console problem mentioned below, you can download the new 4.3 version of the packages (only available for Visual Studio 2005/2008).

Key new features:

  • *Support for Mac OS X*
  • Visual Studio 2010 support
  • Bullet library update to 2.77
  • OIS library update to 1.3
  • Support for CEGUI 0.7 —> Support for Arch Linux and even SuSE
  • Improved install target
  • Compiles now with GCC 4.6
  • Ogre Cg Shader plugin activated for Linux if available
  • And of course lots of bug fixes

There are also some regressions:

  • No support for CEGUI 0.5, Ogre 1.4 and boost 1.35 - 1.39 any more
  • In game console is not working in main menu for CEGUI 0.7
  • Tolua (just the C lib, not the application) and CEGUILua libraries are no longer in our repository. —> You will need to get these as well when compiling Orxonox
  • And of course lots of new bugs we don't yet know about
  • Property svn:eol-style set to native
File size: 15.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30/**
31@file
32@brief
33    Implementation of the Core singleton with its global variables (avoids boost include)
34*/
35
36#include "Core.h"
37
38#include <cassert>
39#include <cstdlib>
40#include <ctime>
41#include <fstream>
42#include <vector>
43
44#ifdef ORXONOX_PLATFORM_WINDOWS
45#  ifndef WIN32_LEAN_AND_MEAN
46#    define WIN32_LEAN_AND_MEAN
47#  endif
48#  include <windows.h>
49#  undef min
50#  undef max
51#endif
52
53#include "util/Clock.h"
54#include "util/Debug.h"
55#include "util/Exception.h"
56#include "util/Scope.h"
57#include "util/ScopedSingletonManager.h"
58#include "util/SignalHandler.h"
59#include "PathConfig.h"
60#include "CommandLineParser.h"
61#include "ConfigFileManager.h"
62#include "ConfigValueIncludes.h"
63#include "CoreIncludes.h"
64#include "DynLibManager.h"
65#include "GameMode.h"
66#include "GraphicsManager.h"
67#include "GUIManager.h"
68#include "Identifier.h"
69#include "Language.h"
70#include "LuaState.h"
71#include "command/ConsoleCommand.h"
72#include "command/IOConsole.h"
73#include "command/TclBind.h"
74#include "command/TclThreadManager.h"
75#include "input/InputManager.h"
76
77namespace orxonox
78{
79    //! Static pointer to the singleton
80    Core* Core::singletonPtr_s  = 0;
81
82    SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
83#if !defined(ORXONOX_PLATFORM_APPLE) && !defined(ORXONOX_USE_WINMAIN)
84    SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");
85#endif
86
87#ifdef ORXONOX_PLATFORM_WINDOWS
88    SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");
89#endif
90
91    Core::Core(const std::string& cmdLine)
92        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
93        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
94        // Cleanup guard for external console commands that don't belong to an Identifier
95        , consoleCommandDestroyer_(ConsoleCommand::destroyAll)
96        , bGraphicsLoaded_(false)
97        , bStartIOConsole_(true)
98        , lastLevelTimestamp_(0)
99        , ogreConfigTimestamp_(0)
100    {
101        // Set the hard coded fixed paths
102        this->pathConfig_.reset(new PathConfig());
103
104        // Create a new dynamic library manager
105        this->dynLibManager_.reset(new DynLibManager());
106
107        // Load modules
108        const std::vector<std::string>& modulePaths = this->pathConfig_->getModulePaths();
109        for (std::vector<std::string>::const_iterator it = modulePaths.begin(); it != modulePaths.end(); ++it)
110        {
111            try
112            {
113                this->dynLibManager_->load(*it);
114            }
115            catch (...)
116            {
117                COUT(1) << "Couldn't load module \"" << *it << "\": " << Exception::handleMessage() << std::endl;
118            }
119        }
120
121        // Parse command line arguments AFTER the modules have been loaded (static code!)
122        CommandLineParser::parseCommandLine(cmdLine);
123
124        // Set configurable paths like log, config and media
125        this->pathConfig_->setConfigurablePaths();
126
127        // create a signal handler (only active for Linux)
128        // This call is placed as soon as possible, but after the directories are set
129        this->signalHandler_.reset(new SignalHandler());
130        this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");
131
132        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% (Windows) was used
133        OutputHandler::getInstance().setLogPath(PathConfig::getLogPathString());
134
135        // Parse additional options file now that we know its path
136        CommandLineParser::parseFile();
137
138#ifdef ORXONOX_PLATFORM_WINDOWS
139        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
140        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
141        // the timer though).
142        int limitToCPU = CommandLineParser::getValue("limitToCPU");
143        if (limitToCPU > 0)
144            setThreadAffinity(static_cast<unsigned int>(limitToCPU));
145#endif
146
147        // Manage ini files and set the default settings file (usually orxonox.ini)
148        this->configFileManager_.reset(new ConfigFileManager());
149        this->configFileManager_->setFilename(ConfigFileType::Settings,
150            CommandLineParser::getValue("settingsFile").getString());
151
152        // Required as well for the config values
153        this->languageInstance_.reset(new Language());
154
155        // Do this soon after the ConfigFileManager has been created to open up the
156        // possibility to configure everything below here
157        ClassIdentifier<Core>::getIdentifier("Core")->initialiseObject(this, "Core", true);
158        this->setConfigValues();
159
160#if !defined(ORXONOX_PLATFORM_APPLE) && !defined(ORXONOX_USE_WINMAIN)
161        // Create persistent IO console
162        if (CommandLineParser::getValue("noIOConsole").getBool())
163        {
164            ModifyConfigValue(bStartIOConsole_, tset, false);
165        }
166        if (this->bStartIOConsole_)
167            this->ioConsole_.reset(new IOConsole());
168#endif
169
170        // creates the class hierarchy for all classes with factories
171        Identifier::createClassHierarchy();
172
173        // Load OGRE excluding the renderer and the render window
174        this->graphicsManager_.reset(new GraphicsManager(false));
175
176        // initialise Tcl
177        this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));
178        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
179
180        // Create singletons that always exist (in other libraries)
181        this->rootScope_.reset(new Scope<ScopeID::Root>());
182
183        // Generate documentation instead of normal run?
184        std::string docFilename;
185        CommandLineParser::getValue("generateDoc", &docFilename);
186        if (!docFilename.empty())
187        {
188            std::ofstream docFile(docFilename.c_str());
189            if (docFile.is_open())
190            {
191                CommandLineParser::generateDoc(docFile);
192                docFile.close();
193            }
194            else
195                COUT(0) << "Error: Could not open file for documentation writing" << endl;
196        }
197    }
198
199    /**
200    @brief
201        All destruction code is handled by scoped_ptrs and ScopeGuards.
202    */
203    Core::~Core()
204    {
205        // Remove us from the object lists again to avoid problems when destroying them
206        this->unregisterObject();
207    }
208
209    //! Function to collect the SetConfigValue-macro calls.
210    void Core::setConfigValues()
211    {
212#ifdef ORXONOX_RELEASE
213        const unsigned int defaultLevelLogFile = 3;
214        SetConfigValue(bDevMode_, false)
215            .description("Developer mode. If not set, hides some things from the user to not confuse him.");
216#else
217        const unsigned int defaultLevelLogFile = 4;
218        SetConfigValue(bDevMode_, true)
219            .description("Developer mode. If not set, hides some things from the user to not confuse him.");
220#endif
221        SetConfigValueExternal(softDebugLevelLogFile_, "OutputHandler", "softDebugLevelLogFile", defaultLevelLogFile)
222            .description("The maximum level of debug output shown in the log file");
223        OutputHandler::getInstance().setSoftDebugLevel(OutputHandler::logFileOutputListenerName_s, this->softDebugLevelLogFile_);
224
225        SetConfigValue(language_, Language::getInstance().defaultLanguage_)
226            .description("The language of the in game text")
227            .callback(this, &Core::languageChanged);
228        SetConfigValue(bInitRandomNumberGenerator_, true)
229            .description("If true, all random actions are different each time you start the game")
230            .callback(this, &Core::initRandomNumberGenerator);
231        SetConfigValue(bStartIOConsole_, true)
232            .description("Set to false if you don't want to use the IOConsole (for Lua debugging for instance)");
233        SetConfigValue(lastLevelTimestamp_, 0)
234            .description("Timestamp when the last level was started.");
235        SetConfigValue(ogreConfigTimestamp_, 0)
236            .description("Timestamp when the ogre config file was changed.");
237    }
238
239    //! Callback function if the language has changed.
240    void Core::languageChanged()
241    {
242        // Read the translation file after the language was configured
243        Language::getInstance().readTranslatedLanguageFile();
244    }
245
246    void Core::initRandomNumberGenerator()
247    {
248        static bool bInitialized = false;
249        if (!bInitialized && this->bInitRandomNumberGenerator_)
250        {
251            srand(static_cast<unsigned int>(time(0)));
252            rand();
253            bInitialized = true;
254        }
255    }
256
257    void Core::loadGraphics()
258    {
259        // Any exception should trigger this, even in upgradeToGraphics (see its remarks)
260        Loki::ScopeGuard unloader = Loki::MakeObjGuard(*this, &Core::unloadGraphics);
261
262        // Upgrade OGRE to receive a render window
263        try
264        {
265            graphicsManager_->upgradeToGraphics();
266        }
267        catch (const InitialisationFailedException&)
268        {
269            // Exit the application if the Ogre config dialog was canceled
270            COUT(1) << Exception::handleMessage() << std::endl;
271            exit(EXIT_FAILURE);
272        }
273        catch (...)
274        {
275            // Recovery from this is very difficult. It requires to completely
276            // destroy Ogre related objects and load again (without graphics).
277            // However since Ogre 1.7 there seems to be a problem when Ogre
278            // throws an exception and the graphics engine then gets destroyed
279            // and reloaded between throw and catch (access violation in MSVC).
280            // That's why we abort completely and only display the exception.
281            COUT(1) << "An exception occurred during upgrade to graphics. "
282                    << "That is unrecoverable. The message was:" << endl
283                    << Exception::handleMessage() << endl;
284            abort();
285        }
286
287        // Calls the InputManager which sets up the input devices.
288        inputManager_.reset(new InputManager());
289
290        // Load the CEGUI interface
291        guiManager_.reset(new GUIManager(inputManager_->getMousePosition()));
292
293        bGraphicsLoaded_ = true;
294        GameMode::bShowsGraphics_s = true;
295
296        // Load some sort of a debug overlay (only denoted by its name, "debug.oxo")
297        graphicsManager_->loadDebugOverlay();
298
299        // Create singletons associated with graphics (in other libraries)
300        graphicsScope_.reset(new Scope<ScopeID::Graphics>());
301
302        unloader.Dismiss();
303    }
304
305    void Core::unloadGraphics()
306    {
307        this->graphicsScope_.reset();
308        this->guiManager_.reset();
309        this->inputManager_.reset();
310        this->graphicsManager_.reset();
311
312        // Load Ogre::Root again, but without the render system
313        try
314            { this->graphicsManager_.reset(new GraphicsManager(false)); }
315        catch (...)
316        {
317            COUT(0) << "An exception occurred during 'unloadGraphics':" << Exception::handleMessage() << std::endl
318                    << "Another exception might be being handled which may lead to undefined behaviour!" << std::endl
319                    << "Terminating the program." << std::endl;
320            abort();
321        }
322
323        bGraphicsLoaded_ = false;
324        GameMode::bShowsGraphics_s = false;
325    }
326
327    //! Sets the language in the config-file back to the default.
328    void Core::resetLanguage()
329    {
330        ResetConfigValue(language_);
331    }
332
333    /**
334    @note
335        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
336            (Object-oriented Graphics Rendering Engine)
337        For the latest info, see http://www.ogre3d.org/
338
339        Copyright (c) 2000-2008 Torus Knot Software Ltd
340
341        OGRE is licensed under the LGPL. For more info, see OGRE license.
342    */
343    void Core::setThreadAffinity(int limitToCPU)
344    {
345#ifdef ORXONOX_PLATFORM_WINDOWS
346
347        if (limitToCPU <= 0)
348            return;
349
350        unsigned int coreNr = limitToCPU - 1;
351        // Get the current process core mask
352        DWORD procMask;
353        DWORD sysMask;
354#  if _MSC_VER >= 1400 && defined (_M_X64)
355        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
356#  else
357        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
358#  endif
359
360        // If procMask is 0, consider there is only one core available
361        // (using 0 as procMask will cause an infinite loop below)
362        if (procMask == 0)
363            procMask = 1;
364
365        // if the core specified with coreNr is not available, take the lowest one
366        if (!(procMask & (1 << coreNr)))
367            coreNr = 0;
368
369        // Find the lowest core that this process uses and coreNr suggests
370        DWORD threadMask = 1;
371        while ((threadMask & procMask) == 0 || (threadMask < (1u << coreNr)))
372            threadMask <<= 1;
373
374        // Set affinity to the first core
375        SetThreadAffinityMask(GetCurrentThread(), threadMask);
376#endif
377    }
378
379    void Core::preUpdate(const Clock& time)
380    {
381        // Update singletons before general ticking
382        ScopedSingletonManager::preUpdate<ScopeID::Root>(time);
383        if (this->bGraphicsLoaded_)
384        {
385            // Process input events
386            this->inputManager_->preUpdate(time);
387            // Update GUI
388            this->guiManager_->preUpdate(time);
389            // Update singletons before general ticking
390            ScopedSingletonManager::preUpdate<ScopeID::Graphics>(time);
391        }
392        // Process console events and status line
393        if (this->ioConsole_ != NULL)
394            this->ioConsole_->preUpdate(time);
395        // Process thread commands
396        this->tclThreadManager_->preUpdate(time);
397    }
398
399    void Core::postUpdate(const Clock& time)
400    {
401        // Update singletons just before rendering
402        ScopedSingletonManager::postUpdate<ScopeID::Root>(time);
403        if (this->bGraphicsLoaded_)
404        {
405            // Update singletons just before rendering
406            ScopedSingletonManager::postUpdate<ScopeID::Graphics>(time);
407            // Render (doesn't throw)
408            this->graphicsManager_->postUpdate(time);
409        }
410    }
411
412    void Core::updateLastLevelTimestamp()
413    {
414        ModifyConfigValue(lastLevelTimestamp_, set, static_cast<long long>(time(NULL)));
415    }
416
417    void Core::updateOgreConfigTimestamp()
418    {
419        ModifyConfigValue(ogreConfigTimestamp_, set, static_cast<long long>(time(NULL)));
420    }
421}
Note: See TracBrowser for help on using the repository browser.