Finished basic key binding system. Minor other cleanups.

This commit is contained in:
Nicolay Korslund 2010-06-08 13:53:34 +02:00
parent 4fbada8605
commit f3d7f2e25a
23 changed files with 144 additions and 220 deletions

View file

@ -28,13 +28,16 @@ set(OGRE ogre/renderer.cpp)
set(OGRE_HEADER ogre/renderer.hpp)
set(INPUT input/oismanager.cpp)
set(INPUT_HEADER input/oismanager.hpp input/listener.hpp)
set(INPUT_HEADER input/oismanager.hpp input/listener.hpp input/func_binder.hpp input/dispatch_map.hpp input/dispatcher.hpp)
set(GAME game/main.cpp game/esm_store/store.cpp game/cell_store.cpp)
set(GAME_HEADER game/cell_store.hpp game/esm_store/reclists.hpp game/esm_store/store.hpp)
set(GAME game/main.cpp)
set(GAME_HEADER game/mwinput/inputmanager.hpp)
set(GAMEREND game/render/mwscene.cpp game/render/cell.cpp)
set(GAMEREND_HEADER game/render/cell.hpp game/render/mwscene.hpp)
set(ESM_STORE esm_store/store.cpp esm_store/cell_store.cpp)
set(ESM_STORE_HEADER esm_store/cell_store.hpp esm_store/reclists.hpp esm_store/store.hpp)
set(GAMEREND game/mwrender/mwscene.cpp game/mwrender/cell.cpp)
set(GAMEREND_HEADER game/mwrender/cell.hpp game/mwrender/mwscene.hpp)
set(ESM_HEADER esm/defs.hpp esm/loadcell.hpp esm/loadfact.hpp esm/loadltex.hpp
esm/loadskil.hpp
@ -87,7 +90,8 @@ add_executable(openmw
${NIF} ${NIF_HEADER}
${NIFOGRE} ${NIFOGRE_HEADER}
${MANGLE_VFS}
${GAME} ${GAME_HEADER}
${GAME}
${ESM_STORE} ${ESM_STORE_HEADER}
${GAMEREND} ${GAMEREND_HEADER}
${ESM_HEADER})

View file

@ -1,3 +1,7 @@
NOTE: This README is for ardekantur's Mac branch of OpenMW. A README
for the main branch has yet to be written. If you want to submit one,
please send me a message!
OpenMW
======

View file

@ -10,7 +10,7 @@
(looking up references.) Neither of these modules depend on us.
*/
#include "esm_store/store.hpp"
#include "store.hpp"
#include "esm/records.hpp"
#include "mangle/tools/str_exception.hpp"
#include <list>

View file

@ -1,13 +1,13 @@
#include <iostream>
#include "cell_store.hpp"
#include "render/cell.hpp"
#include "render/mwscene.hpp"
#include "esm_store/cell_store.hpp"
#include "bsa/bsa_archive.hpp"
#include "ogre/renderer.hpp"
#include "tools/fileops.hpp"
#include "input/oismanager.hpp"
#include "input/listener.hpp"
#include "mwrender/cell.hpp"
#include "mwrender/mwscene.hpp"
#include "mwinput/inputmanager.hpp"
using namespace std;
@ -44,10 +44,10 @@ void maintest()
cout << "\nSetting up cell rendering\n";
// Sets up camera, scene manager etc
Render::MWScene scene(ogre);
MWRender::MWScene scene(ogre);
// This connects the cell data with the rendering scene.
Render::CellRender rend(cell, scene);
MWRender::CellRender rend(cell, scene);
// Load the cell and insert it into the renderer
rend.show();
@ -55,10 +55,7 @@ void maintest()
cout << "Setting up input system\n";
// Sets up the input system
Input::OISManager input(ogre);
// Add the frame and input listener
Input::ExitListener frame(ogre, input);
MWInput::MWInputManager input(ogre);
cout << "\nStart! Press Q/ESC or close window to exit.\n";

View file

@ -0,0 +1,44 @@
#ifndef _INPUT_MWINPUTMANAGER_H
#define _INPUT_MWINPUTMANAGER_H
#include "input/listener.hpp"
#include "input/dispatcher.hpp"
#include "boost/bind.hpp"
namespace MWInput
{
enum Actions
{
A_Quit, // Exit the program
A_LAST // Marker for the last item
};
// Class that handles all input and key bindings for OpenMW
class MWInputManager
{
Input::Dispatcher disp;
Input::OISManager input;
Input::InputListener listener;
public:
MWInputManager(Render::OgreRenderer &ogre)
: disp(A_LAST),
input(ogre),
listener(ogre, input, disp)
{
using namespace Input;
using namespace OIS;
// Bind MW-specific functions
disp.funcs.bind(A_Quit,
boost::bind(&InputListener::exitNow, &listener),
"Quit program");
// Key bindings
disp.bind(KC_Q, A_Quit);
disp.bind(KC_ESCAPE, A_Quit);
}
};
}
#endif

View file

@ -4,7 +4,7 @@
#include "nifogre/ogre_nif_loader.hpp"
using namespace Render;
using namespace MWRender;
using namespace Ogre;
using namespace ESMS;

View file

@ -1,10 +1,10 @@
#ifndef _GAME_RENDER_CELL_H
#define _GAME_RENDER_CELL_H
#include "../cell_store.hpp"
#include "esm_store/cell_store.hpp"
#include "mwscene.hpp"
namespace Render
namespace MWRender
{
/**
This class is responsible for inserting meshes and other

View file

@ -9,10 +9,10 @@
#include "OgreCamera.h"
#include "OgreTextureManager.h"
using namespace Render;
using namespace MWRender;
using namespace Ogre;
MWScene::MWScene(OgreRenderer &_rend)
MWScene::MWScene(Render::OgreRenderer &_rend)
: rend(_rend)
{
Root *root = rend.getRoot();

View file

@ -11,7 +11,7 @@ namespace Ogre
class SceneNode;
}
namespace Render
namespace MWRender
{
/** Class responsible for Morrowind-specific interfaces to OGRE.
@ -20,7 +20,7 @@ namespace Render
*/
class MWScene
{
OgreRenderer &rend;
Render::OgreRenderer &rend;
Ogre::SceneManager *sceneMgr;
Ogre::Camera *camera;
Ogre::Viewport *vp;
@ -31,7 +31,7 @@ namespace Render
Ogre::SceneNode *mwRoot;
public:
MWScene(OgreRenderer &_rend);
MWScene(Render::OgreRenderer &_rend);
Ogre::SceneNode *getRoot() { return mwRoot; }
Ogre::SceneManager *getMgr() { return sceneMgr; }

View file

@ -48,7 +48,7 @@ struct DispatchMap
}
/// Check if a given input is bound to anything
bool isBound(int in)
bool isBound(int in) const
{
return map.find(in) != map.end();
}
@ -60,10 +60,12 @@ struct DispatchMap
The returned set is only intended for immediate iteration. Do not
store references to it.
*/
const OutList &getList(int in)
const OutList &getList(int in) const
{
assert(isBound(in));
const OutList &out = map[in];
InMap::const_iterator it = map.find(in);
assert(it != map.end());
const OutList &out = it->second;
assert(!out.empty());
return out;
}

44
input/dispatcher.hpp Normal file
View file

@ -0,0 +1,44 @@
#ifndef _INPUT_DISPATCHER_H
#define _INPUT_DISPATCHER_H
#include "dispatch_map.hpp"
#include "func_binder.hpp"
namespace Input {
struct Dispatcher
{
DispatchMap map;
FuncBinder funcs;
/**
Constructor. Takes the number of actions and passes it to
FuncBinder.
*/
Dispatcher(int actions) : funcs(actions) {}
void bind(int in, int out) { map.bind(in, out); }
void unbind(int in, int out) { map.unbind(in, out); }
bool isBound(int in) const { return map.isBound(in); }
/**
Instigate an event. It is translated through the dispatch map and
sent to the function bindings.
*/
typedef DispatchMap::OutList _O;
void event(int index, const void* p=NULL) const
{
// No bindings, nothing happens
if(!isBound(index))
return;
// Get the mapped actions and execute them
const _O &list = map.getList(index);
_O::const_iterator it;
for(it = list.begin(); it != list.end(); it++)
funcs.call(*it, p);
}
};
}
#endif

View file

@ -1,78 +0,0 @@
#ifndef _INPUT_EVENT_DISPATCHER_H
#define _INPUT_EVENT_DISPATCHER_H
#include "dispatch_map.hpp"
#include <boost/function.hpp>
namespace Input {
/**
The EventDispatcher translates an input event (as given by an
identifying index and an optional void pointer) into an output
event function call.
*/
class EventDispatcher
{
DispatchMap map;
/*
The event callback function that is called for all events. The
first parameter is the input event. The second parameter is the
resolved output event. The third is an optional user-defined
parameter passed to call().
*/
typedef boost::function<void(int,int,void*)> EventCallback;
EventCallback callback;
// Carpal-tunnel prevention
typedef DispatchMap::OutList _OL;
public:
/// Create an event binding connection
void bind(int in, int out)
{ map.bind(in,out); }
/// Dissolve an event binding connection
void unbind(int in, int out)
{ map.unbind(in, out); }
/// Check if a given input is bound to anything
bool isBound(int in)
{ return map.isBound(in); }
/// Register the callback you want to use to handle events.
void setCallback(EventCallback cb)
{ callback = cb; }
/**
Instigate an event.
This will look up the input event number (first parameter), and
call the event callback for each output number associated with
(bound to) that input.
The optional second paramter is also passed to the callback.
If no output is bound to the given event number, the callback
is never called.
*/
void call(int event, void *p = NULL)
{
// You have to set the callback before using call().
assert(!callback.empty());
// Not bound? Exit.
if(!isBound(event)) return;
// Dispatch to all events.
const _OL &list = map.getList(event);
for(_OL::const_iterator it = list.begin();
it != list.end(); it++)
callback(event, *it, p);
}
};
}
#endif

View file

@ -22,7 +22,7 @@ namespace Input {
permanent references to it unless you've planning for this on the
calling side as well.
*/
typedef boost::function<void(int,void*)> Action;
typedef boost::function<void(int,const void*)> Action;
/**
The FuncBinder is a simple struct that binds user-defined indices
@ -73,22 +73,22 @@ public:
Call a specific action. Takes an optional parameter that is
passed to the action.
*/
void call(int index, void *p=NULL)
void call(int index, const void *p=NULL) const
{
assert(index >= 0 && index < bindings.size());
FuncBinding &fb = bindings[index];
const FuncBinding &fb = bindings[index];
if(fb.action) fb.action(index, p);
}
/// Check if a given index is bound to anything
bool isBound(int index)
bool isBound(int index) const
{
assert(index >= 0 && index < bindings.size());
return !bindings[index].action.empty();
}
/// Return the name associated with an action (empty if not bound)
const std::string &getName(int index)
const std::string &getName(int index) const
{
assert(index >= 0 && index < bindings.size());
return bindings[index].name;

View file

@ -3,19 +3,21 @@
#include "oismanager.hpp"
#include "ogre/renderer.hpp"
#include "dispatcher.hpp"
#include <OgreFrameListener.h>
#include <OgreRenderWindow.h>
namespace Input
{
struct ExitListener : Ogre::FrameListener,
OIS::KeyListener,
OIS::MouseListener
struct InputListener : Ogre::FrameListener,
OIS::KeyListener,
OIS::MouseListener
{
ExitListener(Render::OgreRenderer &rend,
Input::OISManager &input)
: doExit(false)
InputListener(Render::OgreRenderer &rend,
Input::OISManager &input,
const Input::Dispatcher &_disp)
: doExit(false), disp(_disp)
{
// Set up component pointers
mWindow = rend.getWindow();
@ -45,17 +47,8 @@ namespace Input
bool keyPressed( const OIS::KeyEvent &arg )
{
/*
std::cout << "KeyPressed {" << arg.key
<< ", " << ((OIS::Keyboard*)(arg.device))->getAsString(arg.key)
<< "} || Character (" << (char)arg.text << ")\n";
*/
using namespace OIS;
if(arg.key == KC_Q ||
arg.key == KC_ESCAPE)
exitNow();
// Pass the event to the dispatcher
disp.event(arg.key, &arg);
return true;
}
@ -81,6 +74,7 @@ namespace Input
private:
const Dispatcher &disp;
Ogre::RenderWindow *mWindow;
OIS::Mouse *mMouse;
OIS::Keyboard *mKeyboard;

View file

@ -1,6 +1,6 @@
GCC=g++
all: funcbind_test dispatch_map_test event_dispatcher_test
all: funcbind_test dispatch_map_test
funcbind_test: funcbind_test.cpp ../func_binder.hpp
$(GCC) $< -o $@
@ -8,8 +8,5 @@ funcbind_test: funcbind_test.cpp ../func_binder.hpp
dispatch_map_test: dispatch_map_test.cpp ../dispatch_map.hpp
$(GCC) $< -o $@
event_dispatcher_test: event_dispatcher_test.cpp ../event_dispatcher.hpp
$(GCC) $< -o $@
clean:
rm *_test

View file

@ -1,54 +0,0 @@
#include <iostream>
using namespace std;
#include "../event_dispatcher.hpp"
using namespace Input;
void callback(int in, int out, void *p)
{
cout << " Got event: in=" << in << " out=" << out << endl;
}
EventDispatcher dsp;
void callAll()
{
cout << "\nDuty calls:\n";
for(int i=1; i<5; i++)
{
cout << " Calling event " << i << ":\n";
dsp.call(i);
}
}
int main()
{
cout << "Testing the event dispatcher\n";
dsp.setCallback(&callback);
callAll();
dsp.bind(2,1);
dsp.bind(1,10);
dsp.bind(14,-12);
dsp.bind(2,-137);
callAll();
dsp.unbind(1,8);
dsp.unbind(1,10);
dsp.unbind(2,-137);
dsp.unbind(2,1);
callAll();
dsp.bind(3, 19);
dsp.bind(4, 18);
dsp.bind(4, 18);
callAll();
return 0;
}

View file

@ -3,16 +3,16 @@ using namespace std;
#include "../func_binder.hpp"
void f1(int i, void *p)
void f1(int i, const void *p)
{
cout << " F1 i=" << i << endl;
if(p)
cout << " Got a nice gift: "
<< *((float*)p) << endl;
<< *((const float*)p) << endl;
}
void f2(int i, void *p)
void f2(int i, const void *p)
{
cout << " F2 i=" << i << endl;
}

View file

@ -1,30 +0,0 @@
Testing the event dispatcher
Duty calls:
Calling event 1:
Calling event 2:
Calling event 3:
Calling event 4:
Duty calls:
Calling event 1:
Got event: in=1 out=10
Calling event 2:
Got event: in=2 out=-137
Got event: in=2 out=1
Calling event 3:
Calling event 4:
Duty calls:
Calling event 1:
Calling event 2:
Calling event 3:
Calling event 4:
Duty calls:
Calling event 1:
Calling event 2:
Calling event 3:
Got event: in=3 out=19
Calling event 4:
Got event: in=4 out=18