Commit 86d6f190 authored by scrawl's avatar scrawl

Input system rewrite

parent 39f87bee
......@@ -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;
......
This diff is collapsed.
......@@ -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
#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);
}
#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
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})
/* -------------------------------------------------------
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);
}
}
}
\ No newline at end of file
/* -------------------------------------------------------
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