Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Mar 31, 2010, 1:05:28 AM (14 years ago)
Author:
rgrieder
Message:

Merged revisions 6621-6661 to gamestates2.

Location:
code/branches/gamestates2
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • code/branches/gamestates2

  • code/branches/gamestates2/src/libraries/core/Core.cc

    r6595 r6662  
    7878
    7979    SetCommandLineArgument(settingsFile, "orxonox.ini").information("THE configuration file");
     80    SetCommandLineSwitch(noIOConsole).information("Use this if you don't want to use the IOConsole (for instance for Lua debugging)");
    8081#ifdef ORXONOX_PLATFORM_WINDOWS
    8182    SetCommandLineArgument(limitToCPU, 1).information("Limits the program to one CPU/core (1, 2, 3, etc.). Default is the first core (faster than off)");
     
    8889        , consoleCommandDestroyer_(CommandExecutor::destroyExternalCommands)
    8990        , bGraphicsLoaded_(false)
     91        , bStartIOConsole_(true)
    9092    {
    9193        // Set the hard coded fixed paths
     
    149151
    150152        // create persistent io console
    151         this->ioConsole_.reset(new IOConsole());
     153        if (CommandLineParser::getValue("noIOConsole").getBool())
     154        {
     155            ModifyConfigValue(bStartIOConsole_, tset, false);
     156        }
     157        if (this->bStartIOConsole_)
     158            this->ioConsole_.reset(new IOConsole());
    152159
    153160        // creates the class hierarchy for all classes with factories
     
    193200            .description("If true, all random actions are different each time you start the game")
    194201            .callback(this, &Core::initRandomNumberGenerator);
     202        SetConfigValue(bStartIOConsole_, true)
     203            .description("Set to false if you don't want to use the IOConsole (for Lua debugging for instance)");
    195204    }
    196205
     
    327336        }
    328337        // Process console events and status line
    329         this->ioConsole_->preUpdate(time);
     338        if (this->ioConsole_ != NULL)
     339            this->ioConsole_->preUpdate(time);
    330340        // Process thread commands
    331341        this->tclThreadManager_->preUpdate(time);
  • code/branches/gamestates2/src/libraries/core/Core.h

    r6595 r6662  
    9797            scoped_ptr<TclBind>           tclBind_;
    9898            scoped_ptr<TclThreadManager>  tclThreadManager_;
    99             scoped_ptr<Scope<ScopeID::Root> >     rootScope_;
     99            scoped_ptr<Scope<ScopeID::Root> > rootScope_;
    100100            // graphical
    101101            scoped_ptr<GraphicsManager>   graphicsManager_;     //!< Interface to OGRE
     
    108108            std::string                   language_;                   //!< The language
    109109            bool                          bInitRandomNumberGenerator_; //!< If true, srand(time(0)) is called
     110            bool                          bStartIOConsole_;            //!< Set to false if you don't want to use the IOConsole
    110111
    111112            static Core*                  singletonPtr_s;
  • code/branches/gamestates2/src/libraries/core/GUIManager.cc

    r6595 r6662  
    253253    }
    254254
    255     const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showMouse, TriBool::Value useKeyboard, bool bBlockJoyStick)
     255    const std::string& GUIManager::createInputState(const std::string& name, TriBool::Value showCursor, TriBool::Value useKeyboard, bool bBlockJoyStick)
    256256    {
    257257        InputState* state = InputManager::getInstance().createInputState(name);
    258258
    259         if (GraphicsManager::getInstance().isFullScreen() && showMouse == TriBool::True ||
    260            !GraphicsManager::getInstance().isFullScreen() && showMouse == TriBool::False)
     259        /* Table that maps isFullScreen() and showCursor to mouseExclusive
     260        isFullscreen / showCursor | True  | False | Dontcare
     261        ----------------------------------------------------
     262        true                      | True  | True  | Dontcare
     263        ----------------------------------------------------
     264        false                     | False | True  | Dontcare
     265        */
     266        if (showCursor == TriBool::Dontcare)
     267            state->setMouseExclusive(TriBool::Dontcare);
     268        else if (GraphicsManager::getInstance().isFullScreen() || showCursor == TriBool::False)
    261269            state->setMouseExclusive(TriBool::True);
    262270        else
    263             state->setMouseExclusive(TriBool::Dontcare);
    264 
    265         if (showMouse == TriBool::True)
     271            state->setMouseExclusive(TriBool::False);
     272
     273        if (showCursor == TriBool::True)
    266274            state->setMouseHandler(this);
    267         else if (showMouse == TriBool::False)
     275        else if (showCursor == TriBool::False)
    268276            state->setMouseHandler(&InputHandler::EMPTY);
    269277
  • code/branches/gamestates2/src/libraries/core/GUIManager.h

    r6595 r6662  
    8181        void setBackground(const std::string& name);
    8282
    83         const std::string& createInputState(const std::string& name, TriBool::Value showMouse = TriBool::True, TriBool::Value useKeyboard = TriBool::True, bool bBlockJoyStick = false); // tolua_export
     83        const std::string& createInputState(const std::string& name, TriBool::Value showCursor = TriBool::True, TriBool::Value useKeyboard = TriBool::True, bool bBlockJoyStick = false); // tolua_export
    8484
    8585        void setCamera(Ogre::Camera* camera);
  • code/branches/gamestates2/src/libraries/core/LuaState.cc

    r6417 r6662  
    3737
    3838#include "util/Debug.h"
     39#include "util/Exception.h"
     40#include "util/ScopeGuard.h"
     41#include "IOConsole.h"
    3942#include "Resource.h"
    4043#include "ToluaBindCore.h"
     
    5457        // Create new lua state and configure it
    5558        luaState_ = lua_open();
     59        Loki::ScopeGuard luaStateGuard = Loki::MakeGuard(&lua_close, luaState_);
    5660#if LUA_VERSION_NUM == 501
    5761        luaL_openlibs(luaState_);
     
    7882
    7983        // Parse init script
    80         this->doFile("LuaStateInit.lua");
     84        if (!this->doFile("LuaStateInit.lua"))
     85            ThrowException(InitialisationFailed, "Running LuaStateInit.lua failed");
     86
     87        luaStateGuard.Dismiss();
    8188    }
    8289
     
    96103    }
    97104
    98     void LuaState::includeFile(const std::string& filename)
     105    bool LuaState::includeFile(const std::string& filename)
    99106    {
    100107        shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
    101108        if (sourceInfo != NULL)
    102             this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
    103         else
    104             COUT(2) << "LuaState: Cannot include file '" << filename << "'." << std::endl;
    105     }
    106 
    107     void LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
     109            return this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
     110        else
     111        {
     112            COUT(2) << "LuaState: Cannot include file '" << filename << "' (not found)." << std::endl;
     113            return false;
     114        }
     115    }
     116
     117    bool LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
    108118    {
    109119        // Parse string with provided include parser (otherwise don't preparse at all)
     
    114124            luaInput = code;
    115125
    116         this->doString(luaInput, sourceFileInfo);
    117     }
    118 
    119     void LuaState::doFile(const std::string& filename)
     126        if (sourceFileInfo != NULL)
     127        {
     128            // Also fill a map with the actual source code. This is just for the include* commands
     129            // where the content of sourceFileInfo->filename doesn't match 'code'
     130            this->sourceCodeMap_[sourceFileInfo->filename] = code;
     131        }
     132
     133        bool returnValue = this->doString(luaInput, sourceFileInfo);
     134
     135        if (sourceFileInfo != NULL)
     136        {
     137            // Delete source code entry
     138            if (sourceFileInfo != NULL)
     139                this->sourceCodeMap_.erase(sourceFileInfo->filename);
     140        }
     141
     142        return returnValue;
     143    }
     144
     145    bool LuaState::doFile(const std::string& filename)
    120146    {
    121147        shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
    122148        if (sourceInfo != NULL)
    123             this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
    124         else
    125             COUT(2) << "LuaState: Cannot do file '" << filename << "'." << std::endl;
    126     }
    127 
    128     void LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
     149            return this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
     150        else
     151        {
     152            COUT(2) << "LuaState: Cannot do file '" << filename << "' (not found)." << std::endl;
     153            return false;
     154        }
     155    }
     156
     157    bool LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
    129158    {
    130159        // Save the old source file info
     
    134163            sourceFileInfo_ = sourceFileInfo;
    135164
    136         int error = 0;
     165        std::string chunkname;
     166        if (sourceFileInfo != NULL)
     167        {
     168            // Provide lua_load with the filename for debug purposes
     169            // The '@' is a Lua convention to identify the chunk name as filename
     170            chunkname = '@' + sourceFileInfo->filename;
     171        }
     172        else
     173        {
     174            // Use the code string to identify the chunk
     175            chunkname = code;
     176        }
     177
     178        // Push custom error handler that uses the debugger
     179        int errorHandler = 1;
     180        lua_getglobal(this->luaState_, "errorHandler");
     181        if (lua_isnil(this->luaState_, -1))
     182        {
     183            lua_pop(this->luaState_, 1);
     184            errorHandler = 0;
     185        }
     186
    137187#if LUA_VERSION_NUM != 501
    138188        LoadS ls;
    139189        ls.s = code.c_str();
    140190        ls.size = code.size();
    141         error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, code.c_str());
     191        int error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, chunkname.c_str());
    142192#else
    143         error = luaL_loadstring(luaState_, code.c_str());
     193        int error = luaL_loadbuffer(luaState_, code.c_str(), code.size(), chunkname.c_str());
    144194#endif
    145195
    146         // execute the chunk
     196        switch (error)
     197        {
     198        case LUA_ERRSYNTAX: // Syntax error
     199            COUT(1) << "Lua syntax error: " << lua_tostring(luaState_, -1) << std::endl;
     200            break;
     201        case LUA_ERRMEM:    // Memory allocation error
     202            COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
     203            lua_pop(luaState_, 1);
     204            break;
     205        }
     206
    147207        if (error == 0)
    148             error = lua_pcall(luaState_, 0, 1, 0);
     208        {
     209            // Execute the chunk in protected mode with an error handler function (stack index)
     210            error = lua_pcall(luaState_, 0, 1, errorHandler);
     211
     212            switch (error)
     213            {
     214            case LUA_ERRRUN: // Runtime error
     215                // Remove error string from stack (we already display the error in the
     216                // 'errorHandler' Lua function in LuaStateInit.lua)
     217                lua_pop(luaState_, 1);
     218                break;
     219            case LUA_ERRERR: // Error in the error handler
     220                COUT(1) << "Lua error in error handler: " << lua_tostring(luaState_, -1) << std::endl;
     221                break;
     222            case LUA_ERRMEM: // Memory allocation error
     223                COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
     224                lua_pop(luaState_, 1);
     225                break;
     226            }
     227        }
     228
    149229        if (error != 0)
    150230        {
    151             std::string origin;
    152             if (sourceFileInfo != NULL)
    153                 origin = " originating from " + sourceFileInfo_->filename;
    154             COUT(1) << "Error in Lua-script" << origin << ": " << lua_tostring(luaState_, -1) << std::endl;
    155             // return value is nil
     231            // Push a nil return value
    156232            lua_pushnil(luaState_);
    157233        }
    158         // push return value because it will get lost since the return value of this function is void
     234
     235        // Set return value to a global variable because we cannot return a table in this function
     236        // here. It would work for numbers, pointers and strings, but certainly not for Lua tables.
    159237        lua_setglobal(luaState_, "LuaStateReturnValue");
    160238
    161239        // Load the old info again
    162240        sourceFileInfo_ = oldSourceFileInfo;
     241
     242        return (error == 0);
    163243    }
    164244
     
    180260        else
    181261            return true;
     262    }
     263
     264    //! Returns the content of a file
     265    std::string LuaState::getSourceCode(const std::string& filename)
     266    {
     267        // Try the internal map first to get the actual Lua code
     268        // and not just some pseudo Lua-XML code when using include* commands
     269        std::map<std::string, std::string>::const_iterator it = this->sourceCodeMap_.find(filename);
     270        if (it != this->sourceCodeMap_.end())
     271            return it->second;
     272        shared_ptr<ResourceInfo> info = Resource::getInfo(filename);
     273        if (info == NULL)
     274            return "";
     275        else
     276            return Resource::open(info)->getAsString();
     277    }
     278
     279    bool LuaState::usingIOConsole() const
     280    {
     281        return IOConsole::exists();
    182282    }
    183283
  • code/branches/gamestates2/src/libraries/core/LuaState.h

    r6595 r6662  
    7171        ~LuaState();
    7272
    73         void doFile(const std::string& filename); // tolua_export
    74         void doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
     73        bool doFile(const std::string& filename); // tolua_export
     74        bool doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
    7575
    76         void includeFile(const std::string& filename); // tolua_export
    77         void includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
     76        bool includeFile(const std::string& filename); // tolua_export
     77        bool includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
    7878
    7979        void luaPrint(const std::string& str); // tolua_export
    8080        void luaLog(unsigned int level, const std::string& message); // tolua_export
    8181        bool fileExists(const std::string& filename); // tolua_export
     82        std::string getSourceCode(const std::string& filename); // tolua_export
    8283
    8384        const std::stringstream& getOutput() const { return output_; }
     
    9192
    9293        Functor* createLuaFunctor(const std::string& code) { return new LuaFunctor(code, this); } // tolua_export
     94        //! Tells about whether IOConsole was activated. The Lua debugger only works with a normal console.
     95        bool usingIOConsole() const; // tolua_export
    9396
    9497        static bool addToluaInterface(int (*function)(lua_State*), const std::string& name);
     
    114117        bool bIsRunning_;
    115118        shared_ptr<ResourceInfo> sourceFileInfo_;
     119        std::map<std::string, std::string> sourceCodeMap_;
    116120        std::string (*includeParseFunction_)(const std::string&);
    117121
  • code/branches/gamestates2/src/libraries/core/Resource.cc

    r6501 r6662  
    2929#include "Resource.h"
    3030
     31#include <boost/filesystem/path.hpp>
    3132#include <OgreException.h>
     33#include <OgreFileSystem.h>
    3234#include <OgreResourceGroupManager.h>
    3335
     
    8991                ptr->group = group;
    9092                ptr->size = it->uncompressedSize;
     93                if (dynamic_cast<Ogre::FileSystemArchive*>(it->archive) != NULL)
     94                {
     95                    boost::filesystem::path base(it->archive->getName());
     96                    base /= it->filename;
     97                    ptr->fileSystemPath = base.string();
     98                }
    9199                return ptr;
    92100            }
  • code/branches/gamestates2/src/libraries/core/Resource.h

    r6417 r6662  
    5757        //! Uncompressed size
    5858        size_t size;
     59        //! Absolute file path ("" for files not on filesystem)
     60        std::string fileSystemPath;
    5961    };
    6062
  • code/branches/gamestates2/src/libraries/core/input/InputDevice.h

    r6417 r6662  
    159159            for (unsigned int iB = 0; iB < pressedButtons_.size(); ++iB)
    160160                for (unsigned int iS = 0; iS < inputStates_.size(); ++iS)
    161                     inputStates_[iS]->buttonEvent<ButtonEvent::THold, Traits>(
     161                    inputStates_[iS]->buttonEvent<ButtonEvent::THold, Traits::ButtonTypeParam>(
    162162                        this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(pressedButtons_[iB]));
    163163
     
    196196            // Call states
    197197            for (unsigned int i = 0; i < inputStates_.size(); ++i)
    198                 inputStates_[i]->buttonEvent<ButtonEvent::TPress, Traits>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
     198                inputStates_[i]->buttonEvent<ButtonEvent::TPress, Traits::ButtonTypeParam>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
    199199        }
    200200
     
    218218            // Call states
    219219            for (unsigned int i = 0; i < inputStates_.size(); ++i)
    220                 inputStates_[i]->buttonEvent<ButtonEvent::TRelease, Traits>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
     220                inputStates_[i]->buttonEvent<ButtonEvent::TRelease, Traits::ButtonTypeParam>(this->getDeviceID(), static_cast<DeviceClass*>(this)->getButtonEventArg(button));
    221221        }
    222222
  • code/branches/gamestates2/src/libraries/core/input/InputHandler.h

    r6105 r6662  
    112112        virtual ~InputHandler() { }
    113113
    114         template<class T> void buttonEvent(unsigned int device, const T& button, ButtonEvent::TPress)
     114        template<class T> void buttonEvent(unsigned int device, T button, ButtonEvent::TPress)
    115115            { this->buttonPressed(button); }
    116         template<class T> void buttonEvent(unsigned int device, const T& button, ButtonEvent::TRelease)
     116        template<class T> void buttonEvent(unsigned int device, T button, ButtonEvent::TRelease)
    117117            { this->buttonReleased(button); }
    118         template<class T> void buttonEvent(unsigned int device, const T& button, ButtonEvent::THold)
     118        template<class T> void buttonEvent(unsigned int device, T button, ButtonEvent::THold)
    119119            { this->buttonHeld(button); }
    120         void buttonEvent(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TPress)
     120        template<> void buttonEvent<JoyStickButtonCode::ByEnum>(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TPress)
    121121            { this->buttonPressed(device - InputDeviceEnumerator::FirstJoyStick, button); }
    122         void buttonEvent(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TRelease)
     122        template<> void buttonEvent<JoyStickButtonCode::ByEnum>(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::TRelease)
    123123            { this->buttonReleased(device - InputDeviceEnumerator::FirstJoyStick, button); }
    124         void buttonEvent(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::THold)
     124        template<> void buttonEvent<JoyStickButtonCode::ByEnum>(unsigned int device, JoyStickButtonCode::ByEnum button, ButtonEvent::THold)
    125125            { this->buttonHeld(device - InputDeviceEnumerator::FirstJoyStick, button); }
    126126
  • code/branches/gamestates2/src/libraries/core/input/InputManager.cc

    r6595 r6662  
    9595        CCOUT(4) << "Constructing..." << std::endl;
    9696
     97        // Allocate space for the function call buffer
     98        this->callBuffer_.reserve(16);
     99
    97100        this->setConfigValues();
    98101
     
    266269        CCOUT(3) << "Destroying..." << std::endl;
    267270
     271        // Leave all active InputStates (except "empty")
     272        while (this->activeStates_.size() > 1)
     273            this->leaveState(this->activeStates_.rbegin()->second->getName());
     274        this->activeStates_.clear();
     275
    268276        // Destroy calibrator helper handler and state
    269277        this->destroyState("calibrator");
    270278        // Destroy KeyDetector and state
    271279        calibratorCallbackHandler_->destroy();
    272         // destroy the empty InputState
     280        // Destroy the empty InputState
    273281        this->destroyStateInternal(this->emptyState_);
    274282
    275         // destroy all user InputStates
     283        // Destroy all user InputStates
    276284        while (statesByName_.size() > 0)
    277285            this->destroyStateInternal(statesByName_.rbegin()->second);
     
    335343    void InputManager::reload()
    336344    {
    337         if (internalState_ & Ticking)
    338         {
    339             // We cannot destroy OIS right now, because reload was probably
    340             // caused by a user clicking on a GUI item. The stack trace would then
    341             // include an OIS method. So it would be a very bad thing to destroy it..
    342             internalState_ |= ReloadRequest;
    343         }
    344         else if (internalState_ & Calibrating)
     345        if (internalState_ & Calibrating)
    345346            CCOUT(2) << "Warning: Cannot reload input system. Joy sticks are currently being calibrated." << std::endl;
    346347        else
     
    351352    void InputManager::reloadInternal()
    352353    {
    353         CCOUT(3) << "Reloading ..." << std::endl;
     354        CCOUT(4) << "Reloading ..." << std::endl;
    354355
    355356        this->destroyDevices();
     
    357358
    358359        internalState_ &= ~Bad;
    359         internalState_ &= ~ReloadRequest;
    360360        CCOUT(4) << "Reloading complete." << std::endl;
    361361    }
     
    370370        if (internalState_ & Bad)
    371371            ThrowException(General, "InputManager was not correctly reloaded.");
    372 
    373         else if (internalState_ & ReloadRequest)
    374             reloadInternal();
    375 
    376         // check for states to leave
    377         if (!stateLeaveRequests_.empty())
    378         {
    379             for (std::set<InputState*>::iterator it = stateLeaveRequests_.begin();
    380                 it != stateLeaveRequests_.end(); ++it)
    381             {
    382                 (*it)->left();
    383                 // just to be sure that the state actually is registered
    384                 assert(statesByName_.find((*it)->getName()) != statesByName_.end());
    385 
    386                 activeStates_.erase((*it)->getPriority());
    387                 if ((*it)->getPriority() < InputStatePriority::HighPriority)
    388                     (*it)->setPriority(0);
    389                 updateActiveStates();
    390             }
    391             stateLeaveRequests_.clear();
    392         }
    393 
    394         // check for states to enter
    395         if (!stateEnterRequests_.empty())
    396         {
    397             for (std::set<InputState*>::const_iterator it = stateEnterRequests_.begin();
    398                 it != stateEnterRequests_.end(); ++it)
    399             {
    400                 // just to be sure that the state actually is registered
    401                 assert(statesByName_.find((*it)->getName()) != statesByName_.end());
    402 
    403                 if ((*it)->getPriority() == 0)
    404                 {
    405                     // Get smallest possible priority between 1 and maxStateStackSize_s
    406                     for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
    407                         rit != activeStates_.rend(); ++rit)
    408                     {
    409                         if (rit->first < InputStatePriority::HighPriority)
    410                         {
    411                             (*it)->setPriority(rit->first + 1);
    412                             break;
    413                         }
    414                     }
    415                     // In case no normal handler was on the stack
    416                     if ((*it)->getPriority() == 0)
    417                         (*it)->setPriority(1);
    418                 }
    419                 activeStates_[(*it)->getPriority()] = (*it);
    420                 updateActiveStates();
    421                 (*it)->entered();
    422             }
    423             stateEnterRequests_.clear();
    424         }
    425 
    426         // check for states to destroy
    427         if (!stateDestroyRequests_.empty())
    428         {
    429             for (std::set<InputState*>::iterator it = stateDestroyRequests_.begin();
    430                 it != stateDestroyRequests_.end(); ++it)
    431             {
    432                 destroyStateInternal((*it));
    433             }
    434             stateDestroyRequests_.clear();
    435         }
    436372
    437373        // check whether a state has changed its EMPTY situation
     
    448384            updateActiveStates();
    449385
    450         // mark that we now start capturing and distributing input
    451         internalState_ |= Ticking;
    452 
    453         // Capture all the input and handle it
     386        // Capture all the input and collect the function calls
     387        // No event gets triggered here yet!
    454388        BOOST_FOREACH(InputDevice* device, devices_)
    455389            if (device != NULL)
    456390                device->update(time);
    457391
    458         // Update the states
     392        // Collect functions calls for the update
    459393        for (unsigned int i = 0; i < activeStatesTicked_.size(); ++i)
    460394            activeStatesTicked_[i]->update(time.getDeltaTime());
    461395
    462         internalState_ &= ~Ticking;
     396        // Execute all cached function calls in order
     397        // Why so complicated? The problem is that an InputHandler could trigger
     398        // a reload that would destroy the OIS devices or it could even leave and
     399        // then destroy its own InputState. That would of course lead to access
     400        // violations.
     401        // If we delay the calls, then OIS and and the InputStates are not anymore
     402        // in the call stack and can therefore be edited.
     403        for (size_t i = 0; i < this->callBuffer_.size(); ++i)
     404            this->callBuffer_[i]();
     405
     406        this->callBuffer_.clear();
    463407    }
    464408
     
    470414    void InputManager::updateActiveStates()
    471415    {
    472         assert((internalState_ & InputManager::Ticking) == 0);
    473416        // temporary resize
    474417        for (unsigned int i = 0; i < devices_.size(); ++i)
     
    622565        // get pointer from the map with all stored handlers
    623566        std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
    624         if (it != statesByName_.end())
    625         {
    626             // exists
    627             if (activeStates_.find(it->second->getPriority()) == activeStates_.end())
    628             {
    629                 // not active
    630                 if (stateDestroyRequests_.find(it->second) == stateDestroyRequests_.end())
     567        if (it != statesByName_.end() && activeStates_.find(it->second->getPriority()) == activeStates_.end())
     568        {
     569            // exists and not active
     570            if (it->second->getPriority() == 0)
     571            {
     572                // Get smallest possible priority between 1 and maxStateStackSize_s
     573                for (std::map<int, InputState*>::reverse_iterator rit = activeStates_.rbegin();
     574                    rit != activeStates_.rend(); ++rit)
    631575                {
    632                     // not scheduled for destruction
    633                     // prevents a state from being added multiple times
    634                     stateEnterRequests_.insert(it->second);
    635                     return true;
     576                    if (rit->first < InputStatePriority::HighPriority)
     577                    {
     578                        it->second->setPriority(rit->first + 1);
     579                        break;
     580                    }
    636581                }
    637             }
    638             else if (this->stateLeaveRequests_.find(it->second) != this->stateLeaveRequests_.end())
    639             {
    640                 // State already scheduled for leaving --> cancel
    641                 this->stateLeaveRequests_.erase(this->stateLeaveRequests_.find(it->second));
    642             }
     582                // In case no normal handler was on the stack
     583                if (it->second->getPriority() == 0)
     584                    it->second->setPriority(1);
     585            }
     586            activeStates_[it->second->getPriority()] = it->second;
     587            updateActiveStates();
     588            it->second->entered();
     589
     590            return true;
    643591        }
    644592        return false;
     
    654602        // get pointer from the map with all stored handlers
    655603        std::map<std::string, InputState*>::const_iterator it = statesByName_.find(name);
    656         if (it != statesByName_.end())
    657         {
    658             // exists
    659             if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
    660             {
    661                 // active
    662                 stateLeaveRequests_.insert(it->second);
    663                 return true;
    664             }
    665             else if (this->stateEnterRequests_.find(it->second) != this->stateEnterRequests_.end())
    666             {
    667                 // State already scheduled for entering --> cancel
    668                 this->stateEnterRequests_.erase(this->stateEnterRequests_.find(it->second));
    669             }
     604        if (it != statesByName_.end() && activeStates_.find(it->second->getPriority()) != activeStates_.end())
     605        {
     606            // exists and active
     607
     608            it->second->left();
     609
     610            activeStates_.erase(it->second->getPriority());
     611            if (it->second->getPriority() < InputStatePriority::HighPriority)
     612                it->second->setPriority(0);
     613            updateActiveStates();
     614
     615            return true;
    670616        }
    671617        return false;
     
    682628        if (it != statesByName_.end())
    683629        {
    684             if (activeStates_.find(it->second->getPriority()) != activeStates_.end())
    685             {
    686                 // The state is still active. We have to postpone
    687                 stateLeaveRequests_.insert(it->second);
    688                 stateDestroyRequests_.insert(it->second);
    689             }
    690             else if (this->internalState_ & Ticking)
    691             {
    692                 // cannot remove state while ticking
    693                 stateDestroyRequests_.insert(it->second);
    694             }
    695             else
    696                 destroyStateInternal(it->second);
     630            this->leaveState(name);
     631            destroyStateInternal(it->second);
    697632
    698633            return true;
     
    704639    void InputManager::destroyStateInternal(InputState* state)
    705640    {
    706         assert(state && !(this->internalState_ & Ticking));
    707         std::map<int, InputState*>::iterator it = this->activeStates_.find(state->getPriority());
    708         if (it != this->activeStates_.end())
    709         {
    710             this->activeStates_.erase(it);
    711             updateActiveStates();
    712         }
     641        assert(state && this->activeStates_.find(state->getPriority()) == this->activeStates_.end());
    713642        statesByName_.erase(state->getName());
    714643        state->destroy();
  • code/branches/gamestates2/src/libraries/core/input/InputManager.h

    r6595 r6662  
    3636#include <string>
    3737#include <vector>
     38#include <boost/function.hpp>
    3839
    3940#include "util/Singleton.h"
    4041#include "util/TriBool.h"
    4142#include "core/WindowEventListener.h"
    42 #include "InputState.h"
    4343
    4444// tolua_begin
     
    7676            Nothing       = 0x00,
    7777            Bad           = 0x02,
    78             Ticking       = 0x04,
    79             Calibrating   = 0x08,
    80             ReloadRequest = 0x10,
     78            Calibrating   = 0x04,
    8179        };
    8280
     
    170168        //! Returns a pointer to the OIS InputManager. Only you if you know what you're doing!
    171169        OIS::InputManager* getOISInputManager() { return this->oisInputManager_; }
     170        //! Returns the position of the cursor as std::pair of ints
    172171        std::pair<int, int> getMousePosition() const;
     172        //! Tells whether the mouse is used exclusively to the game
     173        bool isMouseExclusive() const { return this->exclusiveMouse_; } // tolua_export
     174
     175        //-------------------------------
     176        // Function call caching
     177        //-------------------------------
     178        void pushCall(const boost::function<void ()>& function)
     179            { this->callBuffer_.push_back(function); }
    173180
    174181        static InputManager& getInstance() { return Singleton<InputManager>::getInstance(); } // tolua_export
     
    208215        std::vector<InputState*>            activeStatesTicked_;   //!< Like activeStates_, but only contains the ones that currently receive events
    209216
    210         std::set<InputState*>               stateEnterRequests_;   //!< Requests to enter a new state
    211         std::set<InputState*>               stateLeaveRequests_;   //!< Requests to leave a running state
    212         std::set<InputState*>               stateDestroyRequests_; //!< Requests to destroy a state
     217        std::vector<boost::function<void ()> > callBuffer_;        //!< Caches all calls from InputStates to be executed afterwards (see preUpdate)
    213218
    214219        static InputManager*                singletonPtr_s;        //!< Pointer reference to the singleton
  • code/branches/gamestates2/src/libraries/core/input/InputPrereqs.h

    r6417 r6662  
    4242#include <ois/OISMouse.h>
    4343#include <ois/OISJoyStick.h>
     44#include "util/OrxEnum.h"
    4445
    4546namespace orxonox
     
    448449        };
    449450    }
     451
     452    //! Enumeration wrapper for input state priorities
     453    struct InputStatePriority : OrxEnum<InputStatePriority>
     454    {
     455        OrxEnumConstructors(InputStatePriority);
     456
     457        static const int Empty        = -1;
     458        static const int Dynamic      = 0;
     459
     460        static const int HighPriority = 1000;
     461        static const int Console      = HighPriority + 0;
     462        static const int Calibrator   = HighPriority + 1;
     463        static const int Detector     = HighPriority + 2;
     464    };
    450465}
    451466
  • code/branches/gamestates2/src/libraries/core/input/InputState.h

    r6595 r6662  
    3535#include <string>
    3636#include <vector>
    37 
    38 #include "util/OrxEnum.h"
     37#include <boost/function.hpp>
     38#include <boost/bind.hpp>
     39
    3940#include "util/TriBool.h"
    4041#include "InputHandler.h"
     42#include "InputManager.h"
    4143#include "JoyStickQuantityListener.h"
     44
     45#define INPUT_STATE_PUSH_CALL(deviceIndex, functionName, ...) \
     46    InputManager::getInstance().pushCall(boost::function<void ()>(boost::bind(&InputHandler::functionName, handlers_[deviceIndex], __VA_ARGS__)))
    4247
    4348namespace orxonox
    4449{
    45     //! Enumeration wrapper for input state priorities
    46     struct InputStatePriority : OrxEnum<InputStatePriority>
    47     {
    48         OrxEnumConstructors(InputStatePriority);
    49 
    50         static const int Empty        = -1;
    51         static const int Dynamic      = 0;
    52 
    53         static const int HighPriority = 1000;
    54         static const int Console      = HighPriority + 0;
    55         static const int Calibrator   = HighPriority + 1;
    56         static const int Detector     = HighPriority + 2;
    57     };
    58 
    59 
    6050    /**
    6151    @brief
     
    144134
    145135        //! Generic function that distributes all 9 button events
    146         template <typename EventType, class Traits>
    147         void buttonEvent(unsigned int device, const typename Traits::ButtonTypeParam button);
     136        template <typename EventType, class ButtonTypeParam>
     137        void buttonEvent(unsigned int device, ButtonTypeParam button);
    148138
    149139        //! Event handler
     
    190180        for (unsigned int i = 0; i < handlers_.size(); ++i)
    191181            if (handlers_[i] != NULL)
    192                 handlers_[i]->allDevicesUpdated(dt);
     182                INPUT_STATE_PUSH_CALL(i, allDevicesUpdated, dt);
    193183    }
    194184
     
    199189        case InputDeviceEnumerator::Keyboard:
    200190            if (handlers_[keyboardIndex_s] != NULL)
    201                 handlers_[keyboardIndex_s]->keyboardUpdated(dt);
     191                INPUT_STATE_PUSH_CALL(keyboardIndex_s, keyboardUpdated, dt);
    202192            break;
    203193
    204194        case InputDeviceEnumerator::Mouse:
    205195            if (handlers_[mouseIndex_s] != NULL)
    206                 handlers_[mouseIndex_s]->mouseUpdated(dt);
     196                INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseUpdated, dt);
    207197            break;
    208198
    209199        default: // joy sticks
    210200            if (handlers_[device] != NULL)
    211                 handlers_[device]->joyStickUpdated(device - firstJoyStickIndex_s, dt);
     201                INPUT_STATE_PUSH_CALL(device, joyStickUpdated, device - firstJoyStickIndex_s, dt);
    212202            break;
    213203        }
    214204    }
    215205
    216     template <typename EventType, class Traits>
    217     FORCEINLINE void InputState::buttonEvent(unsigned int device, const typename Traits::ButtonTypeParam button)
     206    template <typename EventType, class ButtonTypeParam>
     207    FORCEINLINE void InputState::buttonEvent(unsigned int device, typename ButtonTypeParam button)
    218208    {
    219209        assert(device < handlers_.size());
    220210        if (handlers_[device] != NULL)
    221             handlers_[device]->buttonEvent(device, button, EventType());
     211        {
     212            // We have to store the function pointer to tell the compiler about its actual type because of overloading
     213            void (InputHandler::*function)(unsigned int, ButtonTypeParam, EventType) = &InputHandler::buttonEvent<ButtonTypeParam>;
     214            InputManager::getInstance().pushCall(boost::function<void ()>(boost::bind(function, handlers_[device], device, button, EventType())));
     215        }
    222216    }
    223217
     
    225219    {
    226220        if (handlers_[mouseIndex_s] != NULL)
    227             handlers_[mouseIndex_s]->mouseMoved(abs, rel, clippingSize);
     221            INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseMoved, abs, rel, clippingSize);
    228222    }
    229223
     
    231225    {
    232226        if (handlers_[mouseIndex_s] != NULL)
    233             handlers_[mouseIndex_s]->mouseScrolled(abs, rel);
     227            INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseScrolled, abs, rel);
    234228    }
    235229
     
    238232        assert(device < handlers_.size());
    239233        if (handlers_[device] != NULL)
    240             handlers_[device]->axisMoved(device - firstJoyStickIndex_s, axis, value);
     234            INPUT_STATE_PUSH_CALL(device, axisMoved, device - firstJoyStickIndex_s, axis, value);
    241235    }
    242236}
  • code/branches/gamestates2/src/libraries/util/Singleton.h

    r6536 r6662  
    4949    public:
    5050        //! Returns a reference to the singleton instance
    51         static T& getInstance()
     51        FORCEINLINE static T& getInstance()
    5252        {
    5353            assert(T::singletonPtr_s != NULL);
     
    5656
    5757        //! Tells whether the singleton has been created
    58         static bool exists()
     58        FORCEINLINE static bool exists()
    5959        {
    6060            return (T::singletonPtr_s != NULL);
     
    6262
    6363        //! Update method called by ClassSingletonManager (if used)
    64         void preUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->preUpdate(time); }
     64        FORCEINLINE void preUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->preUpdate(time); }
    6565        //! Empty update method for the static polymorphism
    66         void preUpdate(const Clock& time) { }
     66        FORCEINLINE void preUpdate(const Clock& time) { }
    6767        //! Update method called by ClassSingletonManager (if used)
    68         void postUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->postUpdate(time); }
     68        FORCEINLINE void postUpdateSingleton(const Clock& time) { static_cast<T*>(T::singletonPtr_s)->postUpdate(time); }
    6969        //! Empty update method for the static polymorphism
    70         void postUpdate(const Clock& time) { }
     70        FORCEINLINE void postUpdate(const Clock& time) { }
    7171
    7272    protected:
Note: See TracChangeset for help on using the changeset viewer.