Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/gamestates/GSRoot.cc @ 1792

Last change on this file since 1792 was 1792, checked in by rgrieder, 16 years ago

Changed initialisation of TclThreadManager, TclBind and Shell to match the simple singleton concept (runtime assert in the c'tor).
That simplifies things a lot. The instances now 'belong' to GSRoot.

  • Property svn:eol-style set to native
File size: 10.9 KB
RevLine 
[1661]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 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30#include "GSRoot.h"
31
[1686]32#include <OgreLogManager.h>
33#include <OgreRoot.h>
34
[1764]35#include "util/Exception.h"
36#include "util/Debug.h"
[1661]37#include "core/Factory.h"
38#include "core/ConfigFileManager.h"
39#include "core/ConfigValueIncludes.h"
[1686]40#include "core/CoreIncludes.h"
[1661]41#include "core/ConsoleCommand.h"
[1664]42#include "core/CommandLine.h"
[1792]43#include "core/Shell.h"
[1661]44#include "core/TclBind.h"
[1672]45#include "core/TclThreadManager.h"
[1661]46#include "GraphicsEngine.h"
47#include "Settings.h"
48
[1674]49#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
50#  ifndef WIN32_LEAN_AND_MEAN
51#    define WIN32_LEAN_AND_MEAN
52#  endif
53#  include "windows.h"
54
55   //Get around Windows hackery
56#  ifdef max
57#    undef max
58#  endif
59#  ifdef min
60#    undef min
61#  endif
62#endif
63
[1661]64namespace orxonox
65{
[1664]66    SetCommandLineArgument(dataPath, "").setInformation("PATH");
[1691]67    SetCommandLineArgument(limitToCPU, 1).setInformation("0: off | #cpu");
[1663]68
[1661]69    GSRoot::GSRoot()
[1672]70        : RootGameState("root")
[1663]71        , settings_(0)
[1686]72        , ogreRoot_(0)
73        , ogreLogger_(0)
[1661]74        , graphicsEngine_(0)
[1792]75        , tclBind_(0)
76        , tclThreadManager_(0)
77        , shell_(0)
[1661]78    {
[1686]79        RegisterRootObject(GSRoot);
[1661]80    }
81
82    GSRoot::~GSRoot()
83    {
84    }
85
[1686]86    void GSRoot::setConfigValues()
87    {
88        SetConfigValue(ogreConfigFile_,  "ogre.cfg").description("Location of the Ogre config file");
89        SetConfigValue(ogrePluginsFile_, "plugins.cfg").description("Location of the Ogre plugins file");
90        SetConfigValue(ogreLogFile_,     "ogre.log").description("Logfile for messages from Ogre. \
91                                                                 Use \"\" to suppress log file creation.");
92        SetConfigValue(ogreLogLevelTrivial_ , 5).description("Corresponding orxonox debug level for ogre Trivial");
93        SetConfigValue(ogreLogLevelNormal_  , 4).description("Corresponding orxonox debug level for ogre Normal");
94        SetConfigValue(ogreLogLevelCritical_, 2).description("Corresponding orxonox debug level for ogre Critical");
95    }
96
[1661]97    void GSRoot::enter()
98    {
99#if ORXONOX_DEBUG_MODE == 1
[1755]100        ConfigFileManager::getInstance()->setFile(CFT_Settings, "orxonox_d.ini");
[1661]101#else
[1755]102        ConfigFileManager::getInstance()->setFile(CFT_Settings, "orxonox.ini");
[1661]103#endif
104
[1686]105        // do this after the previous call..
106        setConfigValues();
107
[1661]108        // creates the class hierarchy for all classes with factories
109        Factory::createClassHierarchy();
110
[1663]111        // instantiate Settings class
112        this->settings_ = new Settings();
113
[1664]114        std::string dataPath;
[1670]115        CommandLine::getValue("dataPath", &dataPath);
[1664]116        if (dataPath != "")
[1661]117        {
[1664]118            if (*dataPath.end() != '/' && *dataPath.end() != '\\')
119                Settings::tsetDataPath(dataPath + "/");
[1661]120            else
[1664]121                Settings::tsetDataPath(dataPath);
[1661]122        }
123
124        // initialise TCL
[1792]125        this->tclBind_ = new TclBind(Settings::getDataPath());
126        this->tclThreadManager_ = new TclThreadManager(tclBind_->getTclInterpreter());
[1661]127
[1792]128        // create a shell
129        this->shell_ = new Shell();
130
[1686]131        setupOgre();
132
[1662]133        // initialise graphics engine. Doesn't load the render window yet!
[1661]134        graphicsEngine_ = new GraphicsEngine();
135
[1674]136        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
137        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
138        // the timer though).
[1691]139        int limitToCPU;
140        CommandLine::getValue("limitToCPU", &limitToCPU);
141        if (limitToCPU > 0)
142            setThreadAffinity((unsigned int)(limitToCPU - 1));
[1674]143
[1672]144        // add console commands
145        FunctorMember<GSRoot>* functor1 = createFunctor(&GSRoot::exitGame);
146        functor1->setObject(this);
147        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor1, "exit"));
[1664]148
[1670]149        // add console commands
[1689]150        FunctorMember01<GameStateBase, const std::string&>* functor2 = createFunctor(&GameStateBase::requestState);
[1672]151        functor2->setObject(this);
152        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor2, "selectGameState"));
[1661]153    }
154
155    void GSRoot::leave()
156    {
[1792]157        // TODO: remove and destroy console commands
158
[1663]159        delete graphicsEngine_;
[1686]160
161        delete this->ogreRoot_;
162
163#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
164        // delete the ogre log and the logManager (since we have created it).
165        this->ogreLogger_->getDefaultLog()->removeListener(this);
166        this->ogreLogger_->destroyLog(Ogre::LogManager::getSingleton().getDefaultLog());
167        delete this->ogreLogger_;
168#endif
169
[1792]170        delete this->shell_;
171        delete this->tclThreadManager_;
172        delete this->tclBind_;
173
[1670]174        delete settings_;
[1663]175
[1661]176    }
177
[1674]178    void GSRoot::ticked(const Clock& time)
[1661]179    {
[1674]180        TclThreadManager::getInstance().tick(time.getDeltaTime());
[1662]181
[1674]182        this->tickChild(time);
[1662]183    }
[1674]184
185    /**
186    @note
[1691]187        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
[1674]188            (Object-oriented Graphics Rendering Engine)
189        For the latest info, see http://www.ogre3d.org/
190
191        Copyright (c) 2000-2008 Torus Knot Software Ltd
192       
193        OGRE is licensed under the LGPL. For more info, see ogre license info.
194    */
[1691]195    void GSRoot::setThreadAffinity(unsigned int limitToCPU)
[1674]196    {
197#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
198        // Get the current process core mask
199            DWORD procMask;
200            DWORD sysMask;
201#if _MSC_VER >= 1400 && defined (_M_X64)
202            GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
203#else
204            GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
205#endif
206
207            // If procMask is 0, consider there is only one core available
208            // (using 0 as procMask will cause an infinite loop below)
209            if (procMask == 0)
210                    procMask = 1;
211
[1691]212        // if the core specified with limitToCPU is not available, take the lowest one
213        if (!(procMask & (1 << limitToCPU)))
214            limitToCPU = 0;
215
216            // Find the lowest core that this process uses and limitToCPU suggests
[1674]217        DWORD threadMask = 1;
[1691]218            while ((threadMask & procMask) == 0 || (threadMask < (1u << limitToCPU)))
[1674]219                    threadMask <<= 1;
220
221            // Set affinity to the first core
222            SetThreadAffinityMask(GetCurrentThread(), threadMask);
223#endif
224    }
[1686]225
226    /**
227    @brief
228        Creates the Ogre Root object and sets up the ogre log.
229    */
230    void GSRoot::setupOgre()
231    {
232        COUT(3) << "Setting up Ogre..." << std::endl;
233
234        // TODO: LogManager doesn't work on oli platform. The why is yet unknown.
235#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
236        // create a new logManager
237        ogreLogger_ = new Ogre::LogManager();
238        COUT(4) << "Ogre LogManager created" << std::endl;
239
240        // create our own log that we can listen to
241        Ogre::Log *myLog;
242        if (this->ogreLogFile_ == "")
243            myLog = ogreLogger_->createLog("ogre.log", true, false, true);
244        else
245            myLog = ogreLogger_->createLog(this->ogreLogFile_, true, false, false);
246        COUT(4) << "Ogre Log created" << std::endl;
247
248        myLog->setLogDetail(Ogre::LL_BOREME);
249        myLog->addListener(this);
250#endif
251
252        // Root will detect that we've already created a Log
253        COUT(4) << "Creating Ogre Root..." << std::endl;
254
255        if (ogrePluginsFile_ == "")
256        {
257            COUT(2) << "Warning: Ogre plugins file set to \"\". Defaulting to plugins.cfg" << std::endl;
258            ModifyConfigValue(ogrePluginsFile_, tset, "plugins.cfg");
259        }
260        if (ogreConfigFile_ == "")
261        {
262            COUT(2) << "Warning: Ogre config file set to \"\". Defaulting to config.cfg" << std::endl;
263            ModifyConfigValue(ogreConfigFile_, tset, "config.cfg");
264        }
265        if (ogreLogFile_ == "")
266        {
267            COUT(2) << "Warning: Ogre log file set to \"\". Defaulting to ogre.log" << std::endl;
268            ModifyConfigValue(ogreLogFile_, tset, "ogre.log");
269        }
270
271        // check for config file existence because Ogre displays (caught) exceptions if not
272        std::ifstream probe;
273        probe.open(ogreConfigFile_.c_str());
274        if (!probe)
275        {
276            // create a zero sized file
277            std::ofstream creator;
278            creator.open(ogreConfigFile_.c_str());
279            creator.close();
280        }
281        else
282            probe.close();
283
284        ogreRoot_ = new Ogre::Root(ogrePluginsFile_, ogreConfigFile_, ogreLogFile_);
285
286#if 0 // Ogre 1.4.3 doesn't yet support setDebugOutputEnabled(.)
287#if ORXONOX_PLATFORM != ORXONOX_PLATFORM_WIN32
288        // tame the ogre ouput so we don't get all the mess in the console
289        Ogre::Log* defaultLog = Ogre::LogManager::getSingleton().getDefaultLog();
290        defaultLog->setDebugOutputEnabled(false);
291        defaultLog->setLogDetail(Ogre::LL_BOREME);
292        defaultLog->addListener(this);
293#endif
294#endif
295
296        COUT(3) << "Ogre set up done." << std::endl;
297    }
298
299    /**
300    @brief
301        Method called by the LogListener interface from Ogre.
302        We use it to capture Ogre log messages and handle it ourselves.
303    @param message
304        The message to be logged
305    @param lml
306        The message level the log is using
307    @param maskDebug
308        If we are printing to the console or not
309    @param logName
310        The name of this log (so you can have several listeners
311        for different logs, and identify them)
312    */
313    void GSRoot::messageLogged(const std::string& message,
314        Ogre::LogMessageLevel lml, bool maskDebug, const std::string& logName)
315    {
316        int orxonoxLevel;
317        switch (lml)
318        {
319        case Ogre::LML_TRIVIAL:
320            orxonoxLevel = this->ogreLogLevelTrivial_;
321            break;
322        case Ogre::LML_NORMAL:
323            orxonoxLevel = this->ogreLogLevelNormal_;
324            break;
325        case Ogre::LML_CRITICAL:
326            orxonoxLevel = this->ogreLogLevelCritical_;
327            break;
328        default:
329            orxonoxLevel = 0;
330        }
331        OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
332            << "Ogre: " << message << std::endl;
333    }
[1661]334}
Note: See TracBrowser for help on using the repository browser.