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
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #ifndef GLH_GLUT_H
00044 #define GLH_GLUT_H
00045
00046
00047
00048 #ifndef _WIN32
00049 #include <string.h>
00050 #endif
00051 #include <algorithm>
00052 #include <list>
00053
00054 #ifdef MACOS
00055 #include <GLUT/glut.h>
00056 #else
00057 #include <GL/glut.h>
00058 #endif
00059
00060 #include <glh/glh_interactors.h>
00061 #include <glh/glh_convenience.h>
00062
00063 namespace glh
00064 {
00065
00066 class glut_interactor
00067 {
00068 public:
00069 glut_interactor() { enabled = true; }
00070
00071 virtual void display() {}
00072 virtual void idle() {}
00073 virtual void keyboard(unsigned char key, int x, int y) {}
00074 virtual void menu_status(int status, int x, int y) {}
00075 virtual void motion(int x, int y) {}
00076 virtual void mouse(int button, int state, int x, int y) {}
00077 virtual void passive_motion(int x, int y) {}
00078 virtual void reshape(int w, int h) {}
00079 virtual void special(int key, int x, int y) {}
00080 virtual void timer(int value) {}
00081 virtual void visibility(int v) {}
00082
00083 virtual void enable() { enabled = true; }
00084 virtual void disable() { enabled = false; }
00085
00086 bool enabled;
00087 };
00088
00089 std::list<glut_interactor *> interactors;
00090 bool propagate;
00091
00092 void glut_display_function()
00093 {
00094 propagate = true;
00095 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00096 (*it)->display();
00097 }
00098
00099 void glut_idle_function()
00100 {
00101 propagate = true;
00102 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00103 (*it)->idle();
00104 }
00105
00106 void glut_keyboard_function(unsigned char k, int x, int y)
00107 {
00108 propagate = true;
00109 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00110 (*it)->keyboard(k, x, y);
00111 }
00112
00113 void glut_menu_status_function(int status, int x, int y)
00114 {
00115 propagate = true;
00116 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00117 (*it)->menu_status(status, x, y);
00118 }
00119
00120 void glut_motion_function(int x, int y)
00121 {
00122 propagate = true;
00123 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00124 (*it)->motion(x, y);
00125 }
00126
00127 void glut_mouse_function(int button, int state, int x, int y)
00128 {
00129 propagate = true;
00130 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00131 (*it)->mouse(button, state, x, y);
00132 }
00133
00134 void glut_passive_motion_function(int x, int y)
00135 {
00136 propagate = true;
00137 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00138 (*it)->passive_motion(x, y);
00139 }
00140
00141 void glut_reshape_function(int w, int h)
00142 {
00143 propagate = true;
00144 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00145 (*it)->reshape(w,h);
00146 }
00147
00148 void glut_special_function(int k, int x, int y)
00149 {
00150 propagate = true;
00151 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00152 (*it)->special(k, x, y);
00153 }
00154
00155 void glut_timer_function(int v)
00156 {
00157 propagate = true;
00158 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00159 (*it)->timer(v);
00160 }
00161
00162 void glut_visibility_function(int v)
00163 {
00164 propagate = true;
00165 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00166 (*it)->visibility(v);
00167 }
00168
00169
00170 inline void glut_event_processed()
00171 {
00172 propagate = false;
00173 }
00174
00175 inline void glut_helpers_initialize()
00176 {
00177 glutDisplayFunc(glut_display_function);
00178 glutIdleFunc(0);
00179 glutKeyboardFunc(glut_keyboard_function);
00180 glutMenuStatusFunc(glut_menu_status_function);
00181 glutMotionFunc(glut_motion_function);
00182 glutMouseFunc(glut_mouse_function);
00183 glutPassiveMotionFunc(glut_passive_motion_function);
00184 glutReshapeFunc(glut_reshape_function);
00185 glutSpecialFunc(glut_special_function);
00186 glutVisibilityFunc(glut_visibility_function);
00187 }
00188
00189 inline void glut_remove_interactor(glut_interactor *gi)
00190 {
00191 if (interactors.empty())
00192 return;
00193 std::list<glut_interactor *>::iterator it =
00194 std::find(interactors.begin(), interactors.end(), gi);
00195 if(it != interactors.end())
00196 interactors.erase(it);
00197 }
00198
00199 inline void glut_add_interactor(glut_interactor *gi, bool append=true)
00200 {
00201 glut_remove_interactor(gi);
00202 if(append)
00203 interactors.push_back(gi);
00204 else
00205 interactors.push_front(gi);
00206 }
00207
00208 inline void glut_timer(int msec, int value)
00209 {
00210 glutTimerFunc(msec, glut_timer_function, value);
00211 }
00212
00213 inline void glut_idle(bool do_idle)
00214 {
00215 glutIdleFunc(do_idle ? glut_idle_function : 0);
00216 }
00217
00218 class glut_callbacks : public glut_interactor
00219 {
00220 public:
00221 glut_callbacks() :
00222 display_function(0),
00223 idle_function(0),
00224 keyboard_function(0),
00225 menu_status_function(0),
00226 motion_function(0),
00227 mouse_function(0),
00228 passive_motion_function(0),
00229 reshape_function(0),
00230 special_function(0),
00231 timer_function(0),
00232 visibility_function()
00233 {}
00234
00235 virtual void display()
00236 { if(display_function) display_function(); }
00237
00238 virtual void idle()
00239 { if(idle_function) idle_function(); }
00240
00241 virtual void keyboard(unsigned char k, int x, int y)
00242 { if(keyboard_function) keyboard_function(k, x, y); }
00243
00244 virtual void menu_status(int status, int x, int y)
00245 { if(menu_status_function) menu_status_function(status, x, y); }
00246
00247 virtual void motion(int x, int y)
00248 { if(motion_function) motion_function(x,y); }
00249
00250 virtual void mouse(int button, int state, int x, int y)
00251 { if(mouse_function) mouse_function(button, state, x, y); }
00252
00253 virtual void passive_motion(int x, int y)
00254 { if(passive_motion_function) passive_motion_function(x, y); }
00255
00256 virtual void reshape(int w, int h)
00257 { if(reshape_function) reshape_function(w, h); }
00258
00259 virtual void special(int key, int x, int y)
00260 { if(special_function) special_function(key, x, y); }
00261
00262 virtual void timer(int value)
00263 { if(timer_function) timer_function(value); }
00264
00265 virtual void visibility(int v)
00266 { if(visibility_function) visibility_function(v); }
00267
00268 void (* display_function) ();
00269 void (* idle_function) ();
00270 void (* keyboard_function) (unsigned char, int, int);
00271 void (* menu_status_function) (int, int, int);
00272 void (* motion_function) (int, int);
00273 void (* mouse_function) (int, int, int, int);
00274 void (* passive_motion_function) (int, int);
00275 void (* reshape_function) (int, int);
00276 void (* special_function) (int, int, int);
00277 void (* timer_function) (int);
00278 void (* visibility_function) (int);
00279
00280 };
00281
00282
00283
00284 class glut_perspective_reshaper : public glut_interactor
00285 {
00286 public:
00287 glut_perspective_reshaper(float infovy = 60.f, float inzNear = .1f, float inzFar = 10.f)
00288 : fovy(infovy), zNear(inzNear), zFar(inzFar), aspect_factor(1) {}
00289
00290 void reshape(int w, int h)
00291 {
00292 width = w; height = h;
00293
00294 if(enabled) apply();
00295 }
00296
00297 void apply()
00298 {
00299 glViewport(0,0,width,height);
00300 glMatrixMode(GL_PROJECTION);
00301 glLoadIdentity();
00302 apply_projection();
00303 glMatrixMode(GL_MODELVIEW);
00304 }
00305
00306 matrix4f get_projection()
00307 {
00308 aspect = aspect_factor * float(width)/float(height);
00309 if ( aspect < 1 )
00310 {
00311
00312
00313 float fovx = fovy;
00314 float real_fov = to_degrees(2 * atan(tan(to_radians(fovx/2))/aspect));
00315 return perspective(real_fov, aspect, zNear, zFar);
00316 }
00317 else
00318 return perspective(fovy, aspect, zNear, zFar);
00319 }
00320
00321 void apply_projection()
00322 {
00323 glMultMatrixf(get_projection().m);
00324 }
00325
00326 matrix4f get_projection_inverse()
00327 {
00328 aspect = aspect_factor * float(width)/float(height);
00329 if ( aspect < 1 )
00330 {
00331
00332
00333 float fovx = fovy;
00334 float real_fov = to_degrees(2 * atan(tan(to_radians(fovx/2))/aspect));
00335 return perspective_inverse(real_fov, aspect, zNear, zFar);
00336 }
00337 else
00338 return perspective_inverse(fovy, aspect, zNear, zFar);
00339 }
00340
00341 void apply_projection_inverse()
00342 {
00343 glMultMatrixf(get_projection_inverse().m);
00344 }
00345
00346 int width, height;
00347 float fovy, aspect, zNear, zFar;
00348 float aspect_factor;
00349 };
00350
00351
00352
00353
00354 class glut_simple_interactor : public glut_interactor
00355 {
00356 public:
00357 glut_simple_interactor()
00358 {
00359 num_modes = 0;
00360 active = false;
00361 width = height = 0;
00362 x0 = y0 = x = y = dx = dy = 0;
00363 }
00364
00365 virtual void mouse(int button, int state, int X, int Y)
00366 {
00367 for(int i=0; i < num_modes; i++)
00368 {
00369 if(enabled && button == cond[i].activate_on && state == GLUT_DOWN &&
00370 (! cond[i].use_modifiers || (cond[i].modifiers == glutGetModifiers())) )
00371 {
00372 mode = i;
00373 active = true;
00374 x = x0 = X;
00375 y = y0 = height - Y;
00376 dx = dy = 0;
00377 break;
00378 }
00379 else if (enabled && button == cond[i].activate_on && state == GLUT_UP)
00380 {
00381 if(dx == 0 && dy == 0)
00382 update();
00383 active = false;
00384 dx = dy = 0;
00385 mode = -1;
00386 break;
00387 }
00388 }
00389 }
00390
00391 virtual void motion(int X, int Y)
00392 {
00393 if(enabled && active)
00394 {
00395 dx = X - x; dy = (height - Y) - y;
00396 x = X; y = height - Y;
00397 update();
00398 }
00399 }
00400
00401 void reshape(int w, int h)
00402 {
00403 width = w; height = h;
00404 }
00405
00406 virtual void apply_transform() = 0;
00407 virtual void apply_inverse_transform() = 0;
00408 virtual matrix4f get_transform() = 0;
00409 virtual matrix4f get_inverse_transform() = 0;
00410
00411 virtual void update() {}
00412
00413 struct activate_condition
00414 {
00415 activate_condition()
00416 {
00417 activate_on = GLUT_LEFT_BUTTON;
00418 use_modifiers = true;
00419 modifiers = 0;
00420 }
00421 int activate_on;
00422 bool use_modifiers;
00423 int modifiers;
00424 };
00425
00426 activate_condition cond[2];
00427 bool active;
00428 int x0, y0;
00429 int x, y;
00430 int dx, dy;
00431 int width, height;
00432 int num_modes;
00433 int mode;
00434 };
00435
00436
00437 class glut_translator : public translator, public glut_simple_interactor
00438 {
00439 public:
00440
00441 void update()
00442 {
00443 if(mode == 0)
00444 pan(dx, dy);
00445 else if(mode == 1)
00446 dolly(-dy);
00447 glutPostRedisplay();
00448 }
00449
00450 void apply_transform()
00451 {
00452
00453 glTranslatef(t[0], t[1], t[2]);
00454 }
00455
00456 void apply_inverse_transform()
00457 {
00458
00459 glTranslatef(-t[0], -t[1], -t[2]);
00460 }
00461
00462 matrix4f get_transform()
00463 {
00464 return translator::get_transform();
00465 }
00466
00467 matrix4f get_inverse_transform()
00468 {
00469 return translator::get_inverse_transform();
00470 }
00471
00472 };
00473
00474
00475 class glut_trackball : public glut_simple_interactor, public trackball
00476 {
00477 public:
00478
00479 void update()
00480 {
00481 radius = width < height ? width : height;
00482 radius /= 2.f;
00483 offset = vec3f(width/2.f, height/2.f, 0);
00484 rotate(x-dx, y-dy, x, y);
00485 glutPostRedisplay();
00486 }
00487
00488 void apply_transform()
00489 {
00490 glTranslatef(centroid[0], centroid[1], centroid[2]);
00491 glh_rotate(r);
00492 glTranslatef(-centroid[0], -centroid[1], -centroid[2]);
00493 }
00494
00495 void apply_inverse_transform()
00496 {
00497 glTranslatef(centroid[0], centroid[1], centroid[2]);
00498 glh_rotate(r.inverse());
00499 glTranslatef(-centroid[0], -centroid[1], -centroid[2]);
00500 }
00501
00502 matrix4f get_transform()
00503 {
00504 return trackball::get_transform();
00505 }
00506
00507 matrix4f get_inverse_transform()
00508 {
00509 return trackball::get_inverse_transform();
00510 }
00511
00512 };
00513
00514 inline void glut_exit_on_escape(unsigned char k, int x = 0, int y = 0)
00515 { if(k==27) exit(0); }
00516
00517 struct glut_simple_mouse_interactor : public glut_interactor
00518 {
00519
00520 public:
00521 glut_simple_mouse_interactor(int num_buttons_to_use=3)
00522 {
00523 configure_buttons(num_buttons_to_use);
00524 camera_mode = false;
00525 }
00526
00527 void enable()
00528 {
00529 trackball.enable();
00530 translator.enable();
00531 }
00532
00533 void disable()
00534 {
00535 trackball.disable();
00536 translator.disable();
00537 }
00538
00539 void set_camera_mode(bool cam)
00540 {
00541 camera_mode = cam;
00542 if(camera_mode)
00543 {
00544 trackball.invert_increment = true;
00545 translator.invert_increment = true;
00546 translator.parent_rotation = & trackball.r;
00547 }
00548 else
00549 {
00550 trackball.invert_increment = false;
00551 translator.invert_increment = false;
00552 if(translator.parent_rotation == &trackball.r) translator.parent_rotation = 0;
00553 }
00554 }
00555 void configure_buttons(int num_buttons_to_use = 3)
00556 {
00557 switch(num_buttons_to_use)
00558 {
00559 case 1:
00560
00561 trackball.num_modes = 1;
00562 trackball.cond[0].activate_on = GLUT_LEFT_BUTTON;
00563 trackball.cond[0].modifiers = 0;
00564 trackball.cond[0].use_modifiers = true;
00565
00566 translator.num_modes = 2;
00567 translator.cond[0].activate_on = GLUT_LEFT_BUTTON;
00568 translator.cond[0].modifiers = GLUT_ACTIVE_SHIFT;
00569 translator.cond[0].use_modifiers = true;
00570 translator.cond[1].activate_on = GLUT_LEFT_BUTTON;
00571 translator.cond[1].modifiers = GLUT_ACTIVE_CTRL;
00572 translator.cond[1].use_modifiers = true;
00573 break;
00574
00575 case 2:
00576
00577 trackball.num_modes = 1;
00578 trackball.cond[0].activate_on = GLUT_LEFT_BUTTON;
00579 trackball.cond[0].modifiers = 0;
00580 trackball.cond[0].use_modifiers = true;
00581
00582 translator.num_modes = 2;
00583 translator.cond[0].activate_on = GLUT_MIDDLE_BUTTON;
00584 translator.cond[0].modifiers = 0;
00585 translator.cond[0].use_modifiers = true;
00586 translator.cond[1].activate_on = GLUT_LEFT_BUTTON;
00587 translator.cond[1].modifiers = GLUT_ACTIVE_CTRL;
00588 translator.cond[1].use_modifiers = true;
00589
00590 break;
00591
00592 case 3:
00593 default:
00594
00595 trackball.num_modes = 1;
00596 trackball.cond[0].activate_on = GLUT_LEFT_BUTTON;
00597 trackball.cond[0].modifiers = 0;
00598 trackball.cond[0].use_modifiers = true;
00599
00600 translator.num_modes = 2;
00601 translator.cond[0].activate_on = GLUT_MIDDLE_BUTTON;
00602 translator.cond[0].modifiers = 0;
00603 translator.cond[0].use_modifiers = true;
00604 translator.cond[1].activate_on = GLUT_RIGHT_BUTTON;
00605 translator.cond[1].modifiers = 0;
00606 translator.cond[1].use_modifiers = true;
00607
00608 break;
00609 }
00610 }
00611
00612 virtual void motion(int x, int y)
00613 {
00614 trackball.motion(x,y);
00615 translator.motion(x,y);
00616 }
00617
00618 virtual void mouse(int button, int state, int x, int y)
00619 {
00620 trackball.mouse(button, state, x, y);
00621 translator.mouse(button, state, x, y);
00622 }
00623
00624 virtual void reshape(int x, int y)
00625 {
00626 trackball.reshape(x,y);
00627 translator.reshape(x,y);
00628 }
00629
00630 void apply_transform()
00631 {
00632 translator.apply_transform();
00633 trackball.apply_transform();
00634 }
00635
00636 void apply_inverse_transform()
00637 {
00638 trackball.apply_inverse_transform();
00639 translator.apply_inverse_transform();
00640 }
00641
00642 matrix4f get_transform()
00643 {
00644 return ( translator.get_transform() *
00645 trackball.get_transform() );
00646 }
00647
00648 matrix4f get_inverse_transform()
00649 {
00650 return ( trackball.get_inverse_transform() *
00651 translator.get_inverse_transform() );
00652 }
00653
00654 void set_parent_rotation(rotationf *rp)
00655 {
00656 trackball.parent_rotation = rp;
00657 translator.parent_rotation = rp;
00658 }
00659
00660 bool camera_mode;
00661 glut_trackball trackball;
00662 glut_translator translator;
00663 };
00664
00665 }
00666
00667 #endif