Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/orxonox/GraphicsEngine.cc @ 1653

Last change on this file since 1653 was 1653, checked in by rgrieder, 16 years ago
  • getInstance is probably more suitable than getSingleton (as x3n has already done so in most of his classes) I changed it in Orxonox and GraphicsEngine. Maybe more to come.
  • Removed derivation from BaseObject in InputState (templates work well too, don't need a factory at all)
  • Property svn:eol-style set to native
File size: 15.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 *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007
25 *   Co-authors:
26 *      Felix Schulthess
27 *
28 */
29
30/**
31@file
32@brief
33    Implementation of an partial interface to Ogre.
34*/
35
36#include "OrxonoxStableHeaders.h"
37#include "GraphicsEngine.h"
38
39#include <fstream>
40
41#include <OgreConfigFile.h>
42#include <OgreException.h>
43#include <OgreLogManager.h>
44#include <OgreRoot.h>
45#include <OgreSceneManager.h>
46#include <OgreTextureManager.h>
47#include <OgreViewport.h>
48
49#include "core/CoreIncludes.h"
50#include "core/ConfigValueIncludes.h"
51#include "core/Debug.h"
52#include "core/CommandExecutor.h"
53#include "core/ConsoleCommand.h"
54#include "core/Exception.h"
55
56#include "overlays/console/InGameConsole.h"
57#include "overlays/OverlayGroup.h"
58#include "tools/ParticleInterface.h"
59#include "Settings.h"
60#include "tools/WindowEventListener.h"
61
62#include "objects/CameraHandler.h"
63
64namespace orxonox
65{
66    SetConsoleCommand(GraphicsEngine, printScreen, true).setKeybindMode(KeybindMode::OnPress);
67
68    GraphicsEngine* GraphicsEngine::singletonRef_s = 0;
69
70    /**
71    @brief
72        Returns the singleton instance.
73    @return
74        The only instance of GraphicsEngine.
75    */
76    /*static*/ GraphicsEngine& GraphicsEngine::getInstance()
77    {
78        assert(singletonRef_s);
79        return *singletonRef_s;
80    }
81
82    /**
83    @brief
84        Non-initialising constructor.
85    */
86    GraphicsEngine::GraphicsEngine()
87        : root_(0)
88        , renderWindow_(0)
89        , levelSceneManager_(0)
90        , viewport_(0)
91    {
92        RegisterObject(GraphicsEngine);
93
94        assert(singletonRef_s == 0);
95        singletonRef_s = this;
96
97        this->detailLevelParticle_ = 0;
98
99        this->setConfigValues();
100        CCOUT(4) << "Constructed" << std::endl;
101    }
102
103    void GraphicsEngine::setConfigValues()
104    {
105        SetConfigValue(resourceFile_,    "resources.cfg").description("Location of the resources file in the data path.");
106        SetConfigValue(ogreConfigFile_,  "ogre.cfg").description("Location of the Ogre config file");
107        SetConfigValue(ogrePluginsFile_, "plugins.cfg").description("Location of the Ogre plugins file");
108        SetConfigValue(ogreLogFile_,     "ogre.log").description("Logfile for messages from Ogre. \
109                                                                 Use \"\" to suppress log file creation.");
110        SetConfigValue(ogreLogLevelTrivial_ , 5).description("Corresponding orxonox debug level for ogre Trivial");
111        SetConfigValue(ogreLogLevelNormal_  , 4).description("Corresponding orxonox debug level for ogre Normal");
112        SetConfigValue(ogreLogLevelCritical_, 2).description("Corresponding orxonox debug level for ogre Critical");
113
114        unsigned int old = this->detailLevelParticle_;
115        SetConfigValue(detailLevelParticle_, 2).description("O: off, 1: low, 2: normal, 3: high");
116
117        if (this->detailLevelParticle_ != old)
118            for (Iterator<ParticleInterface> it = ObjectList<ParticleInterface>::begin(); it; ++it)
119                it->detailLevelChanged(this->detailLevelParticle_);
120    }
121
122    /**
123    @brief
124        Destroys all the Ogre related objects
125    */
126    GraphicsEngine::~GraphicsEngine()
127    {
128        CCOUT(4) << "Destroying objects..." << std::endl;
129        Ogre::WindowEventUtilities::removeWindowEventListener(this->renderWindow_, this);
130        if (this->root_)
131            delete this->root_;
132
133#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
134        // delete the ogre log and the logManager (since we have created it).
135        if (Ogre::LogManager::getSingletonPtr() != 0)
136        {
137            Ogre::LogManager::getSingleton().getDefaultLog()->removeListener(this);
138            Ogre::LogManager::getSingleton().destroyLog(Ogre::LogManager::getSingleton().getDefaultLog());
139            delete Ogre::LogManager::getSingletonPtr();
140        }
141        CCOUT(4) << "Destroying objects done" << std::endl;
142#endif
143
144        singletonRef_s = 0;
145    }
146
147    /**
148    @brief
149        Creates the Ogre Root object and sets up the ogre log.
150    */
151    void GraphicsEngine::setup()
152    {
153        CCOUT(3) << "Setting up..." << std::endl;
154
155        // TODO: LogManager doesn't work on oli platform. The why is yet unknown.
156#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
157        // create a new logManager
158        Ogre::LogManager* logger = new Ogre::LogManager();
159        CCOUT(4) << "Ogre LogManager created" << std::endl;
160
161        // create our own log that we can listen to
162        Ogre::Log *myLog;
163        if (this->ogreLogFile_ == "")
164            myLog = logger->createLog("ogre.log", true, false, true);
165        else
166            myLog = logger->createLog(this->ogreLogFile_, true, false, false);
167        CCOUT(4) << "Ogre Log created" << std::endl;
168
169        myLog->setLogDetail(Ogre::LL_BOREME);
170        myLog->addListener(this);
171#endif
172
173        // Root will detect that we've already created a Log
174        CCOUT(4) << "Creating Ogre Root..." << std::endl;
175
176        if (ogrePluginsFile_ == "")
177        {
178            COUT(2) << "Warning: Ogre plugins file set to \"\". Defaulting to plugins.cfg" << std::endl;
179            ModifyConfigValue(ogrePluginsFile_, tset, "plugins.cfg");
180        }
181        if (ogreConfigFile_ == "")
182        {
183            COUT(2) << "Warning: Ogre config file set to \"\". Defaulting to config.cfg" << std::endl;
184            ModifyConfigValue(ogreConfigFile_, tset, "config.cfg");
185        }
186        if (ogreLogFile_ == "")
187        {
188            COUT(2) << "Warning: Ogre log file set to \"\". Defaulting to ogre.log" << std::endl;
189            ModifyConfigValue(ogreLogFile_, tset, "ogre.log");
190        }
191
192        root_ = new Ogre::Root(ogrePluginsFile_, ogreConfigFile_, ogreLogFile_);
193
194        // We don't need plugins for the dedicated..
195        //if (!root_->getInstalledPlugins().size() > 0)
196        //{
197        //    ThrowException(PluginsNotFound, "No Ogre plugins declared. Cannot load Ogre.");
198        //}
199
200#if 0 // Ogre 1.4.3 doesn't yet support setDebugOutputEnabled(.)
201#if ORXONOX_PLATFORM != ORXONOX_PLATFORM_WIN32
202        // tame the ogre ouput so we don't get all the mess in the console
203        Ogre::Log* defaultLog = Ogre::LogManager::getSingleton().getDefaultLog();
204        defaultLog->setDebugOutputEnabled(false);
205        defaultLog->setLogDetail(Ogre::LL_BOREME);
206        defaultLog->addListener(this);
207#endif
208#endif
209
210        CCOUT(4) << "Creating Ogre Root done" << std::endl;
211
212        // specify where Ogre has to look for resources. This call doesn't parse anything yet!
213        declareRessourceLocations();
214
215        CCOUT(3) << "Set up done." << std::endl;
216    }
217
218    void GraphicsEngine::declareRessourceLocations()
219    {
220        CCOUT(4) << "Declaring Resources" << std::endl;
221        //TODO: Specify layout of data file and maybe use xml-loader
222        //TODO: Work with ressource groups (should be generated by a special loader)
223
224        if (resourceFile_ == "")
225        {
226            COUT(2) << "Warning: Ogre resource file set to \"\". Defaulting to resources.cfg" << std::endl;
227            ModifyConfigValue(resourceFile_, tset, "resources.cfg");
228        }
229
230        // Load resource paths from data file using configfile ressource type
231        Ogre::ConfigFile cf;
232        try
233        {
234            cf.load(Settings::getDataPath() + resourceFile_);
235        }
236        catch (...)
237        {
238            //COUT(1) << ex.getFullDescription() << std::endl;
239            COUT(0) << "Have you forgotten to set the data path in orxnox.ini?" << std::endl;
240            throw;
241        }
242
243        // Go through all sections & settings in the file
244        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
245
246        std::string secName, typeName, archName;
247        while (seci.hasMoreElements())
248        {
249            try
250            {
251                secName = seci.peekNextKey();
252                Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
253                Ogre::ConfigFile::SettingsMultiMap::iterator i;
254                for (i = settings->begin(); i != settings->end(); ++i)
255                {
256                    typeName = i->first; // for instance "FileSystem" or "Zip"
257                    archName = i->second; // name (and location) of archive
258
259                    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
260                        std::string(Settings::getDataPath() + archName), typeName, secName);
261                }
262            }
263            catch (Ogre::Exception& ex)
264            {
265                COUT(1) << ex.getFullDescription() << std::endl;
266            }
267        }
268    }
269
270    void GraphicsEngine::loadRenderer()
271    {
272        CCOUT(4) << "Configuring Renderer" << std::endl;
273
274        // check for file existence because Ogre displays exceptions if not
275        std::ifstream probe;
276        probe.open(ogreConfigFile_.c_str());
277        if (!probe)
278        {
279            // create a zero sized file
280            std::ofstream creator;
281            creator.open(ogreConfigFile_.c_str());
282            creator.close();
283        }
284        else
285            probe.close();
286
287        if (!root_->restoreConfig())
288            if (!root_->showConfigDialog())
289                ThrowException(InitialisationFailed, "Could not show Ogre configuration dialogue.");
290
291        CCOUT(4) << "Creating render window" << std::endl;
292
293        this->renderWindow_ = root_->initialise(true, "OrxonoxV2");
294
295        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, this);
296
297        //Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
298
299        // create a full screen default viewport
300        this->viewport_ = this->renderWindow_->addViewport(0, 0);
301    }
302
303    void GraphicsEngine::initialiseResources()
304    {
305        CCOUT(4) << "Initialising resources" << std::endl;
306        //TODO: Do NOT load all the groups, why are we doing that? And do we really do that? initialise != load...
307        try
308        {
309            Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
310            /*Ogre::StringVector str = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
311            for (unsigned int i = 0; i < str.size(); i++)
312            {
313            Ogre::ResourceGroupManager::getSingleton().loadResourceGroup(str[i]);
314            }*/
315        }
316        catch (...)
317        {
318            CCOUT(2) << "Error: There was a serious error when initialising the resources." << std::endl;
319            throw;
320        }
321    }
322
323    /**
324    @brief
325        Creates the SceneManager
326    */
327    void GraphicsEngine::createNewScene()
328    {
329        CCOUT(4) << "Creating new SceneManager..." << std::endl;
330        if (levelSceneManager_)
331        {
332            CCOUT(2) << "SceneManager already exists! Skipping." << std::endl;
333        }
334        this->levelSceneManager_ = this->root_->createSceneManager(Ogre::ST_GENERIC, "LevelSceneManager");
335        CCOUT(3) << "Created SceneManager: " << levelSceneManager_->getName() << std::endl;
336    }
337
338    /**
339    @brief
340        Returns the window handle of the render window.
341        At least the InputHandler uses this to create the OIS::InputManager
342    @return
343        The window handle of the render window
344    */
345    size_t GraphicsEngine::getWindowHandle()
346    {
347        if (this->renderWindow_)
348        {
349            size_t windowHnd = 0;
350            this->renderWindow_->getCustomAttribute("WINDOW", &windowHnd);
351            return windowHnd;
352        }
353        else
354            return 0;
355    }
356
357    /**
358    @brief
359        Get the width of the render window
360    @return
361        The width of the render window
362    */
363    int GraphicsEngine::getWindowWidth() const
364    {
365        if (this->renderWindow_)
366            return this->renderWindow_->getWidth();
367        else
368            return 0;
369    }
370
371    /**
372    @brief
373        Get the height of the render window
374    @return
375        The height of the render window
376    */
377    int GraphicsEngine::getWindowHeight() const
378    {
379        if (this->renderWindow_)
380            return this->renderWindow_->getHeight();
381        else
382            return 0;
383    }
384
385    /**
386    @brief
387        Returns the window aspect ratio height/width.
388    @return
389        The window aspect ratio
390    */
391    float GraphicsEngine::getWindowAspectRatio() const
392    {
393        if (this->renderWindow_)
394            return (float)this->renderWindow_->getHeight() / (float)this->renderWindow_->getWidth();
395        else
396            return 1.0f;
397    }
398
399    /**
400    @brief
401        Method called by the LogListener interface from Ogre.
402        We use it to capture Ogre log messages and handle it ourselves.
403    @param message
404        The message to be logged
405    @param lml
406        The message level the log is using
407    @param maskDebug
408        If we are printing to the console or not
409    @param logName
410        The name of this log (so you can have several listeners
411        for different logs, and identify them)
412    */
413    void GraphicsEngine::messageLogged(const std::string& message,
414        Ogre::LogMessageLevel lml, bool maskDebug, const std::string &logName)
415    {
416        int orxonoxLevel;
417        switch (lml)
418        {
419        case Ogre::LML_TRIVIAL:
420            orxonoxLevel = this->ogreLogLevelTrivial_;
421            break;
422        case Ogre::LML_NORMAL:
423            orxonoxLevel = this->ogreLogLevelNormal_;
424            break;
425        case Ogre::LML_CRITICAL:
426            orxonoxLevel = this->ogreLogLevelCritical_;
427            break;
428        default:
429            orxonoxLevel = 0;
430        }
431        OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
432            << "Ogre: " << message << std::endl;
433    }
434
435    /**
436    @brief
437        Window has moved.
438    @param rw
439        The render window it occured in
440    */
441    void GraphicsEngine::windowMoved(Ogre::RenderWindow *rw)
442    {
443        for (Iterator<orxonox::WindowEventListener> it = ObjectList<orxonox::WindowEventListener>::start(); it; ++it)
444            it->windowMoved();
445    }
446
447    /**
448    @brief
449        Window has resized.
450    @param rw
451        The render window it occured in
452    @note
453        GraphicsEngine has a render window stored itself. This is the same
454        as rw. But we have to be careful when using multiple render windows!
455    */
456    void GraphicsEngine::windowResized(Ogre::RenderWindow *rw)
457    {
458        for (Iterator<orxonox::WindowEventListener> it = ObjectList<orxonox::WindowEventListener>::start(); it; ++it)
459            it->windowResized(this->renderWindow_->getWidth(), this->renderWindow_->getHeight());
460    }
461
462    /**
463    @brief
464        Window focus has changed.
465    @param rw
466        The render window it occured in
467    */
468    void GraphicsEngine::windowFocusChanged(Ogre::RenderWindow *rw)
469    {
470        for (Iterator<orxonox::WindowEventListener> it = ObjectList<orxonox::WindowEventListener>::start(); it; ++it)
471            it->windowFocusChanged();
472    }
473
474    /**
475    @brief
476        Window was closed.
477    @param rw
478        The render window it occured in
479    */
480    void GraphicsEngine::windowClosed(Ogre::RenderWindow *rw)
481    {
482        // using CommandExecutor in order to avoid depending on Orxonox.h.
483        CommandExecutor::execute("exit", false);
484    }
485
486
487    /*static*/ void GraphicsEngine::printScreen()
488    {
489        if (getInstance().renderWindow_)
490        {
491            getInstance().renderWindow_->writeContentsToTimestampedFile("shot_", ".jpg");
492        }
493    }
494}
Note: See TracBrowser for help on using the repository browser.