Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Mar 30, 2010, 12:13:33 PM (15 years ago)
Author:
rgrieder
Message:

Implemented indirect function calls for input events. It simply means that when you hit the mouse button, the resulting call stack will not include OIS nor an InputState anymore.
—> You can reload the InputManager (happens when mouse mode changes) or even modify the InputState situation (like InputManager::leaveState or even destroyState) directly now.
—> I was able to remove the indirect execution of following methods in the InputManager: leaveInputState, enterInputState, destroyInputState and reload.

Location:
code/branches/gamestate/src/libraries/core/input
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • code/branches/gamestate/src/libraries/core/input/InputDevice.h

    r6417 r6657  
    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/gamestate/src/libraries/core/input/InputHandler.h

    r6105 r6657  
    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/gamestate/src/libraries/core/input/InputManager.cc

    r6537 r6657  
    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/gamestate/src/libraries/core/input/InputManager.h

    r6656 r6657  
    3636#include <string>
    3737#include <vector>
     38#include <boost/function.hpp>
    3839
    3940#include "util/Singleton.h"
     
    7576            Nothing       = 0x00,
    7677            Bad           = 0x02,
    77             Ticking       = 0x04,
    78             Calibrating   = 0x08,
    79             ReloadRequest = 0x10,
     78            Calibrating   = 0x04,
    8079        };
    8180
     
    171170        std::pair<int, int> getMousePosition() const;
    172171
     172        //-------------------------------
     173        // Function call caching
     174        //-------------------------------
     175        void pushCall(const boost::function<void ()>& function)
     176            { this->callBuffer_.push_back(function); }
     177
    173178        static InputManager& getInstance() { return Singleton<InputManager>::getInstance(); } // tolua_export
    174179
     
    207212        std::vector<InputState*>            activeStatesTicked_;   //!< Like activeStates_, but only contains the ones that currently receive events
    208213
    209         std::set<InputState*>               stateEnterRequests_;   //!< Requests to enter a new state
    210         std::set<InputState*>               stateLeaveRequests_;   //!< Requests to leave a running state
    211         std::set<InputState*>               stateDestroyRequests_; //!< Requests to destroy a state
     214        std::vector<boost::function<void ()> > callBuffer_;        //!< Caches all calls from InputStates to be executed afterwards (see preUpdate)
    212215
    213216        static InputManager*                singletonPtr_s;        //!< Pointer reference to the singleton
  • code/branches/gamestate/src/libraries/core/input/InputState.h

    r6656 r6657  
    3535#include <string>
    3636#include <vector>
     37#include <boost/function.hpp>
     38#include <boost/bind.hpp>
    3739
    3840#include "util/TriBool.h"
    3941#include "InputHandler.h"
     42#include "InputManager.h"
    4043#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__)))
    4147
    4248namespace orxonox
     
    128134
    129135        //! Generic function that distributes all 9 button events
    130         template <typename EventType, class Traits>
    131         void buttonEvent(unsigned int device, const typename Traits::ButtonTypeParam button);
     136        template <typename EventType, class ButtonTypeParam>
     137        void buttonEvent(unsigned int device, ButtonTypeParam button);
    132138
    133139        //! Event handler
     
    174180        for (unsigned int i = 0; i < handlers_.size(); ++i)
    175181            if (handlers_[i] != NULL)
    176                 handlers_[i]->allDevicesUpdated(dt);
     182                INPUT_STATE_PUSH_CALL(i, allDevicesUpdated, dt);
    177183    }
    178184
     
    183189        case InputDeviceEnumerator::Keyboard:
    184190            if (handlers_[keyboardIndex_s] != NULL)
    185                 handlers_[keyboardIndex_s]->keyboardUpdated(dt);
     191                INPUT_STATE_PUSH_CALL(keyboardIndex_s, keyboardUpdated, dt);
    186192            break;
    187193
    188194        case InputDeviceEnumerator::Mouse:
    189195            if (handlers_[mouseIndex_s] != NULL)
    190                 handlers_[mouseIndex_s]->mouseUpdated(dt);
     196                INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseUpdated, dt);
    191197            break;
    192198
    193199        default: // joy sticks
    194200            if (handlers_[device] != NULL)
    195                 handlers_[device]->joyStickUpdated(device - firstJoyStickIndex_s, dt);
     201                INPUT_STATE_PUSH_CALL(device, joyStickUpdated, device - firstJoyStickIndex_s, dt);
    196202            break;
    197203        }
    198204    }
    199205
    200     template <typename EventType, class Traits>
    201     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)
    202208    {
    203209        assert(device < handlers_.size());
    204210        if (handlers_[device] != NULL)
    205             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        }
    206216    }
    207217
     
    209219    {
    210220        if (handlers_[mouseIndex_s] != NULL)
    211             handlers_[mouseIndex_s]->mouseMoved(abs, rel, clippingSize);
     221            INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseMoved, abs, rel, clippingSize);
    212222    }
    213223
     
    215225    {
    216226        if (handlers_[mouseIndex_s] != NULL)
    217             handlers_[mouseIndex_s]->mouseScrolled(abs, rel);
     227            INPUT_STATE_PUSH_CALL(mouseIndex_s, mouseScrolled, abs, rel);
    218228    }
    219229
     
    222232        assert(device < handlers_.size());
    223233        if (handlers_[device] != NULL)
    224             handlers_[device]->axisMoved(device - firstJoyStickIndex_s, axis, value);
     234            INPUT_STATE_PUSH_CALL(device, axisMoved, device - firstJoyStickIndex_s, axis, value);
    225235    }
    226236}
Note: See TracChangeset for help on using the changeset viewer.