00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <PVLE/Config.h>
00028 #include <PVLE/Input/Control.h>
00029 #include <PVLE/Util/Singleton.h>
00030 #include <boost/static_assert.hpp>
00031 #include <boost/lexical_cast.hpp>
00032 #include <boost/cast.hpp>
00033
00034 #ifdef PVLE_USE_INTROSPECTION
00035 # include <osgIntrospection/Reflection>
00036 # include <osgIntrospection/Type>
00037 # include <osgDB/DynamicLibrary>
00038 #endif
00039
00040 #include <osg/ref_ptr>
00041
00042
00043
00044 #include <algorithm>
00045
00046 void ControlState::resetAllAxis() { std::fill(pAxis, pAxis+MAX_AXIS, 0.f); }
00047
00048 ControlState::ControlState() : nbSwitchesOn(0) {
00049 resetAllSwitches();
00050 resetAllAxis();
00051 }
00052
00053
00054
00056 const char * switchesNames[] = {
00057 "NONE",
00058 "FORWARD", "BACKWARD", "LEFT", "RIGHT", "STRAFE_LEFT", "STRAFE_RIGHT", "UP", "DOWN",
00059 "ROLL_LEFT", "ROLL_RIGHT",
00060 "JUMP", "CROUCH",
00061 "FAST_TOGGLE", "ALWAYS_FAST",
00062 "FASTER", "SLOWER",
00063 "FIRE1", "FIRE2", "FIRE3", "FIRE4", "FIRE5",
00064 "WEAPON_NEXT", "WEAPON_PREV", "WEAPON_TOGGLE",
00065 "WEAPON1", "WEAPON2", "WEAPON3", "WEAPON4", "WEAPON5", "WEAPON6", "WEAPON7", "WEAPON8", "WEAPON9", "WEAPON10",
00066 "WEAPON11", "WEAPON12", "WEAPON13", "WEAPON14", "WEAPON15", "WEAPON16", "WEAPON17", "WEAPON18", "WEAPON19", "WEAPON20",
00067 "DROP_WEAPON", "DROP_ALTERNATE",
00068 "TARGET", "TARGET_NEXT", "TARGET_PREV", "SHOW_INFO",
00069 "VIEW_NEXT", "VIEW_PREV",
00070 "ZOOM_IN", "ZOOM_OUT",
00071 "VIEW1", "VIEW2", "VIEW3", "VIEW4", "VIEW5", "VIEW6", "VIEW7", "VIEW8", "VIEW9", "VIEW10", "VIEW11", "VIEW12", "VIEW13", "VIEW14", "VIEW15",
00072 "PAUSE",
00073 "SCREENSHOT",
00074 "TOGGLE_FULLSCREEN",
00075 "BRAKE", "RESET",
00076 "MENU", "SCORE_MENU",
00077 "OK", "CANCEL"
00078 };
00079
00080 BOOST_STATIC_ASSERT(sizeof(switchesNames) / sizeof(char *) == ControlState::MAX_STARNDARD_SWITCH);
00081
00082 const char * axisNames[ControlState::MAX_AXIS] = {
00083 "AXIS_X", "AXIS_Y", "AXIS_Z",
00084 "AXIS_SCROLL_1", "AXIS_SCROLL_2", "AXIS_SCROLL_3", "AXIS_SCROLL_4"
00085 };
00086
00087
00088
00089 #ifdef PVLE_NETWORKING
00090
00091 #include <tnl/tnlCertificate.h>
00092 #include <tnl/tnlBitStream.h>
00093 #include <PVLE/Network/PVLEGhostConnection.h>
00094
00095 TNL_IMPLEMENT_NETEVENT(NetControlEvent, TNL::NetClassGroupGameMask, 0);
00096
00097 void NetControlEvent::pack(TNL::EventConnection * pConnection, TNL::BitStream * pStream) {
00098 ASSERT(type < LAST_NETWORK_EVENT);
00099 pStream->writeEnum(type, LAST_NETWORK_EVENT);
00100 if (type == AXIS) {
00101
00102 pStream->writeEnum(data.axisMovement.first, ControlState::MAX_AXIS);
00103 pStream->write(data.axisMovement.second);
00104 } else {
00105
00106 pStream->writeEnum(data.switchId.first, ControlState::MAX_SWITCH);
00107 pStream->write(data.switchId.second);
00108 }
00109 }
00110
00111 void NetControlEvent::unpack(TNL::EventConnection * pConnection, TNL::BitStream * pStream) {
00112 type = static_cast<EEventType>(pStream->readEnum(LAST_NETWORK_EVENT));
00113 if (type == AXIS) {
00114
00115 data.axisMovement.first = static_cast<ControlState::EAxisId>(pStream->readEnum(ControlState::MAX_AXIS));
00116 pStream->read(&data.axisMovement.second);
00117 } else {
00118
00119 data.switchId.first = static_cast<ControlState::ESwitchId>(pStream->readEnum(ControlState::MAX_SWITCH));
00120 pStream->read(&data.switchId.second);
00121 }
00122 }
00123
00124 void NetControlEvent::process(TNL::EventConnection * pConnection) {
00125 boost::polymorphic_downcast<PVLEGhostConnection *>(pConnection)->receiveControlEvent(*this);
00126 }
00127 #endif
00128
00129
00130
00131 const char * const VERSION_TEXT = "Version:";
00132 const char * const SWITCHES_TEXT = "-----Key_bindings-----";
00133 const char * const AXIS_TEXT = "-----Axis_bindings-----";
00134 const UINT BINDINGS_FILE_VERSION = 5;
00135
00136
00137
00138 #include <fstream>
00139
00140
00141 #include <osgGA/GUIEventAdapter>
00142
00143 #ifdef PVLE_USE_INTROSPECTION
00144
00145 class OSGWrapperLoader : public Util::Singleton<OSGWrapperLoader> {
00146 public:
00147 void openLibrary(const std::string& str) { osg::ref_ptr<osgDB::DynamicLibrary> & lib = getPointerForName(str); if (lib.valid()) return; lib = osgDB::DynamicLibrary::loadLibrary(createLibraryNameForWrapper(str)); }
00148 void closeLibrary(const std::string& str) { osg::ref_ptr<osgDB::DynamicLibrary> & lib = getPointerForName(str); if (!lib.valid()) return; lib = NULL; }
00149
00150 protected:
00151 osg::ref_ptr<osgDB::DynamicLibrary> osgLib, osgDBLib, osgFXLib, osgGALib, osgParticleLib, osgProducerLib, osgSimLib, osgTerrainLib, osgTextLib, osgUtilLib;
00152
00153 osg::ref_ptr<osgDB::DynamicLibrary> & getPointerForName(const std::string& str) {
00154 if (str == "osg") return osgLib;
00155 if (str == "osgDB") return osgDBLib;
00156 if (str == "osgFX") return osgFXLib;
00157 if (str == "osgGA") return osgGALib;
00158 if (str == "osgParticle") return osgParticleLib;
00159 if (str == "osgProducer") return osgProducerLib;
00160 if (str == "osgSim") return osgSimLib;
00161 if (str == "osgTerrain") return osgTerrainLib;
00162 if (str == "osgText") return osgTextLib;
00163 if (str == "osgUtil") return osgUtilLib;
00164 THROW_TRACED_EXCEPTION("Unknown library (" + str + ")");
00165 }
00166
00167
00168 static std::string createLibraryNameForWrapper(const std::string& ext) {
00169 #if defined(WIN32)
00170
00171 #ifdef __CYGWIN__
00172 return "cygosgwrapper_"+ext+".dll";
00173 #elif defined(__MINGW32__)
00174 return "libosgwrapper_"+ext+".dll";
00175 #else
00176 #ifdef _DEBUG
00177 return "osgwrapper_"+ext+"d.dll";
00178 #else
00179 return "osgwrapper_"+ext+".dll";
00180 #endif
00181 #endif
00182 #elif macintosh
00183 return "osgwrapper_"+ext;
00184 #elif defined(__hpux__)
00185
00186 return "osgwrapper_"+ext+".sl";
00187 #else
00188 return "osgwrapper_"+ext+".so";
00189 #endif
00190 }
00191 };
00192
00193
00194 typedef osgIntrospection::EnumLabelMap LabelMap;
00195
00197 class KeyMap {
00198 public:
00199 KeyMap() {
00200 try {
00201 OSGWrapperLoader::instance().openLibrary("osgGA");
00202 const osgIntrospection::Type & introKeysEnum = osgIntrospection::Reflection::getType("osgGA::GUIEventAdapter::KeySymbol");
00203 ASSERT(introKeysEnum.isEnum());
00204 map = &introKeysEnum.getEnumLabels();
00205 ASSERT(map);
00206 } catch (osgIntrospection::TypeNotFoundException e) {
00207 OSGWrapperLoader::instance().closeLibrary("osgGA");
00208 THROW_TRACED_EXCEPTION(e.what());
00209 }
00210 }
00211
00212 std::string operator()(int key) const {
00213 osgIntrospection::EnumLabelMap::const_iterator itKey = map->find(key);
00214 if (itKey != map->end()) return itKey->second;
00215 if (key > BUTTON_JOY_MODIFIER) return "JOY_" + boost::lexical_cast<std::string>(key-BUTTON_JOY_MODIFIER);
00216 if (key > BUTTON_MOUSE_MODIFIER) return "MOUSE_" + boost::lexical_cast<std::string>(key-BUTTON_MOUSE_MODIFIER);
00217 if (key >=32 && key<=255) return std::string()+static_cast<char>(key);
00218 LOG_ERROR << "Invalid key number found in bindings (" << key << ")" << std::endl;
00219 return std::string();
00220 }
00221
00222 protected:
00223 friend class InvKeyMap;
00224 const osgIntrospection::EnumLabelMap * map;
00225 };
00226
00228 class InvKeyMap {
00229 public:
00230 InvKeyMap() {
00231
00232 const KeyMap keyMap;
00233 for(osgIntrospection::EnumLabelMap::const_iterator it=keyMap.map->begin(), itEnd=keyMap.map->end(); it!=itEnd; ++it) map.insert(std::pair<std::string, int>(it->second, it->first));
00234 }
00235
00236 int operator()(const std::string & key) const {
00237 std::map<std::string, int>::const_iterator itKey = map.find(key);
00238 if (itKey != map.end()) return itKey->second;
00239 if (key.length() == 1) return key[0];
00240 if (key.substr(0, 4) == "JOY_") {
00241 try {
00242 return BUTTON_JOY_MODIFIER + boost::lexical_cast<int>(key.substr(4, std::string::npos));
00243 } catch (boost::bad_lexical_cast e) {
00244 LOG_ERROR << "Invalid joystick button found in bindings file (" << key << ")" << std::endl;
00245 return 0;
00246 }
00247 }
00248 if (key.substr(0, 6) == "MOUSE_") {
00249 try {
00250 return BUTTON_MOUSE_MODIFIER + boost::lexical_cast<int>(key.substr(6, std::string::npos));
00251 } catch (boost::bad_lexical_cast e) {
00252 LOG_ERROR << "Invalid mouse button found in bindings file (" << key << ")" << std::endl;
00253 return 0;
00254 }
00255 }
00256 LOG_ERROR << "Invalid key found in bindings file (" << key << ")" << std::endl;
00257 return 0;
00258 }
00259
00260 protected:
00261 std::map<std::string, int> map;
00262 };
00263
00264 #else
00265
00267 class KeyMap {
00268 public:
00269 KeyMap() {}
00270 inline std::string operator()(int key) const { return boost::lexical_cast<std::string>(key); }
00271 };
00272
00274 class InvKeyMap {
00275 public:
00276 InvKeyMap() {}
00277 inline int operator()(const std::string & key) const {
00278 try {
00279 return boost::lexical_cast<int>(key);
00280 } catch (boost::bad_lexical_cast e) {
00281 LOG_ERROR << "Invalid binding key (" << key << ")" << std::endl;
00282 return 0;
00283 }
00284 }
00285 };
00286
00287 #endif
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 void saveBindings(const Bindings & k, const AxisBindings & a, const boost::filesystem::path & path, const char ** userSwitchesNames, UINT nbUserSwitchesNames, UINT userBindingsFileVersion) {
00299 DBG_TRY_BLOCK_START
00300 ASSERT(nbUserSwitchesNames <= ControlState::NB_USER_SWITCHES);
00301
00302
00303 const KeyMap keyMap;
00304
00305
00306 std::ofstream ofs(path.native_file_string().c_str());
00307
00308
00309 ofs << VERSION_TEXT << " " << BINDINGS_FILE_VERSION << " " << userBindingsFileVersion << "\n";
00310
00311 ofs << SWITCHES_TEXT << "\n";
00312 const char * switchText;
00313 for(Bindings::const_iterator it=k.begin(), itEnd=k.end(); it!=itEnd; ++it) {
00314 ASSERT(it->second != ControlState::MAX_SWITCH);
00315 if (it->second < ControlState::MAX_STARNDARD_SWITCH) switchText = switchesNames[it->second];
00316 else {
00317 UINT switchTextIndex = it->second - ControlState::USER_SWITCH_0;
00318 ASSERT(userSwitchesNames && switchTextIndex < nbUserSwitchesNames);
00319 switchText = userSwitchesNames[switchTextIndex];
00320 }
00321 std::string keyStr(keyMap(it->first));
00322 if (!keyStr.empty()) ofs << switchText << " " << keyStr << "\n";
00323 }
00324 ofs << AXIS_TEXT << "\n";
00325 for(AxisBindings::const_iterator it=a.begin(), itEnd=a.end(); it!=itEnd; ++it) {
00326 ASSERT(it->second.axisId != ControlState::MAX_AXIS);
00327 ofs << axisNames[it->second.axisId] << " " << it->second.accel << " " << it->second.sensitivity << " " << it->second.deadzone << " ";
00328 if (it->first >= AXIS_JOY_MODIFIER) ofs << "JOY_AXIS_" << (it->first-AXIS_JOY_MODIFIER) << "\n";
00329 else if (it->first >= AXIS_MOUSE_MODIFIER) ofs << "MOUSE_AXIS_" << (it->first-AXIS_MOUSE_MODIFIER) << "\n";
00330 else ofs << "KEYB_AXIS_" << it->first << "\n";
00331 }
00332
00333 #ifdef PVLE_USE_INTROSPECTION
00334 OSGWrapperLoader::instance().closeLibrary("osgGA");
00335 #endif
00336
00337 DBG_TRY_BLOCK_END
00338 }
00339
00340
00341 struct SimpleStrComp {
00342 bool operator()(const char* a, const char* b) const { ASSERT(a && b); return strcmp(a, b) <0; }
00343 };
00344
00345
00346 bool loadBindings(Bindings & k, AxisBindings & a, const boost::filesystem::path & path, const char ** userSwitchesNames, UINT nbUserSwitchesNames, UINT userBindingsFileVersion) {
00347 DBG_TRY_BLOCK_START
00348 ASSERT(nbUserSwitchesNames <= ControlState::NB_USER_SWITCHES);
00349
00350 k.clear();
00351 a.clear();
00352
00353
00354 typedef std::map<const char*, ControlState::ESwitchId, SimpleStrComp> TTextToSwitch;
00355 TTextToSwitch switchesId;
00356 const char ** itName = switchesNames;
00357 for(UINT i=0; i<ControlState::MAX_STARNDARD_SWITCH; ++i, ++itName) switchesId.insert(std::pair<const char*, ControlState::ESwitchId>(*itName, static_cast<ControlState::ESwitchId>(i)));
00358 itName = userSwitchesNames;
00359 for(UINT i=0; i<nbUserSwitchesNames; ++i, ++itName) switchesId.insert(std::pair<const char*, ControlState::ESwitchId>(*itName, static_cast<ControlState::ESwitchId>(ControlState::USER_SWITCH_0 + i)));
00360
00361
00362 typedef std::map<const char*, ControlState::EAxisId, SimpleStrComp> TTextToAxis;
00363 TTextToAxis axisId;
00364 itName = axisNames;
00365 for(UINT i=0; i<ControlState::MAX_AXIS; ++i, ++itName) axisId.insert(std::pair<const char*, ControlState::EAxisId>(*itName, static_cast<ControlState::EAxisId>(i)));
00366
00367
00368 const InvKeyMap ikeyMap;
00369
00370
00371 std::string switchName, keyName;
00372 AxisControl aControl;
00373 TTextToSwitch::const_iterator itSwitch;
00374 TTextToAxis::const_iterator itAxis;
00375
00376
00377 std::ifstream ifs(path.native_file_string().c_str());
00378 std::string read;
00379
00380 UINT version = UINT_MAX;
00381 UINT userVersion = UINT_MAX;
00382 ifs >> read >> version;
00383 ASSERT(read == VERSION_TEXT);
00384
00385 if (version >= 4) ifs >> userVersion;
00386 else userVersion = 0;
00387 if (version != BINDINGS_FILE_VERSION || userVersion != userBindingsFileVersion) {
00388 LOG_ERROR << "Version of bindings file (" << version << "-" << userVersion << ") and executable (" << BINDINGS_FILE_VERSION << "-" << userBindingsFileVersion << ") does not match. Using default parameters." << std::endl;
00389 setDefaultBindings(k, a);
00390 return false;
00391 }
00392
00393 ifs >> read;
00394 ASSERT(read == SWITCHES_TEXT);
00395
00396 ifs >> switchName >> keyName;
00397 std::ifstream::pos_type posSave;
00398 while(switchName != AXIS_TEXT && ifs.good()) {
00399 itSwitch = switchesId.find(switchName.c_str());
00400 if (itSwitch == switchesId.end()) LOG_ERROR << "Invalid control found in key bindings file (" << switchName << ")" << std::endl;
00401 else {
00402
00403 int keyID = ikeyMap(keyName);
00404 if (keyID) k[keyID] = itSwitch->second;
00405 posSave = ifs.tellg();
00406 ifs >> switchName >> keyName;
00407 }
00408 }
00409
00410 ifs.seekg(posSave);
00411
00412 ifs >> read;
00413 ASSERT(read == AXIS_TEXT);
00414
00415
00416 #define axisName switchName
00417 ifs >> axisName >> aControl.accel >> aControl.sensitivity >> aControl.deadzone >> keyName;
00418 while(ifs.good()) {
00419 itAxis = axisId.find(axisName.c_str());
00420 if (itAxis == axisId.end()) LOG_ERROR << "Invalid axis found in key bindings file (" << axisName << ")" << std::endl;
00421
00422 else {
00423 aControl.axisId = itAxis->second;
00424
00425 if (keyName.substr(0, 9) == "JOY_AXIS_") {
00426 try {
00427 a[AXIS_JOY_MODIFIER + boost::lexical_cast<int>(keyName.substr(9, std::string::npos))] = aControl;
00428 } catch (boost::bad_lexical_cast e) { LOG_ERROR << "Invalid joystick axis found in bindings file (" << keyName << ")" << std::endl; }
00429 }
00430 else if (keyName.substr(0, 11) == "MOUSE_AXIS_") {
00431 try {
00432 a[AXIS_MOUSE_MODIFIER + boost::lexical_cast<int>(keyName.substr(11, std::string::npos))] = aControl;
00433 } catch (boost::bad_lexical_cast e) { LOG_ERROR << "Invalid mouse axis found in bindings file (" << keyName << ")" << std::endl; }
00434 }
00435 else if (keyName.substr(0, 10) == "KEYB_AXIS_") {
00436 try {
00437 a[boost::lexical_cast<int>(keyName.substr(10, std::string::npos))] = aControl;
00438 } catch (boost::bad_lexical_cast e) { LOG_ERROR << "Invalid keyboard axis found in bindings file (" << keyName << ")" << std::endl; }
00439 }
00440 else {
00441 LOG_ERROR << "Invalid axis found in bindings file (" << keyName << ")" << std::endl;
00442 }
00443
00444 ifs >> axisName >> aControl.accel >> aControl.sensitivity >> aControl.deadzone >> keyName;
00445 }
00446 }
00447
00448 #ifdef PVLE_USE_INTROSPECTION
00449 OSGWrapperLoader::instance().closeLibrary("osgGA");
00450 #endif
00451
00452 #undef axisName
00453
00454 return true;
00455 DBG_TRY_BLOCK_END
00456 }
00457
00458 void setDefaultBindings(Bindings & k, AxisBindings & a) {
00459
00460 k['z'] = ControlState::FORWARD;
00461 k['s'] = ControlState::BACKWARD;
00462 k['q'] = ControlState::STRAFE_LEFT;
00463 k['d'] = ControlState::STRAFE_RIGHT;
00464 k['o'] = ControlState::LEFT;
00465 k['p'] = ControlState::RIGHT;
00466 k['a'] = ControlState::UP;
00467 k['w'] = ControlState::DOWN;
00468 k['c'] = ControlState::CROUCH;
00469 k['x'] = ControlState::DROP_WEAPON;
00470 k['w'] = ControlState::DROP_ALTERNATE;
00471
00472 k[osgGA::GUIEventAdapter::KEY_Shift_L] = ControlState::FAST_TOGGLE;
00473 k[osgGA::GUIEventAdapter::KEY_Shift_R] = ControlState::FAST_TOGGLE;
00474
00475 k['+'] = ControlState::FASTER;
00476 k['-'] = ControlState::SLOWER;
00477 k[osgGA::GUIEventAdapter::KEY_KP_Add] = ControlState::FASTER;
00478 k[osgGA::GUIEventAdapter::KEY_KP_Subtract] = ControlState::SLOWER;
00479 k[osgGA::GUIEventAdapter::KEY_Page_Up] = ControlState::FASTER;
00480 k[osgGA::GUIEventAdapter::KEY_Page_Down] = ControlState::SLOWER;
00481
00482 k[osgGA::GUIEventAdapter::KEY_Control_L] = ControlState::FIRE1;
00483
00484 k[osgGA::GUIEventAdapter::KEY_Space] = ControlState::BRAKE;
00485 k[osgGA::GUIEventAdapter::KEY_BackSpace] = ControlState::RESET;
00486
00487 k[osgGA::GUIEventAdapter::KEY_F1] = ControlState::MENU;
00488 k[osgGA::GUIEventAdapter::KEY_F2] = ControlState::SCORE_MENU;
00489 k[osgGA::GUIEventAdapter::KEY_Tab] = ControlState::SCORE_MENU;
00490 k[osgGA::GUIEventAdapter::KEY_Delete] = ControlState::CANCEL;
00491 k[osgGA::GUIEventAdapter::KEY_Pause] = ControlState::PAUSE;
00492
00493
00494 k[BUTTON_MOUSE_MODIFIER + osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON] = ControlState::FIRE1;
00495 k[BUTTON_MOUSE_MODIFIER + osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON] = ControlState::JUMP;
00496 k[BUTTON_MOUSE_MODIFIER + osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON] = ControlState::JUMP;
00497
00498
00499
00500
00501
00502 a[AXIS_MOUSE_MODIFIER + 0] = AxisControl(ControlState::AXIS_X, 1.3, 80, 1);
00503 a[AXIS_MOUSE_MODIFIER + 1] = AxisControl(ControlState::AXIS_Y, 1.3, -80, 1);
00504 a[AXIS_MOUSE_MODIFIER + 2] = AxisControl(ControlState::AXIS_SCROLL_1, 1, 1, 0);
00505 a[AXIS_MOUSE_MODIFIER + 3] = AxisControl(ControlState::AXIS_SCROLL_2, 1, 1, 0);
00506
00507
00508 }
00509