Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1880 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
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 "tools/Timer.h"
47#include "GraphicsEngine.h"
48#include "Settings.h"
49
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
65namespace orxonox
66{
67    SetCommandLineArgument(dataPath, "").setInformation("PATH");
68    SetCommandLineArgument(limitToCPU, 1).setInformation("0: off | #cpu");
69
70    GSRoot::GSRoot()
71        : RootGameState("root")
72        , settings_(0)
73        , ogreRoot_(0)
74        , ogreLogger_(0)
75        , graphicsEngine_(0)
76        , tclBind_(0)
77        , tclThreadManager_(0)
78        , shell_(0)
79    {
80        RegisterRootObject(GSRoot);
81    }
82
83    GSRoot::~GSRoot()
84    {
85    }
86
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
98    void GSRoot::enter()
99    {
100#if ORXONOX_DEBUG_MODE == 1
101        ConfigFileManager::getInstance().setFile(CFT_Settings, "orxonox_d.ini");
102#else
103        ConfigFileManager::getInstance().setFile(CFT_Settings, "orxonox.ini");
104#endif
105
106        // do this after the previous call..
107        setConfigValues();
108
109        // creates the class hierarchy for all classes with factories
110        Factory::createClassHierarchy();
111
112        // instantiate Settings class
113        this->settings_ = new Settings();
114
115        std::string dataPath;
116        CommandLine::getValue("dataPath", &dataPath);
117        if (dataPath != "")
118        {
119            if (*dataPath.end() != '/' && *dataPath.end() != '\\')
120                Settings::tsetDataPath(dataPath + "/");
121            else
122                Settings::tsetDataPath(dataPath);
123        }
124
125        // initialise TCL
126        this->tclBind_ = new TclBind(Settings::getDataPath());
127        this->tclThreadManager_ = new TclThreadManager(tclBind_->getTclInterpreter());
128
129        // create a shell
130        this->shell_ = new Shell();
131
132        setupOgre();
133
134        // initialise graphics engine. Doesn't load the render window yet!
135        graphicsEngine_ = new GraphicsEngine();
136
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).
140        int limitToCPU;
141        CommandLine::getValue("limitToCPU", &limitToCPU);
142        if (limitToCPU > 0)
143            setThreadAffinity((unsigned int)(limitToCPU - 1));
144
145        // add console commands
146        FunctorMember<GSRoot>* functor1 = createFunctor(&GSRoot::exitGame);
147        functor1->setObject(this);
148        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor1, "exit"));
149
150        // add console commands
151        FunctorMember01<GameStateBase, const std::string&>* functor2 = createFunctor(&GameStateBase::requestState);
152        functor2->setObject(this);
153        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor2, "selectGameState"));
154    }
155
156    void GSRoot::leave()
157    {
158        // TODO: remove and destroy console commands
159
160        delete graphicsEngine_;
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
171        delete this->shell_;
172        delete this->tclThreadManager_;
173        delete this->tclBind_;
174
175        delete settings_;
176
177    }
178
179    void GSRoot::ticked(const Clock& time)
180    {
181        TclThreadManager::getInstance().tick(time.getDeltaTime());
182
183        for (ObjectList<TimerBase>::iterator it = ObjectList<TimerBase>::begin(); it; ++it)
184            it->tick(time);
185
186        this->tickChild(time);
187    }
188
189    /**
190    @note
191        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
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    */
199    void GSRoot::setThreadAffinity(unsigned int limitToCPU)
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
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
221        DWORD threadMask = 1;
222            while ((threadMask & procMask) == 0 || (threadMask < (1u << limitToCPU)))
223                    threadMask <<= 1;
224
225            // Set affinity to the first core
226            SetThreadAffinityMask(GetCurrentThread(), threadMask);
227#endif
228    }
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    }
338}
Note: See TracBrowser for help on using the repository browser.