Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

TimerBase are now ticked in GSRoot to be able to use them anywhere.

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