Input system rewrite

actorid
scrawl 13 years ago
parent 39f87bee0e
commit 86d6f190bf

@ -96,19 +96,13 @@ ENDIF()
set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
set(MANGLE_INPUT ${LIBDIR}/mangle/input/servers/ois_driver.cpp)
set(MANGLE_ALL ${MANGLE_INPUT})
source_group(libs\\mangle FILES ${MANGLE_ALL})
set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/mouselook.cpp
${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
${LIBDIR}/openengine/ogre/atlas.cpp
)
set(OENGINE_GUI
${LIBDIR}/openengine/gui/events.cpp
${LIBDIR}/openengine/gui/manager.cpp
)
@ -135,7 +129,7 @@ set(OENGINE_BULLET
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET})
source_group(libs\\openengine FILES ${OENGINE_ALL})
set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL})
set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
# Sound setup
@ -291,6 +285,9 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/input-default.xml
"${OpenMW_BINARY_DIR}/input-default.xml")
configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg")
@ -443,6 +440,7 @@ endif(WIN32)
# Extern
add_subdirectory (extern/shiny)
add_subdirectory (extern/oics)
# Components
add_subdirectory (components)

@ -104,6 +104,7 @@ target_link_libraries(openmw
${MYGUI_PLATFORM_LIBRARIES}
"shiny"
"shiny.OgrePlatform"
"oics"
components
)

@ -67,7 +67,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
mEnvironment.setFrameDuration (evt.timeSinceLastFrame);
// update input
MWBase::Environment::get().getInputManager()->update();
MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame);
// sound
if (mUseSound)
@ -270,6 +270,24 @@ void OMW::Engine::go()
else if (boost::filesystem::exists(globaldefault))
settings.loadUser(globaldefault);
// Get the path for the keybinder xml file
std::string keybinderDefault;
// load user settings if they exist, otherwise just load the default settings as user settings
const std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
const std::string keybinderDefaultLocal = (mCfgMgr.getLocalPath() / "input-default.xml").string();
const std::string keybinderDefaultGlobal = (mCfgMgr.getGlobalPath() / "input-default.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
if (boost::filesystem::exists(keybinderDefaultLocal))
keybinderDefault = keybinderDefaultLocal;
else if (boost::filesystem::exists(keybinderDefaultGlobal))
keybinderDefault = keybinderDefaultGlobal;
else
throw std::runtime_error ("No default input settings found! Make sure the file \"input-default.xml\" was properly installed.");
mFpsLevel = settings.getInt("fps", "HUD");
// load nif overrides
@ -366,9 +384,9 @@ void OMW::Engine::go()
// Sets up the input system
mEnvironment.setInputManager (new MWInput::MWInputManager (*mOgre,
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
MWBase::Environment::get().getWorld()->getPlayer(),
*MWBase::Environment::get().getWindowManager(), mDebug, *this));
*MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderDefault, keybinderUser, keybinderUserExists));
std::cout << "\nPress Q/ESC or close window to exit.\n";

@ -22,7 +22,7 @@ namespace MWBase
virtual ~InputManager() {}
virtual void update() = 0;
virtual void update(float dt) = 0;
virtual void changeInputMode(bool guiMode) = 0;

@ -1,357 +1,200 @@
#include "inputmanagerimp.hpp"
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <openengine/input/dispatcher.hpp>
#include <openengine/input/poller.hpp>
#include <openengine/gui/events.hpp>
#include <openengine/ogre/renderer.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include "../mwbase/windowmanager.hpp"
#include <OIS/OISInputManager.h>
#include <mangle/input/servers/ois_driver.hpp>
#include <mangle/input/filters/eventlist.hpp>
#include <MyGUI_InputManager.h>
#include <MyGUI_RenderManager.h>
#include <libs/platform/strings.h>
#include <extern/oics/ICSInputControlSystem.h>
#include "mouselookevent.hpp"
#include <openengine/ogre/renderer.hpp>
#include "../engine.hpp"
#include "../mwworld/player.hpp"
#include "../mwbase/world.hpp"
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <OgreRoot.h>
#include <OIS/OIS.h>
#include "../mwbase/windowmanager.hpp"
namespace MWInput
{
enum Actions
InputManager::InputManager(OEngine::Render::OgreRenderer &ogre,
MWWorld::Player &player,
MWBase::WindowManager &windows,
bool debug,
OMW::Engine& engine,
const std::string& defaultFile,
const std::string& userFile, bool userFileExists)
: mOgre(ogre)
, mPlayer(player)
, mWindows(windows)
, mEngine(engine)
, mMouseLookEnabled(true)
, mMouseX(ogre.getWindow()->getWidth ()/2.f)
, mMouseY(ogre.getWindow()->getHeight ()/2.f)
, mUserFile(userFile)
, mDragDrop(false)
{
A_Quit, // Exit the program
A_Screenshot, // Take a screenshot
A_Inventory, // Toggle inventory screen
A_Console, // Toggle console screen
A_MoveLeft, // Move player left / right
A_MoveRight,
A_MoveForward, // Forward / Backward
A_MoveBackward,
A_Activate,
A_Use, //Use weapon, spell, etc.
A_Jump,
A_AutoMove, //Toggle Auto-move forward
A_Rest, //Rest
A_Journal, //Journal
A_Weapon, //Draw/Sheath weapon
A_Spell, //Ready/Unready Casting
A_AlwaysRun, //Toggle Always Run
A_CycleSpellLeft, //cycling through spells
A_CycleSpellRight,
A_CycleWeaponLeft,//Cycling through weapons
A_CycleWeaponRight,
A_ToggleSneak, //Toggles Sneak, add Push-Sneak later
A_ToggleWalk, //Toggle Walking/Running
A_Crouch,
A_QuickSave,
A_QuickLoad,
A_QuickMenu,
A_GameMenu,
A_ToggleWeapon,
A_ToggleSpell,
A_LAST // Marker for the last item
};
// Class that handles all input and key bindings for OpenMW
class InputImpl
{
OEngine::Input::DispatcherPtr disp;
OEngine::Render::OgreRenderer &ogre;
Mangle::Input::OISDriver input;
OEngine::Input::Poller poller;
MouseLookEventPtr mouse;
OEngine::GUI::EventInjectorPtr guiEvents;
MWWorld::Player &player;
MWBase::WindowManager &windows;
OMW::Engine& mEngine;
bool mDragDrop;
std::map<std::string, bool> mControlSwitch;
/* InputImpl Methods */
public:
void adjustMouseRegion(int width, int height)
{
input.adjustMouseClippingSize(width, height);
}
private:
void toggleSpell()
{
if (windows.isGuiMode()) return;
Ogre::RenderWindow* window = ogre.getWindow ();
size_t windowHnd;
MWMechanics::DrawState_ state = player.getDrawState();
if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing)
{
player.setDrawState(MWMechanics::DrawState_Spell);
std::cout << "Player has now readied his hands for spellcasting!\n";
}
else
{
player.setDrawState(MWMechanics::DrawState_Nothing);
std::cout << "Player does not have any kind of attack ready now.\n";
}
}
window->getCustomAttribute("WINDOW", &windowHnd);
void toggleWeapon()
{
if (windows.isGuiMode()) return;
std::ostringstream windowHndStr;
OIS::ParamList pl;
MWMechanics::DrawState_ state = player.getDrawState();
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
{
player.setDrawState(MWMechanics::DrawState_Weapon);
std::cout << "Player is now drawing his weapon.\n";
}
else
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
// Set non-exclusive mouse and keyboard input if the user requested
// it.
if (debug)
{
player.setDrawState(MWMechanics::DrawState_Nothing);
std::cout << "Player does not have any kind of attack ready now.\n";
#if defined OIS_WIN32_PLATFORM
pl.insert(std::make_pair(std::string("w32_mouse"),
std::string("DISCL_FOREGROUND" )));
pl.insert(std::make_pair(std::string("w32_mouse"),
std::string("DISCL_NONEXCLUSIVE")));
pl.insert(std::make_pair(std::string("w32_keyboard"),
std::string("DISCL_FOREGROUND")));
pl.insert(std::make_pair(std::string("w32_keyboard"),
std::string("DISCL_NONEXCLUSIVE")));
#elif defined OIS_LINUX_PLATFORM
pl.insert(std::make_pair(std::string("x11_mouse_grab"),
std::string("false")));
pl.insert(std::make_pair(std::string("x11_mouse_hide"),
std::string("false")));
pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
std::string("false")));
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
std::string("true")));
#endif
}
}
void screenshot()
{
mEngine.screenshot();
#ifdef __APPLE_CC__
// Give the application window focus to receive input events
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
#endif
std::vector<std::string> empty;
windows.messageBox ("Screenshot saved", empty);
}
mInputManager = OIS::InputManager::createInputSystem( pl );
/* toggleInventory() is called when the user presses the button to toggle the inventory screen. */
void toggleInventory()
{
using namespace MWGui;
// Create all devices
mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject
( OIS::OISKeyboard, true ));
mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject
( OIS::OISMouse, true ));
if (mDragDrop)
return;
mKeyboard->setEventCallback (this);
mMouse->setEventCallback (this);
bool gameMode = !windows.isGuiMode();
adjustMouseRegion (window->getWidth(), window->getHeight());
// Toggle between game mode and inventory mode
if(gameMode)
windows.pushGuiMode(GM_Inventory);
else if(windows.getMode() == GM_Inventory)
windows.popGuiMode();
MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs);
// .. but don't touch any other mode.
}
std::string configFile;
if (userFileExists)
configFile = userFile;
else
configFile = defaultFile;
// Toggle console
void toggleConsole()
{
using namespace MWGui;
if (mDragDrop)
return;
bool gameMode = !windows.isGuiMode();
// Switch to console mode no matter what mode we are currently
// in, except of course if we are already in console mode
if (!gameMode)
{
if (windows.getMode() == GM_Console)
windows.popGuiMode();
else
windows.pushGuiMode(GM_Console);
}
else
windows.pushGuiMode(GM_Console);
}
std::cout << "Loading input configuration: " << configFile << std::endl;
void toggleJournal()
{
using namespace MWGui;
mInputCtrl = new ICS::InputControlSystem(configFile, true, NULL, NULL, A_LAST);
// Toggle between game mode and journal mode
bool gameMode = !windows.isGuiMode();
for (int i = 0; i < A_LAST; ++i)
{
mInputCtrl->getChannel (i)->addListener (this);
}
if(gameMode)
windows.pushGuiMode(GM_Journal);
else if(windows.getMode() == GM_Journal)
windows.popGuiMode();
// .. but don't touch any other mode.
}
mControlSwitch["playercontrols"] = true;
mControlSwitch["playerfighting"] = true;
mControlSwitch["playerjumping"] = true;
mControlSwitch["playerlooking"] = true;
mControlSwitch["playermagic"] = true;
mControlSwitch["playerviewswitch"] = true;
mControlSwitch["vanitymode"] = true;
void activate()
{
mEngine.activate();
changeInputMode(false);
}
void toggleAutoMove()
InputManager::~InputManager()
{
if (windows.isGuiMode()) return;
player.setAutoMove (!player.getAutoMove());
}
mInputCtrl->save (mUserFile);
void toggleWalking()
{
if (windows.isGuiMode()) return;
player.toggleRunning();
}
delete mInputCtrl;
void toggleMainMenu()
{
if (windows.isGuiMode () && (windows.getMode () == MWGui::GM_MainMenu || windows.getMode () == MWGui::GM_Settings))
windows.popGuiMode();
else
windows.pushGuiMode (MWGui::GM_MainMenu);
mInputManager->destroyInputObject(mKeyboard);
mInputManager->destroyInputObject(mMouse);
OIS::InputManager::destroyInputSystem(mInputManager);
}
// Exit program now button (which is disabled in GUI mode)
void exitNow()
void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue)
{
if(!windows.isGuiMode())
Ogre::Root::getSingleton().queueEndRendering ();
}
if (mDragDrop)
return;
public:
InputImpl(OEngine::Render::OgreRenderer &_ogre,
MWWorld::Player &_player,
MWBase::WindowManager &_windows,
bool debug,
OMW::Engine& engine)
: ogre(_ogre),
input(ogre.getWindow(), !debug),
poller(input),
player(_player),
windows(_windows),
mEngine (engine),
mDragDrop(false)
{
using namespace OEngine::Input;
using namespace OEngine::Render;
using namespace OEngine::GUI;
using namespace Mangle::Input;
using namespace OIS;
disp = DispatcherPtr(new Dispatcher(A_LAST));
// Bind MW-specific functions
disp->funcs.bind(A_Quit, boost::bind(&InputImpl::exitNow, this),
"Quit program");
disp->funcs.bind(A_Screenshot, boost::bind(&InputImpl::screenshot, this),
"Screenshot");
disp->funcs.bind(A_Inventory, boost::bind(&InputImpl::toggleInventory, this),
"Toggle inventory screen");
disp->funcs.bind(A_Console, boost::bind(&InputImpl::toggleConsole, this),
"Toggle console");
disp->funcs.bind(A_Journal, boost::bind(&InputImpl::toggleJournal, this),
"Toggle journal");
disp->funcs.bind(A_Activate, boost::bind(&InputImpl::activate, this),
"Activate");
disp->funcs.bind(A_AutoMove, boost::bind(&InputImpl::toggleAutoMove, this),
"Auto Move");
disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this),
"Toggle Walk/Run");
disp->funcs.bind(A_ToggleWeapon,boost::bind(&InputImpl::toggleWeapon,this),
"Draw Weapon");
disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this),
"Ready hands");
disp->funcs.bind(A_GameMenu, boost::bind(&InputImpl::toggleMainMenu, this),
"Toggle main menu");
mouse = MouseLookEventPtr(new MouseLookEvent());
// This event handler pumps events into MyGUI
guiEvents = EventInjectorPtr(new EventInjector(windows.getGui()));
// Hook 'mouse' and 'disp' up as event handlers into 'input'
// (the OIS driver and event source.) We do this through an
// EventList which dispatches the event to multiple handlers for
// us.
{
EventList *lst = new EventList;
input.setEvent(EventPtr(lst));
lst->add(mouse,Event::EV_MouseMove);
lst->add(disp,Event::EV_KeyDown);
lst->add(guiEvents,Event::EV_ALL);
}
mControlSwitch["playercontrols"] = true;
mControlSwitch["playerfighting"] = true;
mControlSwitch["playerjumping"] = true;
mControlSwitch["playerlooking"] = true;
mControlSwitch["playermagic"] = true;
mControlSwitch["playerviewswitch"] = true;
mControlSwitch["vanitymode"] = true;
changeInputMode(false);
/**********************************
Key binding section
The rest of this function has hard coded key bindings, and is
intended to be replaced by user defined bindings later.
**********************************/
// Key bindings for keypress events
// NOTE: These keys do not require constant polling - use in conjuction with variables in loops.
disp->bind(A_Quit, KC_Q);
disp->bind(A_GameMenu, KC_ESCAPE);
disp->bind(A_Screenshot, KC_SYSRQ);
disp->bind(A_Inventory, KC_I);
disp->bind(A_Console, KC_F1);
disp->bind(A_Journal, KC_J);
disp->bind(A_Activate, KC_SPACE);
disp->bind(A_AutoMove, KC_Z);
disp->bind(A_ToggleSneak, KC_X);
disp->bind(A_ToggleWalk, KC_C);
disp->bind(A_ToggleWeapon,KC_F);
disp->bind(A_ToggleSpell,KC_R);
// Key bindings for polled keys
// NOTE: These keys are constantly being polled. Only add keys that must be checked each frame.
// Arrow keys
poller.bind(A_MoveLeft, KC_LEFT);
poller.bind(A_MoveRight, KC_RIGHT);
poller.bind(A_MoveForward, KC_UP);
poller.bind(A_MoveBackward, KC_DOWN);
// WASD keys
poller.bind(A_MoveLeft, KC_A);
poller.bind(A_MoveRight, KC_D);
poller.bind(A_MoveForward, KC_W);
poller.bind(A_MoveBackward, KC_S);
poller.bind(A_Jump, KC_E);
poller.bind(A_Crouch, KC_LCONTROL);
}
int action = channel->getNumber();
if (currentValue == 1)
{
// trigger action activated
void setDragDrop(bool dragDrop)
{
mDragDrop = dragDrop;
switch (action)
{
case A_GameMenu:
toggleMainMenu ();
break;
case A_Quit:
exitNow();
break;
case A_Screenshot:
screenshot();
break;
case A_Inventory:
toggleInventory ();
break;
case A_Console:
toggleConsole ();
break;
case A_Activate:
activate();
break;
case A_Journal:
toggleJournal ();
break;
case A_AutoMove:
toggleAutoMove ();
break;
case A_ToggleSneak:
/// \todo implement
break;
case A_ToggleWalk:
toggleWalking ();
break;
case A_ToggleWeapon:
toggleWeapon ();
break;
case A_ToggleSpell:
toggleSpell ();
break;
}
}
}
//NOTE: Used to check for movement keys
void update ()
void InputManager::update(float dt)
{
// Tell OIS to handle all input events
input.capture();
mKeyboard->capture();
mMouse->capture();
// update values of channels (as a result of pressed keys)
mInputCtrl->update(dt);
// Update windows/gui as a result of input events
// For instance this could mean opening a new window/dialog,
@ -359,150 +202,314 @@ private:
// ensure that window/gui changes appear quickly while
// avoiding that window/gui changes does not happen in
// event callbacks (which may crash)
windows.update();
mWindows.update();
// Disable movement in Gui mode
if (mWindows.isGuiMode()) return;
if (windows.isGuiMode()) return;
// Configure player movement according to keyboard input. Actual movement will
// be done in the physics system.
if (mControlSwitch["playercontrols"]) {
if (poller.isDown(A_MoveLeft))
if (mControlSwitch["playercontrols"])
{
if (actionIsActive(A_MoveLeft))
{
player.setAutoMove (false);
player.setLeftRight (1);
mPlayer.setAutoMove (false);
mPlayer.setLeftRight (1);
}
else if (poller.isDown(A_MoveRight))
else if (actionIsActive(A_MoveRight))
{
player.setAutoMove (false);
player.setLeftRight (-1);
mPlayer.setAutoMove (false);
mPlayer.setLeftRight (-1);
}
else
player.setLeftRight (0);
mPlayer.setLeftRight (0);
if (poller.isDown(A_MoveForward))
if (actionIsActive(A_MoveForward))
{
player.setAutoMove (false);
player.setForwardBackward (1);
mPlayer.setAutoMove (false);
mPlayer.setForwardBackward (1);
}
else if (poller.isDown(A_MoveBackward))
else if (actionIsActive(A_MoveBackward))
{
player.setAutoMove (false);
player.setForwardBackward (-1);
mPlayer.setAutoMove (false);
mPlayer.setForwardBackward (-1);
}
else
player.setForwardBackward (0);
mPlayer.setForwardBackward (0);
if (poller.isDown(A_Jump) && mControlSwitch["playerjumping"])
player.setUpDown (1);
else if (poller.isDown(A_Crouch))
player.setUpDown (-1);
if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"])
mPlayer.setUpDown (1);
else if (actionIsActive(A_Crouch))
mPlayer.setUpDown (-1);
else
player.setUpDown (0);
mPlayer.setUpDown (0);
}
}
void InputManager::setDragDrop(bool dragDrop)
{
mDragDrop = dragDrop;
}
// Switch between gui modes. Besides controlling the Gui windows
// this also makes sure input is directed to the right place
void changeInputMode(bool guiMode)
void InputManager::changeInputMode(bool guiMode)
{
// Are we in GUI mode now?
if(guiMode)
// Are we in GUI mode now?
if(guiMode)
{
// Disable mouse look
mouse->disable();
// Disable mouse look
mMouseLookEnabled = false;
// Enable GUI events
guiEvents->enabled = true;
// Enable GUI events
mGuiCursorEnabled = true;
}
else
else
{
// Start mouse-looking again if allowed.
if (mControlSwitch["playerlooking"]) {
mouse->enable();
mMouseLookEnabled = true;
}
// Disable GUI events
guiEvents->enabled = false;
// Disable GUI events
mGuiCursorEnabled = false;
}
}
void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed)
{
bool changeRes = false;
for (Settings::CategorySettingVector::const_iterator it = changed.begin();
it != changed.end(); ++it)
{
if (it->first == "Video" && (it->second == "resolution x" || it->second == "resolution y"))
changeRes = true;
}
if (changeRes)
adjustMouseRegion(Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video"));
}
void toggleControlSwitch(std::string sw, bool value)
void InputManager::toggleControlSwitch (const std::string& sw, bool value)
{
if (mControlSwitch[sw] == value) {
return;
}
/// \note 7 switches at all, if-else is relevant
if (sw == "playercontrols" && !value) {
player.setLeftRight(0);
player.setForwardBackward(0);
player.setAutoMove(false);
player.setUpDown(0);
mPlayer.setLeftRight(0);
mPlayer.setForwardBackward(0);
mPlayer.setAutoMove(false);
mPlayer.setUpDown(0);
} else if (sw == "playerjumping" && !value) {
/// \fixme maybe crouching at this time
player.setUpDown(0);
mPlayer.setUpDown(0);
} else if (sw == "playerlooking") {
if (value) {
mouse->enable();
mMouseLookEnabled = true;
} else {
mouse->disable();
mMouseLookEnabled = false;
}
}
mControlSwitch[sw] = value;
}
};
/***CONSTRUCTOR***/
MWInputManager::MWInputManager(OEngine::Render::OgreRenderer &ogre,
MWWorld::Player &player,
MWBase::WindowManager &windows,
bool debug,
OMW::Engine& engine)
{
impl = new InputImpl(ogre,player,windows,debug, engine);
}
/***DESTRUCTOR***/
MWInputManager::~MWInputManager()
{
delete impl;
}
void MWInputManager::update()
{
impl->update();
}
void MWInputManager::setDragDrop(bool dragDrop)
{
impl->setDragDrop(dragDrop);
}
void MWInputManager::changeInputMode(bool guiMode)
{
impl->changeInputMode(guiMode);
}
void MWInputManager::processChangedSettings(const Settings::CategorySettingVector& changed)
{
bool changeRes = false;
for (Settings::CategorySettingVector::const_iterator it = changed.begin();
it != changed.end(); ++it)
{
if (it->first == "Video" && (
it->second == "resolution x"
|| it->second == "resolution y"))
changeRes = true;
}
void InputManager::adjustMouseRegion(int width, int height)
{
const OIS::MouseState &ms = mMouse->getMouseState();
ms.width = width;
ms.height = height;
}
if (changeRes)
impl->adjustMouseRegion(Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video"));
}
bool InputManager::keyPressed( const OIS::KeyEvent &arg )
{
mInputCtrl->keyPressed (arg);
if (mGuiCursorEnabled)
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.key), arg.text);
return true;
}
void MWInputManager::toggleControlSwitch (const std::string& sw, bool value)
bool InputManager::keyReleased( const OIS::KeyEvent &arg )
{
impl->toggleControlSwitch(sw, value);
mInputCtrl->keyReleased (arg);
if (mGuiCursorEnabled)
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key));
return true;
}
bool InputManager::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
mInputCtrl->mousePressed (arg, id);
if (mGuiCursorEnabled)
MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id));
return true;
}
bool InputManager::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
mInputCtrl->mouseReleased (arg, id);
if (mGuiCursorEnabled)
MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id));
return true;
}
bool InputManager::mouseMoved( const OIS::MouseEvent &arg )
{
mInputCtrl->mouseMoved (arg);
if (mGuiCursorEnabled)
{
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
// We keep track of our own mouse position, so that moving the mouse while in
// game mode does not move the position of the GUI cursor
mMouseX += arg.state.X.rel;
mMouseY += arg.state.Y.rel;
mMouseX = std::max(0, std::min(mMouseX, viewSize.width));
mMouseY = std::max(0, std::min(mMouseY, viewSize.height));
MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, arg.state.Z.abs);
}
if (mMouseLookEnabled)
{
float x = arg.state.X.rel * 0.2;
float y = arg.state.Y.rel * 0.2;
MWBase::World *world = MWBase::Environment::get().getWorld();
world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true);
}
return true;
}
void InputManager::toggleMainMenu()
{
if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings))
mWindows.popGuiMode();
else
mWindows.pushGuiMode (MWGui::GM_MainMenu);
}
void InputManager::toggleSpell()
{
if (mWindows.isGuiMode()) return;
MWMechanics::DrawState_ state = mPlayer.getDrawState();
if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing)
{
mPlayer.setDrawState(MWMechanics::DrawState_Spell);
std::cout << "Player has now readied his hands for spellcasting!\n" << std::endl;
}
else
{
mPlayer.setDrawState(MWMechanics::DrawState_Nothing);
std::cout << "Player does not have any kind of attack ready now.\n" << std::endl;
}
}
void InputManager::toggleWeapon()
{
if (mWindows.isGuiMode()) return;
MWMechanics::DrawState_ state = mPlayer.getDrawState();
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
{
mPlayer.setDrawState(MWMechanics::DrawState_Weapon);
std::cout << "Player is now drawing his weapon.\n" << std::endl;
}
else
{
mPlayer.setDrawState(MWMechanics::DrawState_Nothing);
std::cout << "Player does not have any kind of attack ready now.\n" << std::endl;
}
}
void InputManager::screenshot()
{
mEngine.screenshot();
std::vector<std::string> empty;
mWindows.messageBox ("Screenshot saved", empty);
}
void InputManager::toggleInventory()
{
bool gameMode = !mWindows.isGuiMode();
// Toggle between game mode and inventory mode
if(gameMode)
mWindows.pushGuiMode(MWGui::GM_Inventory);
else if(mWindows.getMode() == MWGui::GM_Inventory)
mWindows.popGuiMode();
// .. but don't touch any other mode.
}
void InputManager::toggleConsole()
{
bool gameMode = !mWindows.isGuiMode();
// Switch to console mode no matter what mode we are currently
// in, except of course if we are already in console mode
if (!gameMode)
{
if (mWindows.getMode() == MWGui::GM_Console)
mWindows.popGuiMode();
else
mWindows.pushGuiMode(MWGui::GM_Console);
}
else
mWindows.pushGuiMode(MWGui::GM_Console);
}
void InputManager::toggleJournal()
{
// Toggle between game mode and journal mode
bool gameMode = !mWindows.isGuiMode();
if(gameMode)
mWindows.pushGuiMode(MWGui::GM_Journal);
else if(mWindows.getMode() == MWGui::GM_Journal)
mWindows.popGuiMode();
// .. but don't touch any other mode.
}
void InputManager::activate()
{
mEngine.activate();
}
void InputManager::toggleAutoMove()
{
if (mWindows.isGuiMode()) return;
mPlayer.setAutoMove (!mPlayer.getAutoMove());
}
void InputManager::toggleWalking()
{
if (mWindows.isGuiMode()) return;
mPlayer.toggleRunning();
}
// Exit program now button (which is disabled in GUI mode)
void InputManager::exitNow()
{
if(!mWindows.isGuiMode())
Ogre::Root::getSingleton().queueEndRendering ();
}
bool InputManager::actionIsActive (int id)
{
return mInputCtrl->getChannel (id)->getValue () == 1;
}
}

@ -9,20 +9,20 @@
namespace OEngine
{
namespace Render
{
class OgreRenderer;
}
namespace Render
{
class OgreRenderer;
}
}
namespace MWWorld
{
class Player;
class Player;
}
namespace MWBase
{
class WindowManager;
class WindowManager;
}
namespace OMW
@ -30,37 +30,154 @@ namespace OMW
class Engine;
}
namespace ICS
{
class InputControlSystem;
}
namespace OIS
{
class Keyboard;
class Mouse;
class InputManager;
}
#include <OIS/OISKeyboard.h>
#include <OIS/OISMouse.h>
#include <extern/oics/ICSChannelListener.h>
namespace MWInput
{
// Forward declaration of the real implementation.
class InputImpl;
/* Class that handles all input and key bindings for OpenMW.
/**
* @brief Class that handles all input and key bindings for OpenMW.
*/
class InputManager : public MWBase::InputManager, public OIS::KeyListener, public OIS::MouseListener, public ICS::ChannelListener
{
public:
InputManager(OEngine::Render::OgreRenderer &_ogre,
MWWorld::Player&_player,
MWBase::WindowManager &_windows,
bool debug,
OMW::Engine& engine,
const std::string& defaultFile,
const std::string& userFile, bool userFileExists);
virtual ~InputManager();
virtual void update(float dt);
virtual void changeInputMode(bool guiMode);
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
virtual void setDragDrop(bool dragDrop);
virtual void toggleControlSwitch (const std::string& sw, bool value);
public:
virtual bool keyPressed( const OIS::KeyEvent &arg );
virtual bool keyReleased( const OIS::KeyEvent &arg );
virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id );
virtual bool mouseMoved( const OIS::MouseEvent &arg );
virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue);
private:
OEngine::Render::OgreRenderer &mOgre;
MWWorld::Player &mPlayer;
MWBase::WindowManager &mWindows;
OMW::Engine& mEngine;
ICS::InputControlSystem* mInputCtrl;
OIS::Keyboard* mKeyboard;
OIS::Mouse* mMouse;
OIS::InputManager* mInputManager;
std::string mUserFile;
bool mDragDrop;
bool mMouseLookEnabled;
bool mGuiCursorEnabled;
int mMouseX;
int mMouseY;
std::map<std::string, bool> mControlSwitch;
private:
void adjustMouseRegion(int width, int height);
private:
void toggleMainMenu();
void toggleSpell();
void toggleWeapon();
void toggleInventory();
void toggleConsole();
void screenshot();
void toggleJournal();
void activate();
void toggleWalking();
void toggleAutoMove();
void exitNow();
bool actionIsActive (int id);
private:
enum Actions
{
// please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files
A_GameMenu,
A_Quit, // Exit the program
A_Screenshot, // Take a screenshot
A_Inventory, // Toggle inventory screen
A_Console, // Toggle console screen
This class is just an interface. All the messy details are in
inputmanager.cpp.
*/
struct MWInputManager : public MWBase::InputManager
{
InputImpl *impl;
A_MoveLeft, // Move player left / right
A_MoveRight,
A_MoveForward, // Forward / Backward
A_MoveBackward,
public:
MWInputManager(OEngine::Render::OgreRenderer &_ogre,
MWWorld::Player&_player,
MWBase::WindowManager &_windows,
bool debug,
OMW::Engine& engine);
virtual ~MWInputManager();
A_Activate,
virtual void update();
A_Use, //Use weapon, spell, etc.
A_Jump,
A_AutoMove, //Toggle Auto-move forward
A_Rest, //Rest
A_Journal, //Journal
A_Weapon, //Draw/Sheath weapon
A_Spell, //Ready/Unready Casting
A_AlwaysRun, //Toggle Always Run
A_CycleSpellLeft, //cycling through spells
A_CycleSpellRight,
A_CycleWeaponLeft,//Cycling through weapons
A_CycleWeaponRight,
A_ToggleSneak, //Toggles Sneak, add Push-Sneak later
A_ToggleWalk, //Toggle Walking/Running
A_Crouch,
virtual void changeInputMode(bool guiMode);
A_QuickSave,
A_QuickLoad,
A_QuickMenu,
A_ToggleWeapon,
A_ToggleSpell,
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
A_LAST // Marker for the last item
};
virtual void setDragDrop(bool dragDrop);
virtual void toggleControlSwitch (const std::string& sw, bool value);
};
};
}
#endif

@ -1,28 +0,0 @@
#include "mouselookevent.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include <OIS/OIS.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
using namespace OIS;
using namespace MWInput;
void MouseLookEvent::event(Type type, int index, const void *p)
{
if (type != EV_MouseMove || mDisabled) {
return;
}
MouseEvent *arg = (MouseEvent*)(p);
float x = arg->state.X.rel * sensX;
float y = arg->state.Y.rel * sensY;
MWBase::World *world = MWBase::Environment::get().getWorld();
world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true);
}

@ -1,57 +0,0 @@
#ifndef _MWINPUT_MOUSELOOKEVENT_H
#define _MWINPUT_MOUSELOOKEVENT_H
/*
A mouse-look class for Ogre. Accepts input events from Mangle::Input
and translates them.
You can adjust the mouse sensibility and switch to a different
camera. The mouselook class also has an optional wrap protection
that keeps the camera from flipping upside down.
You can disable the mouse looker at any time by calling
setCamera(NULL), and reenable it by setting the camera back.
NOTE: The current implementation will ONLY work for native OIS
events.
*/
#include <mangle/input/event.hpp>
namespace MWInput
{
class MouseLookEvent : public Mangle::Input::Event
{
float sensX, sensY; // Mouse sensibility
bool flipProt; // Flip protection
bool mDisabled;
public:
MouseLookEvent(float sX = 0.2, float sY = 0.2, bool prot=true)
: sensX(sX), sensY(sY), flipProt(prot)
{}
void setSens(float sX, float sY) {
sensX = sX;
sensY = sY;
}
void setProt(bool p) {
flipProt = p;
}
void disable() {
mDisabled = true;
}
void enable() {
mDisabled = false;
}
void event(Type type, int index, const void *p);
};
typedef boost::shared_ptr<MouseLookEvent> MouseLookEventPtr;
}
#endif

@ -0,0 +1,20 @@
set(OICS_LIBRARY "oics")
# Sources
set(OICS_SOURCE_FILES
ICSChannel.cpp
ICSControl.cpp
ICSInputControlSystem.cpp
ICSInputControlSystem_keyboard.cpp
ICSInputControlSystem_mouse.cpp
ICSInputControlSystem_joystick.cpp
tinyxml.cpp
tinyxmlparser.cpp
tinyxmlerror.cpp
tinystr.cpp
)
add_library(${OICS_LIBRARY} STATIC ${OICS_SOURCE_FILES})
link_directories(${CMAKE_CURRENT_BINARY_DIR})

@ -0,0 +1,258 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSInputControlSystem.h"
#define B1(t) (t*t)
#define B2(t) (2*t*(1-t))
#define B3(t) ((1-t)*(1-t))
namespace ICS
{
Channel::Channel(int number, float initialValue
, float bezierMidPointY, float bezierMidPointX, float symmetricAt, float bezierStep)
: mNumber(number)
, mValue(initialValue)
, mSymmetricAt(symmetricAt)
, mBezierStep(bezierStep)
{
mBezierMidPoint.x = bezierMidPointX;
mBezierMidPoint.y = bezierMidPointY;
setBezierFunction(bezierMidPointY, bezierMidPointX, symmetricAt, bezierStep);
}
float Channel::getValue()
{
if(mValue == 0 || mValue == 1)
{
return mValue;
}
BezierFunction::iterator it = mBezierFunction.begin();
//size_t size_minus_1 = mBezierFunction.size() - 1;
BezierFunction::iterator last = mBezierFunction.end();
last--;
for ( ; it != last ; )
{
BezierPoint left = (*it);
BezierPoint right = (*(++it));
if( (left.x <= mValue) && (right.x > mValue) )
{
float val = left.y - (left.x - mValue) * (left.y - right.y) / (left.x - right.x);
return std::max<float>(0.0,std::min<float>(1.0, val));
}
}
return -1;
}
void Channel::setValue(float value)
{
float previousValue = this->getValue();
mValue = value;
if(previousValue != value)
{
notifyListeners(previousValue);
}
}
void Channel::notifyListeners(float previousValue)
{
std::list<ChannelListener*>::iterator pos = mListeners.begin();
while (pos != mListeners.end())
{
((ChannelListener* )(*pos))->channelChanged((Channel*)this, this->getValue(), previousValue);
++pos;
}
}
void Channel::addControl(Control* control, Channel::ChannelDirection dir, float percentage)
{
ControlChannelBinderItem ccBinderItem;
ccBinderItem.control = control;
ccBinderItem.direction = dir;
ccBinderItem.percentage = percentage;
mAttachedControls.push_back(ccBinderItem);
}
Channel::ControlChannelBinderItem Channel::getAttachedControlBinding(Control* control)
{
for(std::vector<ControlChannelBinderItem>::iterator it = mAttachedControls.begin() ;
it != mAttachedControls.end() ; it++)
{
if((*it).control == control)
{
return (*it);
}
}
ControlChannelBinderItem nullBinderItem;
nullBinderItem.control = NULL;
nullBinderItem.direction = Channel/*::ChannelDirection*/::DIRECT;
nullBinderItem.percentage = 0;
return nullBinderItem;
}
void Channel::update()
{
if(this->getControlsCount() == 1)
{
ControlChannelBinderItem ccBinderItem = mAttachedControls.back();
float diff = ccBinderItem.control->getValue() - ccBinderItem.control->getInitialValue();
if(ccBinderItem.direction == ICS::Channel::DIRECT)
{
this->setValue(ccBinderItem.control->getInitialValue() + (ccBinderItem.percentage * diff));
}
else
{
this->setValue(ccBinderItem.control->getInitialValue() - (ccBinderItem.percentage * diff));
}
}
else
{
float val = 0;
std::vector<ControlChannelBinderItem>::const_iterator it;
for(it=mAttachedControls.begin(); it!=mAttachedControls.end(); ++it)
{
ControlChannelBinderItem ccBinderItem = (*it);
float diff = ccBinderItem.control->getValue() - ccBinderItem.control->getInitialValue();
if(ccBinderItem.direction == ICS::Channel::DIRECT)
{
val += (ccBinderItem.percentage * diff);
}
else
{
val -= (ccBinderItem.percentage * diff);
}
}
if(mAttachedControls.size() > 0)
{
this->setValue(mAttachedControls.begin()->control->getInitialValue() + val);
}
}
}
void Channel::setBezierFunction(float bezierMidPointY, float bezierMidPointX, float symmetricAt, float bezierStep)
{
mBezierMidPoint.x = bezierMidPointX;
mBezierMidPoint.y = bezierMidPointY;
mBezierStep = bezierStep;
mSymmetricAt = symmetricAt;
mBezierFunction.clear();
BezierPoint start;
start.x = 0;
start.y = 0;
BezierPoint end;
end.x = 1;
end.y = 1;
mBezierFunction.push_front(end);
FilterInterval interval;
interval.startX = start.x;
interval.startY = start.y;
interval.midX = mBezierMidPoint.x;
interval.midY = mBezierMidPoint.y;
interval.endX = end.x;
interval.endY = end.y;
interval.step = bezierStep;
mIntervals.push_back(interval);
if(!(mBezierMidPoint.x == 0.5 && mBezierMidPoint.y == 0.5))
{
float t = mBezierStep;
while(t < 1)
{
BezierPoint p;
p.x = start.x * B1(t) + mBezierMidPoint.x * B2(t) + end.x * B3(t);
p.y = start.y * B1(t) + mBezierMidPoint.y * B2(t) + end.y * B3(t);
mBezierFunction.push_front(p);
t += mBezierStep;
}
}
mBezierFunction.push_front(start);
}
void Channel::addBezierInterval(float startX, float startY, float midX, float midY
, float endX, float endY, float step)
{
FilterInterval interval;
interval.startX = startX;
interval.startY = startY;
interval.midX = midX;
interval.midY = midY;
interval.endX = endX;
interval.endY = endY;
interval.step = step;
mIntervals.push_back(interval);
float t = 0;
while(t <= 1)
{
BezierPoint p;
p.x = startX * B1(t) + midX * B2(t) + endX * B3(t);
p.y = startY * B1(t) + midY * B2(t) + endY * B3(t);
BezierFunction::iterator it = mBezierFunction.begin();
while( it != mBezierFunction.end() )
{
BezierPoint left = (*it);
BezierPoint right;
++it;
if( it != mBezierFunction.end() )
{
right = (*it);
}
else
{
right.x = endX;
right.y = endY;
}
if(p.x > left.x && p.x < right.x)
{
mBezierFunction.insert(it, p);
break;
}
}
t += 1.0f / ((endX-startX)/step);
}
}
}

@ -0,0 +1,122 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#ifndef _Channel_H_
#define _Channel_H_
#include "ICSPrerequisites.h"
#include "ICSChannelListener.h"
namespace ICS
{
struct FilterInterval{
//std::string type; //! @todo uncomment when more types implemented
float startX;
float startY;
float midX;
float midY;
float endX;
float endY;
float step;
};
typedef std::list<FilterInterval> IntervalList;
class DllExport Channel
{
public:
enum ChannelDirection
{
INVERSE = -1, DIRECT = 1
};
typedef struct {
ChannelDirection direction;
float percentage;
Control* control;
} ControlChannelBinderItem;
Channel(int number, float initialValue = 0.5
, float bezierMidPointY = 0.5, float bezierMidPointX = 0.5
, float symmetricAt = 0, float bezierStep = 0.2); //! @todo implement symetry
~Channel(){};
void setValue(float value);
float getValue();
inline int getNumber(){ return mNumber; };
void addControl(Control* control, Channel::ChannelDirection dir, float percentage);
inline size_t getControlsCount(){ return mAttachedControls.size(); };
std::vector<ControlChannelBinderItem> getAttachedControls(){ return mAttachedControls; };
ControlChannelBinderItem getAttachedControlBinding(Control* control);
void addListener(ChannelListener* ob){ mListeners.push_back(ob); };
void removeListener(ChannelListener* ob){ mListeners.remove(ob); };
void update();
void setBezierFunction(float bezierMidPointY, float bezierMidPointX = 0.5
, float symmetricAt = 0, float bezierStep = 0.2);
void addBezierInterval(float startX, float startY, float midX, float midY
, float endX, float endY, float step = 0.1);
IntervalList& getIntervals(){ return mIntervals; };
protected:
int mNumber;
float mValue;
struct BezierPoint{
float x;
float y;
bool operator < (const BezierPoint& other){ return x < other.x; }
};
typedef std::list<BezierPoint> BezierFunction;
BezierPoint mBezierMidPoint;
BezierFunction mBezierFunction;
float mSymmetricAt;
float mBezierStep;
IntervalList mIntervals;
std::vector<ControlChannelBinderItem> mAttachedControls;
std::list<ChannelListener* > mListeners;
void notifyListeners(float previousValue);
};
}
#endif

@ -0,0 +1,46 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#ifndef _ChannelListener_H_
#define _ChannelListener_H_
#include "ICSPrerequisites.h"
#include "ICSChannel.h"
namespace ICS
{
class DllExport ChannelListener
{
public:
virtual void channelChanged(Channel* channel, float currentValue, float previousValue) = 0;
};
}
#endif

@ -0,0 +1,161 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSInputControlSystem.h"
#include "ICSControl.h"
namespace ICS
{
Control::Control(const std::string name, bool autoChangeDirectionOnLimitsAfterStop, bool autoReverseToInitialValue
, float initialValue, float stepSize, float stepsPerSeconds, bool axisBindable)
: mName(name)
, mValue(initialValue)
, mInitialValue(initialValue)
, mStepSize(stepSize)
, mStepsPerSeconds(stepsPerSeconds)
, mAutoReverseToInitialValue(autoReverseToInitialValue)
, mIgnoreAutoReverse(false)
, mAutoChangeDirectionOnLimitsAfterStop(autoChangeDirectionOnLimitsAfterStop)
, mAxisBindable(axisBindable)
, currentChangingDirection(STOP)
{
}
Control::~Control()
{
mAttachedChannels.clear();
}
void Control::setValue(float value)
{
float previousValue = mValue;
mValue = std::max<float>(0.0,std::min<float>(1.0,value));
if(mValue != previousValue)
{
updateChannels();
notifyListeners(previousValue);
}
}
void Control::attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage)
{
mAttachedChannels.push_back(channel);
channel->addControl(this, direction, percentage);
}
void Control::updateChannels()
{
std::list<Channel*>::iterator pos = mAttachedChannels.begin();
while (pos != mAttachedChannels.end())
{
((Channel* )(*pos))->update();
++pos;
}
}
void Control::notifyListeners(float previousValue)
{
std::list<ControlListener*>::iterator pos = mListeners.begin();
while (pos != mListeners.end())
{
((ControlListener* )(*pos))->controlChanged((Control*)this, this->getValue(), previousValue);
++pos;
}
}
void Control::setChangingDirection(ControlChangingDirection direction)
{
currentChangingDirection = direction;
mPendingActions.push_back(direction);
}
void Control::update(float timeSinceLastFrame)
{
if(mPendingActions.size() > 0)
{
size_t timedActionsCount = 0;
std::list<Control::ControlChangingDirection>::iterator cached_end = mPendingActions.end();
for(std::list<Control::ControlChangingDirection>::iterator it = mPendingActions.begin() ;
it != cached_end ; it++)
{
if( (*it) != Control::STOP )
{
timedActionsCount++;
}
}
float timeSinceLastFramePart = timeSinceLastFrame / std::max<size_t>(1, timedActionsCount);
for(std::list<Control::ControlChangingDirection>::iterator it = mPendingActions.begin() ;
it != cached_end ; it++)
{
if( (*it) != Control::STOP )
{
this->setValue(mValue +
(((int)(*it)) * mStepSize * mStepsPerSeconds * (timeSinceLastFramePart)));
}
else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue )
{
if(mValue > mInitialValue)
{
this->setValue( std::max<float>( mInitialValue,
mValue - (mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))));
}
else if(mValue < mInitialValue)
{
this->setValue( std::min<float>( mInitialValue,
mValue + (mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))));
}
}
}
mPendingActions.clear();
}
else if( currentChangingDirection != Control::STOP )
{
this->setValue(mValue +
(((int)currentChangingDirection) * mStepSize * mStepsPerSeconds * (timeSinceLastFrame)));
}
else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue )
{
if(mValue > mInitialValue)
{
this->setValue( std::max<float>( mInitialValue,
mValue - (mStepSize * mStepsPerSeconds * (timeSinceLastFrame))));
}
else if(mValue < mInitialValue)
{
this->setValue( std::min<float>( mInitialValue,
mValue + (mStepSize * mStepsPerSeconds * (timeSinceLastFrame))));
}
}
}
}

@ -0,0 +1,107 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#ifndef _Control_H_
#define _Control_H_
#include "ICSPrerequisites.h"
#include "ICSChannel.h"
#include "ICSControlListener.h"
namespace ICS
{
class DllExport Control
{
public:
enum ControlChangingDirection
{
DECREASE = -1, STOP = 0, INCREASE = 1
};
Control(const std::string name, bool autoChangeDirectionOnLimitsAfterStop = false, bool autoReverseToInitialValue = false, float initialValue = 0.5, float stepSize = 0.1, float stepsPerSeconds = 2.0, bool axisBindable = true);
~Control();
void setChangingDirection(ControlChangingDirection direction);
inline ControlChangingDirection getChangingDirection(){ return currentChangingDirection; };
void setValue(float value);
inline float getValue(){ return mValue; };
inline float getInitialValue(){ return mInitialValue; };
void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0);
std::list<Channel*> getAttachedChannels(){ return mAttachedChannels; };
inline float getStepSize(){ return mStepSize; };
inline float getStepsPerSeconds(){ return mStepsPerSeconds; };
inline void setIgnoreAutoReverse(bool value){ mIgnoreAutoReverse = value; }; // mouse disable autoreverse
inline bool isAutoReverseIgnored(){ return mIgnoreAutoReverse; };
inline bool getAutoReverse(){ return mAutoReverseToInitialValue; };
inline bool getAutoChangeDirectionOnLimitsAfterStop(){ return mAutoChangeDirectionOnLimitsAfterStop; };
inline std::string getName(){ return mName; };
inline bool isAxisBindable(){ return mAxisBindable; };
inline void setAxisBindable(bool value){ mAxisBindable = value; };
inline void addListener(ControlListener* ob){ mListeners.push_back(ob); };
inline void removeListener(ControlListener* ob){ mListeners.remove(ob); };
void update(float timeSinceLastFrame);
protected:
float mValue;
float mInitialValue;
std::string mName;
float mStepSize;
float mStepsPerSeconds;
bool mAutoReverseToInitialValue;
bool mIgnoreAutoReverse;
bool mAutoChangeDirectionOnLimitsAfterStop;
bool mAxisBindable;
Control::ControlChangingDirection currentChangingDirection;
std::list<Channel*> mAttachedChannels;
std::list<ControlListener*> mListeners;
std::list<Control::ControlChangingDirection> mPendingActions;
protected:
void updateChannels();
void notifyListeners(float previousValue);
};
}
#endif

@ -0,0 +1,46 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#ifndef _ControlListener_H_
#define _ControlListener_H_
#include "ICSPrerequisites.h"
#include "ICSControl.h"
namespace ICS
{
class DllExport ControlListener
{
public:
virtual void controlChanged(Control* control, float currentValue, float previousValue) = 0;
};
}
#endif

@ -0,0 +1,929 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSInputControlSystem.h"
namespace ICS
{
InputControlSystem::InputControlSystem(std::string file, bool active
, DetectingBindingListener* detectingBindingListener
, InputControlSystemLog* log, size_t channelCount)
: mFileName(file)
, mDetectingBindingListener(detectingBindingListener)
, mDetectingBindingControl(NULL)
, mLog(log)
, mXmouseAxisBinded(false), mYmouseAxisBinded(false)
{
ICS_LOG(" - Creating InputControlSystem - ");
this->mActive = active;
this->fillOISKeysMap();
ICS_LOG("Channel count = " + ToString<size_t>(channelCount) );
for(size_t i=0;i<channelCount;i++)
{
mChannels.push_back(new Channel((int)i));
}
if(file != "")
{
TiXmlDocument* xmlDoc;
TiXmlElement* xmlRoot;
ICS_LOG("Loading file \""+file+"\"");
xmlDoc = new TiXmlDocument(file.c_str());
xmlDoc->LoadFile();
if(xmlDoc->Error())
{
std::ostringstream message;
message << "TinyXml reported an error reading \""+ file + "\". Row " <<
(int)xmlDoc->ErrorRow() << ", Col " << (int)xmlDoc->ErrorCol() << ": " <<
xmlDoc->ErrorDesc() ;
ICS_LOG(message.str());
delete xmlDoc;
return;
}
xmlRoot = xmlDoc->RootElement();
if(std::string(xmlRoot->Value()) != "Controller") {
ICS_LOG("Error: Invalid Controller file. Missing <Controller> element.");
delete xmlDoc;
return;
}
TiXmlElement* xmlControl = xmlRoot->FirstChildElement("Control");
size_t controlChannelCount = 0;
while(xmlControl)
{
TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel");
while(xmlChannel)
{
controlChannelCount = std::max(channelCount, FromString<size_t>(xmlChannel->Attribute("number")));
xmlChannel = xmlChannel->NextSiblingElement("Channel");
}
xmlControl = xmlControl->NextSiblingElement("Control");
}
if(controlChannelCount > channelCount)
{
size_t dif = controlChannelCount - channelCount;
ICS_LOG("Warning: default channel count exceeded. Adding " + ToString<size_t>(dif) + " channels" );
for(size_t i = channelCount ; i < controlChannelCount ; i++)
{
mChannels.push_back(new Channel((int)i));
}
}
ICS_LOG("Applying filters to channels");
//<ChannelFilter number="0">
// <interval type="bezier" startX="0.0" startY="0.0" midX="0.25" midY="0.5" endX="0.5" endY="0.5" step="0.1" />
// <interval type="bezier" startX="0.5" startY="0.5" midX="0.75" midY="0.5" endX="1.0" endY="1.0" step="0.1" />
//</ChannelFilter>
TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter");
while(xmlChannelFilter)
{
int ch = FromString<int>(xmlChannelFilter->Attribute("number"));
TiXmlElement* xmlInterval = xmlChannelFilter->FirstChildElement("Interval");
while(xmlInterval)
{
std::string type = xmlInterval->Attribute("type");
if(type == "bezier")
{
float step = 0.1;
float startX = FromString<float>(xmlInterval->Attribute("startX"));
float startY = FromString<float>(xmlInterval->Attribute("startY"));
float midX = FromString<float>(xmlInterval->Attribute("midX"));
float midY = FromString<float>(xmlInterval->Attribute("midY"));
float endX = FromString<float>(xmlInterval->Attribute("endX"));
float endY = FromString<float>(xmlInterval->Attribute("endY"));
step = FromString<float>(xmlInterval->Attribute("step"));
ICS_LOG("Applying Bezier filter to channel [number="
+ ToString<int>(ch) + ", startX="
+ ToString<float>(startX) + ", startY="
+ ToString<float>(startY) + ", midX="
+ ToString<float>(midX) + ", midY="
+ ToString<float>(midY) + ", endX="
+ ToString<float>(endX) + ", endY="
+ ToString<float>(endY) + ", step="
+ ToString<float>(step) + "]");
mChannels.at(ch)->addBezierInterval(startX, startY, midX, midY, endX, endY, step);
}
xmlInterval = xmlInterval->NextSiblingElement("Interval");
}
xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter");
}
xmlControl = xmlRoot->FirstChildElement("Control");
while(xmlControl)
{
bool axisBindable = true;
if(xmlControl->Attribute("axisBindable"))
{
axisBindable = (std::string( xmlControl->Attribute("axisBindable") ) == "true");
}
ICS_LOG("Adding Control [name="
+ std::string( xmlControl->Attribute("name") ) + ", autoChangeDirectionOnLimitsAfterStop="
+ std::string( xmlControl->Attribute("autoChangeDirectionOnLimitsAfterStop") ) + ", autoReverseToInitialValue="
+ std::string( xmlControl->Attribute("autoReverseToInitialValue") ) + ", initialValue="
+ std::string( xmlControl->Attribute("initialValue") ) + ", stepSize="
+ std::string( xmlControl->Attribute("stepSize") ) + ", stepsPerSeconds="
+ std::string( xmlControl->Attribute("stepsPerSeconds") ) + ", axisBindable="
+ std::string( (axisBindable)? "true" : "false" ) + "]");
float _stepSize = 0;
if(xmlControl->Attribute("stepSize"))
{
std::string value(xmlControl->Attribute("stepSize"));
if(value == "MAX")
{
_stepSize = ICS_MAX;
}
else
{
_stepSize = FromString<float>(value.c_str());
}
}
else
{
ICS_LOG("Warning: no stepSize value found. Default value is 0.");
}
float _stepsPerSeconds = 0;
if(xmlControl->Attribute("stepsPerSeconds"))
{
std::string value(xmlControl->Attribute("stepsPerSeconds"));
if(value == "MAX")
{
_stepsPerSeconds = ICS_MAX;
}
else
{
_stepsPerSeconds = FromString<float>(value.c_str());
}
}
else
{
ICS_LOG("Warning: no stepSize value found. Default value is 0.");
}
addControl( new Control(xmlControl->Attribute("name")
, std::string( xmlControl->Attribute("autoChangeDirectionOnLimitsAfterStop") ) == "true"
, std::string( xmlControl->Attribute("autoReverseToInitialValue") ) == "true"
, FromString<float>(xmlControl->Attribute("initialValue"))
, _stepSize
, _stepsPerSeconds
, axisBindable) );
loadKeyBinders(xmlControl);
loadMouseAxisBinders(xmlControl);
loadMouseButtonBinders(xmlControl);
loadJoystickAxisBinders(xmlControl);
loadJoystickButtonBinders(xmlControl);
loadJoystickPOVBinders(xmlControl);
loadJoystickSliderBinders(xmlControl);
// Attach controls to channels
TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel");
while(xmlChannel)
{
ICS_LOG("\tAttaching control to channel [number="
+ std::string( xmlChannel->Attribute("number") ) + ", direction="
+ std::string( xmlChannel->Attribute("direction") ) + "]");
float percentage = 1;
if(xmlChannel->Attribute("percentage"))
{
if(StringIsNumber<float>(xmlChannel->Attribute("percentage")))
{
float val = FromString<float>(xmlChannel->Attribute("percentage"));
if(val > 1 || val < 0)
{
ICS_LOG("ERROR: attaching percentage value range is [0,1]");
}
else
{
percentage = val;
}
}
else
{
ICS_LOG("ERROR: attaching percentage value range is [0,1]");
}
}
int chNumber = FromString<int>(xmlChannel->Attribute("number"));
if(std::string(xmlChannel->Attribute("direction")) == "DIRECT")
{
mControls.back()->attachChannel(mChannels[ chNumber ],Channel::DIRECT, percentage);
}
else if(std::string(xmlChannel->Attribute("direction")) == "INVERSE")
{
mControls.back()->attachChannel(mChannels[ chNumber ],Channel::INVERSE, percentage);
}
xmlChannel = xmlChannel->NextSiblingElement("Channel");
}
xmlControl = xmlControl->NextSiblingElement("Control");
}
std::vector<Channel *>::const_iterator o;
for(o = mChannels.begin(); o != mChannels.end(); ++o)
{
(*o)->update();
}
delete xmlDoc;
}
ICS_LOG(" - InputControlSystem Created - ");
}
InputControlSystem::~InputControlSystem()
{
ICS_LOG(" - Deleting InputControlSystem (" + mFileName + ") - ");
mJoystickIDList.clear();
std::vector<Channel *>::const_iterator o;
for(o = mChannels.begin(); o != mChannels.end(); ++o)
{
delete (*o);
}
mChannels.clear();
std::vector<Control *>::const_iterator o2;
for(o2 = mControls.begin(); o2 != mControls.end(); ++o2)
{
delete (*o2);
}
mControls.clear();
mControlsKeyBinderMap.clear();
mControlsMouseButtonBinderMap.clear();
mControlsJoystickButtonBinderMap.clear();
mKeys.clear();
mKeyCodes.clear();
ICS_LOG(" - InputControlSystem deleted - ");
}
std::string InputControlSystem::getBaseFileName()
{
size_t found = mFileName.find_last_of("/\\");
std::string file = mFileName.substr(found+1);
return file.substr(0, file.find_last_of("."));
}
bool InputControlSystem::save(std::string fileName)
{
if(fileName != "")
{
mFileName = fileName;
}
TiXmlDocument doc( mFileName.c_str() );
TiXmlDeclaration dec;
dec.Parse( "<?xml version='1.0' encoding='utf-8'?>", 0, TIXML_ENCODING_UNKNOWN );
doc.InsertEndChild(dec);
TiXmlElement Controller( "Controller" );
for(std::vector<Channel*>::const_iterator o = mChannels.begin() ; o != mChannels.end(); o++)
{
ICS::IntervalList intervals = (*o)->getIntervals();
if(intervals.size() > 1) // all channels have a default linear filter
{
TiXmlElement ChannelFilter( "ChannelFilter" );
ChannelFilter.SetAttribute("number", ToString<int>((*o)->getNumber()).c_str());
ICS::IntervalList::const_iterator interval = intervals.begin();
while( interval != intervals.end() )
{
// if not default linear filter
if(!( interval->step == 0.2f
&& interval->startX == 0.0f
&& interval->startY == 0.0f
&& interval->midX == 0.5f
&& interval->midY == 0.5f
&& interval->endX == 1.0f
&& interval->endY == 1.0f ))
{
TiXmlElement XMLInterval( "Interval" );
XMLInterval.SetAttribute("type", "bezier");
XMLInterval.SetAttribute("step", ToString<float>(interval->step).c_str());
XMLInterval.SetAttribute("startX", ToString<float>(interval->startX).c_str());
XMLInterval.SetAttribute("startY", ToString<float>(interval->startY).c_str());
XMLInterval.SetAttribute("midX", ToString<float>(interval->midX).c_str());
XMLInterval.SetAttribute("midY", ToString<float>(interval->midY).c_str());
XMLInterval.SetAttribute("endX", ToString<float>(interval->endX).c_str());
XMLInterval.SetAttribute("endY", ToString<float>(interval->endY).c_str());
ChannelFilter.InsertEndChild(XMLInterval);
}
interval++;
}
Controller.InsertEndChild(ChannelFilter);
}
}
for(std::vector<Control*>::const_iterator o = mControls.begin() ; o != mControls.end(); o++)
{
TiXmlElement control( "Control" );
control.SetAttribute( "name", (*o)->getName().c_str() );
if((*o)->getAutoChangeDirectionOnLimitsAfterStop())
{
control.SetAttribute( "autoChangeDirectionOnLimitsAfterStop", "true" );
}
else
{
control.SetAttribute( "autoChangeDirectionOnLimitsAfterStop", "false" );
}
if((*o)->getAutoReverse())
{
control.SetAttribute( "autoReverseToInitialValue", "true" );
}
else
{
control.SetAttribute( "autoReverseToInitialValue", "false" );
}
control.SetAttribute( "initialValue", ToString<float>((*o)->getInitialValue()).c_str() );
if((*o)->getStepSize() == ICS_MAX)
{
control.SetAttribute( "stepSize", "MAX" );
}
else
{
control.SetAttribute( "stepSize", ToString<float>((*o)->getStepSize()).c_str() );
}
if((*o)->getStepsPerSeconds() == ICS_MAX)
{
control.SetAttribute( "stepsPerSeconds", "MAX" );
}
else
{
control.SetAttribute( "stepsPerSeconds", ToString<float>((*o)->getStepsPerSeconds()).c_str() );
}
if(!(*o)->isAxisBindable())
{
control.SetAttribute( "axisBindable", "false" );
}
if(getKeyBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != OIS::KC_UNASSIGNED)
{
TiXmlElement keyBinder( "KeyBinder" );
keyBinder.SetAttribute( "key", keyCodeToString(
getKeyBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)).c_str() );
keyBinder.SetAttribute( "direction", "INCREASE" );
control.InsertEndChild(keyBinder);
}
if(getKeyBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != OIS::KC_UNASSIGNED)
{
TiXmlElement keyBinder( "KeyBinder" );
keyBinder.SetAttribute( "key", keyCodeToString(
getKeyBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)).c_str() );
keyBinder.SetAttribute( "direction", "DECREASE" );
control.InsertEndChild(keyBinder);
}
if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)
!= InputControlSystem/*::NamedAxis*/::UNASSIGNED)
{
TiXmlElement binder( "MouseBinder" );
InputControlSystem::NamedAxis axis =
getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE);
if(axis == InputControlSystem/*::NamedAxis*/::X)
{
binder.SetAttribute( "axis", "X" );
}
else if(axis == InputControlSystem/*::NamedAxis*/::Y)
{
binder.SetAttribute( "axis", "Y" );
}
else if(axis == InputControlSystem/*::NamedAxis*/::Z)
{
binder.SetAttribute( "axis", "Z" );
}
binder.SetAttribute( "direction", "INCREASE" );
control.InsertEndChild(binder);
}
if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)
!= InputControlSystem/*::NamedAxis*/::UNASSIGNED)
{
TiXmlElement binder( "MouseBinder" );
InputControlSystem::NamedAxis axis =
getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE);
if(axis == InputControlSystem/*::NamedAxis*/::X)
{
binder.SetAttribute( "axis", "X" );
}
else if(axis == InputControlSystem/*::NamedAxis*/::Y)
{
binder.SetAttribute( "axis", "Y" );
}
else if(axis == InputControlSystem/*::NamedAxis*/::Z)
{
binder.SetAttribute( "axis", "Z" );
}
binder.SetAttribute( "direction", "DECREASE" );
control.InsertEndChild(binder);
}
if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE)
!= ICS_MAX_DEVICE_BUTTONS)
{
TiXmlElement binder( "MouseButtonBinder" );
unsigned int button = getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE);
if(button == OIS::/*MouseButtonID::*/MB_Left)
{
binder.SetAttribute( "button", "LEFT" );
}
else if(button == OIS::/*MouseButtonID::*/MB_Middle)
{
binder.SetAttribute( "button", "MIDDLE" );
}
else if(button == OIS::/*MouseButtonID::*/MB_Right)
{
binder.SetAttribute( "button", "RIGHT" );
}
else
{
binder.SetAttribute( "button", ToString<unsigned int>(button).c_str() );
}
binder.SetAttribute( "direction", "INCREASE" );
control.InsertEndChild(binder);
}
if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE)
!= ICS_MAX_DEVICE_BUTTONS)
{
TiXmlElement binder( "MouseButtonBinder" );
unsigned int button = getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE);
if(button == OIS::/*MouseButtonID::*/MB_Left)
{
binder.SetAttribute( "button", "LEFT" );
}
else if(button == OIS::/*MouseButtonID::*/MB_Middle)
{
binder.SetAttribute( "button", "MIDDLE" );
}
else if(button == OIS::/*MouseButtonID::*/MB_Right)
{
binder.SetAttribute( "button", "RIGHT" );
}
else
{
binder.SetAttribute( "button", ToString<unsigned int>(button).c_str() );
}
binder.SetAttribute( "direction", "DECREASE" );
control.InsertEndChild(binder);
}
JoystickIDList::const_iterator it = mJoystickIDList.begin();
while(it != mJoystickIDList.end())
{
int deviceId = *it;
if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)
!= /*NamedAxis::*/UNASSIGNED)
{
TiXmlElement binder( "JoystickAxisBinder" );
binder.SetAttribute( "axis", ToString<int>(
getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() );
binder.SetAttribute( "direction", "INCREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
control.InsertEndChild(binder);
}
if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)
!= /*NamedAxis::*/UNASSIGNED)
{
TiXmlElement binder( "JoystickAxisBinder" );
binder.SetAttribute( "axis", ToString<int>(
getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() );
binder.SetAttribute( "direction", "DECREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
control.InsertEndChild(binder);
}
if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)
!= ICS_MAX_DEVICE_BUTTONS)
{
TiXmlElement binder( "JoystickButtonBinder" );
binder.SetAttribute( "button", ToString<unsigned int>(
getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() );
binder.SetAttribute( "direction", "INCREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
control.InsertEndChild(binder);
}
if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)
!= ICS_MAX_DEVICE_BUTTONS)
{
TiXmlElement binder( "JoystickButtonBinder" );
binder.SetAttribute( "button", ToString<unsigned int>(
getJoystickButtonBinding(*o, *it, Control/*::ControlChangingDirection*/::DECREASE)).c_str() );
binder.SetAttribute( "direction", "DECREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
control.InsertEndChild(binder);
}
if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE).index >= 0)
{
TiXmlElement binder( "JoystickPOVBinder" );
POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE);
binder.SetAttribute( "pov", ToString<int>(POVPair.index).c_str() );
binder.SetAttribute( "direction", "INCREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
if(POVPair.axis == ICS::InputControlSystem::EastWest)
{
binder.SetAttribute( "axis", "EastWest" );
}
else
{
binder.SetAttribute( "axis", "NorthSouth" );
}
control.InsertEndChild(binder);
}
if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE).index >= 0)
{
TiXmlElement binder( "JoystickPOVBinder" );
POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE);
binder.SetAttribute( "pov", ToString<int>(POVPair.index).c_str() );
binder.SetAttribute( "direction", "DECREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
if(POVPair.axis == ICS::InputControlSystem::EastWest)
{
binder.SetAttribute( "axis", "EastWest" );
}
else
{
binder.SetAttribute( "axis", "NorthSouth" );
}
control.InsertEndChild(binder);
}
if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)
!= /*NamedAxis::*/UNASSIGNED)
{
TiXmlElement binder( "JoystickSliderBinder" );
binder.SetAttribute( "slider", ToString<int>(
getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() );
binder.SetAttribute( "direction", "INCREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
control.InsertEndChild(binder);
}
if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)
!= /*NamedAxis::*/UNASSIGNED)
{
TiXmlElement binder( "JoystickSliderBinder" );
binder.SetAttribute( "slider", ToString<int>(
getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() );
binder.SetAttribute( "direction", "DECREASE" );
binder.SetAttribute( "deviceId", ToString<int>(deviceId).c_str() );
control.InsertEndChild(binder);
}
it++;
}
std::list<Channel*> channels = (*o)->getAttachedChannels();
for(std::list<Channel*>::iterator it = channels.begin() ;
it != channels.end() ; it++)
{
TiXmlElement binder( "Channel" );
binder.SetAttribute( "number", ToString<int>((*it)->getNumber()).c_str() );
Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction;
if(direction == Channel/*::ChannelDirection*/::DIRECT)
{
binder.SetAttribute( "direction", "DIRECT" );
}
else
{
binder.SetAttribute( "direction", "INVERSE" );
}
float percentage = (*it)->getAttachedControlBinding(*o).percentage;
binder.SetAttribute( "percentage", ToString<float>(percentage).c_str() );
control.InsertEndChild(binder);
}
Controller.InsertEndChild(control);
}
doc.InsertEndChild(Controller);
return doc.SaveFile();
}
void InputControlSystem::update(float lTimeSinceLastFrame)
{
if(mActive)
{
std::vector<Control *>::const_iterator it;
for(it=mControls.begin(); it!=mControls.end(); ++it)
{
(*it)->update(lTimeSinceLastFrame);
}
}
//! @todo Future versions should consider channel exponentials and mixtures, so
// after updating Controls, Channels should be updated according to their values
}
float InputControlSystem::getChannelValue(int i)
{
return std::max<float>(0.0,std::min<float>(1.0,mChannels[i]->getValue()));
}
float InputControlSystem::getControlValue(int i)
{
return mControls[i]->getValue();
}
void InputControlSystem::addJoystick(int deviceId)
{
ICS_LOG("Adding joystick (device id: " + ToString<int>(deviceId) + ")");
for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++)
{
if(mControlsJoystickAxisBinderMap[deviceId].find(j) == mControlsJoystickAxisBinderMap[deviceId].end())
{
ControlAxisBinderItem controlJoystickBinderItem;
controlJoystickBinderItem.direction = Control::STOP;
controlJoystickBinderItem.control = NULL;
mControlsJoystickAxisBinderMap[deviceId][j] = controlJoystickBinderItem;
}
}
mJoystickIDList.push_back(deviceId);
}
Control* InputControlSystem::findControl(std::string name)
{
if(mActive)
{
std::vector<Control *>::const_iterator it;
for(it = mControls.begin(); it != mControls.end(); ++it)
{
if( ((Control*)(*it))->getName() == name)
{
return (Control*)(*it);
}
}
}
return NULL;
}
void InputControlSystem::enableDetectingBindingState(Control* control
, Control::ControlChangingDirection direction)
{
mDetectingBindingControl = control;
mDetectingBindingDirection = direction;
mMouseAxisBindingInitialValues[0] = ICS_MOUSE_AXIS_BINDING_NULL_VALUE;
}
void InputControlSystem::cancelDetectingBindingState()
{
mDetectingBindingControl = NULL;
}
void InputControlSystem::fillOISKeysMap()
{
mKeys["UNASSIGNED"]= OIS::KC_UNASSIGNED;
mKeys["ESCAPE"]= OIS::KC_ESCAPE;
mKeys["1"]= OIS::KC_1;
mKeys["2"]= OIS::KC_2;
mKeys["3"]= OIS::KC_3;
mKeys["4"]= OIS::KC_4;
mKeys["5"]= OIS::KC_5;
mKeys["6"]= OIS::KC_6;
mKeys["7"]= OIS::KC_7;
mKeys["8"]= OIS::KC_8;
mKeys["9"]= OIS::KC_9;
mKeys["0"]= OIS::KC_0;
mKeys["MINUS"]= OIS::KC_MINUS;
mKeys["EQUALS"]= OIS::KC_EQUALS;
mKeys["BACK"]= OIS::KC_BACK;
mKeys["TAB"]= OIS::KC_TAB;
mKeys["Q"]= OIS::KC_Q;
mKeys["W"]= OIS::KC_W;
mKeys["E"]= OIS::KC_E;
mKeys["R"]= OIS::KC_R;
mKeys["T"]= OIS::KC_T;
mKeys["Y"]= OIS::KC_Y;
mKeys["U"]= OIS::KC_U;
mKeys["I"]= OIS::KC_I;
mKeys["O"]= OIS::KC_O;
mKeys["P"]= OIS::KC_P;
mKeys["LBRACKET"]= OIS::KC_LBRACKET;
mKeys["RBRACKET"]= OIS::KC_RBRACKET;
mKeys["RETURN"]= OIS::KC_RETURN;
mKeys["LCONTROL"]= OIS::KC_LCONTROL;
mKeys["A"]= OIS::KC_A;
mKeys["S"]= OIS::KC_S;
mKeys["D"]= OIS::KC_D;
mKeys["F"]= OIS::KC_F;
mKeys["G"]= OIS::KC_G;
mKeys["H"]= OIS::KC_H;
mKeys["J"]= OIS::KC_J;
mKeys["K"]= OIS::KC_K;
mKeys["L"]= OIS::KC_L;
mKeys["SEMICOLON"]= OIS::KC_SEMICOLON;
mKeys["APOSTROPHE"]= OIS::KC_APOSTROPHE;
mKeys["GRAVE"]= OIS::KC_GRAVE;
mKeys["LSHIFT"]= OIS::KC_LSHIFT;
mKeys["BACKSLASH"]= OIS::KC_BACKSLASH;
mKeys["Z"]= OIS::KC_Z;
mKeys["X"]= OIS::KC_X;
mKeys["C"]= OIS::KC_C;
mKeys["V"]= OIS::KC_V;
mKeys["B"]= OIS::KC_B;
mKeys["N"]= OIS::KC_N;
mKeys["M"]= OIS::KC_M;
mKeys["COMMA"]= OIS::KC_COMMA;
mKeys["PERIOD"]= OIS::KC_PERIOD;
mKeys["SLASH"]= OIS::KC_SLASH;
mKeys["RSHIFT"]= OIS::KC_RSHIFT;
mKeys["MULTIPLY"]= OIS::KC_MULTIPLY;
mKeys["LMENU"]= OIS::KC_LMENU;
mKeys["SPACE"]= OIS::KC_SPACE;
mKeys["CAPITAL"]= OIS::KC_CAPITAL;
mKeys["F1"]= OIS::KC_F1;
mKeys["F2"]= OIS::KC_F2;
mKeys["F3"]= OIS::KC_F3;
mKeys["F4"]= OIS::KC_F4;
mKeys["F5"]= OIS::KC_F5;
mKeys["F6"]= OIS::KC_F6;
mKeys["F7"]= OIS::KC_F7;
mKeys["F8"]= OIS::KC_F8;
mKeys["F9"]= OIS::KC_F9;
mKeys["F10"]= OIS::KC_F10;
mKeys["F11"]= OIS::KC_F11;
mKeys["F12"]= OIS::KC_F12;
mKeys["NUMLOCK"]= OIS::KC_NUMLOCK;
mKeys["SCROLL"]= OIS::KC_SCROLL;
mKeys["NUMPAD7"]= OIS::KC_NUMPAD7;
mKeys["NUMPAD8"]= OIS::KC_NUMPAD8;
mKeys["NUMPAD9"]= OIS::KC_NUMPAD9;
mKeys["SUBTRACT"]= OIS::KC_SUBTRACT;
mKeys["NUMPAD4"]= OIS::KC_NUMPAD4;
mKeys["NUMPAD5"]= OIS::KC_NUMPAD5;
mKeys["NUMPAD6"]= OIS::KC_NUMPAD6;
mKeys["ADD"]= OIS::KC_ADD;
mKeys["NUMPAD1"]= OIS::KC_NUMPAD1;
mKeys["NUMPAD2"]= OIS::KC_NUMPAD2;
mKeys["NUMPAD3"]= OIS::KC_NUMPAD3;
mKeys["NUMPAD0"]= OIS::KC_NUMPAD0;
mKeys["DECIMAL"]= OIS::KC_DECIMAL;
mKeys["RCONTROL"]= OIS::KC_RCONTROL;
mKeys["DIVIDE"]= OIS::KC_DIVIDE;
mKeys["SYSRQ"]= OIS::KC_SYSRQ;
mKeys["RMENU"]= OIS::KC_RMENU;
mKeys["PAUSE"]= OIS::KC_PAUSE;
mKeys["HOME"]= OIS::KC_HOME;
mKeys["UP"]= OIS::KC_UP;
mKeys["PGUP"]= OIS::KC_PGUP;
mKeys["LEFT"]= OIS::KC_LEFT;
mKeys["RIGHT"]= OIS::KC_RIGHT;
mKeys["END"]= OIS::KC_END;
mKeys["DOWN"]= OIS::KC_DOWN;
mKeys["PGDOWN"]= OIS::KC_PGDOWN;
mKeys["INSERT"]= OIS::KC_INSERT;
mKeys["DELETE"]= OIS::KC_DELETE;
mKeys["LWIN"]= OIS::KC_LWIN;
mKeys["RWIN"]= OIS::KC_RWIN;
mKeys["APPS"]= OIS::KC_APPS;
mKeys["NUMPADENTER"]= OIS::KC_NUMPADENTER;
for(std::map<std::string, OIS::KeyCode>::iterator it = mKeys.begin()
; it != mKeys.end() ; it++)
{
mKeyCodes[ it->second ] = it->first;
}
}
std::string InputControlSystem::keyCodeToString(OIS::KeyCode key)
{
return mKeyCodes[key];
}
OIS::KeyCode InputControlSystem::stringToKeyCode(std::string key)
{
return mKeys[key];
}
}

@ -0,0 +1,256 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#ifndef _InputControlSystem_H_
#define _InputControlSystem_H_
#include "ICSPrerequisites.h"
#include "ICSControl.h"
#include "ICSChannel.h"
#define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() );
#define ICS_MAX_JOYSTICK_AXIS 16
#define ICS_MOUSE_BINDING_MARGIN 30
#define ICS_JOYSTICK_AXIS_BINDING_MARGIN 10000
#define ICS_JOYSTICK_SLIDER_BINDING_MARGIN 10000
#define ICS_MOUSE_AXIS_BINDING_NULL_VALUE std::numeric_limits<int>::max()
namespace ICS
{
class DllExport InputControlSystemLog
{
public:
virtual void logMessage(const char* text) = 0;
};
class DllExport InputControlSystem :
public OIS::MouseListener,
public OIS::KeyListener,
public OIS::JoyStickListener
{
public:
enum NamedAxis { X = -1, Y = -2, Z = -3, UNASSIGNED = -4 };
enum POVAxis { NorthSouth = 0, EastWest = 1 };
typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions
typedef std::list<int> JoystickIDList;
typedef struct
{
int index;
POVAxis axis;
} POVBindingPair;
InputControlSystem(std::string file = "", bool active = true
, DetectingBindingListener* detectingBindingListener = NULL
, InputControlSystemLog* log = NULL, size_t channelCount = 16);
~InputControlSystem();
std::string getFileName(){ return mFileName; };
std::string getBaseFileName();
void setDetectingBindingListener(DetectingBindingListener* detectingBindingListener){ mDetectingBindingListener = detectingBindingListener; };
DetectingBindingListener* getDetectingBindingListener(){ return mDetectingBindingListener; };
// in seconds
void update(float timeSinceLastFrame);
inline Channel* getChannel(int i){ return mChannels[i]; };
float getChannelValue(int i);
inline int getChannelCount(){ return (int)mChannels.size(); };
inline Control* getControl(int i){ return mControls[i]; };
float getControlValue(int i);
inline int getControlCount(){ return (int)mControls.size(); };
inline void addControl(Control* control){ mControls.push_back(control); };
Control* findControl(std::string name);
inline void activate(){ this->mActive = true; };
inline void deactivate(){ this->mActive = false; };
void addJoystick(int deviceId);
JoystickIDList& getJoystickIdList(){ return mJoystickIDList; };
// MouseListener
bool mouseMoved(const OIS::MouseEvent &evt);
bool mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID);
bool mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID);
// KeyListener
bool keyPressed(const OIS::KeyEvent &evt);
bool keyReleased(const OIS::KeyEvent &evt);
// JoyStickListener
bool buttonPressed(const OIS::JoyStickEvent &evt, int button);
bool buttonReleased(const OIS::JoyStickEvent &evt, int button);
bool axisMoved(const OIS::JoyStickEvent &evt, int axis);
bool povMoved(const OIS::JoyStickEvent &evt, int index);
bool sliderMoved(const OIS::JoyStickEvent &evt, int index);
void addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction);
void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction);
void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction);
void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction);
void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction);
void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction);
void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction);
void removeKeyBinding(OIS::KeyCode key);
void removeMouseAxisBinding(NamedAxis axis);
void removeMouseButtonBinding(unsigned int button);
void removeJoystickAxisBinding(int deviceId, int axis);
void removeJoystickButtonBinding(int deviceId, unsigned int button);
void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis);
void removeJoystickSliderBinding(int deviceId, int index);
OIS::KeyCode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction);
NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction);
unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction);
int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction);
unsigned int getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction);
POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction);
int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction);
std::string keyCodeToString(OIS::KeyCode key);
OIS::KeyCode stringToKeyCode(std::string key);
void enableDetectingBindingState(Control* control, Control::ControlChangingDirection direction);
void cancelDetectingBindingState();
bool save(std::string fileName = "");
protected:
void loadKeyBinders(TiXmlElement* xmlControlNode);
void loadMouseAxisBinders(TiXmlElement* xmlControlNode);
void loadMouseButtonBinders(TiXmlElement* xmlControlNode);
void loadJoystickAxisBinders(TiXmlElement* xmlControlNode);
void loadJoystickButtonBinders(TiXmlElement* xmlControlNode);
void loadJoystickPOVBinders(TiXmlElement* xmlControlNode);
void loadJoystickSliderBinders(TiXmlElement* xmlControlNode);
void addMouseAxisBinding_(Control* control, int axis, Control::ControlChangingDirection direction);
void removeMouseAxisBinding_(int axis);
protected:
typedef struct {
Control::ControlChangingDirection direction;
Control* control;
} ControlKeyBinderItem;
typedef ControlKeyBinderItem ControlAxisBinderItem;
typedef ControlKeyBinderItem ControlButtonBinderItem;
typedef ControlKeyBinderItem ControlPOVBinderItem;
typedef ControlKeyBinderItem ControlSliderBinderItem;
typedef struct {
Control* control;
Control::ControlChangingDirection direction;
} PendingActionItem;
std::list<PendingActionItem> mPendingActions;
std::string mFileName;
typedef std::map<OIS::KeyCode, ControlKeyBinderItem> ControlsKeyBinderMapType; // <KeyCode, [direction, control]>
typedef std::map<int, ControlAxisBinderItem> ControlsAxisBinderMapType; // <axis, [direction, control]>
typedef std::map<int, ControlButtonBinderItem> ControlsButtonBinderMapType; // <button, [direction, control]>
typedef std::map<int, ControlPOVBinderItem> ControlsPOVBinderMapType; // <index, [direction, control]>
typedef std::map<int, ControlSliderBinderItem> ControlsSliderBinderMapType; // <index, [direction, control]>
typedef std::map<int, ControlsAxisBinderMapType> JoystickAxisBinderMapType; // <joystick_id, <axis, [direction, control]> >
typedef std::map<int, ControlsButtonBinderMapType> JoystickButtonBinderMapType; // <joystick_id, <button, [direction, control]> >
typedef std::map<int, std::map<int, ControlsPOVBinderMapType> > JoystickPOVBinderMapType; // <joystick_id, <index, <axis, [direction, control]> > >
typedef std::map<int, ControlsSliderBinderMapType> JoystickSliderBinderMapType; // <joystick_id, <index, [direction, control]> >
ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // <axis, [direction, control]>
ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // <int, [direction, control]>
JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // <joystick_id, <axis, [direction, control]> >
JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // <joystick_id, <button, [direction, control]> >
JoystickPOVBinderMapType mControlsJoystickPOVBinderMap; // <joystick_id, <index, <axis, [direction, control]> > >
JoystickSliderBinderMapType mControlsJoystickSliderBinderMap; // <joystick_id, <index, [direction, control]> >
std::vector<Control *> mControls;
std::vector<Channel *> mChannels;
ControlsKeyBinderMapType mControlsKeyBinderMap;
std::map<std::string, OIS::KeyCode> mKeys;
std::map<OIS::KeyCode, std::string> mKeyCodes;
bool mActive;
InputControlSystemLog* mLog;
DetectingBindingListener* mDetectingBindingListener;
Control* mDetectingBindingControl;
Control::ControlChangingDirection mDetectingBindingDirection;
bool mXmouseAxisBinded;
bool mYmouseAxisBinded;
JoystickIDList mJoystickIDList;
int mMouseAxisBindingInitialValues[3];
private:
void fillOISKeysMap();
};
class DllExport DetectingBindingListener
{
public:
virtual void keyBindingDetected(InputControlSystem* ICS, Control* control
, OIS::KeyCode key, Control::ControlChangingDirection direction);
virtual void mouseAxisBindingDetected(InputControlSystem* ICS, Control* control
, InputControlSystem::NamedAxis axis, Control::ControlChangingDirection direction);
virtual void mouseButtonBindingDetected(InputControlSystem* ICS, Control* control
, unsigned int button, Control::ControlChangingDirection direction);
virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, int axis, Control::ControlChangingDirection direction);
virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, unsigned int button, Control::ControlChangingDirection direction);
virtual void joystickPOVBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction);
virtual void joystickSliderBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, int slider, Control::ControlChangingDirection direction);
};
static const float ICS_MAX = std::numeric_limits<float>::max();
}
#endif

@ -0,0 +1,665 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSInputControlSystem.h"
namespace ICS
{
// load xml
void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder");
while(xmlJoystickBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlJoystickBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlJoystickBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
addJoystickAxisBinding(mControls.back(), FromString<int>(xmlJoystickBinder->Attribute("deviceId"))
, FromString<int>(xmlJoystickBinder->Attribute("axis")), dir);
xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder");
}
}
void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder");
while(xmlJoystickButtonBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlJoystickButtonBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlJoystickButtonBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
addJoystickButtonBinding(mControls.back(), FromString<int>(xmlJoystickButtonBinder->Attribute("deviceId"))
, FromString<int>(xmlJoystickButtonBinder->Attribute("button")), dir);
xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder");
}
}
void InputControlSystem::loadJoystickPOVBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlJoystickPOVBinder = xmlControlNode->FirstChildElement("JoystickPOVBinder");
while(xmlJoystickPOVBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
InputControlSystem::POVAxis axis = /*POVAxis::*/NorthSouth;
if(std::string(xmlJoystickPOVBinder->Attribute("axis")) == "EastWest")
{
axis = /*POVAxis::*/EastWest;
}
addJoystickPOVBinding(mControls.back(), FromString<int>(xmlJoystickPOVBinder->Attribute("deviceId"))
, FromString<int>(xmlJoystickPOVBinder->Attribute("pov")), axis, dir);
xmlJoystickPOVBinder = xmlJoystickPOVBinder->NextSiblingElement("JoystickPOVBinder");
}
}
void InputControlSystem::loadJoystickSliderBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlJoystickSliderBinder = xmlControlNode->FirstChildElement("JoystickSliderBinder");
while(xmlJoystickSliderBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
addJoystickSliderBinding(mControls.back(), FromString<int>(xmlJoystickSliderBinder->Attribute("deviceId"))
, FromString<int>(xmlJoystickSliderBinder->Attribute("slider")), dir);
xmlJoystickSliderBinder = xmlJoystickSliderBinder->NextSiblingElement("JoystickSliderBinder");
}
}
// add bindings
void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding AxisBinder [deviceid="
+ ToString<int>(deviceId) + ", axis="
+ ToString<int>(axis) + ", direction="
+ ToString<int>(direction) + "]");
ControlAxisBinderItem controlAxisBinderItem;
controlAxisBinderItem.control = control;
controlAxisBinderItem.direction = direction;
mControlsJoystickAxisBinderMap[ deviceId ][ axis ] = controlAxisBinderItem;
}
void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding JoystickButtonBinder [deviceId="
+ ToString<int>(deviceId) + ", button="
+ ToString<int>(button) + ", direction="
+ ToString<int>(direction) + "]");
ControlButtonBinderItem controlJoystickButtonBinderItem;
controlJoystickButtonBinderItem.direction = direction;
controlJoystickButtonBinderItem.control = control;
mControlsJoystickButtonBinderMap[ deviceId ][ button ] = controlJoystickButtonBinderItem;
}
void InputControlSystem::addJoystickPOVBinding(Control* control, int deviceId, int index, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding JoystickPOVBinder [deviceId="
+ ToString<int>(deviceId) + ", pov="
+ ToString<int>(index) + ", axis="
+ ToString<int>(axis) + ", direction="
+ ToString<int>(direction) + "]");
ControlPOVBinderItem ControlPOVBinderItem;
ControlPOVBinderItem.direction = direction;
ControlPOVBinderItem.control = control;
mControlsJoystickPOVBinderMap[ deviceId ][ index ][ axis ] = ControlPOVBinderItem;
}
void InputControlSystem::addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding JoystickSliderBinder [deviceId="
+ ToString<int>(deviceId) + ", direction="
+ ToString<int>(index) + ", direction="
+ ToString<int>(direction) + "]");
ControlSliderBinderItem ControlSliderBinderItem;
ControlSliderBinderItem.direction = direction;
ControlSliderBinderItem.control = control;
mControlsJoystickSliderBinderMap[ deviceId ][ index ] = ControlSliderBinderItem;
}
// get bindings
int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction)
{
if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end())
{
ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].begin();
while(it != mControlsJoystickAxisBinderMap[deviceId].end())
{
if(it->first >= 0 && it->second.control == control && it->second.direction == direction)
{
return it->first;
}
it++;
}
}
return /*NamedAxis::*/UNASSIGNED;
}
unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction)
{
if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end())
{
ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].begin();
while(it != mControlsJoystickButtonBinderMap[deviceId].end())
{
if(it->second.control == control && it->second.direction == direction)
{
return it->first;
}
it++;
}
}
return ICS_MAX_DEVICE_BUTTONS;
}
InputControlSystem::POVBindingPair InputControlSystem::getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction)
{
POVBindingPair result;
result.index = -1;
if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end())
{
//ControlsAxisBinderMapType::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin();
std::map<int, ControlsPOVBinderMapType>::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin();
while(it != mControlsJoystickPOVBinderMap[deviceId].end())
{
ControlsPOVBinderMapType::const_iterator it2 = it->second.begin();
while(it2 != it->second.end())
{
if(it2->second.control == control && it2->second.direction == direction)
{
result.index = it->first;
result.axis = (POVAxis)it2->first;
return result;
}
it2++;
}
it++;
}
}
return result;
}
int InputControlSystem::getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction)
{
if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end())
{
ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].begin();
while(it != mControlsJoystickSliderBinderMap[deviceId].end())
{
if(it->second.control == control && it->second.direction == direction)
{
return it->first;
}
it++;
}
}
return /*NamedAxis::*/UNASSIGNED;
}
// remove bindings
void InputControlSystem::removeJoystickAxisBinding(int deviceId, int axis)
{
if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end())
{
ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].find(axis);
if(it != mControlsJoystickAxisBinderMap[deviceId].end())
{
mControlsJoystickAxisBinderMap[deviceId].erase(it);
}
}
}
void InputControlSystem::removeJoystickButtonBinding(int deviceId, unsigned int button)
{
if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end())
{
ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].find(button);
if(it != mControlsJoystickButtonBinderMap[deviceId].end())
{
mControlsJoystickButtonBinderMap[deviceId].erase(it);
}
}
}
void InputControlSystem::removeJoystickPOVBinding(int deviceId, int index, POVAxis axis)
{
if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end())
{
std::map<int, ControlsPOVBinderMapType>::iterator it = mControlsJoystickPOVBinderMap[deviceId].find(index);
if(it != mControlsJoystickPOVBinderMap[deviceId].end())
{
if(it->second.find(axis) != it->second.end())
{
mControlsJoystickPOVBinderMap[deviceId].find(index)->second.erase( it->second.find(axis) );
}
}
}
}
void InputControlSystem::removeJoystickSliderBinding(int deviceId, int index)
{
if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end())
{
ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].find(index);
if(it != mControlsJoystickSliderBinderMap[deviceId].end())
{
mControlsJoystickSliderBinderMap[deviceId].erase(it);
}
}
}
// joyStick listeners
bool InputControlSystem::buttonPressed(const OIS::JoyStickEvent &evt, int button)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end())
{
ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button);
if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end())
{
it->second.control->setIgnoreAutoReverse(false);
if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop())
{
it->second.control->setChangingDirection(it->second.direction);
}
else
{
if(it->second.control->getValue() == 1)
{
it->second.control->setChangingDirection(Control::DECREASE);
}
else if(it->second.control->getValue() == 0)
{
it->second.control->setChangingDirection(Control::INCREASE);
}
}
}
}
}
else if(mDetectingBindingListener)
{
mDetectingBindingListener->joystickButtonBindingDetected(this,
mDetectingBindingControl, evt.device->getID(), button, mDetectingBindingDirection);
}
}
return true;
}
bool InputControlSystem::buttonReleased(const OIS::JoyStickEvent &evt, int button)
{
if(mActive)
{
if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end())
{
ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button);
if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end())
{
it->second.control->setChangingDirection(Control::STOP);
}
}
}
return true;
}
bool InputControlSystem::axisMoved(const OIS::JoyStickEvent &evt, int axis)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
if(mControlsJoystickAxisBinderMap.find(evt.device->getID()) != mControlsJoystickAxisBinderMap.end())
{
ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index
Control* ctrl = joystickBinderItem.control;
if(ctrl)
{
ctrl->setIgnoreAutoReverse(true);
if(joystickBinderItem.direction == Control::INCREASE)
{
float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS;
float valDisplaced = (float)( evt.state.mAxes[axis].abs - OIS::JoyStick::MIN_AXIS);
ctrl->setValue( valDisplaced / axisRange );
}
else if(joystickBinderItem.direction == Control::DECREASE)
{
float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS;
float valDisplaced = (float)(evt.state.mAxes[axis].abs - OIS::JoyStick::MIN_AXIS);
ctrl->setValue( 1 - ( valDisplaced / axisRange ) );
}
}
}
}
else if(mDetectingBindingListener)
{
//ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index
//Control* ctrl = joystickBinderItem.control;
//if(ctrl && ctrl->isAxisBindable())
if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable())
{
if( abs( evt.state.mAxes[axis].abs ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN)
{
mDetectingBindingListener->joystickAxisBindingDetected(this,
mDetectingBindingControl, evt.device->getID(), axis, mDetectingBindingDirection);
}
}
}
}
return true;
}
bool InputControlSystem::povMoved(const OIS::JoyStickEvent &evt, int index)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
if(mControlsJoystickPOVBinderMap.find(evt.device->getID()) != mControlsJoystickPOVBinderMap.end())
{
std::map<int, ControlsPOVBinderMapType>::const_iterator i = mControlsJoystickPOVBinderMap[ evt.device->getID() ].find(index);
if(i != mControlsJoystickPOVBinderMap[ evt.device->getID() ].end())
{
if(evt.state.mPOV[index].direction != OIS::Pov::West
&& evt.state.mPOV[index].direction != OIS::Pov::East
&& evt.state.mPOV[index].direction != OIS::Pov::Centered)
{
ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth );
if(it != i->second.end())
{
it->second.control->setIgnoreAutoReverse(false);
if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop())
{
if(evt.state.mPOV[index].direction == OIS::Pov::North
|| evt.state.mPOV[index].direction == OIS::Pov::NorthWest
|| evt.state.mPOV[index].direction == OIS::Pov::NorthEast)
{
it->second.control->setChangingDirection(it->second.direction);
}
else
{
it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction));
}
}
else
{
if(it->second.control->getValue() == 1)
{
it->second.control->setChangingDirection(Control::DECREASE);
}
else if(it->second.control->getValue() == 0)
{
it->second.control->setChangingDirection(Control::INCREASE);
}
}
}
}
if(evt.state.mPOV[index].direction != OIS::Pov::North
&& evt.state.mPOV[index].direction != OIS::Pov::South
&& evt.state.mPOV[index].direction != OIS::Pov::Centered)
{
ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest );
if(it != i->second.end())
{
it->second.control->setIgnoreAutoReverse(false);
if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop())
{
if(evt.state.mPOV[index].direction == OIS::Pov::East
|| evt.state.mPOV[index].direction == OIS::Pov::NorthEast
|| evt.state.mPOV[index].direction == OIS::Pov::SouthEast)
{
it->second.control->setChangingDirection(it->second.direction);
}
else
{
it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction));
}
}
else
{
if(it->second.control->getValue() == 1)
{
it->second.control->setChangingDirection(Control::DECREASE);
}
else if(it->second.control->getValue() == 0)
{
it->second.control->setChangingDirection(Control::INCREASE);
}
}
}
}
if(evt.state.mPOV[index].direction == OIS::Pov::Centered)
{
ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth );
if(it != i->second.end())
{
it->second.control->setChangingDirection(Control::STOP);
}
it = i->second.find( /*POVAxis::*/EastWest );
if(it != i->second.end())
{
it->second.control->setChangingDirection(Control::STOP);
}
}
}
}
}
else if(mDetectingBindingListener)
{
if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable())
{
if(evt.state.mPOV[index].direction == OIS::Pov::West
|| evt.state.mPOV[index].direction == OIS::Pov::East
|| evt.state.mPOV[index].direction == OIS::Pov::North
|| evt.state.mPOV[index].direction == OIS::Pov::South)
{
POVAxis povAxis = NorthSouth;
if(evt.state.mPOV[index].direction == OIS::Pov::West
|| evt.state.mPOV[index].direction == OIS::Pov::East)
{
povAxis = EastWest;
}
mDetectingBindingListener->joystickPOVBindingDetected(this,
mDetectingBindingControl, evt.device->getID(), index, povAxis, mDetectingBindingDirection);
}
}
}
}
return true;
}
bool InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end())
{
ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ];
Control* ctrl = joystickBinderItem.control;
if(ctrl)
{
ctrl->setIgnoreAutoReverse(true);
if(joystickBinderItem.direction == Control::INCREASE)
{
float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS;
float valDisplaced = (float)( evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS);
ctrl->setValue( valDisplaced / axisRange );
}
else if(joystickBinderItem.direction == Control::DECREASE)
{
float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS;
float valDisplaced = (float)(evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS);
ctrl->setValue( 1 - ( valDisplaced / axisRange ) );
}
}
}
}
else if(mDetectingBindingListener)
{
/*ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ];
Control* ctrl = joystickBinderItem.control;
if(ctrl && ctrl->isAxisBindable())
{*/
if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable())
{
if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN)
{
mDetectingBindingListener->joystickSliderBindingDetected(this,
mDetectingBindingControl, evt.device->getID(), index, mDetectingBindingDirection);
}
}
}
}
return true;
}
// joystick auto bindings
void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, int axis, Control::ControlChangingDirection direction)
{
// if the joystick axis is used by another control, remove it
ICS->removeJoystickAxisBinding(deviceId, axis);
// if the control has an axis assigned, remove it
int oldAxis = ICS->getJoystickAxisBinding(control, deviceId, direction);
if(oldAxis != InputControlSystem::UNASSIGNED)
{
ICS->removeJoystickAxisBinding(deviceId, oldAxis);
}
ICS->addJoystickAxisBinding(control, deviceId, axis, direction);
ICS->cancelDetectingBindingState();
}
void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, unsigned int button, Control::ControlChangingDirection direction)
{
// if the joystick button is used by another control, remove it
ICS->removeJoystickButtonBinding(deviceId, button);
// if the control has a joystick button assigned, remove it
unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceId, direction);
if(oldButton != ICS_MAX_DEVICE_BUTTONS)
{
ICS->removeJoystickButtonBinding(deviceId, oldButton);
}
ICS->addJoystickButtonBinding(control, deviceId, button, direction);
ICS->cancelDetectingBindingState();
}
void DetectingBindingListener::joystickPOVBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction)
{
// if the joystick slider is used by another control, remove it
ICS->removeJoystickPOVBinding(deviceId, pov, axis);
// if the control has a joystick button assigned, remove it
ICS::InputControlSystem::POVBindingPair oldPOV = ICS->getJoystickPOVBinding(control, deviceId, direction);
if(oldPOV.index >= 0 && oldPOV.axis == axis)
{
ICS->removeJoystickPOVBinding(deviceId, oldPOV.index, oldPOV.axis);
}
ICS->addJoystickPOVBinding(control, deviceId, pov, axis, direction);
ICS->cancelDetectingBindingState();
}
void DetectingBindingListener::joystickSliderBindingDetected(InputControlSystem* ICS, Control* control
, int deviceId, int slider, Control::ControlChangingDirection direction)
{
// if the joystick slider is used by another control, remove it
ICS->removeJoystickSliderBinding(deviceId, slider);
// if the control has a joystick slider assigned, remove it
int oldSlider = ICS->getJoystickSliderBinding(control, deviceId, direction);
if(oldSlider != InputControlSystem::/*NamedAxis::*/UNASSIGNED)
{
ICS->removeJoystickSliderBinding(deviceId, oldSlider);
}
ICS->addJoystickSliderBinding(control, deviceId, slider, direction);
ICS->cancelDetectingBindingState();
}
}

@ -0,0 +1,156 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSInputControlSystem.h"
namespace ICS
{
void InputControlSystem::loadKeyBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlKeyBinder = xmlControlNode->FirstChildElement("KeyBinder");
while(xmlKeyBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlKeyBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlKeyBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
addKeyBinding(mControls.back(), mKeys[xmlKeyBinder->Attribute("key")], dir);
xmlKeyBinder = xmlKeyBinder->NextSiblingElement("KeyBinder");
}
}
void InputControlSystem::addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding KeyBinder [key="
+ keyCodeToString(key) + ", direction="
+ ToString<int>(direction) + "]");
ControlKeyBinderItem controlKeyBinderItem;
controlKeyBinderItem.control = control;
controlKeyBinderItem.direction = direction;
mControlsKeyBinderMap[ key ] = controlKeyBinderItem;
}
void InputControlSystem::removeKeyBinding(OIS::KeyCode key)
{
ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.find(key);
if(it != mControlsKeyBinderMap.end())
{
mControlsKeyBinderMap.erase(it);
}
}
OIS::KeyCode InputControlSystem::getKeyBinding(Control* control
, ICS::Control::ControlChangingDirection direction)
{
ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.begin();
while(it != mControlsKeyBinderMap.end())
{
if(it->second.control == control && it->second.direction == direction)
{
return it->first;
}
it++;
}
return OIS::KC_UNASSIGNED;
}
bool InputControlSystem::keyPressed(const OIS::KeyEvent &evt)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key);
if(it != mControlsKeyBinderMap.end())
{
it->second.control->setIgnoreAutoReverse(false);
if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop())
{
it->second.control->setChangingDirection(it->second.direction);
}
else
{
if(it->second.control->getValue() == 1)
{
it->second.control->setChangingDirection(Control::DECREASE);
}
else if(it->second.control->getValue() == 0)
{
it->second.control->setChangingDirection(Control::INCREASE);
}
}
}
}
else if(mDetectingBindingListener)
{
mDetectingBindingListener->keyBindingDetected(this,
mDetectingBindingControl, evt.key, mDetectingBindingDirection);
}
}
return true;
}
bool InputControlSystem::keyReleased(const OIS::KeyEvent &evt)
{
if(mActive)
{
ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key);
if(it != mControlsKeyBinderMap.end())
{
it->second.control->setChangingDirection(Control::STOP);
}
}
return true;
}
void DetectingBindingListener::keyBindingDetected(InputControlSystem* ICS, Control* control
, OIS::KeyCode key, Control::ControlChangingDirection direction)
{
// if the key is used by another control, remove it
ICS->removeKeyBinding(key);
// if the control has a key assigned, remove it
OIS::KeyCode oldKey = ICS->getKeyBinding(control, direction);
if(oldKey != OIS::KC_UNASSIGNED)
{
ICS->removeKeyBinding(oldKey);
}
ICS->addKeyBinding(control, key, direction);
ICS->cancelDetectingBindingState();
}
}

@ -0,0 +1,397 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSInputControlSystem.h"
namespace ICS
{
// load xml
void InputControlSystem::loadMouseAxisBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlMouseBinder = xmlControlNode->FirstChildElement("MouseBinder");
while(xmlMouseBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlMouseBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlMouseBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
NamedAxis axis = /*NamedAxis::*/ X;
if((*xmlMouseBinder->Attribute("axis")) == 'Y')
{
axis = /*NamedAxis::*/ Y;
}
else if((*xmlMouseBinder->Attribute("axis")) == 'Z')
{
axis = /*NamedAxis::*/ Z;
}
addMouseAxisBinding(mControls.back(), axis, dir);
xmlMouseBinder = xmlMouseBinder->NextSiblingElement("MouseBinder");
}
}
void InputControlSystem::loadMouseButtonBinders(TiXmlElement* xmlControlNode)
{
TiXmlElement* xmlMouseButtonBinder = xmlControlNode->FirstChildElement("MouseButtonBinder");
while(xmlMouseButtonBinder)
{
Control::ControlChangingDirection dir = Control::STOP;
if(std::string(xmlMouseButtonBinder->Attribute("direction")) == "INCREASE")
{
dir = Control::INCREASE;
}
else if(std::string(xmlMouseButtonBinder->Attribute("direction")) == "DECREASE")
{
dir = Control::DECREASE;
}
int button = 0;
if(std::string(xmlMouseButtonBinder->Attribute("button")) == "LEFT")
{
button = OIS::/*MouseButtonID::*/MB_Left;
}
else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "RIGHT")
{
button = OIS::/*MouseButtonID::*/MB_Right;
}
else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "MIDDLE")
{
button = OIS::/*MouseButtonID::*/MB_Middle;
}
else
{
button = FromString<int>(xmlMouseButtonBinder->Attribute("button"));
}
addMouseButtonBinding(mControls.back(), button, dir);
xmlMouseButtonBinder = xmlMouseButtonBinder->NextSiblingElement("MouseButtonBinder");
}
}
// add bindings
void InputControlSystem::addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction)
{
if(axis == /*NamedAxis::*/X)
{
mXmouseAxisBinded = true;
}
else if(axis == /*NamedAxis::*/Y)
{
mYmouseAxisBinded = true;
}
addMouseAxisBinding_(control, axis, direction);
}
/*protected*/ void InputControlSystem::addMouseAxisBinding_(Control* control, int axis, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding AxisBinder [axis="
+ ToString<int>(axis) + ", direction="
+ ToString<int>(direction) + "]");
ControlAxisBinderItem controlAxisBinderItem;
controlAxisBinderItem.control = control;
controlAxisBinderItem.direction = direction;
mControlsMouseAxisBinderMap[ axis ] = controlAxisBinderItem;
}
void InputControlSystem::addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction)
{
ICS_LOG("\tAdding MouseButtonBinder [button="
+ ToString<int>(button) + ", direction="
+ ToString<int>(direction) + "]");
ControlButtonBinderItem controlMouseButtonBinderItem;
controlMouseButtonBinderItem.direction = direction;
controlMouseButtonBinderItem.control = control;
mControlsMouseButtonBinderMap[ button ] = controlMouseButtonBinderItem;
}
// get bindings
InputControlSystem::NamedAxis InputControlSystem::getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction)
{
ControlsAxisBinderMapType::iterator it = mControlsMouseAxisBinderMap.begin();
while(it != mControlsMouseAxisBinderMap.end())
{
if(it->first < 0 && it->second.control == control && it->second.direction == direction)
{
return (InputControlSystem::NamedAxis)(it->first);
}
it++;
}
return /*NamedAxis::*/UNASSIGNED;
}
//int InputControlSystem::getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction)
//{
// ControlsAxisBinderMapType::iterator it = mControlsMouseAxisBinderMap.begin();
// while(it != mControlsMouseAxisBinderMap.end())
// {
// if(it->first >= 0 && it->second.control == control && it->second.direction == direction)
// {
// return it->first;
// }
// it++;
// }
// return /*NamedAxis::*/UNASSIGNED;
//}
unsigned int InputControlSystem::getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction)
{
ControlsButtonBinderMapType::iterator it = mControlsMouseButtonBinderMap.begin();
while(it != mControlsMouseButtonBinderMap.end())
{
if(it->second.control == control && it->second.direction == direction)
{
return it->first;
}
it++;
}
return ICS_MAX_DEVICE_BUTTONS;
}
// remove bindings
void InputControlSystem::removeMouseAxisBinding(NamedAxis axis)
{
if(axis == /*NamedAxis::*/X)
{
mXmouseAxisBinded = false;
}
else if(axis == /*NamedAxis::*/Y)
{
mYmouseAxisBinded = false;
}
removeMouseAxisBinding_(axis);
}
/*protected*/ void InputControlSystem::removeMouseAxisBinding_(int axis)
{
ControlsAxisBinderMapType::iterator it = mControlsMouseAxisBinderMap.find(axis);
if(it != mControlsMouseAxisBinderMap.end())
{
mControlsMouseAxisBinderMap.erase(it);
}
}
void InputControlSystem::removeMouseButtonBinding(unsigned int button)
{
ControlsButtonBinderMapType::iterator it = mControlsMouseButtonBinderMap.find(button);
if(it != mControlsMouseButtonBinderMap.end())
{
mControlsMouseButtonBinderMap.erase(it);
}
}
// mouse Listeners
bool InputControlSystem::mouseMoved(const OIS::MouseEvent &evt)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
if(mXmouseAxisBinded && evt.state.X.rel)
{
ControlAxisBinderItem mouseBinderItem = mControlsMouseAxisBinderMap[ /*NamedAxis::*/X ];
Control* ctrl = mouseBinderItem.control;
ctrl->setIgnoreAutoReverse(true);
if(mouseBinderItem.direction == Control::INCREASE)
{
ctrl->setValue( float( (evt.state.X.abs) / float(evt.state.width) ) );
}
else if(mouseBinderItem.direction == Control::DECREASE)
{
ctrl->setValue( 1 - float( evt.state.X.abs / float(evt.state.width) ) );
}
}
if(mYmouseAxisBinded && evt.state.Y.rel)
{
ControlAxisBinderItem mouseBinderItem = mControlsMouseAxisBinderMap[ /*NamedAxis::*/Y ];
Control* ctrl = mouseBinderItem.control;
ctrl->setIgnoreAutoReverse(true);
if(mouseBinderItem.direction == Control::INCREASE)
{
ctrl->setValue( float( (evt.state.Y.abs) / float(evt.state.height) ) );
}
else if(mouseBinderItem.direction == Control::DECREASE)
{
ctrl->setValue( 1 - float( evt.state.Y.abs / float(evt.state.height) ) );
}
}
//! @todo Whats the range of the Z axis?
/*if(evt.state.Z.rel)
{
ControlAxisBinderItem mouseBinderItem = mControlsAxisBinderMap[ NamedAxis::Z ];
Control* ctrl = mouseBinderItem.control;
ctrl->setIgnoreAutoReverse(true);
if(mouseBinderItem.direction == Control::INCREASE)
{
ctrl->setValue( float( (evt.state.Z.abs) / float(evt.state.¿width?) ) );
}
else if(mouseBinderItem.direction == Control::DECREASE)
{
ctrl->setValue( float( (1 - evt.state.Z.abs) / float(evt.state.¿width?) ) );
}
}*/
}
else if(mDetectingBindingListener)
{
if(mDetectingBindingControl->isAxisBindable())
{
if(mMouseAxisBindingInitialValues[0] == ICS_MOUSE_AXIS_BINDING_NULL_VALUE)
{
mMouseAxisBindingInitialValues[0] = 0;
mMouseAxisBindingInitialValues[1] = 0;
mMouseAxisBindingInitialValues[2] = 0;
}
mMouseAxisBindingInitialValues[0] += evt.state.X.rel;
mMouseAxisBindingInitialValues[1] += evt.state.Y.rel;
mMouseAxisBindingInitialValues[2] += evt.state.Z.rel;
if( abs(mMouseAxisBindingInitialValues[0]) > ICS_MOUSE_BINDING_MARGIN )
{
mDetectingBindingListener->mouseAxisBindingDetected(this,
mDetectingBindingControl, X, mDetectingBindingDirection);
}
else if( abs(mMouseAxisBindingInitialValues[1]) > ICS_MOUSE_BINDING_MARGIN )
{
mDetectingBindingListener->mouseAxisBindingDetected(this,
mDetectingBindingControl, Y, mDetectingBindingDirection);
}
else if( abs(mMouseAxisBindingInitialValues[2]) > ICS_MOUSE_BINDING_MARGIN )
{
mDetectingBindingListener->mouseAxisBindingDetected(this,
mDetectingBindingControl, Z, mDetectingBindingDirection);
}
}
}
}
return true;
}
bool InputControlSystem::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn)
{
if(mActive)
{
if(!mDetectingBindingControl)
{
ControlsButtonBinderMapType::const_iterator it = mControlsMouseButtonBinderMap.find((int)btn);
if(it != mControlsMouseButtonBinderMap.end())
{
it->second.control->setIgnoreAutoReverse(false);
if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop())
{
it->second.control->setChangingDirection(it->second.direction);
}
else
{
if(it->second.control->getValue() == 1)
{
it->second.control->setChangingDirection(Control::DECREASE);
}
else if(it->second.control->getValue() == 0)
{
it->second.control->setChangingDirection(Control::INCREASE);
}
}
}
}
else if(mDetectingBindingListener)
{
mDetectingBindingListener->mouseButtonBindingDetected(this,
mDetectingBindingControl, btn, mDetectingBindingDirection);
}
}
return true;
}
bool InputControlSystem::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn)
{
if(mActive)
{
ControlsButtonBinderMapType::const_iterator it = mControlsMouseButtonBinderMap.find((int)btn);
if(it != mControlsMouseButtonBinderMap.end())
{
it->second.control->setChangingDirection(Control::STOP);
}
}
return true;
}
// mouse auto bindings
void DetectingBindingListener::mouseAxisBindingDetected(InputControlSystem* ICS, Control* control
, InputControlSystem::NamedAxis axis, Control::ControlChangingDirection direction)
{
// if the mouse axis is used by another control, remove it
ICS->removeMouseAxisBinding(axis);
// if the control has an axis assigned, remove it
InputControlSystem::NamedAxis oldAxis = ICS->getMouseAxisBinding(control, direction);
if(oldAxis != InputControlSystem::UNASSIGNED)
{
ICS->removeMouseAxisBinding(oldAxis);
}
ICS->addMouseAxisBinding(control, axis, direction);
ICS->cancelDetectingBindingState();
}
void DetectingBindingListener::mouseButtonBindingDetected(InputControlSystem* ICS, Control* control
, unsigned int button, Control::ControlChangingDirection direction)
{
// if the mouse button is used by another control, remove it
ICS->removeMouseButtonBinding(button);
// if the control has a mouse button assigned, remove it
unsigned int oldButton = ICS->getMouseButtonBinding(control, direction);
if(oldButton != ICS_MAX_DEVICE_BUTTONS)
{
ICS->removeMouseButtonBinding(oldButton);
}
ICS->addMouseButtonBinding(control, button, direction);
ICS->cancelDetectingBindingState();
}
}

@ -0,0 +1,27 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
#include "ICSPrerequisites.h"

@ -0,0 +1,111 @@
/* -------------------------------------------------------
Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es)
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------- */
//! @todo add mouse wheel support
#ifndef _InputControlSystem_Prerequisites_H_
#define _InputControlSystem_Prerequisites_H_
/// Include external headers
#include <sstream>
#include <fstream>
#include <vector>
#include <map>
#include <list>
#include <limits>
#include "tinyxml.h"
#define OIS_DYNAMIC_LIB
#include <OIS.h>
#include <OISMouse.h>
#include <OISKeyboard.h>
#include <OISJoyStick.h>
#include <OISInputManager.h>
/// Define the dll export qualifier if compiling for Windows
/*
#ifdef ICS_PLATFORM_WIN32
#ifdef ICS_LIB
#define DllExport __declspec (dllexport)
#else
#define DllExport __declspec (dllimport)
#endif
#else
#define DllExport
#endif
*/
#define DllExport
// Define some macros
#define ICS_DEPRECATED __declspec(deprecated("Deprecated. It will be removed in future versions."))
/// Version defines
#define ICS_VERSION_MAJOR 0
#define ICS_VERSION_MINOR 3
#define ICS_VERSION_PATCH 1
#define ICS_MAX_DEVICE_BUTTONS 30
namespace ICS
{
template <typename T>
bool StringIsNumber ( const std::string &Text )
{
std::stringstream ss(Text);
T result;
return ss >> result ? true : false;
}
// from http://www.cplusplus.com/forum/articles/9645/
template <typename T>
std::string ToString ( T value )
{
std::stringstream ss;
ss << value;
return ss.str();
}
// from http://www.cplusplus.com/forum/articles/9645/
template <typename T>
T FromString ( const std::string &Text )//Text not by const reference so that the function can be used with a
{ //character array as argument
std::stringstream ss(Text);
T result;
return ss >> result ? result : 0;
}
class InputControlSystem;
class Channel;
class ChannelListener;
class Control;
class ControlListener;
class DetectingBindingListener;
class InputControlSystemLog;
}
#endif

@ -0,0 +1,116 @@
/*
www.sourceforge.net/projects/tinyxml
Original file by Yves Berquin.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
* THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005.
*/
#ifndef TIXML_USE_STL
#include "tinystr.h"
// Error value for find primitive
const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
// Null rep.
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
void TiXmlString::reserve (size_type cap)
{
if (cap > capacity())
{
TiXmlString tmp;
tmp.init(length(), cap);
memcpy(tmp.start(), data(), length());
swap(tmp);
}
}
TiXmlString& TiXmlString::assign(const char* str, size_type len)
{
size_type cap = capacity();
if (len > cap || cap > 3*(len + 8))
{
TiXmlString tmp;
tmp.init(len);
memcpy(tmp.start(), str, len);
swap(tmp);
}
else
{
memmove(start(), str, len);
set_size(len);
}
return *this;
}
TiXmlString& TiXmlString::append(const char* str, size_type len)
{
size_type newsize = length() + len;
if (newsize > capacity())
{
reserve (newsize + capacity());
}
memmove(finish(), str, len);
set_size(newsize);
return *this;
}
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
{
TiXmlString tmp;
tmp.reserve(a.length() + b.length());
tmp += a;
tmp += b;
return tmp;
}
TiXmlString operator + (const TiXmlString & a, const char* b)
{
TiXmlString tmp;
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
tmp.reserve(a.length() + b_len);
tmp += a;
tmp.append(b, b_len);
return tmp;
}
TiXmlString operator + (const char* a, const TiXmlString & b)
{
TiXmlString tmp;
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
tmp.reserve(a_len + b.length());
tmp.append(a, a_len);
tmp += b;
return tmp;
}
#endif // TIXML_USE_STL

@ -0,0 +1,319 @@
/*
www.sourceforge.net/projects/tinyxml
Original file by Yves Berquin.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
/*
* THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
*
* - completely rewritten. compact, clean, and fast implementation.
* - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
* - fixed reserve() to work as per specification.
* - fixed buggy compares operator==(), operator<(), and operator>()
* - fixed operator+=() to take a const ref argument, following spec.
* - added "copy" constructor with length, and most compare operators.
* - added swap(), clear(), size(), capacity(), operator+().
*/
#ifndef TIXML_USE_STL
#ifndef TIXML_STRING_INCLUDED
#define TIXML_STRING_INCLUDED
#include <assert.h>
#include <string.h>
/* The support for explicit isn't that universal, and it isn't really
required - it is used to check that the TiXmlString class isn't incorrectly
used. Be nice to old compilers and macro it here:
*/
#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
// Microsoft visual studio, version 6 and higher.
#define TIXML_EXPLICIT explicit
#elif defined(__GNUC__) && (__GNUC__ >= 3 )
// GCC version 3 and higher.s
#define TIXML_EXPLICIT explicit
#else
#define TIXML_EXPLICIT
#endif
/*
TiXmlString is an emulation of a subset of the std::string template.
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
Only the member functions relevant to the TinyXML project have been implemented.
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
a string and there's no more room, we allocate a buffer twice as big as we need.
*/
class TiXmlString
{
public :
// The size type used
typedef size_t size_type;
// Error value for find primitive
static const size_type npos; // = -1;
// TiXmlString empty constructor
TiXmlString () : rep_(&nullrep_)
{
}
// TiXmlString copy constructor
TiXmlString ( const TiXmlString & copy) : rep_(0)
{
init(copy.length());
memcpy(start(), copy.data(), length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
{
init( static_cast<size_type>( strlen(copy) ));
memcpy(start(), copy, length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
{
init(len);
memcpy(start(), str, len);
}
// TiXmlString destructor
~TiXmlString ()
{
quit();
}
// = operator
TiXmlString& operator = (const char * copy)
{
return assign( copy, (size_type)strlen(copy));
}
// = operator
TiXmlString& operator = (const TiXmlString & copy)
{
return assign(copy.start(), copy.length());
}
// += operator. Maps to append
TiXmlString& operator += (const char * suffix)
{
return append(suffix, static_cast<size_type>( strlen(suffix) ));
}
// += operator. Maps to append
TiXmlString& operator += (char single)
{
return append(&single, 1);
}
// += operator. Maps to append
TiXmlString& operator += (const TiXmlString & suffix)
{
return append(suffix.data(), suffix.length());
}
// Convert a TiXmlString into a null-terminated char *
const char * c_str () const { return rep_->str; }
// Convert a TiXmlString into a char * (need not be null terminated).
const char * data () const { return rep_->str; }
// Return the length of a TiXmlString
size_type length () const { return rep_->size; }
// Alias for length()
size_type size () const { return rep_->size; }
// Checks if a TiXmlString is empty
bool empty () const { return rep_->size == 0; }
// Return capacity of string
size_type capacity () const { return rep_->capacity; }
// single char extraction
const char& at (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// [] operator
char& operator [] (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// find a char in a string. Return TiXmlString::npos if not found
size_type find (char lookup) const
{
return find(lookup, 0);
}
// find a char in a string from an offset. Return TiXmlString::npos if not found
size_type find (char tofind, size_type offset) const
{
if (offset >= length()) return npos;
for (const char* p = c_str() + offset; *p != '\0'; ++p)
{
if (*p == tofind) return static_cast< size_type >( p - c_str() );
}
return npos;
}
void clear ()
{
//Lee:
//The original was just too strange, though correct:
// TiXmlString().swap(*this);
//Instead use the quit & re-init:
quit();
init(0,0);
}
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
function DOES NOT clear the content of the TiXmlString if any exists.
*/
void reserve (size_type cap);
TiXmlString& assign (const char* str, size_type len);
TiXmlString& append (const char* str, size_type len);
void swap (TiXmlString& other)
{
Rep* r = rep_;
rep_ = other.rep_;
other.rep_ = r;
}
private:
void init(size_type sz) { init(sz, sz); }
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
char* start() const { return rep_->str; }
char* finish() const { return rep_->str + rep_->size; }
struct Rep
{
size_type size, capacity;
char str[1];
};
void init(size_type sz, size_type cap)
{
if (cap)
{
// Lee: the original form:
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
// doesn't work in some cases of new being overloaded. Switching
// to the normal allocation, although use an 'int' for systems
// that are overly picky about structure alignment.
const size_type bytesNeeded = sizeof(Rep) + cap;
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
rep_->str[ rep_->size = sz ] = '\0';
rep_->capacity = cap;
}
else
{
rep_ = &nullrep_;
}
}
void quit()
{
if (rep_ != &nullrep_)
{
// The rep_ is really an array of ints. (see the allocator, above).
// Cast it back before delete, so the compiler won't incorrectly call destructors.
delete [] ( reinterpret_cast<int*>( rep_ ) );
}
}
Rep * rep_;
static Rep nullrep_;
} ;
inline bool operator == (const TiXmlString & a, const TiXmlString & b)
{
return ( a.length() == b.length() ) // optimization on some platforms
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
}
inline bool operator < (const TiXmlString & a, const TiXmlString & b)
{
return strcmp(a.c_str(), b.c_str()) < 0;
}
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
TiXmlString operator + (const TiXmlString & a, const char* b);
TiXmlString operator + (const char* a, const TiXmlString & b);
/*
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
Only the operators that we need for TinyXML have been developped.
*/
class TiXmlOutStream : public TiXmlString
{
public :
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const TiXmlString & in)
{
*this += in;
return *this;
}
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const char * in)
{
*this += in;
return *this;
}
} ;
#endif // TIXML_STRING_INCLUDED
#endif // TIXML_USE_STL

File diff suppressed because it is too large Load Diff

1802
extern/oics/tinyxml.h vendored

File diff suppressed because it is too large Load Diff

@ -0,0 +1,53 @@
/*
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "tinyxml.h"
// The goal of the seperate error file is to make the first
// step towards localization. tinyxml (currently) only supports
// english error messages, but the could now be translated.
//
// It also cleans up the code a bit.
//
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
{
"No error",
"Error",
"Failed to open file",
"Memory allocation failed.",
"Error parsing Element.",
"Failed to read Element name",
"Error reading Element value.",
"Error reading Attributes.",
"Error: empty tag.",
"Error reading end tag.",
"Error parsing Unknown.",
"Error parsing Comment.",
"Error parsing Declaration.",
"Error document empty.",
"Error null (0) or unexpected EOF found in input stream.",
"Error parsing CDATA.",
"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8" ?>
<Controller>
<Control name="GameMenu" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="ESCAPE" direction="INCREASE" />
<Channel number="0" direction="DIRECT" percentage="1" />
</Control>
<Control name="Quit" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="Q" direction="INCREASE" />
<Channel number="1" direction="DIRECT" percentage="1" />
</Control>
<Control name="Screenshot" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="SYSRQ" direction="INCREASE" />
<Channel number="2" direction="DIRECT" percentage="1" />
</Control>
<Control name="Inventory" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="I" direction="INCREASE" />
<Channel number="3" direction="DIRECT" percentage="1" />
</Control>
<Control name="Console" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="F1" direction="INCREASE" />
<Channel number="4" direction="DIRECT" percentage="1" />
</Control>
<Control name="MoveLeft" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="A" direction="INCREASE" />
<KeyBinder key="LEFT" direction="INCREASE" />
<Channel number="5" direction="DIRECT" percentage="1" />
</Control>
<Control name="MoveRight" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="D" direction="INCREASE" />
<KeyBinder key="RIGHT" direction="INCREASE" />
<Channel number="6" direction="DIRECT" percentage="1" />
</Control>
<Control name="MoveForward" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="W" direction="INCREASE" />
<KeyBinder key="UP" direction="INCREASE" />
<Channel number="7" direction="DIRECT" percentage="1" />
</Control>
<Control name="MoveBackward" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="S" direction="INCREASE" />
<KeyBinder key="DOWN" direction="INCREASE" />
<Channel number="8" direction="DIRECT" percentage="1" />
</Control>
<Control name="Activate" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="SPACE" direction="INCREASE" />
<Channel number="9" direction="DIRECT" percentage="1" />
</Control>
<Control name="Jump" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="E" direction="INCREASE" />
<Channel number="11" direction="DIRECT" percentage="1" />
</Control>
<Control name="AutoMove" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="Z" direction="INCREASE" />
<Channel number="12" direction="DIRECT" percentage="1" />
</Control>
<Control name="Journal" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="J" direction="INCREASE" />
<Channel number="14" direction="DIRECT" percentage="1" />
</Control>
<Control name="Sneak" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="X" direction="INCREASE" />
<Channel number="22" direction="DIRECT" percentage="1" />
</Control>
<Control name="Walk" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="C" direction="INCREASE" />
<Channel number="23" direction="DIRECT" percentage="1" />
</Control>
<Control name="Crouch" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="LCONTROL" direction="INCREASE" />
<Channel number="24" direction="DIRECT" percentage="1" />
</Control>
<Control name="ReadyWeapon" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="F" direction="INCREASE" />
<Channel number="28" direction="DIRECT" percentage="1" />
</Control>
<Control name="ReadySpell" autoChangeDirectionOnLimitsAfterStop="false" autoReverseToInitialValue="true" initialValue="0" stepSize="MAX" stepsPerSeconds="MAX">
<KeyBinder key="R" direction="INCREASE" />
<Channel number="29" direction="DIRECT" percentage="1" />
</Control>
</Controller>

@ -1,3 +0,0 @@
upload_docs.sh
docs
*~

File diff suppressed because it is too large Load Diff

@ -1,26 +0,0 @@
Minimal Abstraction Game Layer (Mangle) is licensed under the
'zlib/libpng' license:
----
Copyright (c) 2009 Nicolay Korslund
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

@ -1,129 +0,0 @@
Welcome to Mangle v0.1
----------------------
Written by: Nicolay Korslund (korslund@gmail.com)
License: zlib/png (see LICENSE.txt)
WWW: http://asm-soft.com/mangle/
Documentation: http://asm-soft.com/mangle/docs
Mangle is the project name for a small set of generic interfaces for
various game middleware libraries, such as sound, input, graphics, and
so on. You can imagine that it stands for "Minimal Abstraction Game
Layer", if you like. It will consist of several more or less
independent modules, one for each of these areas. These may be used
together to build an entire game engine, or they can be used
individually as separate libraries.
However, Mangle does NOT actually implement a game engine, or any new
fundamental functionality. More on that below.
Currently there's modules for sound and streams / archives (virtual
file systems.) More will come in the future (including input, 2D/3D
graphics, GUI, physics, and more.)
Main idea
---------
The idea behind Mangle is to provide a uniform, consistent interface
to other game libraries. The library does not provide ANY
functionality on its own. Instead it connects to a backend
implementation of your choice (or of your making.)
The Sound module, for example, currently has backends for OpenAL
(output only), FFmpeg (input only) and for Audiere. Hopefully we'll
add IrrKlang, FMod, DirectSound, Miles and more in the future. It can
combine libraries to get more complete functionality (like using
OpenAL for output and FFmpeg to decode sound files), and it's also
easy to write your own backend if you're using a different (or
home-brewed) sound system.
Regardless of what backend you use, the front-end interfaces (found
eg. in sound/output.h) is identical, and as a library user you
shouldn't notice much difference at all if you swap one backend for
another at a later point. It should Just Work.
The interfaces themselves are also quite simple. Setting up a sound
stream from FFmpeg or other decoder into OpenAL can be quite hairy -
but with Mangle the hairy parts have already been written for you. You
just plug the parts together.
The goal in the long run is to support a wide variety of game-related
libraries, and as many backend libraries (free and commercial) as
possible, so that you the user will have to write as little code as
possible.
What is it good for
-------------------
The main point of Mangle, as we said above, is that it connects to any
library of your choice "behind the scenes" but provides the same,
super-simple interface front-end for all of them. There can benefit
you in many ways:
- If you want to use a new library that Mangle support. You don't have
to scour the net for tutorials and usage examples, since much of the
common usage code is already included in the implementation classes.
- If you don't want to pollute your code with library-specific code.
The Mangle interfaces can help you keep your code clean, and its
user interface is often simpler than the exteral library one.
- If you want to quickly connect different libraries together, it
really helps if they speak a common language. The Mangle interfaces
are exactly that - a common language between libraries. Do you need
Audiere to load sounds from a weird archive format only implemented
for PhysFS, all channeled through the OGRE resource system? No
problem!
- If you are creating a library that depends on a specific feature
(such as sound), but you don't want to lock your users into any
specific sound library. Mangle works as an abstraction that lets
your users select their own implementation.
- If you want to support multiple backends for your game/app, or want
to make it possible to easily switch backends later. You can select
backends at compile time or even at runtime. For example you might
want to switch to to a commercial sound library at a later stage in
development, or you may want to use a different input library on
console platforms than on PC.
The Mangle implementations are extremely light-weight - often just one
or two cpp/h pairs per module. You can plug them directly into your
program, there's no separate library building step required.
Since the library aims to be very modularly put together, you can
also, in many cases, just copy-and-paste the parts you need and ignore
the rest. Or modify stuff without fearing that the whole 'system' will
come crashing down, because there is no big 'system' to speak of.
Past and future
---------------
Mangle started out as (and still is) a spin-off from OpenMW, another
project I am personally working on ( http://openmw.com/ ). OpenMW is
an attempt to recreate the engine behind the commercial game
Morrowind, using only open source software.
The projects are still tightly interlinked, and they will continue to
be until OpenMW is finished. Most near-future work on Mangle will be
focused chiefly on OpenMW at the moment. However I will gladly include
external contributions and suggestions that are not OpenMW-related if
someone sends them to me.
Conclusion
----------
As you might have guessed, Mangle is more a concept in development
than a finished library right now.
All feedback, ideas, concepts, questions and code are very
welcome. Send them to: korslund@gmail.com
I will put up a forum later as well if there's enough interest.

@ -1,29 +0,0 @@
#ifndef MANGLE_INPUT_OGREINPUTFRAME_H
#define MANGLE_INPUT_OGREINPUTFRAME_H
/*
This Ogre FrameListener calls capture() on an input driver every frame.
*/
#include <OgreFrameListener.h>
#include "../driver.hpp"
namespace Mangle {
namespace Input {
struct OgreInputCapture : Ogre::FrameListener
{
Mangle::Input::Driver &driver;
OgreInputCapture(Mangle::Input::Driver &drv)
: driver(drv) {}
bool frameStarted(const Ogre::FrameEvent &evt)
{
driver.capture();
return true;
}
};
}}
#endif

@ -1,69 +0,0 @@
#ifndef MANGLE_INPUT_DRIVER_H
#define MANGLE_INPUT_DRIVER_H
#include "event.hpp"
namespace Mangle
{
namespace Input
{
/** Input::Driver is the main interface to any input system that
handles keyboard and/or mouse input, along with any other
input source like joysticks.
It is really a generalized event system, and could also be
used for non-input related events. The definition of the event
codes and structures are entirely dependent on the
implementation.
A system-independent key code list will be found in keys.hpp,
and input drivers should privide optional translations to/from
this list for full compatibility.
*/
struct Driver
{
Driver() {}
virtual ~Driver() {}
/** Captures input and produces the relevant events from it. An
event callback must be set with setEvent(), or all events
will be ignored.
*/
virtual void capture() = 0;
/** Check the state of a given key or button. The key/button
definitions depends on the driver.
*/
virtual bool isDown(int index) = 0;
/** Show or hide system mouse cursor
*/
virtual void showMouse(bool show) = 0;
/** Set the event handler for input events. The evt->event()
function is called for each event. The meaning of the index
and *p parameters will be specific to each driver and to
each input system.
*/
void setEvent(EventPtr evt)
{ event = evt; }
/** Instigate an event. Is used internally for all events, but
can also be called from the outside to "fake" events from
this driver.
*/
void makeEvent(Event::Type type, int index, const void *p=NULL)
{
if(event)
event->event(type,index,p);
}
private:
/// Holds the event callback set byt setEvent()
EventPtr event;
};
typedef boost::shared_ptr<Driver> DriverPtr;
}
}
#endif

@ -1,46 +0,0 @@
#ifndef MANGLE_INPUT_EVENT_H
#define MANGLE_INPUT_EVENT_H
#include "../tools/shared_ptr.hpp"
namespace Mangle
{
namespace Input
{
/** Generic callback for input events. The meaning of the
parameters depend on the system producing the events.
*/
struct Event
{
/// Event types
enum Type
{
EV_Unknown = 1, // Unknown event type
EV_KeyDown = 2, // Keyboard button was pressed
EV_KeyUp = 4, // Keyboard button was released
EV_Keyboard = 6, // All keyboard events
EV_MouseMove = 8, // Mouse movement
EV_MouseDown = 16, // Mouse button pressed
EV_MouseUp = 32, // Mouse button released
EV_Mouse = 56, // All mouse events
EV_ALL = 63 // All events
};
/**
Called upon all events. The first parameter give the event
type, the second gives additional data (usually the local
keysym or button index as defined by the driver), and the
pointer points to the full custom event structure provided by
the driver (the type may vary depending on the EventType,
this is defined in the Driver documentation.)
*/
virtual void event(Type type, int index, const void *p) = 0;
virtual ~Event() {}
};
typedef boost::shared_ptr<Event> EventPtr;
}
}
#endif

@ -1,47 +0,0 @@
#ifndef MANGLE_INPUT_EVENTLIST_H
#define MANGLE_INPUT_EVENTLIST_H
#include "../event.hpp"
#include <vector>
namespace Mangle
{
namespace Input
{
/** And Event handler that distributes each event to a list of
other handlers. Supports filtering events by their Type
parameter.
*/
struct EventList : Event
{
struct Filter
{
EventPtr evt;
int flags;
};
std::vector<Filter> list;
void add(EventPtr e, int flags = EV_ALL)
{
Filter f;
f.evt = e;
f.flags = flags;
list.push_back(f);
}
virtual void event(Type type, int index, const void *p)
{
std::vector<Filter>::iterator it;
for(it=list.begin(); it!=list.end(); it++)
{
if(type & it->flags)
it->evt->event(type,index,p);
}
}
};
typedef boost::shared_ptr<EventList> EventListPtr;
}
}
#endif

@ -1,154 +0,0 @@
#include "ois_driver.hpp"
#include <cassert>
#include <sstream>
#include <OgreRenderWindow.h>
#include <OIS/OIS.h>
#ifdef __APPLE_CC__
#include <Carbon/Carbon.h>
#endif
using namespace Mangle::Input;
using namespace OIS;
struct Mangle::Input::OISListener : OIS::KeyListener, OIS::MouseListener
{
OISDriver &drv;
OISListener(OISDriver &driver)
: drv(driver) {}
bool keyPressed( const OIS::KeyEvent &arg )
{
drv.makeEvent(Event::EV_KeyDown, arg.key, &arg);
return true;
}
bool keyReleased( const OIS::KeyEvent &arg )
{
drv.makeEvent(Event::EV_KeyUp, arg.key, &arg);
return true;
}
bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
// Mouse button events are handled as key events
// TODO: Translate mouse buttons into pseudo-keysyms
drv.makeEvent(Event::EV_MouseDown, id, &arg);
return true;
}
bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
// TODO: ditto
drv.makeEvent(Event::EV_MouseUp, id, &arg);
return true;
}
bool mouseMoved( const OIS::MouseEvent &arg )
{
drv.makeEvent(Event::EV_MouseMove, -1, &arg);
return true;
}
};
OISDriver::OISDriver(Ogre::RenderWindow *window, bool exclusive)
{
assert(window);
size_t windowHnd;
window->getCustomAttribute("WINDOW", &windowHnd);
std::ostringstream windowHndStr;
ParamList pl;
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
// Set non-exclusive mouse and keyboard input if the user requested
// it.
if(!exclusive)
{
#if defined OIS_WIN32_PLATFORM
pl.insert(std::make_pair(std::string("w32_mouse"),
std::string("DISCL_FOREGROUND" )));
pl.insert(std::make_pair(std::string("w32_mouse"),
std::string("DISCL_NONEXCLUSIVE")));
pl.insert(std::make_pair(std::string("w32_keyboard"),
std::string("DISCL_FOREGROUND")));
pl.insert(std::make_pair(std::string("w32_keyboard"),
std::string("DISCL_NONEXCLUSIVE")));
#elif defined OIS_LINUX_PLATFORM
pl.insert(std::make_pair(std::string("x11_mouse_grab"),
std::string("false")));
pl.insert(std::make_pair(std::string("x11_mouse_hide"),
std::string("false")));
pl.insert(std::make_pair(std::string("x11_keyboard_grab"),
std::string("false")));
pl.insert(std::make_pair(std::string("XAutoRepeatOn"),
std::string("true")));
#endif
}
#ifdef __APPLE_CC__
// Give the application window focus to receive input events
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
#endif
inputMgr = InputManager::createInputSystem( pl );
// Create all devices
keyboard = static_cast<Keyboard*>(inputMgr->createInputObject
( OISKeyboard, true ));
mouse = static_cast<Mouse*>(inputMgr->createInputObject
( OISMouse, true ));
// Set mouse region
const MouseState &ms = mouse->getMouseState();
ms.width = window->getWidth();
ms.height = window->getHeight();
// Set up the input listener
listener = new OISListener(*this);
keyboard-> setEventCallback(listener);
mouse-> setEventCallback(listener);
}
OISDriver::~OISDriver()
{
// Delete the listener object
delete listener;
if(inputMgr == NULL) return;
// Kill the input systems. This will reset input options such as key
// repeat rate.
inputMgr->destroyInputObject(keyboard);
inputMgr->destroyInputObject(mouse);
InputManager::destroyInputSystem(inputMgr);
inputMgr = NULL;
}
void OISDriver::capture()
{
// Capture keyboard and mouse events
keyboard->capture();
mouse->capture();
}
bool OISDriver::isDown(int index)
{
// TODO: Extend to mouse buttons as well
return keyboard->isKeyDown((OIS::KeyCode)index);
}
void OISDriver::adjustMouseClippingSize(int width, int height)
{
const OIS::MouseState &ms = mouse->getMouseState();
ms.width = width;
ms.height = height;
}

@ -1,50 +0,0 @@
#ifndef MANGLE_INPUT_OIS_DRIVER_H
#define MANGLE_INPUT_OIS_DRIVER_H
#include "../driver.hpp"
namespace OIS
{
class InputManager;
class Mouse;
class Keyboard;
}
namespace Ogre
{
class RenderWindow;
}
namespace Mangle
{
namespace Input
{
struct OISListener;
/** Input driver for OIS, the input manager typically used with
Ogre.
*/
struct OISDriver : Driver
{
/// If exclusive=true, then we capture mouse and keyboard from
/// the OS.
OISDriver(Ogre::RenderWindow *window, bool exclusive=true);
~OISDriver();
void adjustMouseClippingSize(int width, int height);
void capture();
bool isDown(int index);
/// Not currently supported.
void showMouse(bool) {}
private:
OIS::InputManager *inputMgr;
OIS::Mouse *mouse;
OIS::Keyboard *keyboard;
OISListener *listener;
};
}
}
#endif

@ -1,54 +0,0 @@
#include "sdl_driver.hpp"
#include <SDL.h>
using namespace Mangle::Input;
void SDLDriver::capture()
{
// Poll for events
SDL_Event evt;
while(SDL_PollEvent(&evt))
{
Event::Type type = Event::EV_Unknown;
int index = -1;
switch(evt.type)
{
// For key events, send the keysym as the index.
case SDL_KEYDOWN:
type = Event::EV_KeyDown;
index = evt.key.keysym.sym;
break;
case SDL_KEYUP:
type = Event::EV_KeyUp;
index = evt.key.keysym.sym;
break;
case SDL_MOUSEMOTION:
type = Event::EV_MouseMove;
break;
// Add more event types later
}
// Pass the event along, using -1 as index for unidentified
// event types.
makeEvent(type, index, &evt);
}
}
bool SDLDriver::isDown(int index)
{
int num;
Uint8 *keys = SDL_GetKeyState(&num);
assert(index >= 0 && index < num);
// The returned array from GetKeyState is indexed by the
// SDLK_KEYNAME enums and is just a list of bools. If the indexed
// value is true, the button is down.
return keys[index];
}
void SDLDriver::showMouse(bool show)
{
SDL_ShowCursor(show?SDL_ENABLE:SDL_DISABLE);
}

@ -1,27 +0,0 @@
#ifndef MANGLE_INPUT_SDL_DRIVER_H
#define MANGLE_INPUT_SDL_DRIVER_H
#include "../driver.hpp"
namespace Mangle
{
namespace Input
{
/** Input driver for SDL. As the input system of SDL is seldomly
used alone (most often along with the video system), it is
assumed that you do your own initialization and cleanup of SDL
before and after using this driver.
The Event.event() calls will be given the proper EV_ type, the
key index (for key up/down events), and a pointer to the full
SDL_Event structure.
*/
struct SDLDriver : Driver
{
void capture();
bool isDown(int index);
void showMouse(bool);
};
}
}
#endif

@ -1,2 +0,0 @@
*_test
ogre.cfg

@ -1,15 +0,0 @@
GCC=g++ -Wall
all: sdl_driver_test ois_driver_test evtlist_test
sdl_driver_test: sdl_driver_test.cpp
$(GCC) $< ../servers/sdl_driver.cpp -o $@ -I/usr/include/SDL/ -lSDL
ois_driver_test: ois_driver_test.cpp
$(GCC) $< ../servers/ois_driver.cpp -o $@ -I/usr/local/include/OGRE/ -lOgreMain -lOIS -lboost_filesystem
evtlist_test: evtlist_test.cpp ../filters/eventlist.hpp ../event.hpp
$(GCC) $< -o $@
clean:
rm *_test

@ -1,35 +0,0 @@
#include <iostream>
#include "../driver.hpp"
#include <unistd.h>
using namespace std;
using namespace Mangle::Input;
Driver *input;
struct MyCB : Event
{
void event(Event::Type type, int i, const void *p)
{
cout << "got event: type=" << type << " index=" << i << endl;
}
};
void mainLoop(int argc, int quitKey)
{
cout << "Hold the Q key to quit:\n";
input->setEvent(EventPtr(new MyCB));
while(!input->isDown(quitKey))
{
input->capture();
usleep(20000);
if(argc == 1)
{
cout << "You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly\n";
break;
}
}
delete input;
cout << "\nBye bye!\n";
}

@ -1,45 +0,0 @@
#include <iostream>
#include "../filters/eventlist.hpp"
using namespace std;
using namespace Mangle::Input;
struct MyEvent : Event
{
int ii;
MyEvent(int i) : ii(i) {}
void event(Event::Type type, int i, const void *p)
{
cout << " #" << ii << " got event: type=" << type << " index=" << i << endl;
}
};
EventList lst;
int iii=1;
void make(int flags)
{
lst.add(EventPtr(new MyEvent(iii++)), flags);
}
void send(Event::Type type)
{
cout << "Sending type " << type << endl;
lst.event(type,0,NULL);
}
int main()
{
make(Event::EV_ALL);
make(Event::EV_KeyDown);
make(Event::EV_KeyUp | Event::EV_MouseDown);
send(Event::EV_Unknown);
send(Event::EV_KeyDown);
send(Event::EV_KeyUp);
send(Event::EV_MouseDown);
cout << "Enough of that\n";
return 0;
}

@ -1,51 +0,0 @@
#include "common.cpp"
#include "../servers/ois_driver.hpp"
#include <Ogre.h>
#include <OIS/OIS.h>
#include <boost/filesystem.hpp>
bool isFile(const char *name)
{
boost::filesystem::path cfg_file_path(name);
return boost::filesystem::exists(cfg_file_path);
}
using namespace Ogre;
using namespace OIS;
Root *root;
RenderWindow *window;
void setupOgre()
{
// Disable logging
new LogManager;
Log *log = LogManager::getSingleton().createLog("");
log->setDebugOutputEnabled(false);
bool useConfig = isFile("ogre.cfg");
// Set up Root
root = new Root("plugins.cfg", "ogre.cfg", "");
// Configure
if(!useConfig)
root->showConfigDialog();
else
root->restoreConfig();
// Initialize OGRE window
window = root->initialise(true, "test", "");
}
int main(int argc, char** argv)
{
setupOgre();
input = new OISDriver(window);
mainLoop(argc, KC_Q);
delete root;
return 0;
}

@ -1,12 +0,0 @@
Sending type 1
#1 got event: type=1 index=0
Sending type 2
#1 got event: type=2 index=0
#2 got event: type=2 index=0
Sending type 4
#1 got event: type=4 index=0
#3 got event: type=4 index=0
Sending type 16
#1 got event: type=16 index=0
#3 got event: type=16 index=0
Enough of that

@ -1,5 +0,0 @@
Hold the Q key to quit:
got event: type=8 index=-1
You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly
Bye bye!

@ -1,5 +0,0 @@
Hold the Q key to quit:
got event: type=1 index=-1
You are running in script mode, aborting. Run this test with a parameter (any at all) to test the input loop properly
Bye bye!

@ -1,12 +0,0 @@
# Defines plugins to load
# Define plugin folder
PluginFolder=/usr/local/lib/OGRE/
# Define plugins
Plugin=RenderSystem_GL
Plugin=Plugin_ParticleFX
Plugin=Plugin_OctreeSceneManager
# Plugin=Plugin_CgProgramManager

@ -1,16 +0,0 @@
#include "common.cpp"
#include "../servers/sdl_driver.hpp"
#include <SDL.h>
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(640, 480, 0, SDL_SWSURFACE);
input = new SDLDriver();
mainLoop(argc, SDLK_q);
SDL_Quit();
return 0;
}

@ -1,18 +0,0 @@
#!/bin/bash
make || exit
mkdir -p output
PROGS=*_test
for a in $PROGS; do
if [ -f "output/$a.out" ]; then
echo "Running $a:"
./$a | diff output/$a.out -
else
echo "Creating $a.out"
./$a > "output/$a.out"
git add "output/$a.out"
fi
done

@ -1,63 +0,0 @@
#ifndef MANGLE_REND2D_DRIVER_H
#define MANGLE_REND2D_DRIVER_H
#include <string>
#include "sprite.hpp"
namespace Mangle
{
namespace Rend2D
{
/**
The driver is the connection to the backend system that powers
2D sprite rendering. For example the backend could be SDL or
any other 2D-capable graphics library.
*/
struct Driver
{
/// Get the screen sprite
virtual Sprite *getScreen() = 0;
/// Sets the video mode.
virtual void setVideoMode(int width, int height, int bpp=32, bool fullscreen=false) = 0;
/** Update the screen. Until this function is called, none of
the changes written to the screen sprite will be visible.
*/
virtual void update() = 0;
/// Set the window title, as well as the title of the window
/// when "iconified"
virtual void setWindowTitle(const std::string &title,
const std::string &icon) = 0;
/// Set the window title
void setWindowTitle(const std::string &title) { setWindowTitle(title,title); }
/// Load sprite from an image file. Thows an exception on
/// failure.
virtual Sprite* loadImage(const std::string &file) = 0;
/// Load a sprite from an image file stored in memory. Throws
/// exception on failure.
virtual Sprite* loadImage(const void* data, size_t size) = 0;
/** @brief Set gamma value for all colors.
Note: Setting this in windowed mode will affect the ENTIRE
SCREEN!
*/
virtual void setGamma(float gamma) = 0;
/// Set gamma individually for red, green, blue
virtual void setGamma(float red, float green, float blue) = 0;
/// Get screen width
virtual int width() = 0;
/// Get screen height
virtual int height() = 0;
};
}
}
#endif

@ -1,259 +0,0 @@
#include "sdl_driver.hpp"
#include <SDL.h>
#include <SDL_image.h>
#include <stdexcept>
#include <cassert>
using namespace Mangle::Rend2D;
const SpriteData *SDL_Sprite::lock()
{
// Make sure we aren't already locked
assert(!data.pixels);
// Lock the surface and set up the data structure
SDL_LockSurface(surface);
data.pixels = surface->pixels;
data.w = surface->w;
data.h = surface->h;
data.pitch = surface->pitch;
data.bypp = surface->format->BytesPerPixel;
return &data;
}
void SDL_Sprite::unlock()
{
if(data.pixels)
{
SDL_UnlockSurface(surface);
data.pixels = NULL;
}
}
// This is a really crappy and slow implementation, only intended for
// testing purposes. Use lock/unlock for faster pixel drawing.
void SDL_Sprite::pixel(int x, int y, int color)
{
SDL_LockSurface(surface);
int bpp = surface->format->BytesPerPixel;
char *p = (char*)surface->pixels + y*surface->pitch + x*bpp;
switch(bpp)
{
case 1: *p = color; break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
{
p[0] = (color >> 16) & 0xff;
p[1] = (color >> 8) & 0xff;
p[2] = color & 0xff;
}
else
{
p[0] = color & 0xff;
p[1] = (color >> 8) & 0xff;
p[2] = (color >> 16) & 0xff;
}
break;
case 4:
*(int*)p = color;
break;
}
SDL_UnlockSurface(surface);
}
void SDL_Sprite::draw(Sprite *s, // Must be SDL_Sprite
int x, int y, // Destination position
int sx, int sy, // Source position
int w, int h // Amount to draw. -1 means remainder.
)
{
// Get source surface
SDL_Sprite *other = dynamic_cast<SDL_Sprite*>(s);
assert(other != NULL);
SDL_Surface *img = other->getSurface();
// Check coordinate validity
assert(sx <= img->w && sy <= img->h);
assert(x <= surface->w && y <= surface->h);
assert(sx >= 0 && sy >= 0);
// Compute width and height if necessary
if(w == -1) w = img->w - sx;
if(h == -1) h = img->h - sy;
// Check them if they're valid
assert(w >= 0 && w <= img->w);
assert(h >= 0 && h <= img->h);
SDL_Rect dest;
dest.x = x;
dest.y = y;
dest.w = w;
dest.h = h;
SDL_Rect src;
src.x = sx;
src.y = sy;
src.w = w;
src.h = h;
// Do the Blitman
SDL_BlitSurface(img, &src, surface, &dest);
}
SDL_Sprite::SDL_Sprite(SDL_Surface *s, bool autoDelete)
: surface(s), autoDel(autoDelete)
{
assert(surface != NULL);
data.pixels = NULL;
}
SDL_Sprite::~SDL_Sprite()
{
if(autoDel)
SDL_FreeSurface(surface);
}
void SDL_Sprite::fill(int value)
{
SDL_FillRect(surface, NULL, value);
}
int SDL_Sprite::width() { return surface->w; }
int SDL_Sprite::height() { return surface->h; }
SDLDriver::SDLDriver() : display(NULL), realDisp(NULL), softDouble(false)
{
if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1)
throw std::runtime_error("Error initializing SDL video");
}
SDLDriver::~SDLDriver()
{
if(display) delete display;
SDL_Quit();
}
void SDLDriver::setVideoMode(int width, int height, int bpp, bool fullscreen)
{
unsigned int flags;
if(display) delete display;
if (fullscreen)
// Assume fullscreen mode allows a double-bufferd hardware
// mode. We need more test code for this to be safe though.
flags = SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF;
else
flags = SDL_SWSURFACE;
// Create the surface and check it
realDisp = SDL_SetVideoMode(width, height, bpp, flags);
if(realDisp == NULL)
throw std::runtime_error("Failed setting SDL video mode");
// Code for software double buffering. I haven't found this to be
// any speed advantage at all in windowed mode (it's slower, as one
// would expect.) Not properly tested in fullscreen mode with
// hardware buffers, but it will probably only be an improvement if
// we do excessive writing (ie. write each pixel on average more
// than once) or try to read from the display buffer.
if(softDouble)
{
// Make a new surface with the same attributes as the real
// display surface.
SDL_Surface *back = SDL_DisplayFormat(realDisp);
assert(back != NULL);
// Create a sprite representing the double buffer
display = new SDL_Sprite(back);
}
else
{
// Create a sprite directly representing the display surface.
// The 'false' parameter means do not autodelete the screen
// surface upon exit (since SDL manages it)
display = new SDL_Sprite(realDisp, false);
}
}
/// Update the screen
void SDLDriver::update()
{
// Blit the soft double buffer onto the real display buffer
if(softDouble)
SDL_BlitSurface(display->getSurface(), NULL, realDisp, NULL );
if(realDisp)
SDL_Flip(realDisp);
}
/// Set the window title, as well as the title of the window when
/// "iconified"
void SDLDriver::setWindowTitle(const std::string &title,
const std::string &icon)
{
SDL_WM_SetCaption( title.c_str(), icon.c_str() );
}
// Convert the given surface to display format.
static SDL_Surface* convertImage(SDL_Surface* surf)
{
if(surf != NULL)
{
// Convert the image to the display buffer format, for faster
// blitting
SDL_Surface *surf2 = SDL_DisplayFormat(surf);
SDL_FreeSurface(surf);
surf = surf2;
}
return surf;
}
/// Load sprite from an image file, using SDL_image.
Sprite* SDLDriver::loadImage(const std::string &file)
{
SDL_Surface *surf = IMG_Load(file.c_str());
surf = convertImage(surf);
if(surf == NULL)
throw std::runtime_error("SDL failed to load image file '" + file + "'");
return spriteFromSDL(surf);
}
/// Load sprite from an SDL_RWops structure. autoFree determines
/// whether the RWops struct should be closed/freed after use.
Sprite* SDLDriver::loadImage(SDL_RWops *src, bool autoFree)
{
SDL_Surface *surf = IMG_Load_RW(src, autoFree);
surf = convertImage(surf);
if(surf == NULL)
throw std::runtime_error("SDL failed to load image");
return spriteFromSDL(surf);
}
/// Load a sprite from an image file stored in memory. Uses
/// SDL_image.
Sprite* SDLDriver::loadImage(const void* data, size_t size)
{
SDL_RWops *rw = SDL_RWFromConstMem(data, size);
return loadImage(rw, true);
}
void SDLDriver::setGamma(float red, float green, float blue)
{
SDL_SetGamma(red,green,blue);
}
/// Convert an existing SDL surface into a sprite
Sprite* SDLDriver::spriteFromSDL(SDL_Surface *surf, bool autoFree)
{
assert(surf);
return new SDL_Sprite(surf, autoFree);
}
void SDLDriver::sleep(int ms) { SDL_Delay(ms); }
unsigned int SDLDriver::ticks() { return SDL_GetTicks(); }

@ -1,125 +0,0 @@
#ifndef MANGLE_DRAW2D_SDL_H
#define MANGLE_DRAW2D_SDL_H
#include "../driver.hpp"
// Predeclarations keep the streets safe at night
struct SDL_Surface;
struct SDL_RWops;
namespace Mangle
{
namespace Rend2D
{
/// SDL-implementation of Sprite
struct SDL_Sprite : Sprite
{
/** Draw a sprite in the given position. Can only draw other SDL
sprites.
*/
void draw(Sprite *s, // Must be SDL_Sprite
int x, int y, // Destination position
int sx=0, int sy=0, // Source position
int w=-1, int h=-1 // Amount to draw. -1 means remainder.
);
SDL_Sprite(SDL_Surface *s, bool autoDelete=true);
~SDL_Sprite();
// Information retrieval
int width();
int height();
SDL_Surface *getSurface() { return surface; }
// Fill with a given pixel value
void fill(int value);
// Set one pixel
void pixel(int x, int y, int value);
const SpriteData *lock();
void unlock();
private:
// The SDL surface
SDL_Surface* surface;
// Used for locking
SpriteData data;
// If true, delete this surface when the canvas is destructed
bool autoDel;
};
class SDLDriver : public Driver
{
// The main display surface
SDL_Sprite *display;
// The actual display surface. May or may not be the same
// surface pointed to by 'display' above, depending on the
// softDouble flag.
SDL_Surface *realDisp;
// If true, we do software double buffering.
bool softDouble;
public:
SDLDriver();
~SDLDriver();
/// Sets the video mode. Will create the window if it is not
/// already set up. Note that for SDL, bpp=0 means use current
/// bpp.
void setVideoMode(int width, int height, int bpp=0, bool fullscreen=false);
/// Update the screen
void update();
/// Set the window title, as well as the title of the window
/// when "iconified"
void setWindowTitle(const std::string &title,
const std::string &icon);
// Include overloads from our Glorious parent
using Driver::setWindowTitle;
/// Load sprite from an image file, using SDL_image.
Sprite* loadImage(const std::string &file);
/// Load sprite from an SDL_RWops structure. autoFree determines
/// whether the RWops struct should be closed/freed after use.
Sprite* loadImage(SDL_RWops *src, bool autoFree=false);
/// Load a sprite from an image file stored in memory. Uses
/// SDL_image.
Sprite* loadImage(const void* data, size_t size);
/// Set gamma value
void setGamma(float gamma) { setGamma(gamma,gamma,gamma); }
/// Set gamma individually for red, green, blue
void setGamma(float red, float green, float blue);
/// Convert an existing SDL surface into a sprite
Sprite* spriteFromSDL(SDL_Surface *surf, bool autoFree = true);
// Get width and height
int width() { return display ? display->width() : 0; }
int height() { return display ? display->height() : 0; }
/// Get the screen sprite
Sprite *getScreen() { return display; }
/// Not really a graphic-related function, but very
/// handly. Sleeps the given number of milliseconds using
/// SDL_Delay().
void sleep(int ms);
/// Get the number of ticks since SDL initialization, using
/// SDL_GetTicks().
unsigned int ticks();
};
}
}
#endif

@ -1,311 +0,0 @@
#include "sdl_gl_driver.hpp"
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_opengl.h>
#include <stdexcept>
#include <cassert>
using namespace Mangle::Rend2D;
void SDLGL_Sprite::draw(Sprite *s, // Must be SDLGL_Sprite
int x, int y, // Destination position
int sx, int sy, // Source position
int w, int h // Amount to draw. -1 means remainder.
)
{
// Get source surface
SDLGL_Sprite *other = dynamic_cast<SDLGL_Sprite*>(s);
assert(other != NULL);
SDL_Surface *img = other->getSurface();
// Check coordinate validity
assert(sx <= img->w && sy <= img->h);
assert(x <= surface->w && y <= surface->h);
assert(sx >= 0 && sy >= 0);
// Compute width and height if necessary
if(w == -1) w = img->w - sx;
if(h == -1) h = img->h - sy;
// Check them if they're valid
assert(w >= 0 && w <= img->w);
assert(h >= 0 && h <= img->h);
SDL_Rect dest;
dest.x = x;
dest.y = y;
dest.w = w;
dest.h = h;
SDL_Rect src;
src.x = sx;
src.y = sy;
src.w = w;
src.h = h;
// Do the Blitman
SDL_BlitSurface(img, &src, surface, &dest);
}
SDLGL_Sprite::SDLGL_Sprite(SDL_Surface *s, bool autoDelete)
: surface(s), autoDel(autoDelete)
{
assert(surface != NULL);
}
SDLGL_Sprite::~SDLGL_Sprite()
{
if(autoDel)
SDL_FreeSurface(surface);
}
void SDLGL_Sprite::fill(int value)
{
SDL_FillRect(surface, NULL, value);
}
int SDLGL_Sprite::width() { return surface->w; }
int SDLGL_Sprite::height() { return surface->h; }
SDLGLDriver::SDLGLDriver() : display(NULL), realDisp(NULL)
{
if (SDL_InitSubSystem( SDL_INIT_VIDEO ) == -1)
throw std::runtime_error("Error initializing SDL video");
}
SDLGLDriver::~SDLGLDriver()
{
if(display) delete display;
SDL_Quit();
}
// Surface used for the screen. Since OpenGL surfaces must have sizes
// that are powers of 2, we have to "fake" the returned display size
// to match the screen, not the surface itself. If we don't use this,
// the client program will get confused about the actual size of our
// screen, thinking it is bigger than it is.
struct FakeSizeSprite : SDLGL_Sprite
{
int fakeW, fakeH;
FakeSizeSprite(SDL_Surface *s, int fw, int fh)
: SDLGL_Sprite(s), fakeW(fw), fakeH(fh)
{}
int width() { return fakeW; }
int height() { return fakeH; }
};
static int makePow2(int num)
{
assert(num);
if((num & (num-1)) != 0)
{
int cnt = 0;
while(num)
{
num >>= 1;
cnt++;
}
num = 1 << cnt;
}
return num;
}
void SDLGLDriver::setVideoMode(int width, int height, int bpp, bool fullscreen)
{
unsigned int flags;
if(display) delete display;
flags = SDL_OPENGL;
if (fullscreen)
flags |= SDL_FULLSCREEN;
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 );
// Create the surface and check it
screen = SDL_SetVideoMode(width, height, bpp, flags);
if(screen == NULL)
throw std::runtime_error("Failed setting SDL video mode");
// Expand width and height to be powers of 2
int width2 = makePow2(width);
int height2 = makePow2(height);
// Create a new SDL surface of this size
const SDL_PixelFormat& fmt = *(screen->format);
realDisp = SDL_CreateRGBSurface(SDL_SWSURFACE,width2,height2,
fmt.BitsPerPixel,
fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask);
// Create a sprite directly representing the display surface. This
// allows the user to blit to it directly.
display = new FakeSizeSprite(realDisp, width, height);
// Set up the OpenGL format
nOfColors = fmt.BytesPerPixel;
if(nOfColors == 4)
{
if (fmt.Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
}
else if(nOfColors == 3)
{
if (fmt.Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
}
else
assert(0 && "unsupported screen format");
glEnable(GL_TEXTURE_2D);
// Have OpenGL generate a texture object handle for us
glGenTextures( 1, &texture );
// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );
// Set the texture's stretching properties
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
void SDLGLDriver::updateNoSwap()
{
if(!realDisp) return;
// Fist, set up the screen texture:
// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );
// Edit the texture object's image data
glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, realDisp->w, realDisp->h, 0,
texture_format, GL_UNSIGNED_BYTE, realDisp->pixels );
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// OpenGL barf. Set up the projection to match our screen
int vPort[4];
glGetIntegerv(GL_VIEWPORT, vPort);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBegin( GL_QUADS );
// Needed to move the screen into the right place
int diff = screen->h - realDisp->h;
// Bottom-left vertex (corner)
glTexCoord2i( 0, 1 );
glVertex3f(0,diff,0);
// Bottom-right vertex (corner)
glTexCoord2i( 1, 1 );
glVertex3f( realDisp->w, diff, 0.f );
// Top-right vertex (corner)
glTexCoord2i( 1, 0 );
glVertex3f( realDisp->w, screen->h, 0.f );
// Top-left vertex (corner)
glTexCoord2i( 0, 0 );
glVertex3f( 0, screen->h, 0.f );
glEnd();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
void SDLGLDriver::swap()
{
SDL_GL_SwapBuffers();
}
void SDLGLDriver::update()
{
updateNoSwap();
swap();
}
/// Set the window title, as well as the title of the window when
/// "iconified"
void SDLGLDriver::setWindowTitle(const std::string &title,
const std::string &icon)
{
SDL_WM_SetCaption( title.c_str(), icon.c_str() );
}
// Convert the given surface to display format.
static SDL_Surface* convertImage(SDL_Surface* surf)
{
if(surf != NULL)
{
// Convert the image to the display buffer format, for faster
// blitting
SDL_Surface *surf2 = SDL_DisplayFormat(surf);
SDL_FreeSurface(surf);
surf = surf2;
}
return surf;
}
/// Load sprite from an image file, using SDL_image.
Sprite* SDLGLDriver::loadImage(const std::string &file)
{
SDL_Surface *surf = IMG_Load(file.c_str());
surf = convertImage(surf);
if(surf == NULL)
throw std::runtime_error("SDL failed to load image file '" + file + "'");
return spriteFromSDL(surf);
}
/// Load sprite from an SDL_RWops structure. autoFree determines
/// whether the RWops struct should be closed/freed after use.
Sprite* SDLGLDriver::loadImage(SDL_RWops *src, bool autoFree)
{
SDL_Surface *surf = IMG_Load_RW(src, autoFree);
surf = convertImage(surf);
if(surf == NULL)
throw std::runtime_error("SDL failed to load image");
return spriteFromSDL(surf);
}
/// Load a sprite from an image file stored in memory. Uses
/// SDL_image.
Sprite* SDLGLDriver::loadImage(const void* data, size_t size)
{
SDL_RWops *rw = SDL_RWFromConstMem(data, size);
return loadImage(rw, true);
}
void SDLGLDriver::setGamma(float red, float green, float blue)
{
SDL_SetGamma(red,green,blue);
}
/// Convert an existing SDL surface into a sprite
Sprite* SDLGLDriver::spriteFromSDL(SDL_Surface *surf, bool autoFree)
{
assert(surf);
return new SDLGL_Sprite(surf, autoFree);
}
void SDLGLDriver::sleep(int ms) { SDL_Delay(ms); }
unsigned int SDLGLDriver::ticks() { return SDL_GetTicks(); }

@ -1,132 +0,0 @@
#ifndef MANGLE_DRAW2D_SDLGL_H
#define MANGLE_DRAW2D_SDLGL_H
/** This driver is similar to SDLDriver, except that it uses SDL on
top of OpenGL.
I've decided to make it a separate file instead of just adding
optional OpenGL support to the original, so that pure SDL users
don't have to add OpenGL as a dependency.
*/
#include "../driver.hpp"
// Predeclarations keep the streets safe at night
struct SDL_Surface;
struct SDL_RWops;
namespace Mangle
{
namespace Rend2D
{
/// SDL-implementation of Sprite
struct SDLGL_Sprite : Sprite
{
/** Draw a sprite in the given position. Can only draw other SDL
sprites.
*/
void draw(Sprite *s, // Must be SDLGL_Sprite
int x, int y, // Destination position
int sx=0, int sy=0, // Source position
int w=-1, int h=-1 // Amount to draw. -1 means remainder.
);
SDLGL_Sprite(SDL_Surface *s, bool autoDelete=true);
~SDLGL_Sprite();
// Information retrieval
virtual int width();
virtual int height();
SDL_Surface *getSurface() { return surface; }
// Fill with a given pixel value
void fill(int value);
private:
// The SDL surface
SDL_Surface* surface;
// If true, delete this surface when the canvas is destructed
bool autoDel;
};
class SDLGLDriver : public Driver
{
// The main display surface
SDLGL_Sprite *display;
// The screen surface. This is completely unused.
SDL_Surface *screen;
// The display surface and main GL texture. These are used when
// drawing the entire screen as one surface, as a drop-in
// replacement for SDLDriver.
SDL_Surface *realDisp;
unsigned int texture;
int nOfColors, texture_format;
public:
SDLGLDriver();
~SDLGLDriver();
/// Sets the video mode. Will create the window if it is not
/// already set up. Note that for SDL, bpp=0 means use current
/// bpp.
void setVideoMode(int width, int height, int bpp=0, bool fullscreen=false);
/// Update the screen
void update();
/// Calls SDL_GL_SwapBuffers
void swap();
/// Draw surface to screen but do not call SDL_GL_SwapBuffers()
void updateNoSwap();
/// Set the window title, as well as the title of the window
/// when "iconified"
void setWindowTitle(const std::string &title,
const std::string &icon);
// Include overloads from our Glorious parent
using Driver::setWindowTitle;
/// Load sprite from an image file, using SDL_image.
Sprite* loadImage(const std::string &file);
/// Load sprite from an SDL_RWops structure. autoFree determines
/// whether the RWops struct should be closed/freed after use.
Sprite* loadImage(SDL_RWops *src, bool autoFree=false);
/// Load a sprite from an image file stored in memory. Uses
/// SDL_image.
Sprite* loadImage(const void* data, size_t size);
/// Set gamma value
void setGamma(float gamma) { setGamma(gamma,gamma,gamma); }
/// Set gamma individually for red, green, blue
void setGamma(float red, float green, float blue);
/// Convert an existing SDL surface into a sprite
Sprite* spriteFromSDL(SDL_Surface *surf, bool autoFree = true);
// Get width and height
int width() { return display ? display->width() : 0; }
int height() { return display ? display->height() : 0; }
/// Get the screen sprite
Sprite *getScreen() { return display; }
/// Not really a graphic-related function, but very
/// handly. Sleeps the given number of milliseconds using
/// SDL_Delay().
void sleep(int ms);
/// Get the number of ticks since SDL initialization, using
/// SDL_GetTicks().
unsigned int ticks();
};
}
}
#endif

@ -1,57 +0,0 @@
#ifndef MANGLE_REND2D_SPRITE_H
#define MANGLE_REND2D_SPRITE_H
namespace Mangle
{
namespace Rend2D
{
/**
A pointer to sprite data for direct drawing. Only to be used
while the corresponding sprite is locked.
*/
struct SpriteData
{
void *pixels; // Pixel data
int w, h; // Width and height
int pitch, bypp; // Pitch (bytes) and bytes per pixel
};
/**
A Sprite is either a bitmap to be drawn or an output of area
for blitting other bitmaps, or both. They are created by the
Driver.
*/
struct Sprite
{
/// Draw a sprite in the given position
virtual void draw(Sprite *s, // The sprite to draw
int x, int y, // Destination position
int sx=0, int sy=0, // Source position
int w=-1, int h=-1 // Amount to draw. -1 means remainder.
) = 0;
virtual ~Sprite() {}
// Information retrieval
virtual int width() = 0;
virtual int height() = 0;
/// Fill the sprite with the given pixel value. The pixel format
/// depends on the format of the sprite.
virtual void fill(int value) = 0;
/// Set one pixel value. The pixel format depends on the sprite
/// format. This is not expected to be fast, and in some
/// implementations may not work at all.
virtual void pixel(int x, int y, int value) {}
/// Lock sprite for direct drawing, and return a struct
/// containing the necessary pointer. When finished, unlock the
/// sprite with unlock(). May return NULL, if so then direct
/// drawing is not possible.
virtual const SpriteData *lock() { return NULL; }
virtual void unlock() {}
};
}
}
#endif

@ -1,15 +0,0 @@
GCC=g++ -Wall -Werror
all: sdl_test sdl_move_test sdlgl_move_test
sdl_test: sdl_test.cpp
$(GCC) $< ../servers/sdl_driver.cpp -o $@ -I/usr/include/SDL/ -lSDL -lSDL_image
sdl_move_test: sdl_move_test.cpp ../servers/sdl_driver.cpp
$(GCC) $^ -o $@ -I/usr/include/SDL/ -lSDL -lSDL_image
sdlgl_move_test: sdlgl_move_test.cpp ../servers/sdl_gl_driver.cpp
$(GCC) $^ -o $@ -I/usr/include/SDL/ -lSDL -lSDL_image -lGL
clean:
rm *_test

@ -1,11 +0,0 @@
Loading SDL driver.
Creating window.
Current mode: 640x480
Setting fancy title, cause we like fancy titles.
Loading tile1-blue.png from file.
Loading tile1-yellow.png from memory.
Going bananas.
Taking a breather.
WOW DID YOU SEE THAT!?
Mucking about with the gamma settings
Done.

@ -1,30 +0,0 @@
#include <iostream>
#include <fstream>
using namespace std;
#include "../servers/sdl_driver.hpp"
using namespace Mangle::Rend2D;
int main()
{
SDLDriver sdl;
sdl.setVideoMode(640,480,0,false);
sdl.setWindowTitle("Testing 123");
Sprite *screen = sdl.getScreen();
const char* imgName = "tile1-blue.png";
Sprite *image = sdl.loadImage(imgName);
for(int frames=0; frames<170; frames++)
{
screen->fill(0);
for(int j=0; j<10; j++)
for(int i=0; i<25; i++)
screen->draw(image, 2*frames+30*j, 20*i);
sdl.update();
sdl.sleep(10);
}
return 0;
}

@ -1,65 +0,0 @@
#include <iostream>
#include <fstream>
using namespace std;
#include "../servers/sdl_driver.hpp"
using namespace Mangle::Rend2D;
int main()
{
cout << "Loading SDL driver.\n";
SDLDriver sdl;
cout << "Creating window.\n";
sdl.setVideoMode(640,480);
cout << "Current mode: " << sdl.width() << "x" << sdl.height() << endl;
cout << "Setting fancy title, cause we like fancy titles.\n";
sdl.setWindowTitle("Chief executive window");
// Display surface
Sprite *screen = sdl.getScreen();
const char* imgName = "tile1-blue.png";
cout << "Loading " << imgName << " from file.\n";
Sprite *image = sdl.loadImage(imgName);
const char* imgName2 = "tile1-yellow.png";
cout << "Loading " << imgName2 << " from memory.\n";
Sprite *image2;
{
// This is hard-coded for file sizes below 500 bytes, so obviously
// you shouldn't mess with the image files.
ifstream file(imgName2, ios::binary);
char buf[500];
file.read(buf, 500);
int size = file.gcount();
image2 = sdl.loadImage(buf, size);
}
cout << "Going bananas.\n";
for(int i=1; i<20; i++)
screen->draw(image, 30*i, 20*i);
cout << "Taking a breather.\n";
sdl.update();
for(int i=1; i<20; i++)
screen->draw(image2, 30*(20-i), 20*i);
sdl.sleep(800);
sdl.update();
cout << "WOW DID YOU SEE THAT!?\n";
sdl.sleep(800);
cout << "Mucking about with the gamma settings\n";
sdl.setGamma(2.0, 0.1, 0.8);
sdl.sleep(100);
sdl.setGamma(0.6, 2.1, 2.1);
sdl.sleep(100);
sdl.setGamma(1.6);
sdl.sleep(100);
cout << "Done.\n";
return 0;
}

@ -1,31 +0,0 @@
#include <iostream>
#include <fstream>
using namespace std;
#include "../servers/sdl_gl_driver.hpp"
using namespace Mangle::Rend2D;
int main()
{
SDLGLDriver sdl;
sdl.setVideoMode(640,480,0,false);
sdl.setWindowTitle("Testing 123");
Sprite *screen = sdl.getScreen();
const char* imgName = "tile1-blue.png";
Sprite *image = sdl.loadImage(imgName);
for(int frames=0; frames<170; frames++)
{
screen->fill(0);
for(int j=0; j<10; j++)
for(int i=0; i<25; i++)
screen->draw(image, 2*frames+30*j, 20*i);
sdl.update();
sdl.sleep(5);
}
return 0;
}

@ -1,18 +0,0 @@
#!/bin/bash
make || exit
mkdir -p output
PROGS=*_test
for a in $PROGS; do
if [ -f "output/$a.out" ]; then
echo "Running $a:"
./$a | diff output/$a.out -
else
echo "Creating $a.out"
./$a > "output/$a.out"
git add "output/$a.out"
fi
done

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

@ -1,16 +0,0 @@
#!/bin/bash
function run()
{
echo "TESTING $1"
cd "$1/tests/"
./test.sh
cd ../../
}
run stream
run vfs
run sound
run input
run rend2d
run .

@ -1 +0,0 @@
*_test

@ -1,14 +0,0 @@
GCC=g++ -I../
all: ogrevfs_audiere_openal_test
I_OGRE=$(shell pkg-config --cflags OGRE)
L_OGRE=$(shell pkg-config --libs OGRE)
L_OPENAL=$(shell pkg-config --libs openal)
L_AUDIERE=-laudiere
ogrevfs_audiere_openal_test: ogrevfs_audiere_openal_test.cpp ../vfs/servers/ogre_vfs.cpp ../sound/sources/audiere_source.cpp ../sound/outputs/openal_out.cpp ../stream/clients/audiere_file.cpp
$(GCC) $^ -o $@ $(I_OGRE) $(L_OGRE) $(L_OPENAL) $(L_AUDIERE)
clean:
rm *_test

@ -1,49 +0,0 @@
/*
This example combines:
- the OGRE VFS system (to read from zip)
- Audiere (for decoding sound data)
- OpenAL (for sound playback)
*/
#include "sound/filters/openal_audiere.hpp"
#include "vfs/servers/ogre_vfs.hpp"
#include <Ogre.h>
#include <iostream>
using namespace Ogre;
using namespace Mangle;
using namespace std;
int main()
{
// Disable Ogre logging
new LogManager;
Log *log = LogManager::getSingleton().createLog("");
log->setDebugOutputEnabled(false);
// Set up Root
Root *root = new Root("","","");
// Add zip file with a sound in it
root->addResourceLocation("sound.zip", "Zip", "General");
// Ogre file system
VFS::OgreVFS vfs;
// The main sound system
Sound::OpenAL_Audiere_Factory mg;
Sound::SoundPtr snd = mg.load(vfs.open("owl.ogg"));
cout << "Playing 'owl.ogg' from 'sound.zip'\n";
snd->play();
while(snd->isPlaying())
{
usleep(10000);
if(mg.needsUpdate) mg.update();
}
return 0;
}

@ -1 +0,0 @@
Playing 'owl.ogg' from 'sound.zip'

Binary file not shown.

@ -1,18 +0,0 @@
#!/bin/bash
make || exit
mkdir -p output
PROGS=*_test
for a in $PROGS; do
if [ -f "output/$a.out" ]; then
echo "Running $a:"
./$a | diff output/$a.out -
else
echo "Creating $a.out"
./$a > "output/$a.out"
git add "output/$a.out"
fi
done

@ -1,3 +0,0 @@
// This file should include whatever it needs to define the boost/tr1
// shared_ptr<> and weak_ptr<> templates.
#include <boost/smart_ptr.hpp>

@ -1,77 +0,0 @@
#include <MyGUI.h>
#include <OIS/OIS.h>
#include <cassert>
#include "events.hpp"
using namespace OIS;
using namespace OEngine::GUI;
EventInjector::EventInjector(MyGUI::Gui *g)
: gui(g), enabled(true)
, mMouseX(0)
, mMouseY(0)
{
assert(gui);
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
mMouseX = viewSize.width/2;
mMouseY = viewSize.height/2;
}
void EventInjector::event(Type type, int index, const void *p)
{
if(!enabled) return;
if(type & EV_Keyboard)
{
KeyEvent *key = (KeyEvent*)p;
MyGUI::KeyCode code = MyGUI::KeyCode::Enum(key->key);
if(type == EV_KeyDown)
{
/*
This is just a first approximation. Apparently, OIS is
unable to provide reliable unicode characters on all
platforms. At least that's what I surmise from the amount
of workaround that the MyGUI folks have put in place for
this. See Common/Input/OIS/InputManager.cpp in the MyGUI
sources for details.
If the work they have done there is indeed necessary (I
haven't tested that it is, although I have had dubious
experinces with OIS events in the past), then we should
probably adapt all that code here. Or even better,
directly into the OIS input manager in Mangle.
Note that all this only affects the 'text' field, and
should thus only affect typed text in input boxes (which
is still pretty significant.)
*/
MyGUI::Char text = (MyGUI::Char)key->text;
MyGUI::InputManager::getInstance().injectKeyPress(code,text);
}
else
{
MyGUI::InputManager::getInstance().injectKeyRelease(code);
}
}
else if(type & EV_Mouse)
{
MouseEvent *mouse = (MouseEvent*)p;
MyGUI::MouseButton id = MyGUI::MouseButton::Enum(index);
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
// Update mouse position
mMouseX += mouse->state.X.rel;
mMouseY += mouse->state.Y.rel;
mMouseX = std::max(0, std::min(mMouseX, viewSize.width));
mMouseY = std::max(0, std::min(mMouseY, viewSize.height));
if(type == EV_MouseDown)
MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, id);
else if(type == EV_MouseUp)
MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, id);
else
MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mouse->state.Z.abs);
}
}

@ -1,32 +0,0 @@
#ifndef OENGINE_MYGUI_EVENTS_H
#define OENGINE_MYGUI_EVENTS_H
#include <mangle/input/event.hpp>
namespace MyGUI
{
class Gui;
}
namespace OEngine {
namespace GUI
{
/** Event handler that injects OIS events into MyGUI
*/
class EventInjector : public Mangle::Input::Event
{
MyGUI::Gui *gui;
int mMouseX;
int mMouseY;
public:
bool enabled;
EventInjector(MyGUI::Gui *g);
void event(Type type, int index, const void *p);
};
typedef boost::shared_ptr<EventInjector> EventInjectorPtr;
}}
#endif

@ -1,57 +0,0 @@
#include "mouselook.hpp"
#include <OIS/OIS.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
using namespace OIS;
using namespace Ogre;
using namespace OEngine::Render;
void MouseLookEvent::event(Type type, int index, const void *p)
{
if(type != EV_MouseMove || camera == NULL) return;
MouseEvent *arg = (MouseEvent*)(p);
float x = arg->state.X.rel * sensX;
float y = arg->state.Y.rel * sensY;
camera->getParentSceneNode()->getParentSceneNode()->yaw(Degree(-x));
camera->getParentSceneNode()->pitch(Degree(-y));
if(flipProt)
{
// The camera before pitching
/*Quaternion nopitch = camera->getParentSceneNode()->getOrientation();
camera->getParentSceneNode()->pitch(Degree(-y));
// Apply some failsafe measures against the camera flipping
// upside down. Is the camera close to pointing straight up or
// down?
if(Ogre::Vector3(camera->getParentSceneNode()->getOrientation()*Ogre::Vector3::UNIT_Y)[1] <= 0.1)
// If so, undo the last pitch
camera->getParentSceneNode()->setOrientation(nopitch);*/
//camera->getU
// Angle of rotation around the X-axis.
float pitchAngle = (2 * Ogre::Degree(Ogre::Math::ACos(camera->getParentSceneNode()->getOrientation().w)).valueDegrees());
// Just to determine the sign of the angle we pick up above, the
// value itself does not interest us.
float pitchAngleSign = camera->getParentSceneNode()->getOrientation().x;
// Limit the pitch between -90 degress and +90 degrees, Quake3-style.
if (pitchAngle > 90.0f)
{
if (pitchAngleSign > 0)
// Set orientation to 90 degrees on X-axis.
camera->getParentSceneNode()->setOrientation(Ogre::Quaternion(Ogre::Math::Sqrt(0.5f),
Ogre::Math::Sqrt(0.5f), 0, 0));
else if (pitchAngleSign < 0)
// Sets orientation to -90 degrees on X-axis.
camera->getParentSceneNode()->setOrientation(Ogre::Quaternion(Ogre::Math::Sqrt(0.5f),
-Ogre::Math::Sqrt(0.5f), 0, 0));
}
}
}

@ -1,56 +0,0 @@
#ifndef OENGINE_OGRE_MOUSELOOK_H
#define OENGINE_OGRE_MOUSELOOK_H
/*
A mouse-look class for Ogre. Accepts input events from Mangle::Input
and translates them.
You can adjust the mouse sensibility and switch to a different
camera. The mouselook class also has an optional wrap protection
that keeps the camera from flipping upside down.
You can disable the mouse looker at any time by calling
setCamera(NULL), and reenable it by setting the camera back.
NOTE: The current implementation will ONLY work for native OIS
events.
*/
#include <mangle/input/event.hpp>
namespace Ogre
{
class Camera;
}
namespace OEngine {
namespace Render
{
class MouseLookEvent : public Mangle::Input::Event
{
Ogre::Camera* camera;
float sensX, sensY; // Mouse sensibility
bool flipProt; // Flip protection
public:
MouseLookEvent(Ogre::Camera *cam=NULL,
float sX=0.2, float sY=0.2,
bool prot=true)
: camera(cam)
, sensX(sX)
, sensY(sY)
, flipProt(prot)
{}
void setCamera(Ogre::Camera *cam)
{ camera = cam; }
void setSens(float sX, float sY)
{ sensX = sX; sensY = sY; }
void setProt(bool p) { flipProt = p; }
void event(Type type, int index, const void *p);
};
typedef boost::shared_ptr<MouseLookEvent> MouseLookEventPtr;
}}
#endif
Loading…
Cancel
Save