Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core5/src/libraries/core/Core.cc @ 5863

Last change on this file since 5863 was 5863, checked in by rgrieder, 15 years ago

New class: KeyBinderManager (yes, it really was necessary, I'm not such a Fan of zillions of classes as well) and moved the keybind command to it from GSLevel.
This new Singleton simply maps the keybind command to the right KeyBinder, selected by KeyBinderManager::setCurrent().
There is also a default KeyBinder (with keybindings.ini as file), which should do the Trick for now. Other Keybinders should only server special purposes (like in mini games or so).

DELETE YOUR keybindings.ini FILE! =
  • Property svn:eol-style set to native
File size: 16.4 KB
RevLine 
[1505]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
[2896]24 *      Reto Grieder
[1505]25 *   Co-authors:
[2896]26 *      ...
[1505]27 *
28 */
29
30/**
[3196]31@file
32@brief
33    Implementation of the Core singleton with its global variables (avoids boost include)
[1505]34*/
35
[1524]36#include "Core.h"
[2710]37
[1756]38#include <cassert>
[5836]39#include <vector>
[2710]40
41#ifdef ORXONOX_PLATFORM_WINDOWS
[2896]42#  ifndef WIN32_LEAN_AND_MEAN
43#    define WIN32_LEAN_AND_MEAN
44#  endif
[2710]45#  include <windows.h>
[3214]46#  undef min
47#  undef max
[2710]48#endif
49
[5855]50#include "util/Clock.h"
[2896]51#include "util/Debug.h"
[2710]52#include "util/Exception.h"
[2896]53#include "util/SignalHandler.h"
[5836]54#include "PathConfig.h"
[2896]55#include "CommandExecutor.h"
56#include "CommandLine.h"
57#include "ConfigFileManager.h"
58#include "ConfigValueIncludes.h"
59#include "CoreIncludes.h"
[5693]60#include "DynLibManager.h"
[3370]61#include "GameMode.h"
62#include "GraphicsManager.h"
63#include "GUIManager.h"
[2896]64#include "Identifier.h"
[1505]65#include "Language.h"
[5695]66#include "LuaState.h"
[2896]67#include "Shell.h"
68#include "TclBind.h"
69#include "TclThreadManager.h"
[3370]70#include "input/InputManager.h"
[5863]71#include "input/KeyBinderManager.h"
[1505]72
73namespace orxonox
74{
[3196]75    //! Static pointer to the singleton
[3370]76    Core* Core::singletonPtr_s  = 0;
[2662]77
[3280]78    SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
79#ifdef ORXONOX_PLATFORM_WINDOWS
80    SetCommandLineArgument(limitToCPU, 0).information("Limits the program to one cpu/core (1, 2, 3, etc.). 0 turns it off (default)");
81#endif
[2710]82
[3280]83    /**
84    @brief
85        Helper class for the Core singleton: we cannot derive
86        Core from OrxonoxClass because we need to handle the Identifier
87        destruction in the Core destructor.
88    */
89    class CoreConfiguration : public OrxonoxClass
[1505]90    {
[3280]91    public:
92        CoreConfiguration()
93        {
94        }
[2662]95
[3280]96        void initialise()
97        {
98            RegisterRootObject(CoreConfiguration);
99            this->setConfigValues();
100        }
101
102        /**
103            @brief Function to collect the SetConfigValue-macro calls.
104        */
105        void setConfigValues()
[2896]106        {
[3280]107#ifdef NDEBUG
108            const unsigned int defaultLevelConsole = 1;
109            const unsigned int defaultLevelLogfile = 3;
110            const unsigned int defaultLevelShell   = 1;
111#else
112            const unsigned int defaultLevelConsole = 3;
113            const unsigned int defaultLevelLogfile = 4;
114            const unsigned int defaultLevelShell   = 3;
115#endif
116            SetConfigValue(softDebugLevelConsole_, defaultLevelConsole)
117                .description("The maximal level of debug output shown in the console")
118                .callback(this, &CoreConfiguration::debugLevelChanged);
119            SetConfigValue(softDebugLevelLogfile_, defaultLevelLogfile)
120                .description("The maximal level of debug output shown in the logfile")
121                .callback(this, &CoreConfiguration::debugLevelChanged);
122            SetConfigValue(softDebugLevelShell_, defaultLevelShell)
123                .description("The maximal level of debug output shown in the ingame shell")
124                .callback(this, &CoreConfiguration::debugLevelChanged);
125
[3370]126            SetConfigValue(language_, Language::getInstance().defaultLanguage_)
[3280]127                .description("The language of the ingame text")
128                .callback(this, &CoreConfiguration::languageChanged);
129            SetConfigValue(bInitializeRandomNumberGenerator_, true)
130                .description("If true, all random actions are different each time you start the game")
131                .callback(this, &CoreConfiguration::initializeRandomNumberGenerator);
[2896]132        }
[3280]133
134        /**
135            @brief Callback function if the debug level has changed.
136        */
137        void debugLevelChanged()
[2896]138        {
[3280]139            // softDebugLevel_ is the maximum of the 3 variables
140            this->softDebugLevel_ = this->softDebugLevelConsole_;
141            if (this->softDebugLevelLogfile_ > this->softDebugLevel_)
142                this->softDebugLevel_ = this->softDebugLevelLogfile_;
143            if (this->softDebugLevelShell_ > this->softDebugLevel_)
144                this->softDebugLevel_ = this->softDebugLevelShell_;
145
146            OutputHandler::setSoftDebugLevel(OutputHandler::LD_All,     this->softDebugLevel_);
147            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Console, this->softDebugLevelConsole_);
148            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Logfile, this->softDebugLevelLogfile_);
149            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Shell,   this->softDebugLevelShell_);
[2896]150        }
[2662]151
[3280]152        /**
153            @brief Callback function if the language has changed.
154        */
155        void languageChanged()
156        {
157            // Read the translation file after the language was configured
[3370]158            Language::getInstance().readTranslatedLanguageFile();
[3280]159        }
[2896]160
[3280]161        /**
162            @brief Sets the language in the config-file back to the default.
163        */
164        void resetLanguage()
165        {
166            ResetConfigValue(language_);
167        }
168
169        void initializeRandomNumberGenerator()
170        {
171            static bool bInitialized = false;
172            if (!bInitialized && this->bInitializeRandomNumberGenerator_)
173            {
174                srand(static_cast<unsigned int>(time(0)));
175                rand();
176                bInitialized = true;
177            }
178        }
179
180        int softDebugLevel_;                            //!< The debug level
181        int softDebugLevelConsole_;                     //!< The debug level for the console
182        int softDebugLevelLogfile_;                     //!< The debug level for the logfile
183        int softDebugLevelShell_;                       //!< The debug level for the ingame shell
184        std::string language_;                          //!< The language
185        bool bInitializeRandomNumberGenerator_;         //!< If true, srand(time(0)) is called
186    };
187
188
[3323]189    Core::Core(const std::string& cmdLine)
[3370]190        // Cleanup guard for identifier destruction (incl. XMLPort, configValues, consoleCommands)
191        : identifierDestroyer_(Identifier::destroyAllIdentifiers)
192        // Cleanup guard for external console commands that don't belong to an Identifier
193        , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
194        , configuration_(new CoreConfiguration()) // Don't yet create config values!
195        , bGraphicsLoaded_(false)
[3280]196    {
[5693]197        // Set the hard coded fixed paths
[5836]198        this->pathConfig_.reset(new PathConfig());
[3280]199
[5693]200        // Create a new dynamic library manager
201        this->dynLibManager_.reset(new DynLibManager());
[2896]202
[5693]203        // Load modules
[5838]204        const std::vector<std::string>& modulePaths = this->pathConfig_->getModulePaths();
[5836]205        for (std::vector<std::string>::const_iterator it = modulePaths.begin(); it != modulePaths.end(); ++it)
[5693]206        {
[5836]207            try
[5693]208            {
[5836]209                this->dynLibManager_->load(*it);
[5693]210            }
[5836]211            catch (...)
212            {
213                COUT(1) << "Couldn't load module \"" << *it << "\": " << Exception::handleMessage() << std::endl;
214            }
[5693]215        }
216
217        // Parse command line arguments AFTER the modules have been loaded (static code!)
218        CommandLine::parseCommandLine(cmdLine);
219
220        // Set configurable paths like log, config and media
[5836]221        this->pathConfig_->setConfigurablePaths();
[5693]222
[2896]223        // create a signal handler (only active for linux)
224        // This call is placed as soon as possible, but after the directories are set
[3370]225        this->signalHandler_.reset(new SignalHandler());
[5836]226        this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");
[2896]227
[2710]228        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% was used
[5836]229        OutputHandler::getOutStream().setLogPath(PathConfig::getLogPathString());
[2710]230
[3280]231        // Parse additional options file now that we know its path
232        CommandLine::parseFile();
233
234#ifdef ORXONOX_PLATFORM_WINDOWS
235        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
236        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
237        // the timer though).
238        int limitToCPU = CommandLine::getValue("limitToCPU");
239        if (limitToCPU > 0)
240            setThreadAffinity(static_cast<unsigned int>(limitToCPU));
241#endif
242
[2896]243        // Manage ini files and set the default settings file (usually orxonox.ini)
[3370]244        this->configFileManager_.reset(new ConfigFileManager());
[2896]245        this->configFileManager_->setFilename(ConfigFileType::Settings,
246            CommandLine::getValue("settingsFile").getString());
247
[3280]248        // Required as well for the config values
[3370]249        this->languageInstance_.reset(new Language());
[2896]250
[5695]251        // creates the class hierarchy for all classes with factories
[5778]252        Identifier::createClassHierarchy();
[5695]253
[2896]254        // Do this soon after the ConfigFileManager has been created to open up the
255        // possibility to configure everything below here
[3280]256        this->configuration_->initialise();
[2896]257
[5695]258        // Load OGRE excluding the renderer and the render window
259        this->graphicsManager_.reset(new GraphicsManager(false));
[2896]260
261        // initialise Tcl
[5836]262        this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));
[3370]263        this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
[2896]264
265        // create a shell
[3370]266        this->shell_.reset(new Shell());
[5850]267
268        // Create singletons that always exist (in other libraries)
269        this->rootScope_.reset(new Scope<ScopeID::Root>());
[1505]270    }
271
272    /**
[3370]273    @brief
[5695]274        All destruction code is handled by scoped_ptrs and ScopeGuards.
[1505]275    */
[1524]276    Core::~Core()
[1505]277    {
[3370]278    }
[2896]279
[3370]280    void Core::loadGraphics()
281    {
[5695]282        // Any exception should trigger this, even in upgradeToGraphics (see its remarks)
283        Loki::ScopeGuard unloader = Loki::MakeObjGuard(*this, &Core::unloadGraphics);
[2896]284
[5695]285        // Upgrade OGRE to receive a render window
286        graphicsManager_->upgradeToGraphics();
[1505]287
[3370]288        // Calls the InputManager which sets up the input devices.
[5695]289        inputManager_.reset(new InputManager());
[3370]290
[5863]291        // Manages KeyBinders and makes them available
292        keyBinderManager_.reset(new KeyBinderManager());
293
[3370]294        // load the CEGUI interface
[5695]295        guiManager_.reset(new GUIManager(graphicsManager_->getRenderWindow(),
296            inputManager_->getMousePosition(), graphicsManager_->isFullScreen()));
[3370]297
[5850]298        // Create singletons associated with graphics (in other libraries)
299        graphicsScope_.reset(new Scope<ScopeID::Graphics>());
300
[5695]301        unloader.Dismiss();
[3370]302
303        bGraphicsLoaded_ = true;
[1747]304    }
[1505]305
[3370]306    void Core::unloadGraphics()
307    {
[5850]308        this->graphicsScope_.reset();
309        this->guiManager_.reset();
[5863]310        this->keyBinderManager_.reset();
[5850]311        this->inputManager_.reset();
[3370]312        this->graphicsManager_.reset();
313
[5695]314        // Load Ogre::Root again, but without the render system
315        try
316            { this->graphicsManager_.reset(new GraphicsManager(false)); }
317        catch (...)
318        {
[5747]319            COUT(0) << "An exception occurred during 'unloadGraphics':" << Exception::handleMessage() << std::endl
320                    << "Another exception might be being handled which may lead to undefined behaviour!" << std::endl
[5695]321                    << "Terminating the program." << std::endl;
322            abort();
323        }
324
[3370]325        bGraphicsLoaded_ = false;
326    }
327
[1747]328    /**
[3280]329        @brief Returns the softDebugLevel for the given device (returns a default-value if the class is right about to be created).
[1505]330        @param device The device
331        @return The softDebugLevel
332    */
[3280]333    /*static*/ int Core::getSoftDebugLevel(OutputHandler::OutputDevice device)
[1505]334    {
[2662]335        switch (device)
[1505]336        {
[2662]337        case OutputHandler::LD_All:
[3280]338            return Core::getInstance().configuration_->softDebugLevel_;
[2662]339        case OutputHandler::LD_Console:
[3280]340            return Core::getInstance().configuration_->softDebugLevelConsole_;
[2662]341        case OutputHandler::LD_Logfile:
[3280]342            return Core::getInstance().configuration_->softDebugLevelLogfile_;
[2662]343        case OutputHandler::LD_Shell:
[3280]344            return Core::getInstance().configuration_->softDebugLevelShell_;
[2662]345        default:
346            assert(0);
347            return 2;
[1505]348        }
349    }
350
351     /**
352        @brief Sets the softDebugLevel for the given device. Please use this only temporary and restore the value afterwards, as it overrides the configured value.
353        @param device The device
354        @param level The level
355    */
[3280]356    /*static*/ void Core::setSoftDebugLevel(OutputHandler::OutputDevice device, int level)
357    {
[2662]358        if (device == OutputHandler::LD_All)
[3280]359            Core::getInstance().configuration_->softDebugLevel_ = level;
[2662]360        else if (device == OutputHandler::LD_Console)
[3280]361            Core::getInstance().configuration_->softDebugLevelConsole_ = level;
[2662]362        else if (device == OutputHandler::LD_Logfile)
[3280]363            Core::getInstance().configuration_->softDebugLevelLogfile_ = level;
[2662]364        else if (device == OutputHandler::LD_Shell)
[3280]365            Core::getInstance().configuration_->softDebugLevelShell_ = level;
[1747]366
[2662]367        OutputHandler::setSoftDebugLevel(device, level);
[3280]368    }
[1505]369
370    /**
371        @brief Returns the configured language.
372    */
[3280]373    /*static*/ const std::string& Core::getLanguage()
[1505]374    {
[3280]375        return Core::getInstance().configuration_->language_;
[1505]376    }
377
378    /**
379        @brief Sets the language in the config-file back to the default.
380    */
[3280]381    /*static*/ void Core::resetLanguage()
[1505]382    {
[3280]383        Core::getInstance().configuration_->resetLanguage();
[1505]384    }
385
[2710]386    /**
[2896]387    @note
388        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
389            (Object-oriented Graphics Rendering Engine)
390        For the latest info, see http://www.ogre3d.org/
391
392        Copyright (c) 2000-2008 Torus Knot Software Ltd
393
394        OGRE is licensed under the LGPL. For more info, see OGRE license.
[2710]395    */
[2896]396    void Core::setThreadAffinity(int limitToCPU)
[2710]397    {
[3280]398#ifdef ORXONOX_PLATFORM_WINDOWS
399
[2896]400        if (limitToCPU <= 0)
401            return;
[2710]402
[2896]403        unsigned int coreNr = limitToCPU - 1;
404        // Get the current process core mask
405        DWORD procMask;
406        DWORD sysMask;
407#  if _MSC_VER >= 1400 && defined (_M_X64)
408        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
409#  else
410        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
411#  endif
[2710]412
[2896]413        // If procMask is 0, consider there is only one core available
414        // (using 0 as procMask will cause an infinite loop below)
415        if (procMask == 0)
416            procMask = 1;
417
418        // if the core specified with coreNr is not available, take the lowest one
419        if (!(procMask & (1 << coreNr)))
420            coreNr = 0;
421
422        // Find the lowest core that this process uses and coreNr suggests
423        DWORD threadMask = 1;
424        while ((threadMask & procMask) == 0 || (threadMask < (1u << coreNr)))
425            threadMask <<= 1;
426
427        // Set affinity to the first core
428        SetThreadAffinityMask(GetCurrentThread(), threadMask);
429#endif
[2710]430    }
431
[5695]432    void Core::preUpdate(const Clock& time)
[2896]433    {
[5850]434        // singletons from other libraries
435        Scope<ScopeID::Root>::update(time);
[5695]436        if (this->bGraphicsLoaded_)
[3370]437        {
[5695]438            // process input events
439            this->inputManager_->update(time);
440            // process gui events
441            this->guiManager_->update(time);
[5850]442            // graphics singletons from other libraries
443            Scope<ScopeID::Graphics>::update(time);
[3370]444        }
[5695]445        // process thread commands
446        this->tclThreadManager_->update(time);
[2896]447    }
[3370]448
[5695]449    void Core::postUpdate(const Clock& time)
[3370]450    {
[5695]451        if (this->bGraphicsLoaded_)
[3370]452        {
[5695]453            // Render (doesn't throw)
454            this->graphicsManager_->update(time);
[3370]455        }
456    }
[1505]457}
Note: See TracBrowser for help on using the repository browser.