annotate native/Falcon/HapticManager.cpp @ 8:ea7885bd9bff tip

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