Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
force_feedback.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2001-2002 Daniel Horn
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 /*
23  * Force Feedback support by Alexander Rawass <alexannika@users.sourceforge.net>
24  */
25 
26 #include "force_feedback.h"
27 
28 #include "vegastrike.h"
29 #include "vsfilesystem.h"
30 #include "vs_globals.h"
31 
32 #include "config_xml.h"
33 #include "cmd/script/mission.h"
34 #include "options.h"
35 
37 
38 #define FF_DOIT 1
39 
41 {
42 #if HAVE_FORCE_FEEDBACK
43  init();
44 #else
45  have_ff = false;
46  printf( "Force feedback support disabled when compiled\n" );
47 #endif
48 }
49 
51 {
52  if (!have_ff)
53  return;
54 #if HAVE_FORCE_FEEDBACK
55  if (ff_fd != -1) {
56  for (int i = 0; i < N_EFFECTS; i++)
57  stopEffect( i );
58  close( ff_fd );
59  }
60 #endif
61 }
62 
64 {
65  return have_ff;
66 }
67 
68 void ForceFeedback::updateForce( float angle, float strength )
69 {
70  printf( "update force %f degrees %f\n", angle, strength );
71 }
72 
73 void ForceFeedback::updateSpeedEffect( float strength )
74 {
75  printf( "speed effect %f\n", strength );
76 }
77 
78 void ForceFeedback::playHit( float angle, float strength )
79 {
80  printf( "shield hit %f degrees %f\n", angle, strength );
81 }
82 
83 void ForceFeedback::playAfterburner( bool activate )
84 {
85  if (!have_ff)
86  return;
87 #if HAVE_FORCE_FEEDBACK
88  double nowtime = mission->getGametime();
89 
90  int eff_nr = eff_ab_jerk;
91  if (activate == true)
92  eff_last_time[eff_nr] = nowtime;
93  if (activate == true && is_played[eff_nr] == false) {
94  printf( "starting ab\n" );
95  playEffect( eff_ab_wiggle_x );
96  playEffect( eff_ab_wiggle_y );
97  playEffect( eff_ab_jerk );
98 
99  is_played[eff_nr] = true;
100  } else if (activate == false && is_played[eff_nr] == true) {
101  if (nowtime > eff_last_time[eff_nr]+min_effect_time) {
102  printf( "stopped ab\n" );
103  stopEffect( eff_ab_wiggle_x );
104  stopEffect( eff_ab_wiggle_y );
105  stopEffect( eff_ab_jerk );
106 
107  is_played[eff_nr] = false;
108  eff_last_time[eff_nr] = nowtime;
109  }
110  }
111 #endif
112 }
113 
115 {
116  if (!have_ff)
117  return;
118 #if HAVE_FORCE_FEEDBACK
119  int eff_nr = eff_laser_jerk;
120 
121  double nowtime = mission->getGametime();
122  if (nowtime < eff_last_time[eff_nr]+min_effect_time)
123  //to make sure that effects aren't done too fast after another
124  return;
125  playEffect( eff_laser_jerk );
126  playEffect( eff_laser_vibrate );
127 
128  eff_last_time[eff_nr] = nowtime;
129 #endif
130 }
131 
132 void ForceFeedback::playDurationEffect( unsigned int eff_nr, bool activate )
133 {
134  if (!have_ff)
135  return;
136  return;
137 
138 #if HAVE_FORCE_FEEDBACK
139  if (activate == true && is_played[eff_nr] == false) {
140  playEffect( eff_nr );
141  is_played[eff_nr] = true;
142  } else if (activate == false && is_played[eff_nr] == true) {
143  stopEffect( eff_nr );
144  is_played[eff_nr] = false;
145  }
146 #endif
147 }
148 
149 void ForceFeedback::playShortEffect( unsigned int eff_nr )
150 {
151  if (!have_ff)
152  return;
153  return;
154 
155 #if HAVE_FORCE_FEEDBACK
156  double nowtime = mission->getGametime();
157  if (nowtime < eff_last_time[eff_nr]+min_effect_time)
158  //to make sure that effects aren't done too fast after another
159  return;
160  playEffect( eff_nr );
161 
162  eff_last_time[eff_nr] = nowtime;
163 #endif
164 }
165 
166 #if HAVE_FORCE_FEEDBACK
167 
168 void ForceFeedback::playEffect( unsigned int eff_nr )
169 {
170 #if FF_DOIT
171  play.type = EV_FF;
172  play.code = effects[eff_nr].id;
173  play.value = 1;
174  if (write( ff_fd, (const void*) &play, sizeof (play) ) == -1) {
175  perror( "ff: Play effect" );
176  have_ff = false;
177  close( ff_fd );
178  return;
179  }
180 #endif
181 
182  printf( "played effect nr %d\n", eff_nr );
183 }
184 
185 void ForceFeedback::stopEffect( unsigned int eff_nr )
186 {
187 #if FF_DOIT
188  stop.type = EV_FF;
189  stop.code = effects[eff_nr].id;
190  stop.value = 0;
191  if (write( ff_fd, (const void*) &stop, sizeof (stop) ) == -1) {
192  perror( "ff: stop effect" );
193  have_ff = false;
194  close( ff_fd );
195  return;
196  }
197 #endif
198 
199  printf( "stopped effect nr %d\n", eff_nr );
200 }
201 
202 void ForceFeedback::init()
203 {
204  if (!game_options.force_feedback) {
205  printf( "force feedback disabled in config file\n" );
206  return;
207  }
208  char devname[200];
209  sprintf( devname, "/dev/input/event%d", game_options.ff_device );
210 
211  ff_fd = open( devname, O_RDWR );
212  if (ff_fd == -1) {
213  perror( "error while opening force feedback device" );
214  have_ff = false;
215  return;
216  }
217  printf( "Device %s opened\n", devname );
218  /* Query device */
219  if (ioctl( ff_fd, EVIOCGBIT( EV_FF, sizeof (unsigned long)*4 ), features ) == -1) {
220  perror( "ff:Ioctl query" );
221  have_ff = false;
222  close( ff_fd );
223  return;
224  }
225  printf( "Axes query: " );
226  if ( test_bit( ABS_X, features ) ) printf( "Axis X " );
227  if ( test_bit( ABS_Y, features ) ) printf( "Axis Y " );
228  if ( test_bit( ABS_WHEEL, features ) ) printf( "Wheel " );
229  printf( "\nEffects: " );
230  if ( test_bit( FF_CONSTANT, features ) ) printf( "Constant " );
231  if ( test_bit( FF_PERIODIC, features ) ) printf( "Periodic " );
232  if ( test_bit( FF_SPRING, features ) ) printf( "Spring " );
233  if ( test_bit( FF_FRICTION, features ) ) printf( "Friction " );
234  if ( test_bit( FF_RUMBLE, features ) ) printf( "Rumble " );
235  printf( "\nNumber of simultaneous effects: " );
236  if (ioctl( ff_fd, EVIOCGEFFECTS, &n_effects ) == -1) {
237  perror( "Ioctl number of effects" );
238  have_ff = false;
239  close( ff_fd );
240  return;
241  }
242  printf( "nr_effects: %d\n", n_effects );
243  if (n_effects < N_EFFECTS) {
244  printf( "not enough effects in device - ff disabled\n" );
245  close( ff_fd );
246  have_ff = false;
247  return;
248  }
249 #if 0
250  effects[1].type = FF_CONSTANT;
251  effects[1].id = -1;
252  effects[1].u.constant.level = 0x2000; /* Strength : 25 % */
253  effects[1].direction = 0x6000; /* 135 degrees */
254  effects[1].u.constant.envelope.attack_length = 0x100;
255  effects[1].u.constant.envelope.attack_level = 0;
256  effects[1].u.constant.envelope.fade_length = 0x100;
257  effects[1].u.constant.envelope.fade_level = 0;
258  effects[1].trigger.button = 0;
259  effects[1].trigger.interval = 0;
260  effects[1].replay.length = 2000; /* 2 seconds */
261  effects[1].replay.delay = 0;
262 
263  /* download a periodic sinusoidal effect */
264  effects[0].type = FF_PERIODIC;
265  effects[0].id = -1;
266  effects[0].u.periodic.waveform = FF_SINE;
267  effects[0].u.periodic.period = 0.4*0x100; /* 0.1 second */
268  effects[0].u.periodic.magnitude = 0x6000; /* 0.5 * Maximum magnitude */
269  effects[0].u.periodic.offset = 0;
270  effects[0].u.periodic.phase = 0;
271  effects[0].direction = 0x000; /* Along X axis */
272  effects[0].u.periodic.envelope.attack_length = 0x100;
273  effects[0].u.periodic.envelope.attack_level = 0;
274  effects[0].u.periodic.envelope.fade_length = 0x100;
275  effects[0].u.periodic.envelope.fade_level = 0;
276  effects[0].trigger.button = 0;
277  effects[0].trigger.interval = 0;
278  effects[0].replay.length = 500; /* 1 seconds */
279  effects[0].replay.delay = 0;
280 
281  /* download an condition spring effect */
282  effects[2].type = FF_SPRING;
283  effects[2].id = -1;
284  effects[2].u.condition[0].right_saturation = 0x7fff;
285  effects[2].u.condition[0].left_saturation = 0x7fff;
286  effects[2].u.condition[0].right_coeff = 0x2000;
287  effects[2].u.condition[0].left_coeff = 0x2000;
288  effects[2].u.condition[0].deadband = 0x0;
289  effects[2].u.condition[0].center = 0x0;
290  effects[2].u.condition[1] = effects[2].u.condition[0];
291  effects[2].trigger.button = 0;
292  effects[2].trigger.interval = 0;
293  effects[2].replay.length = 0xFFFF;
294  effects[2].replay.delay = 0;
295 
296  /* download an condition damper effect */
297  effects[3].type = FF_DAMPER;
298  effects[3].id = -1;
299  effects[3].u.condition[0].right_saturation = 0x7fff;
300  effects[3].u.condition[0].left_saturation = 0x7fff;
301  effects[3].u.condition[0].right_coeff = 0x2000;
302  effects[3].u.condition[0].left_coeff = 0x2000;
303  effects[3].u.condition[0].deadband = 0x0;
304  effects[3].u.condition[0].center = 0x0;
305  effects[3].u.condition[1] = effects[3].u.condition[0];
306  effects[3].trigger.button = 0;
307  effects[3].trigger.interval = 0;
308  effects[3].replay.length = 2000; /* 2 seconds */
309  effects[3].replay.delay = 0;
310 #endif
311 
312  effects[eff_speed_damper].type = FF_DAMPER;
313  effects[eff_speed_damper].id = -1;
314  effects[eff_speed_damper].u.condition[0].right_saturation = 0x7fff;
315  effects[eff_speed_damper].u.condition[0].left_saturation = 0x7fff;
316  effects[eff_speed_damper].u.condition[0].right_coeff = _is( 3716 );
317  effects[eff_speed_damper].u.condition[0].left_coeff = _is( 3716 );
318  effects[eff_speed_damper].u.condition[0].deadband = 0x0;
319  effects[eff_speed_damper].u.condition[0].center = 0x0;
320  effects[eff_speed_damper].u.condition[1] = effects[eff_speed_damper].u.condition[0];
321  effects[eff_speed_damper].trigger.button = 0;
322  effects[eff_speed_damper].trigger.interval = 0;
323  effects[eff_speed_damper].replay.length = 0xffff;
324  effects[eff_speed_damper].replay.delay = 0;
325 
326  effects[eff_ab_wiggle_x].type = FF_PERIODIC;
327  effects[eff_ab_wiggle_x].id = -1;
328  effects[eff_ab_wiggle_x].u.periodic.waveform = FF_SINE;
329  effects[eff_ab_wiggle_x].u.periodic.period = 0.5*0x100;
330  effects[eff_ab_wiggle_x].u.periodic.magnitude = _is( 2023 );
331  effects[eff_ab_wiggle_x].u.periodic.offset = 0;
332  effects[eff_ab_wiggle_x].u.periodic.phase = 0;
333  effects[eff_ab_wiggle_x].direction = 0x4000;
334  effects[eff_ab_wiggle_x].u.periodic.envelope.attack_length = 2.31*0x100;
335  effects[eff_ab_wiggle_x].u.periodic.envelope.attack_level = 0x7fff;
336  effects[eff_ab_wiggle_x].u.periodic.envelope.fade_length = 0x000;
337  effects[eff_ab_wiggle_x].u.periodic.envelope.fade_level = 0;
338  effects[eff_ab_wiggle_x].trigger.button = 0;
339  effects[eff_ab_wiggle_x].trigger.interval = 0;
340  effects[eff_ab_wiggle_x].replay.length = 0xffff;
341  effects[eff_ab_wiggle_x].replay.delay = 0;
342 
343  effects[eff_ab_wiggle_y].type = FF_PERIODIC;
344  effects[eff_ab_wiggle_y].id = -1;
345  effects[eff_ab_wiggle_y].u.periodic.waveform = FF_SINE;
346  effects[eff_ab_wiggle_y].u.periodic.period = 0.5*0x100;
347  effects[eff_ab_wiggle_y].u.periodic.magnitude = _is( 2023 );
348  effects[eff_ab_wiggle_y].u.periodic.offset = 0;
349  effects[eff_ab_wiggle_y].u.periodic.phase = 0x4000;
350  effects[eff_ab_wiggle_y].direction = 0x0000;
351  effects[eff_ab_wiggle_y].u.periodic.envelope.attack_length = 2.31*0x100;
352  effects[eff_ab_wiggle_y].u.periodic.envelope.attack_level = 0x7fff;
353  effects[eff_ab_wiggle_y].u.periodic.envelope.fade_length = 0x000;
354  effects[eff_ab_wiggle_y].u.periodic.envelope.fade_level = 0;
355  effects[eff_ab_wiggle_y].trigger.button = 0;
356  effects[eff_ab_wiggle_y].trigger.interval = 0;
357  effects[eff_ab_wiggle_y].replay.length = 0xffff;
358  effects[eff_ab_wiggle_y].replay.delay = 0;
359 
360  effects[eff_ab_jerk].type = FF_CONSTANT;
361  effects[eff_ab_jerk].id = -1;
362  effects[eff_ab_jerk].u.constant.level = 0x0;
363  effects[eff_ab_jerk].direction = 0x0000;
364  effects[eff_ab_jerk].u.constant.envelope.attack_length = 0.3*0x100;
365  effects[eff_ab_jerk].u.constant.envelope.attack_level = 0x7fff;
366  effects[eff_ab_jerk].u.constant.envelope.fade_length = 0;
367  effects[eff_ab_jerk].u.constant.envelope.fade_level = 0;
368  effects[eff_ab_jerk].trigger.button = 0;
369  effects[eff_ab_jerk].trigger.interval = 0;
370  effects[eff_ab_jerk].replay.length = 0.3*0x100;
371  effects[eff_ab_jerk].replay.delay = 0;
372 
373  init_bogus( eff_ab_off_x );
374  init_bogus( eff_ab_off_y );
375 #if 0
376  effects[eff_laser_jerk].type = FF_CONSTANT;
377  effects[eff_laser_jerk].id = -1;
378  effects[eff_laser_jerk].u.constant.level = 0x2000;
379  effects[eff_laser_jerk].direction = 0x0000;
380  effects[eff_laser_jerk].u.constant.envelope.attack_length = 0x000;
381  effects[eff_laser_jerk].u.constant.envelope.attack_level = 0;
382  effects[eff_laser_jerk].u.constant.envelope.fade_length = 0x000;
383  effects[eff_laser_jerk].u.constant.envelope.fade_level = 0;
384  effects[eff_laser_jerk].trigger.button = 0;
385  effects[eff_laser_jerk].trigger.interval = 0;
386  effects[eff_laser_jerk].replay.length = 0.2*0x100; /* 2 seconds */
387  effects[eff_laser_jerk].replay.delay = 0;
388 #endif
389 
390  effects[eff_laser_jerk].type = FF_PERIODIC;
391  effects[eff_laser_jerk].id = -1;
392  effects[eff_laser_jerk].u.periodic.waveform = FF_SQUARE;
393  effects[eff_laser_jerk].u.periodic.period = 0.5*0x100;
394  effects[eff_laser_jerk].u.periodic.magnitude = _is( 4573 );
395  effects[eff_laser_jerk].u.periodic.offset = 0;
396  effects[eff_laser_jerk].u.periodic.phase = 0;
397  effects[eff_laser_jerk].direction = 0x0;
398  effects[eff_laser_jerk].u.periodic.envelope.attack_length = 0.043*0x100;
399  effects[eff_laser_jerk].u.periodic.envelope.attack_level = 0x7fff;
400  effects[eff_laser_jerk].u.periodic.envelope.fade_length = 0x000;
401  effects[eff_laser_jerk].u.periodic.envelope.fade_level = 0;
402  effects[eff_laser_jerk].trigger.button = 0;
403  effects[eff_laser_jerk].trigger.interval = 0;
404  effects[eff_laser_jerk].replay.length = 0.2*0x100;
405  effects[eff_laser_jerk].replay.delay = 0;
406 
407  effects[eff_laser_vibrate].type = FF_PERIODIC;
408  effects[eff_laser_vibrate].id = -1;
409  effects[eff_laser_vibrate].u.periodic.waveform = FF_SINE;
410  effects[eff_laser_vibrate].u.periodic.period = 0.5*0x100;
411  effects[eff_laser_vibrate].u.periodic.magnitude = _is( 5023 );
412  effects[eff_laser_vibrate].u.periodic.offset = 0;
413  effects[eff_laser_vibrate].u.periodic.phase = 0;
414  effects[eff_laser_vibrate].direction = 0x4000;
415  effects[eff_laser_vibrate].u.periodic.envelope.attack_length = 0.2*0x100;
416  effects[eff_laser_vibrate].u.periodic.envelope.attack_level = 0x7fff;
417  effects[eff_laser_vibrate].u.periodic.envelope.fade_length = 0x000;
418  effects[eff_laser_vibrate].u.periodic.envelope.fade_level = 0;
419  effects[eff_laser_vibrate].trigger.button = 0;
420  effects[eff_laser_vibrate].trigger.interval = 0;
421  effects[eff_laser_vibrate].replay.length = 0.438*0x100;
422  effects[eff_laser_vibrate].replay.delay = 0;
423 #if ALL_EFFECTS
424  init_bogus( eff_beam_on );
425  init_bogus( eff_beam_off );
426 
427  init_bogus( eff_missile_jerk );
428  init_bogus( eff_missile_vibrate );
429 
430  init_bogus( eff_hit_jerk );
431  init_bogus( eff_hit_vibrate );
432 #endif
433  effects[eff_force].type = FF_CONSTANT;
434  effects[eff_force].id = -1;
435  effects[eff_force].u.constant.level = 0x0; //dynamically
436  effects[eff_force].direction = 0x0; //dynamically
437  effects[eff_force].u.constant.envelope.attack_length = 0x000;
438  effects[eff_force].u.constant.envelope.attack_level = 0;
439  effects[eff_force].u.constant.envelope.fade_length = 0x000;
440  effects[eff_force].u.constant.envelope.fade_level = 0;
441  effects[eff_force].trigger.button = 0;
442  effects[eff_force].trigger.interval = 0;
443  effects[eff_force].replay.length = 0xfff;
444  effects[eff_force].replay.delay = 0;
445  for (int i = 0; i < N_EFFECTS; i++) {
446  printf( "uploading effect %d\n", i );
447  if (ioctl( ff_fd, EVIOCSFF, &effects[i] ) == -1) {
448  perror( "error while uploading effect" );
449  have_ff = false;
450  close( ff_fd );
451  return;
452  }
453  eff_last_time[i] = 0;
454  is_played[i] = false;
455  }
456  min_effect_time = 0.3;
457 
458  playEffect( eff_speed_damper );
459 }
460 
461 void ForceFeedback::init_bogus( int i )
462 {
463  effects[i].type = FF_CONSTANT;
464  effects[i].id = -1;
465  effects[i].u.constant.level = 0x2000; /* Strength : 25 % */
466  effects[i].direction = 0x6000; /* 135 degrees */
467  effects[i].u.constant.envelope.attack_length = 0x100;
468  effects[i].u.constant.envelope.attack_level = 0;
469  effects[i].u.constant.envelope.fade_length = 0x100;
470  effects[i].u.constant.envelope.fade_level = 0;
471  effects[i].trigger.button = 0;
472  effects[i].trigger.interval = 0;
473  effects[i].replay.length = 2000; /* 2 seconds */
474  effects[i].replay.delay = 0;
475 }
476 
477 #endif
478