Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Mar 19, 2009, 10:58:43 AM (15 years ago)
Author:
rgrieder
Message:

Move graphic related content of GSGraphics to GraphicsManager which originally was GraphisEngine (but since we don't have an engine of our own, I renamed it).
Reduced OgreWindowEventUtilities.h dependency from GraphisManager.h (includes windows.h).

File:
1 moved

Legend:

Unmodified
Added
Removed
  • code/branches/gui/src/orxonox/GraphicsManager.cc

    r2797 r2801  
    3535
    3636#include "OrxonoxStableHeaders.h"
    37 #include "GraphicsEngine.h"
    38 
     37#include "GraphicsManager.h"
     38
     39#include <fstream>
     40#include <boost/filesystem.hpp>
     41
     42#include <OgreCompositorManager.h>
     43#include <OgreConfigFile.h>
     44#include <OgreFrameListener.h>
     45#include <OgreRoot.h>
     46#include <OgreLogManager.h>
     47#include <OgreException.h>
    3948#include <OgreRenderWindow.h>
    40 
     49#include <OgreRenderSystem.h>
     50#include <OgreTextureManager.h>
     51#include <OgreViewport.h>
     52#include <OgreWindowEventUtilities.h>
     53
     54#include "SpecialConfig.h"
     55#include "util/Debug.h"
     56#include "util/Exception.h"
     57#include "util/String.h"
     58#include "util/SubString.h"
     59#include "core/ConsoleCommand.h"
     60#include "core/ConfigValueIncludes.h"
    4161#include "core/CoreIncludes.h"
    42 #include "core/ConfigValueIncludes.h"
    43 #include "util/Debug.h"
    44 
     62#include "core/Core.h"
     63#include "tools/WindowEventListener.h"
    4564#include "tools/ParticleInterface.h"
    4665
    4766namespace orxonox
    4867{
    49     //SetConsoleCommand(GraphicsEngine, printScreen, true).setKeybindMode(KeybindMode::OnPress);
    50 
    51     GraphicsEngine* GraphicsEngine::singletonRef_s = 0;
    52 
    53     /**
    54     @brief
    55         Returns the singleton instance.
    56     @return
    57         The only instance of GraphicsEngine.
    58     */
    59     /*static*/ GraphicsEngine& GraphicsEngine::getInstance()
    60     {
    61         assert(singletonRef_s);
    62         return *singletonRef_s;
    63     }
     68    class _OrxonoxExport OgreWindowEventListener : public Ogre::WindowEventListener
     69    {
     70        void windowResized     (Ogre::RenderWindow* rw);
     71        void windowFocusChange (Ogre::RenderWindow* rw);
     72        void windowClosed      (Ogre::RenderWindow* rw);
     73        //void windowMoved       (Ogre::RenderWindow* rw);
     74    };
     75
     76    GraphicsManager* GraphicsManager::singletonRef_s = 0;
    6477
    6578    /**
     
    6780        Non-initialising constructor.
    6881    */
    69     GraphicsEngine::GraphicsEngine()
    70 //        : root_(0)
    71 //        , renderWindow_(0)
    72 //        , viewport_(0)
    73     {
    74         RegisterObject(GraphicsEngine);
     82    GraphicsManager::GraphicsManager()
     83        : ogreRoot_(0)
     84        , ogreLogger_(0)
     85        , renderWindow_(0)
     86        , viewport_(0)
     87        , ogreWindowEventListener_(0)
     88        , avgTickTime_(0.0f)
     89        , avgFramesPerSecond_(0.0f)
     90    {
     91        RegisterObject(GraphicsManager);
    7592
    7693        assert(singletonRef_s == 0);
    7794        singletonRef_s = this;
    7895
    79         this->viewport_ = 0;
    80 
    81         this->detailLevelParticle_ = 0;
     96        this->loaded_ = false;
    8297
    8398        this->setConfigValues();
    84         CCOUT(4) << "Constructed" << std::endl;
    85     }
    86 
    87     void GraphicsEngine::setConfigValues()
    88     {
    89         SetConfigValue(detailLevelParticle_, 2).description("O: off, 1: low, 2: normal, 3: high").callback(this, &GraphicsEngine::detailLevelParticleChanged);
    90     }
    91 
    92     void GraphicsEngine::detailLevelParticleChanged()
    93     {
    94         for (ObjectList<ParticleInterface>::iterator it = ObjectList<ParticleInterface>::begin(); it; ++it)
    95             it->detailLevelChanged(this->detailLevelParticle_);
     99    }
     100
     101    void GraphicsManager::initialise()
     102    {
     103        Core::setShowsGraphics(true);
     104
     105        // Ogre setup procedure
     106        setupOgre();
     107        // load all the required plugins for Ogre
     108        loadOgrePlugins();
     109        // read resource declaration file
     110        this->declareResources();
     111        // Reads ogre config and creates the render window
     112        this->loadRenderer();
     113
     114        // TODO: Spread this
     115        this->initialiseResources();
     116
     117        // add console commands
     118        FunctorMember<GraphicsManager>* functor1 = createFunctor(&GraphicsManager::printScreen);
     119        functor1->setObject(this);
     120        ccPrintScreen_ = createConsoleCommand(functor1, "printScreen");
     121        CommandExecutor::addConsoleCommandShortcut(ccPrintScreen_);
     122
     123        this->loaded_ = true;
    96124    }
    97125
     
    100128        Destroys all the Ogre related objects
    101129    */
    102     GraphicsEngine::~GraphicsEngine()
    103     {
     130    GraphicsManager::~GraphicsManager()
     131    {
     132        if (this->loaded_)
     133        {
     134            delete this->ccPrintScreen_;
     135
     136            if (this->ogreWindowEventListener_)
     137            {
     138                // remove our WindowEventListener first to avoid bad calls after the window has been destroyed
     139                Ogre::WindowEventUtilities::removeWindowEventListener(this->renderWindow_, this->ogreWindowEventListener_);
     140                delete this->ogreWindowEventListener_;
     141            }
     142
     143            // unload all compositors
     144            Ogre::CompositorManager::getSingleton().removeAll();
     145
     146            // destroy render window
     147            Ogre::RenderSystem* renderer = this->ogreRoot_->getRenderSystem();
     148            renderer->destroyRenderWindow("Orxonox");
     149
     150            // Delete OGRE main control organ
     151            delete this->ogreRoot_;
     152
     153            // delete the ogre log and the logManager (since we have created it in the first place).
     154            this->ogreLogger_->getDefaultLog()->removeListener(this);
     155            this->ogreLogger_->destroyLog(Ogre::LogManager::getSingleton().getDefaultLog());
     156            delete this->ogreLogger_;
     157
     158            // Don't showing graphics anymore
     159            Core::setShowsGraphics(false);
     160        }
     161
     162        assert(singletonRef_s);
    104163        singletonRef_s = 0;
    105164    }
     165
     166    void GraphicsManager::setConfigValues()
     167    {
     168        SetConfigValue(resourceFile_,    "resources.cfg")
     169            .description("Location of the resources file in the data path.");
     170        SetConfigValue(ogreConfigFile_,  "ogre.cfg")
     171            .description("Location of the Ogre config file");
     172        SetConfigValue(ogrePluginsFolder_, ORXONOX_OGRE_PLUGINS_FOLDER)
     173            .description("Folder where the Ogre plugins are located.");
     174        SetConfigValue(ogrePlugins_, ORXONOX_OGRE_PLUGINS)
     175            .description("Comma separated list of all plugins to load.");
     176        SetConfigValue(ogreLogFile_,     "ogre.log")
     177            .description("Logfile for messages from Ogre. Use \"\" to suppress log file creation.");
     178        SetConfigValue(ogreLogLevelTrivial_ , 5)
     179            .description("Corresponding orxonox debug level for ogre Trivial");
     180        SetConfigValue(ogreLogLevelNormal_  , 4)
     181            .description("Corresponding orxonox debug level for ogre Normal");
     182        SetConfigValue(ogreLogLevelCritical_, 2)
     183            .description("Corresponding orxonox debug level for ogre Critical");
     184        SetConfigValue(detailLevelParticle_, 2)
     185            .description("O: off, 1: low, 2: normal, 3: high").callback(this, &GraphicsManager::detailLevelParticleChanged);
     186    }
     187
     188    void GraphicsManager::detailLevelParticleChanged()
     189    {
     190        for (ObjectList<ParticleInterface>::iterator it = ObjectList<ParticleInterface>::begin(); it; ++it)
     191            it->detailLevelChanged(this->detailLevelParticle_);
     192    }
     193
     194    void GraphicsManager::update(const Clock& time)
     195    {
     196        if (this->loaded_)
     197        {
     198            Ogre::FrameEvent evt;
     199            evt.timeSinceLastFrame = time.getDeltaTime();
     200            evt.timeSinceLastEvent = time.getDeltaTime(); // note: same time, but shouldn't matter anyway
     201
     202            // don't forget to call _fireFrameStarted to OGRE to make sure
     203            // everything goes smoothly
     204            ogreRoot_->_fireFrameStarted(evt);
     205
     206            // Pump messages in all registered RenderWindows
     207            // This calls the WindowEventListener objects.
     208            Ogre::WindowEventUtilities::messagePump();
     209            // make sure the window stays active even when not focused
     210            // (probably only necessary on windows)
     211            this->renderWindow_->setActive(true);
     212
     213            // render
     214            ogreRoot_->_updateAllRenderTargets();
     215
     216            // again, just to be sure OGRE works fine
     217            ogreRoot_->_fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
     218        }
     219    }
     220
     221    /**
     222    @brief
     223        Creates the Ogre Root object and sets up the ogre log.
     224    */
     225    void GraphicsManager::setupOgre()
     226    {
     227        COUT(3) << "Setting up Ogre..." << std::endl;
     228
     229        if (ogreConfigFile_ == "")
     230        {
     231            COUT(2) << "Warning: Ogre config file set to \"\". Defaulting to config.cfg" << std::endl;
     232            ModifyConfigValue(ogreConfigFile_, tset, "config.cfg");
     233        }
     234        if (ogreLogFile_ == "")
     235        {
     236            COUT(2) << "Warning: Ogre log file set to \"\". Defaulting to ogre.log" << std::endl;
     237            ModifyConfigValue(ogreLogFile_, tset, "ogre.log");
     238        }
     239
     240        boost::filesystem::path ogreConfigFilepath(Core::getConfigPath() / this->ogreConfigFile_);
     241        boost::filesystem::path ogreLogFilepath(Core::getLogPath() / this->ogreLogFile_);
     242
     243        // create a new logManager
     244        // Ogre::Root will detect that we've already created a Log
     245        ogreLogger_ = new Ogre::LogManager();
     246        COUT(4) << "Ogre LogManager created" << std::endl;
     247
     248        // create our own log that we can listen to
     249        Ogre::Log *myLog;
     250        myLog = ogreLogger_->createLog(ogreLogFilepath.string(), true, false, false);
     251        COUT(4) << "Ogre Log created" << std::endl;
     252
     253        myLog->setLogDetail(Ogre::LL_BOREME);
     254        myLog->addListener(this);
     255
     256        COUT(4) << "Creating Ogre Root..." << std::endl;
     257
     258        // check for config file existence because Ogre displays (caught) exceptions if not
     259        if (!boost::filesystem::exists(ogreConfigFilepath))
     260        {
     261            // create a zero sized file
     262            std::ofstream creator;
     263            creator.open(ogreConfigFilepath.string().c_str());
     264            creator.close();
     265        }
     266
     267        // Leave plugins file empty. We're going to do that part manually later
     268        ogreRoot_ = new Ogre::Root("", ogreConfigFilepath.string(), ogreLogFilepath.string());
     269
     270        COUT(3) << "Ogre set up done." << std::endl;
     271    }
     272
     273    void GraphicsManager::loadOgrePlugins()
     274    {
     275        // just to make sure the next statement doesn't segfault
     276        if (ogrePluginsFolder_ == "")
     277            ogrePluginsFolder_ = ".";
     278
     279        boost::filesystem::path folder(ogrePluginsFolder_);
     280        // Do some SubString magic to get the comma separated list of plugins
     281        SubString plugins(ogrePlugins_, ",", " ", false, 92, false, 34, false, 40, 41, false, '\0');
     282        // Use backslash paths on Windows! file_string() already does that though.
     283        for (unsigned int i = 0; i < plugins.size(); ++i)
     284            ogreRoot_->loadPlugin((folder / plugins[i]).file_string());
     285    }
     286
     287    void GraphicsManager::declareResources()
     288    {
     289        CCOUT(4) << "Declaring Resources" << std::endl;
     290        //TODO: Specify layout of data file and maybe use xml-loader
     291        //TODO: Work with ressource groups (should be generated by a special loader)
     292
     293        if (resourceFile_ == "")
     294        {
     295            COUT(2) << "Warning: Ogre resource file set to \"\". Defaulting to resources.cfg" << std::endl;
     296            ModifyConfigValue(resourceFile_, tset, "resources.cfg");
     297        }
     298
     299        // Load resource paths from data file using configfile ressource type
     300        Ogre::ConfigFile cf;
     301        try
     302        {
     303            cf.load((Core::getMediaPath() / resourceFile_).string());
     304        }
     305        catch (...)
     306        {
     307            //COUT(1) << ex.getFullDescription() << std::endl;
     308            COUT(0) << "Have you forgotten to set the data path in orxnox.ini?" << std::endl;
     309            throw;
     310        }
     311
     312        // Go through all sections & settings in the file
     313        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
     314
     315        std::string secName, typeName, archName;
     316        while (seci.hasMoreElements())
     317        {
     318            try
     319            {
     320                secName = seci.peekNextKey();
     321                Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
     322                Ogre::ConfigFile::SettingsMultiMap::iterator i;
     323                for (i = settings->begin(); i != settings->end(); ++i)
     324                {
     325                    typeName = i->first; // for instance "FileSystem" or "Zip"
     326                    archName = i->second; // name (and location) of archive
     327
     328                    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
     329                        (Core::getMediaPath() / archName).string(), typeName, secName);
     330                }
     331            }
     332            catch (Ogre::Exception& ex)
     333            {
     334                COUT(1) << ex.getFullDescription() << std::endl;
     335            }
     336        }
     337    }
     338
     339    void GraphicsManager::loadRenderer()
     340    {
     341        CCOUT(4) << "Configuring Renderer" << std::endl;
     342
     343        if (!ogreRoot_->restoreConfig())
     344            if (!ogreRoot_->showConfigDialog())
     345                ThrowException(InitialisationFailed, "Could not show Ogre configuration dialogue.");
     346
     347        CCOUT(4) << "Creating render window" << std::endl;
     348
     349        this->renderWindow_ = ogreRoot_->initialise(true, "Orxonox");
     350
     351        this->ogreWindowEventListener_ = new OgreWindowEventListener();
     352        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, ogreWindowEventListener_);
     353
     354        Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(0);
     355
     356        // create a full screen default viewport
     357        this->viewport_ = this->renderWindow_->addViewport(0, 0);
     358    }
     359
     360    void GraphicsManager::initialiseResources()
     361    {
     362        CCOUT(4) << "Initialising resources" << std::endl;
     363        //TODO: Do NOT load all the groups, why are we doing that? And do we really do that? initialise != load...
     364        //try
     365        //{
     366            Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
     367            /*Ogre::StringVector str = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
     368            for (unsigned int i = 0; i < str.size(); i++)
     369            {
     370            Ogre::ResourceGroupManager::getSingleton().loadResourceGroup(str[i]);
     371            }*/
     372        //}
     373        //catch (...)
     374        //{
     375        //    CCOUT(2) << "Error: There was a serious error when initialising the resources." << std::endl;
     376        //    throw;
     377        //}
     378    }
     379
     380    /**
     381    @brief
     382        Method called by the LogListener interface from Ogre.
     383        We use it to capture Ogre log messages and handle it ourselves.
     384    @param message
     385        The message to be logged
     386    @param lml
     387        The message level the log is using
     388    @param maskDebug
     389        If we are printing to the console or not
     390    @param logName
     391        The name of this log (so you can have several listeners
     392        for different logs, and identify them)
     393    */
     394    void GraphicsManager::messageLogged(const std::string& message,
     395        Ogre::LogMessageLevel lml, bool maskDebug, const std::string& logName)
     396    {
     397        int orxonoxLevel;
     398        switch (lml)
     399        {
     400        case Ogre::LML_TRIVIAL:
     401            orxonoxLevel = this->ogreLogLevelTrivial_;
     402            break;
     403        case Ogre::LML_NORMAL:
     404            orxonoxLevel = this->ogreLogLevelNormal_;
     405            break;
     406        case Ogre::LML_CRITICAL:
     407            orxonoxLevel = this->ogreLogLevelCritical_;
     408            break;
     409        default:
     410            orxonoxLevel = 0;
     411        }
     412        OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
     413            << "Ogre: " << message << std::endl;
     414    }
     415
     416    void GraphicsManager::printScreen()
     417    {
     418        assert(this->renderWindow_);
     419       
     420        this->renderWindow_->writeContentsToTimestampedFile(Core::getLogPathString() + "screenShot_", ".jpg");
     421    }
     422
     423
     424    /****** OgreWindowEventListener ******/
     425
     426    void OgreWindowEventListener::windowResized(Ogre::RenderWindow* rw)
     427    {
     428        for (ObjectList<orxonox::WindowEventListener>::iterator it
     429            = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
     430            it->windowResized(rw->getWidth(), rw->getHeight());
     431    }
     432    void OgreWindowEventListener::windowFocusChange(Ogre::RenderWindow* rw)
     433    {
     434        for (ObjectList<orxonox::WindowEventListener>::iterator it
     435            = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
     436            it->windowFocusChanged();
     437    }
     438    void OgreWindowEventListener::windowClosed(Ogre::RenderWindow* rw)
     439    {
     440        // TODO: Notify the right class to shut down the Game
     441    }
    106442}
Note: See TracChangeset for help on using the changeset viewer.