Input system rewrite
parent
39f87bee0e
commit
86d6f190bf
@ -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
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 +0,0 @@
|
|||||||
*_test
|
|
@ -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…
Reference in New Issue