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
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 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30#include "GSRoot.h"
31
32#include <OgreLogManager.h>
33#include <OgreRoot.h>
34
35#include "util/Exception.h"
36#include "util/Debug.h"
37#include "core/Factory.h"
38#include "core/ConfigFileManager.h"
39#include "core/ConfigValueIncludes.h"
40#include "core/CoreIncludes.h"
41#include "core/ConsoleCommand.h"
42#include "core/CommandLine.h"
43#include "core/Shell.h"
44#include "core/TclBind.h"
45#include "core/TclThreadManager.h"
46#include "GraphicsEngine.h"
47#include "Settings.h"
48
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
64namespace orxonox
65{
66    SetCommandLineArgument(dataPath, "").setInformation("PATH");
67    SetCommandLineArgument(limitToCPU, 1).setInformation("0: off | #cpu");
68
69    GSRoot::GSRoot()
70        : RootGameState("root")
71        , settings_(0)
72        , ogreRoot_(0)
73        , ogreLogger_(0)
74        , graphicsEngine_(0)
75        , tclBind_(0)
76        , tclThreadManager_(0)
77        , shell_(0)
78    {
79        RegisterRootObject(GSRoot);
80    }
81
82    GSRoot::~GSRoot()
83    {
84    }
85
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
97    void GSRoot::enter()
98    {
99#if ORXONOX_DEBUG_MODE == 1
100        ConfigFileManager::getInstance()->setFile(CFT_Settings, "orxonox_d.ini");
101#else
102        ConfigFileManager::getInstance()->setFile(CFT_Settings, "orxonox.ini");
103#endif
104
105        // do this after the previous call..
106        setConfigValues();
107
108        // creates the class hierarchy for all classes with factories
109        Factory::createClassHierarchy();
110
111        // instantiate Settings class
112        this->settings_ = new Settings();
113
114        std::string dataPath;
115        CommandLine::getValue("dataPath", &dataPath);
116        if (dataPath != "")
117        {
118            if (*dataPath.end() != '/' && *dataPath.end() != '\\')
119                Settings::tsetDataPath(dataPath + "/");
120            else
121                Settings::tsetDataPath(dataPath);
122        }
123
124        // initialise TCL
125        this->tclBind_ = new TclBind(Settings::getDataPath());
126        this->tclThreadManager_ = new TclThreadManager(tclBind_->getTclInterpreter());
127
128        // create a shell
129        this->shell_ = new Shell();
130
131        setupOgre();
132
133        // initialise graphics engine. Doesn't load the render window yet!
134        graphicsEngine_ = new GraphicsEngine();
135
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).
139        int limitToCPU;
140        CommandLine::getValue("limitToCPU", &limitToCPU);
141        if (limitToCPU > 0)
142            setThreadAffinity((unsigned int)(limitToCPU - 1));
143
144        // add console commands
145        FunctorMember<GSRoot>* functor1 = createFunctor(&GSRoot::exitGame);
146        functor1->setObject(this);
147        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor1, "exit"));
148
149        // add console commands
150        FunctorMember01<GameStateBase, const std::string&>* functor2 = createFunctor(&GameStateBase::requestState);
151        functor2->setObject(this);
152        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor2, "selectGameState"));
153    }
154
155    void GSRoot::leave()
156    {
157        // TODO: remove and destroy console commands
158
159        delete graphicsEngine_;
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
170        delete this->shell_;
171        delete this->tclThreadManager_;
172        delete this->tclBind_;
173
174        delete settings_;
175
176    }
177
178    void GSRoot::ticked(const Clock& time)
179    {
180        TclThreadManager::getInstance().tick(time.getDeltaTime());
181
182        this->tickChild(time);
183    }
184
185    /**
186    @note
187        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
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    */
195    void GSRoot::setThreadAffinity(unsigned int limitToCPU)
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
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
217        DWORD threadMask = 1;
218            while ((threadMask & procMask) == 0 || (threadMask < (1u << limitToCPU)))
219                    threadMask <<= 1;
220
221            // Set affinity to the first core
222            SetThreadAffinityMask(GetCurrentThread(), threadMask);
223#endif
224    }
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    }
334}
Note: See TracBrowser for help on using the repository browser.