From 42a826c74592961f2c592c7ba5ab8e8ecfc9c3ec Mon Sep 17 00:00:00 2001 From: Gilles Marckmann <gilles.marckmann@ec-nantes.fr> Date: Fri, 12 Apr 2013 16:01:49 +0000 Subject: [PATCH] Implementation of gamepad for Windows. Now the use of gamepad is available for Linux and Windows. Still to be done for Apple. Very usefull for shell model with compartments (boat, plane, building,...). Allows a good immersion into the model. I advise you to test. Rendering seems to be better on Linux than on Windows: residual offsets on some axes signals are observed which leads to a possible little drifting of the model. Needs to shake joystick. It may come from the gamepad I used which is a old one. --- Common/GamePad.cpp | 459 ++++++++++++++++++++++++----------------- Common/GamePad.h | 122 +++++------ Fltk/Navigator.cpp | 3 +- Fltk/gamepadWindow.cpp | 2 +- 4 files changed, 330 insertions(+), 256 deletions(-) diff --git a/Common/GamePad.cpp b/Common/GamePad.cpp index 2dcf995f7c..c615dc3a1c 100644 --- a/Common/GamePad.cpp +++ b/Common/GamePad.cpp @@ -4,194 +4,275 @@ // bugs and problems to the public mailing list <gmsh@geuz.org>. // // Contributed by Gilles Marckmann <gilles.marckmann@ec-nantes.fr> +// default map is "THRUSTMASTER FireStorm Dual Power"-like +// +// ###### ###### +// # but5 # # but7 # +// .########.. ..#######. +// ............ .......... . +// ...#######... ...########.. +// ..# but4 #... ...# but6 #.. +// ...########....... ........#########.. +// .................... ..................... +// .......#................... .......................... +// ......axis5..........................................####....... +// ........ #...........................................# b3 #....... +// ..........#...........................................# #....... +// ...###< axis4 >###...............................####..####..####... +// ...........#.....................................# b1 #......# b2 #... +// ............#.....................................# #......# #.... +// ............#......................................####........####..... +// .............#.............................................####........... +// ..........................................................# b0 #.......... +// ...........................................................# #........... +// .......................#######................#######.......####............ +// ......................# axis1 ##............## axis3 ##...................... +// .....................## | ##..........## | ##..................... +// ......................#<--axis0-->#..........#<--axis2--> #..................... +// ......................## | ##. .####. .## | ##...................... +// .......................## | ##.. # b9 #...## | ##....................... +// ..........................#######......####......#######......................... +// .................................................................................. +// ..................... .......... ......... ..................... +// .................... .................... +// .................. .................. +// .................. .................. +// .................. ................. +// ................. ................ +// ................ ............... +// .............. .............. +// ............. ............ +// ............ ............ +// .......... .......... +// ....... ........ +// .... ... +// + +#include <cstring> +#include <string> +#include <iostream> +#include <stdio.h> +#include "GamePad.h" +#include "Context.h" +#include <unistd.h> + + +#if defined(WIN32) +#include <math.h> +#endif + +GamePad::GamePad() : active(false), frequency(.01), gamepad_fd(0) { + +#if defined(WIN32) + + for (int i = JOYSTICKID1 ; i < JOYSTICKID2 ; i++) { + if(JOYERR_NOERROR == joyGetDevCaps(i, &caps, sizeof(JOYCAPS)) ) { + /* + std::cout << "Joystick/Gamepad detected: "<< name ; + std::cout << " ( " << (int)caps.wNumAxes <<" axes /" ; + std::cout << (int)caps.wNumButtons <<" buttons)" << std::endl; + std::cout << " Driver name ....... " << caps.szPname << std::endl; + std::cout << " Manufacturer ID ... " << caps.wMid << std::endl; + std::cout << " Product ID ........ " << caps.wPid << std::endl; + std::cout << " RegKey ............ " << caps.szRegKey << std::endl; + std::cout << " OEMVxD ............ " << caps.szOEMVxD << std::endl; + std::cout << " wXmin ............. " << caps.wXmin << std::endl; + std::cout << " wXmax ............. " << caps.wXmax << std::endl; + std::cout << " wYmin ............. " << caps.wYmin << std::endl; + std::cout << " wYmax ............. " << caps.wYmax << std::endl; + std::cout << " wZmin ............. " << caps.wZmin << std::endl; + std::cout << " wZmax ............. " << caps.wZmax << std::endl; + std::cout << " wPeriodMin ........ " << caps.wPeriodMin << std::endl; + std::cout << " wPeriodMax ........ " << caps.wPeriodMax << std::endl; + std::cout << " wRmin ............. " << caps.wRmin << std::endl; + std::cout << " wRmax ............. " << caps.wRmax << std::endl; + std::cout << " wUmin ............. " << caps.wUmin << std::endl; + std::cout << " wUmax ............. " << caps.wUmax << std::endl; + std::cout << " wVmin ............. " << caps.wVmin << std::endl; + std::cout << " wVmax ............. " << caps.wVmax << std::endl; + */ + if(( 1./frequency <(double)caps.wPeriodMin ) ||( 1./frequency >(double)caps.wPeriodMax )){ + frequency=.1/(double)caps.wPeriodMin; + } + gamepad_fd =i; + axes=std::min(GP_AXES,(int)caps.wNumAxes +2); + buttons=std::min(GP_BUTTONS,(int)caps.wNumButtons); + for (int i=0;i<buttons;i++) button[i]=false; + for (int i=0;i<axes;i++) axe[i]=0.; + active = true; + + + } + } + for (int i=0;i<buttons;i++) button[i]=0; + for (int i=0;i<axes;i++) axe[i]=0; + joyGetPosEx( gamepad_fd,&infoex) ; + infoex.dwFlags = JOY_RETURNALL; + +#else +#if defined(__APPLE__) + + // ?? + +#else // LINUX + + gamepad_fd = open(GAMEPAD_DEV, O_RDONLY | O_NONBLOCK); + if (gamepad_fd > 0) { + ioctl(gamepad_fd, JSIOCGNAME(256), name); + ioctl(gamepad_fd, JSIOCGVERSION, &version); + ioctl(gamepad_fd, JSIOCGAXES, &axes); + ioctl(gamepad_fd, JSIOCGBUTTONS, &buttons); + std::cout << "Joystick/Gamepad detected: " << name ; + std::cout << " (version " << version << " / " ; + std::cout << (int)axes <<" axes /" ; + std::cout << (int)buttons <<" buttons)" << std::endl; + active = true; + } +#endif //(__APPLE__) +#endif //(WIN32) + + for (int i=0;i<std::min(9,(int)buttons);i++) button_map[i]=i; + for (int i=0;i<std::min(7,(int)axes);i++) axe_map[i]=i; + axe_map[6]=1; + // another recognized map "Thrustmaster Run'N' Drive Wireless PS3" + // warning :: on Windows we dont have the human-friendly Model Name of the Gamepad + if ( strcmp(name,"Thrustmaster Run'N' Drive Wireless PS3" ) == 0){ + button_map[0]=1; + button_map[1]=0; + button_map[5]=6; + button_map[6]=5; + } +} + + +GamePad::~GamePad() { + active = false; + gamepad_fd = 0; + +#if !defined(WIN32) +#if !defined(__APPLE__) + + close(gamepad_fd); + +#endif //!(__APPLE__) +#endif //!(WIN32) +} + + + +bool GamePad::toggle(const int _nbut) { + bool res; + if( toggle_status[_nbut] ){ res = true; toggle_status[_nbut]=false;} + else { res=false; } + return res; +} + + + +int GamePad::read_event() { + +#if defined(WIN32) + + infoex.dwFlags = JOY_RETURNALL; + joyGetPosEx( gamepad_fd,&infoex) ; + + axe[0]=(double)(( 1.*infoex.dwXpos-32767.)/32767.); + axe[1]=(double)(( 1.*infoex.dwYpos-32767.)/32767.); + axe[2]=(double)(( 1.*infoex.dwRpos-32767.)/32767.); + axe[3]=(double)(( 1.*infoex.dwZpos-32767.)/32767.); + if (infoex.dwPOV < 38000. ) { + double alpha = 3.14159/18000.* infoex.dwPOV; + axe[4]=1.001*sin(alpha); axe[5]=-1.001*cos(alpha); + } + else{ + axe[4]= axe[5]=0.; + } + for (int i=0;i<6;i++) if ( fabs( axe[i]) < .01) axe[i]=0.; + + bool event=false; + int event_num; + bool event_value; + for (int i=0;i<buttons;i++){ + int bin=pow(2,i); + if( button[i] != (bool)(infoex.dwButtons & bin) ) { + event=true; + event_num=i; + event_value=(bool)(infoex.dwButtons & bin); + } + } + if(event){ + if( button[event_num]==0 && event_value ) { toggle_status[event_num]=true; } + button[event_num]= event_value; + } + /* + std::cout<< "--------------------" << std::endl; + std::cout<< infoex.dwXpos << std::endl; + std::cout<< infoex.dwYpos << std::endl; + std::cout<< infoex.dwZpos << std::endl; + std::cout<< infoex.dwRpos << std::endl; + std::cout<< infoex.dwUpos << std::endl; + std::cout<< infoex.dwVpos << std::endl; + std::cout<< infoex.dwButtons << std::endl; + std::cout<< infoex.dwButtonNumber << std::endl; + std::cout<< infoex.dwPOV << std::endl; + */ +#else +#if defined(__APPLE__) + + // ?? + +#else // LINUX + + int result = read(gamepad_fd, &event, sizeof(event)) ; + if (result > 0) { + + switch (event.type) { + case JS_EVENT_INIT: + break; + + case JS_EVENT_INIT | JS_EVENT_AXIS: + break; + + case JS_EVENT_INIT | JS_EVENT_BUTTON: + break; + + case JS_EVENT_AXIS: + axe[(int)event.number]=(double)event.value/32767. ; + break; + + case JS_EVENT_BUTTON: + if(button[(int)event.number]==0. && (bool)event.value) { toggle_status[(int)event.number]=true; } + button[(int)event.number]=(bool)event.value ; + break; + + default: + break; + } + } + +#endif //(__APPLE__) +#endif //(WIN32) + + return 1; +} + + +void GamePad::affiche() { + for (int i=0;i<6;i++) std::cout<<("_________"); + std::cout<<std::endl; std::cout<<" axis "; + for (int i=0;i<6;i++) std::cout<<" | "<<i; + std::cout<<std::endl; std::cout<<" "; + for (int i=0;i<6;i++) std::cout<<" | "<< axe[i] ; + std::cout<<std::endl; + for (int i=0;i<10;i++) std::cout<< ("_____"); + std::cout<<std::endl; std::cout<<" b."; + for (int i=0;i<10;i++) std::cout<<" | "<<i; + std::cout<<std::endl; std::cout<<" "; + for (int i=0;i<10;i++) std::cout<<" | "<<button[i]; + std::cout<<std::endl; + for (int i=0;i<10;i++) std::cout<< ("_____"); + std::cout<<std::endl; + +} -#if defined(WIN32) || defined(__APPLE__) - - - #include <cstring> - #include <string> - #include <iostream> - #include <stdio.h> - #include "GamePad.h" - - GamePad::GamePad() : active(false), frequency(.01), gamepad_fd(0) { - for (int i=0;i<9;i++) button_map[i]=i; - for (int i=0;i<7;i++) axe_map[i]=i; - axe_map[6]=1; - // other recognized map "Thrustmaster Run'N' Drive Wireless PS3" - if ( strcmp(name,"Thrustmaster Run'N' Drive Wireless PS3" ) == 0){ - button_map[0]=1; - button_map[1]=0; - button_map[5]=6; - button_map[6]=5; - } - } - - GamePad::~GamePad() { gamepad_fd = 0;} - - bool GamePad::toggle(const int _nbut) { - bool res; - if( toggle_status[_nbut] ){ res = true; toggle_status[_nbut]=false;} - else { res=false; } - return res; - } - - int GamePad::read_event() { return 1;} - - void GamePad::affiche() {} - - - - -#else // if !win32 => if linux/apple - - #include <cstring> - #include <string> - #include <iostream> - #include <stdio.h> - #include "GamePad.h" - #include "Context.h" - #include <unistd.h> - - GamePad::GamePad() : active(false), frequency(.01), gamepad_fd(0) { - gamepad_fd = open(GAMEPAD_DEV, O_RDONLY | O_NONBLOCK); - if (gamepad_fd > 0) { - ioctl(gamepad_fd, JSIOCGNAME(256), name); - ioctl(gamepad_fd, JSIOCGVERSION, &version); - ioctl(gamepad_fd, JSIOCGAXES, &axes); - ioctl(gamepad_fd, JSIOCGBUTTONS, &buttons); - std::cout << "Joystick/Gamepad detected: " << name ; - std::cout << " (version " << version << " / " ; - std::cout << (int)axes <<" axes /" ; - std::cout << (int)buttons <<" buttons)" << std::endl; - active = true; - } - - // default map is "THRUSTMASTER FireStorm Dual Power"-like - // - // ###### ###### - // # but5 # # but7 # - // .########.. ..#######. - // ............ .......... . - // ...#######... ...########.. - // ..# but4 #... ...# but6 #.. - // ...########....... but9 but10........#########.. - // .................... ..................... - // .......#................... .......................... - // ......axis5..........................................####....... - // ........ #...........................................# b3 #....... - // ..........#...........................................# #....... - // ...###< axis4 >###...............................####..####..####... - // ...........#.....................................# b1 #......# b2 #... - // ............#.....................................# #......# #.... - // ............#......................................####........####..... - // .............#.............................................####........... - // ..........................................................# b0 #.......... - // ...........................................................# #........... - // .......................#######................#######.......####............ - // ......................# axis1 ##............## axis3 ##...................... - // .....................## | ##..........## | ##..................... - // ......................#<--axis0-->#..........#<--axis2--> #..................... - // ......................## | ##. .####. .## | ##...................... - // .......................## | ##.. # b8 #...## | ##....................... - // ..........................#######......####......#######......................... - // .................................................................................. - // ..................... .......... ......... ..................... - // .................... .................... - // .................. .................. - // .................. .................. - // .................. ................. - // ................. ................ - // ................ ............... - // .............. .............. - // ............. ............ - // ............ ............ - // .......... .......... - // ....... ........ - // .... ... - // - - for (int i=0;i<9;i++) button_map[i]=i; - for (int i=0;i<7;i++) axe_map[i]=i; - axe_map[6]=1; - - - // other recognized map "Thrustmaster Run'N' Drive Wireless PS3" - if ( strcmp(name,"Thrustmaster Run'N' Drive Wireless PS3" ) == 0){ - button_map[0]=1; - button_map[1]=0; - button_map[5]=6; - button_map[6]=5; - } - - } - - GamePad::~GamePad() { - if (gamepad_fd > 0) { active = false; close(gamepad_fd); } - gamepad_fd = 0; - } - - bool GamePad::toggle(const int _nbut) { - bool res; - if( toggle_status[_nbut] ){ res = true; toggle_status[_nbut]=false;} - else { res=false; } - return res; - } - - int GamePad::read_event() { - int result = read(gamepad_fd, &event, sizeof(event)) ; - if (result > 0) - { - // time( &rawtime ); - switch (event.type) - { - case JS_EVENT_INIT: - break; - case JS_EVENT_INIT | JS_EVENT_AXIS: - break; - case JS_EVENT_INIT | JS_EVENT_BUTTON: - break; - case JS_EVENT_AXIS: - // std::cout<< "------"<<rawtime<<"---- " <<std::endl; - axe[(int)event.number]=(double)event.value/32767. ; - break; - case JS_EVENT_BUTTON: - // std::cout<< "------"<<rawtime<<"---- " <<std::endl; - if(button[(int)event.number]==0. && (bool)event.value) - { toggle_status[(int)event.number]=true; } - button[(int)event.number]=(bool)event.value ; - - break; - default: - break; - } - } - // std::cout<< "------"<<rawtime<<"---- " <<std::endl; - // else if (event_read){changed=false;} - return 1; - - } - - - void GamePad::affiche() { - // printf ("----------------------------------------------\n"); - for (int i=0;i<axes;i++) printf ("___________"); - printf ("\n"); - for (int i=0;i<axes;i++) printf (" axis %2d |",i); - printf ("\n"); - for (int i=0;i<axes;i++) printf (" %7f |", axe[i] ); - printf ("\n"); - for (int i=0;i<buttons;i++) printf ("_______"); - printf ("\n"); - for (int i=0;i<buttons;i++) printf (" b.%2d |",i); - printf ("\n"); - for (int i=0;i<buttons;i++) printf (" %4d |",button[i]); - printf ("\n"); - for (int i=0;i<buttons;i++) printf ("_______"); - printf ("\n"); - } - - - -#endif // win32 diff --git a/Common/GamePad.h b/Common/GamePad.h index 1b1bfd189b..74ed1ae0dd 100644 --- a/Common/GamePad.h +++ b/Common/GamePad.h @@ -14,70 +14,62 @@ #define GP_AXES 6 - -#if defined(WIN32) || defined(__APPLE__) - - class GamePad { - public: - bool active; - bool toggle_status[GP_BUTTONS]; - bool event_read; - double frequency; - GamePad(); - ~GamePad(); - double axe[GP_AXES]; - bool button[GP_BUTTONS]; - bool toggle(const int _nbut); - int read_event(); - void affiche(); - int button_map[10]; - int axe_map[8]; - private: - int gamepad_fd; - // js_event event; - // __u32 version; - // __u8 axes; - // __u8 buttons; - char name[256]; - }; - - - -#else // !win32 => linux/apple - - - #include <linux/joystick.h> - #include <fcntl.h> - - #define GAMEPAD_DEV "/dev/input/js0" - - class GamePad { - public: - bool active; - bool toggle_status[GP_BUTTONS]; - bool event_read; - double frequency; - GamePad(); - ~GamePad(); - double axe[GP_AXES]; - bool button[GP_BUTTONS]; - bool toggle(const int _nbut); - int read_event(); - void affiche(); - int button_map[10]; - int axe_map[8]; - - - private: - // time_t rawtime; - int gamepad_fd; - js_event event; - __u32 version; - __u8 axes; - __u8 buttons; - char name[256]; - }; - -#endif //win32 +#if defined(WIN32) +#include <windows.h> +#include <mmsystem.h> +#else +#if defined(__APPLE__) +// ?? +#else // LINUX +#include <linux/joystick.h> +#include <fcntl.h> +#define GAMEPAD_DEV "/dev/input/js0" +#endif +#endif + +class GamePad { + public: + bool active; + bool toggle_status[GP_BUTTONS]; + bool event_read; + double frequency; + GamePad(); + ~GamePad(); + double axe[GP_AXES]; + bool button[GP_BUTTONS]; + bool toggle(const int _nbut); + int read_event(); + void affiche(); + int button_map[10]; + int axe_map[8]; + private: + int axe_min[8]; + int axe_max[8]; + int gamepad_fd; + char name[256]; + +#if defined(WIN32) + + JOYCAPS caps; + JOYINFOEX infoex; + JOYINFO info; + int axes; + int buttons; + +#else +#if defined(__APPLE__) + + // ?? + +#else // LINUX + + js_event event; + __u32 version; + __u8 axes; + __u8 buttons; + +#endif +#endif +}; #endif // _GAMEPAD_H_ diff --git a/Fltk/Navigator.cpp b/Fltk/Navigator.cpp index 1f08c869d2..25772b48e2 100644 --- a/Fltk/Navigator.cpp +++ b/Fltk/Navigator.cpp @@ -59,7 +59,7 @@ void Navigator::drawIcons() glPushMatrix(); glLineWidth( (float)CTX::instance()->lineWidth); gl2psLineWidth((float)(CTX::instance()->lineWidth * - CTX::instance()->print.epsLineWidthFactor)); + CTX::instance()->print.epsLineWidthFactor)); glColor4ubv((GLubyte *) & CTX::instance()->color.smallAxes); @@ -601,6 +601,7 @@ void Navigator::drawIcons() glDisable (GL_BLEND); + glDisable (GL_LINE_SMOOTH); glPopMatrix(); } diff --git a/Fltk/gamepadWindow.cpp b/Fltk/gamepadWindow.cpp index cc0f3212be..24d0b45871 100644 --- a/Fltk/gamepadWindow.cpp +++ b/Fltk/gamepadWindow.cpp @@ -43,7 +43,7 @@ static void gamepadWindow_handler(void *data) gamepadWindow* gmpd_win = (gamepadWindow*)data; GamePad* pad = &(CTX::instance()->gamepad); for (int i=0; i<std::min(13,GP_BUTTONS);i++) gmpd_win->gamepad.butt[i]->value(pad->button[i]); - for (int i=0; i<std::min(9,GP_AXES);i++) gmpd_win->gamepad.axe[i]->value(pad->axe[i]); + for (int i=0; i<std::min(9,GP_AXES);i++) gmpd_win->gamepad.axe[i]->value( pad->axe[i] ); Fl::add_timeout(gmpd_win->frequency, gamepadWindow_handler,data); gmpd_win->gamepad.mapping[16]->value(pad->axe_map[1]); } -- GitLab