Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6763 was 6746, checked in by rgrieder, 14 years ago

Merged gamestates2 branch back to trunk.
This brings in some heavy changes in the GUI framework.
It should also fix problems with triggered asserts in the InputManager.

Note: PickupInventory does not seem to work —> Segfault when showing because before, the owner in GUIOverlay::setGUIName is already NULL.
I haven't tested it before, so I can't tell whether it's my changes.

  • Property svn:eol-style set to native
File size: 12.7 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 <vector>
40
41#ifdef ORXONOX_PLATFORM_WINDOWS
42#  ifndef WIN32_LEAN_AND_MEAN
43#    define WIN32_LEAN_AND_MEAN
44#  endif
45#  include <windows.h>
46#  undef min
47#  undef max
48#endif
49
50#include "util/Clock.h"
51#include "util/Debug.h"
52#include "util/Exception.h"
53#include "util/Scope.h"
54#include "util/SignalHandler.h"
55#include "PathConfig.h"
56#include "CommandExecutor.h"
57#include "CommandLineParser.h"
58#include "ConfigFileManager.h"
59#include "ConfigValueIncludes.h"
60#include "CoreIncludes.h"
61#include "DynLibManager.h"
62#include "GameMode.h"
63#include "GraphicsManager.h"
64#include "GUIManager.h"
65#include "Identifier.h"
66#include "Language.h"
67#include "IOConsole.h"
68#include "LuaState.h"
69#include "ScopedSingletonManager.h"
70#include "TclBind.h"
71#include "TclThreadManager.h"
72#include "input/InputManager.h"
73
74namespace orxonox
75{
76    //! Static pointer to the singleton
77    Core* Core::singletonPtr_s  = 0;
78
79    SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
80    SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");
81#ifdef ORXONOX_PLATFORM_WINDOWS
82    SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");
83#endif
84
85    Core::Core(const std::string& cmdLine)
86        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
87        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
88        // Cleanup guard for external console commands that don't belong to an Identifier
89        , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
90        , bGraphicsLoaded_(false)
91        , bStartIOConsole_(true)
92    {
93        // Set the hard coded fixed paths
94        this->pathConfig_.reset(new PathConfig());
95
96        // Create a new dynamic library manager
97        this->dynLibManager_.reset(new DynLibManager());
98
99        // Load modules
100        const std::vector<std::string>& modulePaths = this->pathConfig_->getModulePaths();
101        for (std::vector<std::string>::const_iterator it = modulePaths.begin(); it != modulePaths.end(); ++it)
102        {
103            try
104            {
105                this->dynLibManager_->load(*it);
106            }
107            catch (...)
108            {
109                COUT(1) << "Couldn't load module \"" << *it << "\": " << Exception::handleMessage() << std::endl;
110            }
111        }
112
113        // Parse command line arguments AFTER the modules have been loaded (static code!)
114        CommandLineParser::parseCommandLine(cmdLine);
115
116        // Set configurable paths like log, config and media
117        this->pathConfig_->setConfigurablePaths();
118
119        // create a signal handler (only active for Linux)
120        // This call is placed as soon as possible, but after the directories are set
121        this->signalHandler_.reset(new SignalHandler());
122        this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");
123
124        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% (Windows) was used
125        OutputHandler::getInstance().setLogPath(PathConfig::getLogPathString());
126
127        // Parse additional options file now that we know its path
128        CommandLineParser::parseFile();
129
130#ifdef ORXONOX_PLATFORM_WINDOWS
131        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
132        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
133        // the timer though).
134        int limitToCPU = CommandLineParser::getValue("limitToCPU");
135        if (limitToCPU > 0)
136            setThreadAffinity(static_cast<unsigned int>(limitToCPU));
137#endif
138
139        // Manage ini files and set the default settings file (usually orxonox.ini)
140        this->configFileManager_.reset(new ConfigFileManager());
141        this->configFileManager_->setFilename(ConfigFileType::Settings,
142            CommandLineParser::getValue("settingsFile").getString());
143
144        // Required as well for the config values
145        this->languageInstance_.reset(new Language());
146
147        // Do this soon after the ConfigFileManager has been created to open up the
148        // possibility to configure everything below here
149        ClassIdentifier<Core>::getIdentifier("Core")->initialiseObject(this, "Core", true);
150        this->setConfigValues();
151
152        // create persistent io console
153        if (CommandLineParser::getValue("noIOConsole").getBool())
154        {
155            ModifyConfigValue(bStartIOConsole_, tset, false);
156        }
157        if (this->bStartIOConsole_)
158            this->ioConsole_.reset(new IOConsole());
159
160        // creates the class hierarchy for all classes with factories
161        Identifier::createClassHierarchy();
162
163        // Load OGRE excluding the renderer and the render window
164        this->graphicsManager_.reset(new GraphicsManager(false));
165
166        // initialise Tcl
167        this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));
168        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
169
170        // Create singletons that always exist (in other libraries)
171        this->rootScope_.reset(new Scope<ScopeID::Root>());
172    }
173
174    /**
175    @brief
176        All destruction code is handled by scoped_ptrs and ScopeGuards.
177    */
178    Core::~Core()
179    {
180        // Remove us from the object lists again to avoid problems when destroying them
181        this->unregisterObject();
182    }
183
184    //! Function to collect the SetConfigValue-macro calls.
185    void Core::setConfigValues()
186    {
187#ifdef ORXONOX_RELEASE
188        const unsigned int defaultLevelLogFile = 3;
189#else
190        const unsigned int defaultLevelLogFile = 4;
191#endif
192        setConfigValueGeneric(this, &this->softDebugLevelLogFile_, ConfigFileType::Settings, "OutputHandler", "softDebugLevelLogFile", defaultLevelLogFile)
193            .description("The maximum level of debug output shown in the log file");
194        OutputHandler::getInstance().setSoftDebugLevel(OutputHandler::logFileOutputListenerName_s, this->softDebugLevelLogFile_);
195
196        SetConfigValue(language_, Language::getInstance().defaultLanguage_)
197            .description("The language of the in game text")
198            .callback(this, &Core::languageChanged);
199        SetConfigValue(bInitRandomNumberGenerator_, true)
200            .description("If true, all random actions are different each time you start the game")
201            .callback(this, &Core::initRandomNumberGenerator);
202        SetConfigValue(bStartIOConsole_, true)
203            .description("Set to false if you don't want to use the IOConsole (for Lua debugging for instance)");
204    }
205
206    //! Callback function if the language has changed.
207    void Core::languageChanged()
208    {
209        // Read the translation file after the language was configured
210        Language::getInstance().readTranslatedLanguageFile();
211    }
212
213    void Core::initRandomNumberGenerator()
214    {
215        static bool bInitialized = false;
216        if (!bInitialized && this->bInitRandomNumberGenerator_)
217        {
218            srand(static_cast<unsigned int>(time(0)));
219            rand();
220            bInitialized = true;
221        }
222    }
223
224    void Core::loadGraphics()
225    {
226        // Any exception should trigger this, even in upgradeToGraphics (see its remarks)
227        Loki::ScopeGuard unloader = Loki::MakeObjGuard(*this, &Core::unloadGraphics);
228
229        // Upgrade OGRE to receive a render window
230        graphicsManager_->upgradeToGraphics();
231
232        // Calls the InputManager which sets up the input devices.
233        inputManager_.reset(new InputManager());
234
235        // Load the CEGUI interface
236        guiManager_.reset(new GUIManager(inputManager_->getMousePosition()));
237
238        bGraphicsLoaded_ = true;
239        GameMode::bShowsGraphics_s = true;
240
241        // Load some sort of a debug overlay (only denoted by its name, "debug.oxo")
242        graphicsManager_->loadDebugOverlay();
243
244        // Create singletons associated with graphics (in other libraries)
245        graphicsScope_.reset(new Scope<ScopeID::Graphics>());
246
247        unloader.Dismiss();
248    }
249
250    void Core::unloadGraphics()
251    {
252        this->graphicsScope_.reset();
253        this->guiManager_.reset();
254        this->inputManager_.reset();
255        this->graphicsManager_.reset();
256
257        // Load Ogre::Root again, but without the render system
258        try
259            { this->graphicsManager_.reset(new GraphicsManager(false)); }
260        catch (...)
261        {
262            COUT(0) << "An exception occurred during 'unloadGraphics':" << Exception::handleMessage() << std::endl
263                    << "Another exception might be being handled which may lead to undefined behaviour!" << std::endl
264                    << "Terminating the program." << std::endl;
265            abort();
266        }
267
268        bGraphicsLoaded_ = false;
269        GameMode::bShowsGraphics_s = false;
270    }
271
272    //! Sets the language in the config-file back to the default.
273    void Core::resetLanguage()
274    {
275        ResetConfigValue(language_);
276    }
277
278    /**
279    @note
280        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
281            (Object-oriented Graphics Rendering Engine)
282        For the latest info, see http://www.ogre3d.org/
283
284        Copyright (c) 2000-2008 Torus Knot Software Ltd
285
286        OGRE is licensed under the LGPL. For more info, see OGRE license.
287    */
288    void Core::setThreadAffinity(int limitToCPU)
289    {
290#ifdef ORXONOX_PLATFORM_WINDOWS
291
292        if (limitToCPU <= 0)
293            return;
294
295        unsigned int coreNr = limitToCPU - 1;
296        // Get the current process core mask
297        DWORD procMask;
298        DWORD sysMask;
299#  if _MSC_VER >= 1400 && defined (_M_X64)
300        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
301#  else
302        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
303#  endif
304
305        // If procMask is 0, consider there is only one core available
306        // (using 0 as procMask will cause an infinite loop below)
307        if (procMask == 0)
308            procMask = 1;
309
310        // if the core specified with coreNr is not available, take the lowest one
311        if (!(procMask & (1 << coreNr)))
312            coreNr = 0;
313
314        // Find the lowest core that this process uses and coreNr suggests
315        DWORD threadMask = 1;
316        while ((threadMask & procMask) == 0 || (threadMask < (1u << coreNr)))
317            threadMask <<= 1;
318
319        // Set affinity to the first core
320        SetThreadAffinityMask(GetCurrentThread(), threadMask);
321#endif
322    }
323
324    void Core::preUpdate(const Clock& time)
325    {
326        // Update singletons before general ticking
327        ScopedSingletonManager::preUpdate<ScopeID::Root>(time);
328        if (this->bGraphicsLoaded_)
329        {
330            // Process input events
331            this->inputManager_->preUpdate(time);
332            // Update GUI
333            this->guiManager_->preUpdate(time);
334            // Update singletons before general ticking
335            ScopedSingletonManager::preUpdate<ScopeID::Graphics>(time);
336        }
337        // Process console events and status line
338        if (this->ioConsole_ != NULL)
339            this->ioConsole_->preUpdate(time);
340        // Process thread commands
341        this->tclThreadManager_->preUpdate(time);
342    }
343
344    void Core::postUpdate(const Clock& time)
345    {
346        // Update singletons just before rendering
347        ScopedSingletonManager::postUpdate<ScopeID::Root>(time);
348        if (this->bGraphicsLoaded_)
349        {
350            // Update singletons just before rendering
351            ScopedSingletonManager::postUpdate<ScopeID::Graphics>(time);
352            // Render (doesn't throw)
353            this->graphicsManager_->postUpdate(time);
354        }
355    }
356}
Note: See TracBrowser for help on using the repository browser.