Mercurial > hg > ccmieditor
comparison native/Falcon/HapticManager.cpp @ 5:d66dd5880081
Added support for Falcon Haptic device and Tablet/Mouse as haptic device
author | Fiore Martin <fiore@eecs.qmul.ac.uk> |
---|---|
date | Tue, 10 Jul 2012 22:39:37 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:2c67ac862920 | 5:d66dd5880081 |
---|---|
1 /* | |
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool | |
3 | |
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) | |
5 | |
6 This program is free software: you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation, either version 3 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 */ | |
19 | |
20 #include "HapticManager.h" | |
21 | |
22 using namespace HAPI; | |
23 | |
24 // Render a sphere using OpenGL calls. | |
25 void drawSphere() { | |
26 GLUquadricObj* pObj = gluNewQuadric(); | |
27 gluSphere(pObj, 0.0010, 10, 10); | |
28 gluDeleteQuadric(pObj ); | |
29 } | |
30 | |
31 HapticManager::HapticManager(CollectionsManager * cManager, | |
32 void (*func)( | |
33 const jchar cmd, | |
34 const jint ID, | |
35 const jdouble startx, | |
36 const jdouble starty, | |
37 const jdouble endx, | |
38 const jdouble endy) | |
39 ) | |
40 : executeCommand(func), cm(cManager), force_effect(0), last_touched_point(NULL), | |
41 last_touched_line(NULL),magnetic_mode(LOOSE), pickup_mode(RELEASED), object_unselected(false), | |
42 magnetic_mode_changed(false), pickedup_point(NULL), pickedup_line(NULL) {} | |
43 | |
44 | |
45 bool HapticManager::init (void){ | |
46 | |
47 hd = new AnyHapticsDevice(); | |
48 | |
49 // The haptics renderer to use. | |
50 hd->setHapticsRenderer( new HAPI::GodObjectRenderer() ); | |
51 | |
52 /* init the device */ | |
53 if(hd->initDevice() != HAPIHapticsDevice::SUCCESS){ | |
54 return false; | |
55 } | |
56 | |
57 /* enable the device ( forces and positions will be updated) */ | |
58 hd->enableDevice(); | |
59 | |
60 return true; | |
61 } | |
62 | |
63 /* draws the visual diagram every time it's called. The haptic diagram is redrawn only if * | |
64 * something has changed in the diagram ( redraw_haptic_scene = true ) as, unlike openGL, * | |
65 * it doesn't need to be drawn at each frame but only once */ | |
66 void HapticManager::drawDiagram(bool redraw_haptics_scene, bool pickup, int _attract_to ){ | |
67 | |
68 /* STOP_ATTRACTION means the object has been reached (or eventually deleted). The attraction * | |
69 * force must therefore be stopped and a redrawing of the haptic forces is necessary */ | |
70 if(attraction_mode == STOP_ATTRACTION){ | |
71 attraction_mode = NO_ATTRACTION; | |
72 attract_to = NO_ID; | |
73 redraw_haptics_scene = true; | |
74 } | |
75 | |
76 /* _attract_to is different from NO_ID there is no attraction going on (attraction_mode = NO_ATTRACTION)* | |
77 * It differs from STOP_ATTRACTION in that the haptic scene doesn't have to be repainted */ | |
78 if(_attract_to != NO_ID){ | |
79 attract_to = _attract_to; | |
80 attraction_mode = ACTIVE; | |
81 redraw_haptics_scene = true; | |
82 } | |
83 | |
84 if(magnetic_mode_changed){ | |
85 redraw_haptics_scene = true; | |
86 magnetic_mode_changed = false; | |
87 } | |
88 | |
89 if(pickup){ | |
90 pickup_mode = START_DRAGGING; | |
91 redraw_haptics_scene = true; | |
92 } | |
93 | |
94 /* wash before use */ | |
95 if(redraw_haptics_scene){ | |
96 point_set.clear(); | |
97 line_set.clear(); | |
98 point_id_map.clear(); | |
99 line_id_map.clear(); | |
100 } | |
101 | |
102 /* --- draw the edges --- */ | |
103 glPushAttrib(GL_ENABLE_BIT); | |
104 glColor3f(1.0f,0.0f,0.0f); // Red | |
105 glLineWidth(2.0); | |
106 glDisable(GL_LIGHTING); | |
107 glEnable(GL_COLOR_MATERIAL); | |
108 int numEdges = cm->getEdgesNum(); | |
109 for ( int i = 0; i < numEdges; i++){ | |
110 /* draw the edge in openGL */ | |
111 CollectionsManager::EdgeData & ed = cm->getEdgeData(i); | |
112 glPushAttrib(GL_ENABLE_BIT); | |
113 glLineStipple(1, ed.stipplePattern); | |
114 glEnable(GL_LINE_STIPPLE); | |
115 glBegin(GL_LINES); | |
116 for(unsigned int j = 0; j < ed.getSize(); j++){ | |
117 for(unsigned int k = j; k < ed.getSize(); k++){ | |
118 if(ed.adjMatrix[j][k]){ | |
119 glVertex3d(ed.x[j]*2,ed.y[j]*GRAPHIC_SCALE,0); | |
120 glVertex3d(ed.x[k]*2,ed.y[k]*GRAPHIC_SCALE,0); | |
121 } | |
122 } | |
123 } | |
124 glEnd(); | |
125 glPopAttrib(); | |
126 /* update haptics edge line set if a change in the collection occurred */ | |
127 if(redraw_haptics_scene){ | |
128 /* build the vector with the edges*/ | |
129 for(unsigned int j = 0; j < ed.getSize(); j++){ | |
130 for(unsigned int k = j; k < ed.getSize(); k++){ | |
131 if(ed.adjMatrix[j][k]){ | |
132 line_set.push_back(Collision::LineSegment ( | |
133 Vec3(ed.x[j],ed.y[j],0), | |
134 Vec3(ed.x[k],ed.y[k],0) | |
135 )); | |
136 } | |
137 } | |
138 } | |
139 | |
140 for(vector< HAPI::Collision::LineSegment>::iterator itr = line_set.begin(); itr != line_set.end(); itr++){ | |
141 line_id_map.insert(pair<Collision::LineSegment*,int>(&(*itr),ed.hapticId)); | |
142 } | |
143 } | |
144 } | |
145 glPopAttrib(); | |
146 | |
147 /* --- draw the nodes --- */ | |
148 int numNodes = cm->getNodesNum(); | |
149 glColor3f(1.0f, 1.0f, 1.0f); // white | |
150 for( int i = 0; i < numNodes; i++){ | |
151 /* draw the nodes in openGL */ | |
152 glPushMatrix(); | |
153 CollectionsManager::NodeData &nd = cm->getNodeData(i); | |
154 glTranslated(nd.x*GRAPHIC_SCALE,nd.y*GRAPHIC_SCALE, 0); | |
155 drawSphere(); | |
156 glPopMatrix(); | |
157 | |
158 /* update haptics node line set if a change in the collection occurred */ | |
159 if(redraw_haptics_scene){ | |
160 point_set.push_back(Vec3(nd.x,nd.y,0)); | |
161 point_id_map.insert(pair<Collision::Point*,int>(&(point_set.back()),nd.hapticId)) ; | |
162 } | |
163 } | |
164 | |
165 /* --- update the haptic force if a change in the collection occurred --- */ | |
166 if(redraw_haptics_scene){ | |
167 /* reset the effects and set up new one, otherwise they would accumulate */ | |
168 hd->clearEffects(); | |
169 /* first lines */ | |
170 if(!line_set.empty()){ | |
171 /* force according to the current attraction_mode */ | |
172 int force_factor = (magnetic_mode == STICKY) ? LINE_FORCE_FACTOR_STICKY : LINE_FORCE_FACTOR_LOOSE; | |
173 /* if the user is dragging or looking for an object, the force * | |
174 * factor is always loose until she drops or find the object */ | |
175 if(pickup_mode == DRAGGING || pickup_mode == START_DRAGGING || attraction_mode == ACTIVE){ | |
176 force_factor = LOOSE; | |
177 } | |
178 | |
179 /* update the force */ | |
180 force_effect.reset( new HapticShapeConstraint(new HapticLineSet( line_set, 0 ),force_factor)); | |
181 hd->addEffect(force_effect.get()); | |
182 | |
183 /* recalculate last_touched_line if it was != NULL as the pointed * | |
184 object is now destroyed after clear() and replaced with a new one */ | |
185 if(last_touched_line != NULL){ | |
186 last_touched_line = NULL; | |
187 vector<Collision::LineSegment>::iterator itr; | |
188 Vec3 closest_point, normal, tex_coord; | |
189 for( itr=line_set.begin(); itr != line_set.end(); itr++ ){ | |
190 itr->closestPoint(proxy_pos,closest_point,normal,tex_coord); | |
191 if(pointsDistance(closest_point,proxy_pos) < LINE_COLLISION_THRESHOLD){ | |
192 last_touched_line = &(*itr); | |
193 break; | |
194 } | |
195 } | |
196 if(last_touched_line == NULL){ | |
197 /* touched line was != NULL and now is NULL. It means it has been deleted * | |
198 * while being touched, therefore an unselect command must be issued */ | |
199 object_unselected = true; | |
200 } | |
201 } | |
202 }else if(last_touched_line != NULL){ | |
203 /* if last_touuched_line was != null it means an edge has been deleted * | |
204 * which was being touched, therefore un unselect command must be issued */ | |
205 object_unselected = true; | |
206 /* if there are no lines there cannot be a last touched one */ | |
207 last_touched_line = NULL; | |
208 } | |
209 | |
210 /* now points */ | |
211 if(!point_set.empty()){ | |
212 /* update the force */ | |
213 force_effect.reset( new HapticShapeConstraint(new HapticPointSet( point_set, 0 ),POINT_FORCE_FACTOR ) ); | |
214 hd->addEffect(force_effect.get()); | |
215 | |
216 /* recalculate lastTouchedNode if it was != NULL as the pointed object is now destroyed after clear() */ | |
217 if(last_touched_point != NULL){ | |
218 last_touched_point = NULL; | |
219 vector<Collision::Point>::iterator itr; | |
220 for(itr=point_set.begin(); itr != point_set.end(); itr++ ){ | |
221 if(pointsDistance(itr->position,proxy_pos) < POINT_COLLISION_THRESHOLD ){ | |
222 last_touched_point = &(*itr); | |
223 break; | |
224 } | |
225 } | |
226 if(last_touched_point == NULL){ | |
227 /* touched point was != NULL and now is NULL. It means it has been deleted * | |
228 * while being touched, therefore an unselect command must be issued */ | |
229 object_unselected = true; | |
230 } | |
231 } | |
232 }else if(last_touched_point != NULL){ | |
233 /* if last_touuched_point was != null it means a node has been deleted * | |
234 * which was being touched, therefore un unselect command must be issued */ | |
235 object_unselected = true; | |
236 /* if there are no points there cannot be a last touched one */ | |
237 last_touched_point = NULL; | |
238 } | |
239 | |
240 if(pickup_mode == START_DRAGGING && attraction_mode == NO_ATTRACTION){ | |
241 force_effect.reset(new HapticSpring(proxy_pos,SPRING_FORCE_FACTOR)); | |
242 hd->addEffect(force_effect.get()); | |
243 /* spring force is initialized not pickup_mode goes to DRAGGING*/ | |
244 pickup_mode = DRAGGING; | |
245 }else if(attraction_mode == ACTIVE){ | |
246 bool found = false; | |
247 /* let's look for the object into the nodes */ | |
248 for(map<HAPI::Collision::Point*,int>::iterator itr = point_id_map.begin();itr != point_id_map.end(); itr++){ | |
249 if( (*itr).second == attract_to ){ | |
250 force_effect.reset(new HapticSpring(((*itr).first)->position,SPRING_FORCE_FACTOR)); | |
251 hd->addEffect(force_effect.get()); | |
252 found = true; | |
253 break; | |
254 } | |
255 } | |
256 /* if not found look into the edges */ | |
257 if(!found){ | |
258 for(map<HAPI::Collision::LineSegment*,int>::iterator itr = line_id_map.begin();itr != line_id_map.end(); itr++){ | |
259 if( (*itr).second == attract_to ){ | |
260 HAPI::Collision::LineSegment* line_ptr = (*itr).first; | |
261 force_effect.reset(new HapticSpring( | |
262 midPoint(line_ptr->start, line_ptr->end), | |
263 SPRING_FORCE_FACTOR)); | |
264 hd->addEffect(force_effect.get()); | |
265 found = true; | |
266 break; | |
267 } | |
268 } | |
269 } | |
270 | |
271 if(!found){ | |
272 /* element has been deleted before user could reach it: go back to normal */ | |
273 attraction_mode = STOP_ATTRACTION; | |
274 } | |
275 | |
276 } | |
277 /* just deallocate the memory for the last force effect */ | |
278 force_effect.reset(); | |
279 /* tranfer all the forces to the device */ | |
280 hd->transferObjects(); | |
281 } | |
282 } | |
283 | |
284 | |
285 void HapticManager::drawCursor(){ | |
286 HAPIHapticsRenderer *hr = hd->getHapticsRenderer(); | |
287 if( hr ) { | |
288 /* save the proxy pos in a global variable */ | |
289 proxy_pos = static_cast< HAPIProxyBasedRenderer * >(hr)->getProxyPosition(); | |
290 | |
291 glPushMatrix(); | |
292 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT); | |
293 glTranslatef( (GLfloat)proxy_pos.x*GRAPHIC_SCALE, | |
294 (GLfloat)proxy_pos.y*GRAPHIC_SCALE, | |
295 (GLfloat)proxy_pos.z ); | |
296 glEnable(GL_COLOR_MATERIAL); | |
297 glColor3f(0.0f, 0.5f, 1.0f);// Blue | |
298 drawSphere(); | |
299 glPopAttrib(); | |
300 glPopMatrix(); | |
301 } | |
302 } | |
303 | |
304 bool HapticManager::checkNodeCollision(){ | |
305 /* if the proxy goes far enough from the last touched node, then * | |
306 * lastTouched node can be set back to NULL */ | |
307 bool do_unselect = false; | |
308 if(last_touched_point != NULL){ | |
309 if(pointsDistance(last_touched_point->position, proxy_pos) > POINT_COLLISION_THRESHOLD){ | |
310 last_touched_point = NULL; | |
311 do_unselect = true; | |
312 } | |
313 } | |
314 | |
315 /* find the closest point among those closer than POINT_COLLISION_THRESHOLD */ | |
316 vector<Collision::Point>::iterator itr; | |
317 HAPI::Collision::Point* found_point = NULL; | |
318 double min_dist = POINT_COLLISION_THRESHOLD; | |
319 double dist; | |
320 for(itr=point_set.begin(); itr != point_set.end(); itr++ ){ | |
321 if((dist = pointsDistance(itr->position,proxy_pos)) < min_dist ){ | |
322 found_point = &(*itr); | |
323 min_dist = dist; | |
324 } | |
325 } | |
326 | |
327 if(found_point != NULL){ | |
328 /* if the last touched point is the same, it means the cursor was * | |
329 * already on it therefore do nothing as the node name is uttered only when * | |
330 * the proxy comes across it and not at each frame (it would make a mess) */ | |
331 if(last_touched_point != found_point){ | |
332 last_touched_point = found_point; | |
333 /* Setting last_touched_line to NULL, means untouching the eventual touching line. * | |
334 * When a node is touched, the connected lines are indeed untouched as only one object * | |
335 * at time can be touching the position proxy */ | |
336 last_touched_line = NULL; | |
337 int point_id = point_id_map[last_touched_point]; | |
338 /* select the node for eventual highlighting int the java tree */ | |
339 executeCommand(SELECT_CMD,point_id,0,0,0,0); | |
340 /* utter the name of the node */ | |
341 executeCommand(SPEAK_NAME_CMD,point_id,0,0,0,0); | |
342 if(attraction_mode == ACTIVE && point_id == attract_to){ | |
343 /* we reached the attracting node, stop the attraction force */ | |
344 attraction_mode = STOP_ATTRACTION; | |
345 } | |
346 } | |
347 return true; | |
348 } | |
349 | |
350 if(do_unselect) | |
351 executeCommand(UNSELECT_CMD,0,0,0,0,0); | |
352 | |
353 return false; | |
354 } | |
355 | |
356 bool HapticManager::checkEdgeCollision(){ | |
357 Vec3 closest_point, normal, tex_coord; | |
358 | |
359 /* id is taken from the last touched line is overwritten. To understand why suppose we have an edge * | |
360 * made of two lines A and B. When going from one line to another we don't have to utter the name (see * | |
361 * comment below. last_touched_line goes from a to NULL before being set to B. If lastTouchedLineId is * | |
362 * calculated before checking for NULL-ness it will become -1 and it won't be useful anymore to avoid * | |
363 * uttering the edge name when going from A to B. In this way instead proxy goes from A to B, the id is * | |
364 * to A's, last_touched_line becomes NULL and then it becomes B, but the name is not uttered because id * | |
365 * is the same. This is a very long comment. I want to finish the line to make it look better. bye bye */ | |
366 int lastTouchedLineId = (last_touched_line == NULL) ? - 1 : line_id_map[last_touched_line]; | |
367 | |
368 bool do_unselect = false; | |
369 /* if the proxy goes far enough from the last touched line, then last_touched_line can be set back to NULL */ | |
370 if(last_touched_line != NULL){ | |
371 last_touched_line->closestPoint(proxy_pos,closest_point,normal,tex_coord); | |
372 if(pointsDistance(closest_point, proxy_pos) > LINE_COLLISION_THRESHOLD){ | |
373 last_touched_line = NULL; | |
374 do_unselect = true; | |
375 } | |
376 } | |
377 | |
378 /* find the closest line to the proxy among those closer than LINE_COLLISION_THRESHOLD */ | |
379 vector<Collision::LineSegment>::iterator itr; | |
380 HAPI::Collision::LineSegment* found_line = NULL; | |
381 double min_dist = LINE_COLLISION_THRESHOLD; | |
382 double dist; | |
383 for( itr=line_set.begin(); itr != line_set.end(); itr++ ){ | |
384 itr->closestPoint(proxy_pos,closest_point,normal,tex_coord); | |
385 if((dist = pointsDistance(closest_point,proxy_pos)) < min_dist){ | |
386 found_line = &(*itr); | |
387 min_dist = dist; | |
388 } | |
389 } | |
390 | |
391 if(found_line != NULL){ | |
392 last_touched_line = found_line; | |
393 /* proxy can touch only one object at time either line or point */ | |
394 last_touched_point = NULL; | |
395 /* An edge can be broken into several lines. Such lines will map to the same edge id * | |
396 * If the proxy detouches from a line but immediately touches another line mapped to * | |
397 * the same id, it just means the proxy is going aling the line and therefore no * | |
398 * name must be uttered again (the name must be uttered when touching an edge and * | |
399 * not when touching each line. We keep track of the last touched id and if it's the * | |
400 * as te new touched line id, then nothing is uttered, for we're on the same edge */ | |
401 if(lastTouchedLineId != line_id_map[last_touched_line]){ | |
402 int line_id = line_id_map[last_touched_line]; | |
403 /* select the node for eventual highlighting int the java tree */ | |
404 executeCommand(SELECT_CMD,line_id,0,0,0,0); | |
405 /* utter the name of the edge */ | |
406 executeCommand(SPEAK_NAME_CMD,line_id,0,0,0,0); | |
407 if(attraction_mode == ACTIVE && line_id == attract_to){ | |
408 /* we reached the attracting node, stop the attraction force */ | |
409 attraction_mode = STOP_ATTRACTION; | |
410 } | |
411 } | |
412 return true; | |
413 } | |
414 | |
415 if(do_unselect){ | |
416 executeCommand(UNSELECT_CMD,0,0,0,0,0); | |
417 } | |
418 | |
419 return false; | |
420 } | |
421 | |
422 bool HapticManager::checkUnselection(void){ | |
423 if(object_unselected){ | |
424 object_unselected = false; | |
425 executeCommand(UNSELECT_CMD,0,0,0,0,0); | |
426 return true; | |
427 } | |
428 return false; | |
429 } | |
430 | |
431 bool HapticManager::checkButtons(void){ | |
432 HAPIInt32 status = hd->getButtonStatus(); | |
433 /* handle the buttons. Buttons can be pressed one at time. If a button is pressed all the * | |
434 * other buttons (either when pressed or released) are ignored untill the button is released */ | |
435 if(pressed_button == NO_BUTTON){ | |
436 if(status & FRONT_BUTTON){ | |
437 /* front button pressed, change how magnetic the lines are */ | |
438 pressed_button = FRONT_BUTTON; | |
439 /* switch from sticky to loose and vice versa */ | |
440 magnetic_mode = (magnetic_mode == STICKY) ? LOOSE : STICKY; | |
441 magnetic_mode_changed = true; | |
442 /* make a sound according to the new attraction mode */ | |
443 executeCommand(PLAY_SOUND_CMD, (magnetic_mode == STICKY) ? STICKY_MODE_SOUND : LOOSE_MODE_SOUND ,0,0,0,0); | |
444 return true; | |
445 }else if(status & REAR_BUTTON){ | |
446 pressed_button = REAR_BUTTON; | |
447 /* rear button pressed: First time it picks up an object, second time it drops it */ | |
448 if(pickup_mode == RELEASED){ // pickup mode was released, then now user picked up an object | |
449 if(last_touched_point != NULL){ | |
450 pickedup_point = last_touched_point; | |
451 last_dragging_pos = pickedup_point->position; // last_dragging_pos used in checkMotion | |
452 /* send a pickup command to the Java thread which will in turn issue another pickup * | |
453 * command to this thread (pickup = true in drawDiagram) if the lock could be granted */ | |
454 executeCommand(PICKUP_CMD,point_id_map[last_touched_point],0,0,0,0); | |
455 }else if(last_touched_line != NULL){ | |
456 pickedup_line = last_touched_line; | |
457 pickup_line_pos = proxy_pos; // the point where the line was picked up | |
458 last_dragging_pos = proxy_pos;// last_dragging_pos used in checkMotion | |
459 executeCommand(PICKUP_CMD,line_id_map[last_touched_line],0,0,0,0); | |
460 }/* else user picked up thin air. Do nothing. */ | |
461 }else if(pickup_mode == DRAGGING){ // pickup mode was dragging, then now user dropped an object | |
462 pickup_mode = RELEASED; | |
463 Vec3 & new_position = hapticToScreenSpace(Vec3(proxy_pos), | |
464 cm->getScreenWidth(), | |
465 cm->getScreenHeight()); | |
466 if(pickedup_point){ | |
467 executeCommand(MOVE_CMD,point_id_map[pickedup_point],new_position.x,new_position.y,0,0); | |
468 pickedup_point = NULL; | |
469 }else{ | |
470 hapticToScreenSpace(pickup_line_pos, | |
471 cm->getScreenWidth(), | |
472 cm->getScreenHeight()); | |
473 executeCommand(MOVE_CMD, | |
474 line_id_map[pickedup_line], | |
475 new_position.x, | |
476 new_position.y, | |
477 pickup_line_pos.x, | |
478 pickup_line_pos.y); | |
479 pickedup_line = NULL; | |
480 } | |
481 return true; | |
482 } | |
483 } else if(status & ( LEFT_BUTTON | RIGHT_BUTTON )){ // either left or right button pressed | |
484 pressed_button = (status == LEFT_BUTTON) ? LEFT_BUTTON : RIGHT_BUTTON; | |
485 if(last_touched_point != NULL){ // priority to nodes | |
486 executeCommand(SPEAK_INFO_CMD,point_id_map[last_touched_point], 0,0,0,0); | |
487 return true; | |
488 } | |
489 if(last_touched_line != NULL){ | |
490 executeCommand(SPEAK_INFO_CMD,line_id_map[last_touched_line], 0,0,0,0); | |
491 return true; | |
492 } | |
493 } | |
494 } else if ( /* deactivate the buttons */ | |
495 (pressed_button == FRONT_BUTTON && !(status & FRONT_BUTTON)) || | |
496 (pressed_button == REAR_BUTTON && !(status & REAR_BUTTON)) || | |
497 (pressed_button == LEFT_BUTTON && !(status & LEFT_BUTTON)) || | |
498 (pressed_button == RIGHT_BUTTON && !(status & RIGHT_BUTTON))) | |
499 { | |
500 pressed_button = NO_BUTTON; | |
501 } | |
502 return false; | |
503 } | |
504 | |
505 bool HapticManager::checkMotion(void){ | |
506 if(pickup_mode != DRAGGING) | |
507 return false; | |
508 if(pointsDistance(proxy_pos,last_dragging_pos) > DRAGGING_SOUND_THRESHOLD){ | |
509 last_dragging_pos = proxy_pos; | |
510 executeCommand(PLAY_SOUND_CMD,DRAGGING_SOUND,0,0,0,0); | |
511 return true; | |
512 } | |
513 return false; | |
514 } | |
515 | |
516 void HapticManager::dispose(void){ | |
517 hd->releaseDevice(); | |
518 delete hd; | |
519 } | |
520 | |
521 | |
522 /* static constants initialization */ | |
523 const int HapticManager::NO_ID = 0; | |
524 | |
525 const int HapticManager::GRAPHIC_SCALE = 2; | |
526 const int HapticManager::SPRING_FORCE_FACTOR = 200; | |
527 const int HapticManager::LINE_FORCE_FACTOR_STICKY = 2000; | |
528 const int HapticManager::LINE_FORCE_FACTOR_LOOSE = 100; | |
529 const int HapticManager::POINT_FORCE_FACTOR = 20; | |
530 const double HapticManager::POINT_COLLISION_THRESHOLD = 0.0025; | |
531 const double HapticManager::LINE_COLLISION_THRESHOLD = 0.0025; | |
532 const double HapticManager::DRAGGING_SOUND_THRESHOLD = 0.01; | |
533 | |
534 const int HapticManager::LOOSE_MODE_SOUND = 0; | |
535 const int HapticManager::STICKY_MODE_SOUND = 1; | |
536 const int HapticManager::DRAGGING_SOUND = 3; | |
537 | |
538 const char HapticManager::MOVE_CMD = 'm'; | |
539 const char HapticManager::PLAY_SOUND_CMD = 'g'; | |
540 const char HapticManager::SPEAK_NAME_CMD = 't'; | |
541 const char HapticManager::PICKUP_CMD = 'c'; | |
542 const char HapticManager::SPEAK_INFO_CMD = 'i'; | |
543 const char HapticManager::SELECT_CMD = 's'; | |
544 const char HapticManager::UNSELECT_CMD = 'u'; | |
545 | |
546 const HAPIInt32 HapticManager::FRONT_BUTTON = (1 << 2); | |
547 const HAPIInt32 HapticManager::LEFT_BUTTON = (1 << 1); | |
548 const HAPIInt32 HapticManager::RIGHT_BUTTON = (1 << 3); | |
549 const HAPIInt32 HapticManager::REAR_BUTTON = (1 << 0); | |
550 const HAPIInt32 HapticManager::NO_BUTTON = 0; |