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
00049 #ifdef MACOS
00050 #include <GLUT/glut.h>
00051 #else
00052 #include <GL/glut.h>
00053 #endif
00054
00055 #include <glh/glh_convenience.h>
00056 #include <algorithm>
00057 #include <list>
00058
00059 namespace glh
00060 {
00061
00062 class glut_interactor
00063 {
00064 public:
00065 glut_interactor() { enabled = true; }
00066
00067 virtual void display() {}
00068 virtual void idle() {}
00069 virtual void keyboard(unsigned char key, int x, int y) {}
00070 virtual void menu_status(int status, int x, int y) {}
00071 virtual void motion(int x, int y) {}
00072 virtual void mouse(int button, int state, int x, int y) {}
00073 virtual void passive_motion(int x, int y) {}
00074 virtual void reshape(int w, int h) {}
00075 virtual void special(int key, int x, int y) {}
00076 virtual void timer(int value) {}
00077 virtual void visibility(int v) {}
00078
00079 virtual void enable() { enabled = true; }
00080 virtual void disable() { enabled = false; }
00081
00082 bool enabled;
00083 };
00084
00085 std::list<glut_interactor *> interactors;
00086 bool propagate;
00087
00088 void glut_display_function()
00089 {
00090 propagate = true;
00091 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00092 (*it)->display();
00093 }
00094
00095 void glut_idle_function()
00096 {
00097 propagate = true;
00098 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00099 (*it)->idle();
00100 }
00101
00102 void glut_keyboard_function(unsigned char k, int x, int y)
00103 {
00104 propagate = true;
00105 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00106 (*it)->keyboard(k, x, y);
00107 }
00108
00109 void glut_menu_status_function(int status, int x, int y)
00110 {
00111 propagate = true;
00112 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00113 (*it)->menu_status(status, x, y);
00114 }
00115
00116 void glut_motion_function(int x, int y)
00117 {
00118 propagate = true;
00119 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00120 (*it)->motion(x, y);
00121 }
00122
00123 void glut_mouse_function(int button, int state, int x, int y)
00124 {
00125 propagate = true;
00126 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00127 (*it)->mouse(button, state, x, y);
00128 }
00129
00130 void glut_passive_motion_function(int x, int y)
00131 {
00132 propagate = true;
00133 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00134 (*it)->passive_motion(x, y);
00135 }
00136
00137 void glut_reshape_function(int w, int h)
00138 {
00139 propagate = true;
00140 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00141 (*it)->reshape(w,h);
00142 }
00143
00144 void glut_special_function(int k, int x, int y)
00145 {
00146 propagate = true;
00147 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00148 (*it)->special(k, x, y);
00149 }
00150
00151 void glut_timer_function(int v)
00152 {
00153 propagate = true;
00154 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00155 (*it)->timer(v);
00156 }
00157
00158 void glut_visibility_function(int v)
00159 {
00160 propagate = true;
00161 for(std::list<glut_interactor *>::iterator it=interactors.begin(); it != interactors.end() && propagate; it++)
00162 (*it)->visibility(v);
00163 }
00164
00165
00166 inline void glut_event_processed()
00167 {
00168 propagate = false;
00169 }
00170
00171 inline void glut_helpers_initialize()
00172 {
00173 glutDisplayFunc(glut_display_function);
00174 glutIdleFunc(0);
00175 glutKeyboardFunc(glut_keyboard_function);
00176 glutMenuStatusFunc(glut_menu_status_function);
00177 glutMotionFunc(glut_motion_function);
00178 glutMouseFunc(glut_mouse_function);
00179 glutPassiveMotionFunc(glut_passive_motion_function);
00180 glutReshapeFunc(glut_reshape_function);
00181 glutSpecialFunc(glut_special_function);
00182 glutVisibilityFunc(glut_visibility_function);
00183 }
00184
00185 inline void glut_remove_interactor(glut_interactor *gi)
00186 {
00187 std::list<glut_interactor *>::iterator it =
00188 std::find(interactors.begin(), interactors.end(), gi);
00189 if(it != interactors.end())
00190 interactors.erase(it);
00191 }
00192
00193 inline void glut_add_interactor(glut_interactor *gi, bool append=true)
00194 {
00195 glut_remove_interactor(gi);
00196 if(append)
00197 interactors.push_back(gi);
00198 else
00199 interactors.push_front(gi);
00200 }
00201
00202 inline void glut_timer(int msec, int value)
00203 {
00204 glutTimerFunc(msec, glut_timer_function, value);
00205 }
00206
00207 inline void glut_idle(bool do_idle)
00208 {
00209 glutIdleFunc(do_idle ? glut_idle_function : 0);
00210 }
00211
00212 class glut_callbacks : public glut_interactor
00213 {
00214 public:
00215 glut_callbacks() :
00216 display_function(0),
00217 idle_function(0),
00218 keyboard_function(0),
00219 menu_status_function(0),
00220 motion_function(0),
00221 mouse_function(0),
00222 passive_motion_function(0),
00223 reshape_function(0),
00224 special_function(0),
00225 timer_function(0),
00226 visibility_function()
00227 {}
00228
00229 virtual void display()
00230 { if(display_function) display_function(); }
00231
00232 virtual void idle()
00233 { if(idle_function) idle_function(); }
00234
00235 virtual void keyboard(unsigned char k, int x, int y)
00236 { if(keyboard_function) keyboard_function(k, x, y); }
00237
00238 virtual void menu_status(int status, int x, int y)
00239 { if(menu_status_function) menu_status_function(status, x, y); }
00240
00241 virtual void motion(int x, int y)
00242 { if(motion_function) motion_function(x,y); }
00243
00244 virtual void mouse(int button, int state, int x, int y)
00245 { if(mouse_function) mouse_function(button, state, x, y); }
00246
00247 virtual void passive_motion(int x, int y)
00248 { if(passive_motion_function) passive_motion_function(x, y); }
00249
00250 virtual void reshape(int w, int h)
00251 { if(reshape_function) reshape_function(w, h); }
00252
00253 virtual void special(int key, int x, int y)
00254 { if(special_function) special_function(key, x, y); }
00255
00256 virtual void timer(int value)
00257 { if(timer_function) timer_function(value); }
00258
00259 virtual void visibility(int v)
00260 { if(visibility_function) visibility_function(v); }
00261
00262 void (* display_function) ();
00263 void (* idle_function) ();
00264 void (* keyboard_function) (unsigned char, int, int);
00265 void (* menu_status_function) (int, int, int);
00266 void (* motion_function) (int, int);
00267 void (* mouse_function) (int, int, int, int);
00268 void (* passive_motion_function) (int, int);
00269 void (* reshape_function) (int, int);
00270 void (* special_function) (int, int, int);
00271 void (* timer_function) (int);
00272 void (* visibility_function) (int);
00273
00274 };
00275
00276
00277
00278 class glut_perspective_reshaper : public glut_interactor
00279 {
00280 public:
00281 glut_perspective_reshaper(float infovy = 60.f, float inzNear = .1f, float inzFar = 10.f)
00282 : fovy(infovy), zNear(inzNear), zFar(inzFar), aspect_factor(1) {}
00283
00284 void reshape(int w, int h)
00285 {
00286 width = w; height = h;
00287
00288 if(enabled) apply();
00289 }
00290
00291 void apply()
00292 {
00293 glViewport(0,0,width,height);
00294 glMatrixMode(GL_PROJECTION);
00295 glLoadIdentity();
00296 apply_perspective();
00297 glMatrixMode(GL_MODELVIEW);
00298 }
00299 void apply_perspective()
00300 {
00301 aspect = aspect_factor * float(width)/float(height);
00302 if ( aspect < 1 )
00303 {
00304
00305
00306 float fovx = fovy;
00307 float real_fov = to_degrees(2 * atan(tan(to_radians(fovx/2))/aspect));
00308 gluPerspective(real_fov, aspect, zNear, zFar);
00309 }
00310 else
00311 gluPerspective(fovy, aspect, zNear, zFar);
00312 }
00313 int width, height;
00314 float fovy, aspect, zNear, zFar;
00315 float aspect_factor;
00316 };
00317
00318
00319
00320 class glut_simple_interactor : public glut_interactor
00321 {
00322 public:
00323 glut_simple_interactor()
00324 {
00325 activate_on = GLUT_LEFT_BUTTON;
00326 active = false;
00327 use_modifiers = true;
00328 modifiers = 0;
00329 width = height = 0;
00330 x0 = y0 = x = y = dx = dy = 0;
00331 }
00332
00333 virtual void mouse(int button, int state, int X, int Y)
00334 {
00335 if(enabled && button == activate_on && state == GLUT_DOWN &&
00336 (! use_modifiers || (modifiers == glutGetModifiers())) )
00337 {
00338 active = true;
00339 x = x0 = X;
00340 y = y0 = Y;
00341 dx = dy = 0;
00342 }
00343 else if (enabled && button == activate_on && state == GLUT_UP)
00344 {
00345 if(dx == 0 && dy == 0)
00346 update();
00347 active = false;
00348 dx = dy = 0;
00349 }
00350 }
00351
00352 virtual void motion(int X, int Y)
00353 {
00354 if(enabled && active)
00355 {
00356 dx = X - x; dy = y - Y;
00357 x = X; y = Y;
00358 update();
00359 }
00360 }
00361
00362 void reshape(int w, int h)
00363 {
00364 width = w; height = h;
00365 }
00366
00367 virtual void apply_transform() = 0;
00368 virtual void apply_inverse_transform() = 0;
00369 virtual matrix4f get_transform() = 0;
00370 virtual matrix4f get_inverse_transform() = 0;
00371
00372 virtual void update() {}
00373
00374 int activate_on;
00375 bool use_modifiers;
00376 int modifiers;
00377 bool active;
00378 int x0, y0;
00379 int x, y;
00380 int dx, dy;
00381 int width, height;
00382 };
00383
00384
00385 class glut_pan : public glut_simple_interactor
00386 {
00387 public:
00388 glut_pan()
00389 {
00390 scale = .01f;
00391 invert_increment = false;
00392 parent_rotation = 0;
00393 }
00394 void update()
00395 {
00396 vec3f v(dx, dy, 0);
00397 if(parent_rotation != 0) parent_rotation->mult_vec(v);
00398
00399 if(invert_increment)
00400 pan -= v * scale;
00401 else
00402 pan += v * scale;
00403 glutPostRedisplay();
00404 }
00405
00406 void apply_transform()
00407 {
00408
00409 glTranslatef(pan[0], pan[1], pan[2]);
00410 }
00411
00412 void apply_inverse_transform()
00413 {
00414
00415 glTranslatef(-pan[0], -pan[1], -pan[2]);
00416 }
00417
00418 matrix4f get_transform()
00419 {
00420 matrix4f m;
00421 m.make_identity();
00422 m.set_translate(pan);
00423 return m;
00424 }
00425
00426 matrix4f get_inverse_transform()
00427 {
00428 matrix4f m;
00429 m.make_identity();
00430 m.set_translate(-pan);
00431 return m;
00432 }
00433
00434
00435 bool invert_increment;
00436 const rotationf * parent_rotation;
00437 vec3f pan;
00438 float scale;
00439 };
00440
00441
00442 class glut_dolly : public glut_simple_interactor
00443 {
00444 public:
00445 glut_dolly()
00446 {
00447 scale = .01f;
00448 invert_increment = false;
00449 parent_rotation = 0;
00450 }
00451 void update()
00452 {
00453 vec3f v(0,0,dy);
00454 if(parent_rotation != 0) parent_rotation->mult_vec(v);
00455
00456 if(invert_increment)
00457 dolly += v * scale;
00458 else
00459 dolly -= v * scale;
00460 glutPostRedisplay();
00461 }
00462
00463 void apply_transform()
00464 {
00465
00466 glTranslatef(dolly[0], dolly[1], dolly[2]);
00467 }
00468
00469 void apply_inverse_transform()
00470 {
00471
00472 glTranslatef(-dolly[0], -dolly[1], -dolly[2]);
00473 }
00474
00475 matrix4f get_transform()
00476 {
00477 matrix4f m;
00478 m.make_identity();
00479 m.set_translate(dolly);
00480 return m;
00481 }
00482
00483 matrix4f get_inverse_transform()
00484 {
00485 matrix4f m;
00486 m.make_identity();
00487 m.set_translate(-dolly);
00488 return m;
00489 }
00490
00491
00492 bool invert_increment;
00493 const rotationf * parent_rotation;
00494 vec3f dolly;
00495 float scale;
00496 };
00497
00498
00499 class glut_trackball : public glut_simple_interactor
00500 {
00501 public:
00502 glut_trackball()
00503 {
00504 r = rotationf(vec3f(0, 1, 0), 0);
00505 centroid = vec3f(0,0,0);
00506 scale = 1;
00507 invert_increment = false;
00508 parent_rotation = 0;
00509 legacy_mode = false;
00510 }
00511
00512 void update()
00513 {
00514 if(dx == 0 && dy == 0)
00515 {
00516 incr = rotationf();
00517 return;
00518 }
00519
00520 if(legacy_mode)
00521 {
00522 vec3f v(dy, -dx, 0);
00523 float len = v.normalize();
00524 if(parent_rotation != 0) parent_rotation->mult_vec(v);
00525
00526 if(invert_increment)
00527 incr.set_value(v, -len * scale * -.01);
00528 else
00529 incr.set_value(v, len * scale * -.01);
00530 }
00531 else
00532 {
00533 float min = width < height ? width : height;
00534 min /= 2.f;
00535 vec3f offset(width/2.f, height/2.f, 0);
00536 vec3f a(x-dx, height - (y+dy), 0);
00537 vec3f b( x, height - y , 0);
00538 a -= offset;
00539 b -= offset;
00540 a /= min;
00541 b /= min;
00542
00543 a[2] = pow(2.0f, -0.5f * a.length());
00544 a.normalize();
00545 b[2] = pow(2.0f, -0.5f * b.length());
00546 b.normalize();
00547
00548
00549 vec3f axis = a.cross(b);
00550 axis.normalize();
00551
00552 float angle = acos(a.dot(b));
00553
00554 if(parent_rotation != 0) parent_rotation->mult_vec(axis);
00555
00556 if(invert_increment)
00557 incr.set_value(axis, -angle * scale);
00558 else
00559 incr.set_value(axis, angle * scale);
00560
00561 }
00562
00563
00564 if(incr[3] != 0)
00565 r = incr * r;
00566 glutPostRedisplay();
00567 }
00568
00569 void increment_rotation()
00570 {
00571 if(active) return;
00572
00573 if(incr[3] != 0)
00574 r = incr * r;
00575 glutPostRedisplay();
00576 }
00577
00578 void apply_transform()
00579 {
00580 glTranslatef(centroid[0], centroid[1], centroid[2]);
00581 glh_rotate(r);
00582 glTranslatef(-centroid[0], -centroid[1], -centroid[2]);
00583 }
00584
00585 void apply_inverse_transform()
00586 {
00587 glTranslatef(centroid[0], centroid[1], centroid[2]);
00588 glh_rotate(r.inverse());
00589 glTranslatef(-centroid[0], -centroid[1], -centroid[2]);
00590 }
00591
00592
00593 matrix4f get_transform()
00594 {
00595 matrix4f mt, mr, minvt;
00596 mt.set_translate(centroid);
00597 r.get_value(mr);
00598 minvt.set_translate(-centroid);
00599 return mt * mr * minvt;
00600 }
00601
00602 matrix4f get_inverse_transform()
00603 {
00604 matrix4f mt, mr, minvt;
00605 mt.set_translate(centroid);
00606 r.inverse().get_value(mr);
00607 minvt.set_translate(-centroid);
00608 return mt * mr * minvt;
00609 }
00610
00611 bool invert_increment;
00612 const rotationf * parent_rotation;
00613 rotationf r;
00614 vec3f centroid;
00615 float scale;
00616 bool legacy_mode;
00617 rotationf incr;
00618 };
00619
00620
00621 class glut_rotate : public glut_simple_interactor
00622 {
00623 public:
00624 glut_rotate()
00625 {
00626 rotate_x = rotate_y = 0;
00627 scale = 1;
00628 }
00629 void update()
00630 {
00631 rotate_x += dx * scale;
00632 rotate_y += dy * scale;
00633 glutPostRedisplay();
00634 }
00635
00636 void apply_transform()
00637 {
00638 glRotatef(rotate_x, 0, 1, 0);
00639 glRotatef(rotate_y, -1, 0, 0);
00640 }
00641
00642 void apply_inverse_transform()
00643 {
00644 glRotatef(-rotate_y, -1, 0, 0);
00645 glRotatef(-rotate_x, 0, 1, 0);
00646 }
00647
00648 matrix4f get_transform()
00649 {
00650 rotationf rx(to_radians(rotate_x), 0, 1, 0);
00651 rotationf ry(to_radians(rotate_y), -1, 0, 0);
00652 matrix4f mx, my;
00653 rx.get_value(mx);
00654 ry.get_value(my);
00655 return mx * my;
00656 }
00657
00658 matrix4f get_inverse_transform()
00659 {
00660 rotationf rx(to_radians(-rotate_x), 0, 1, 0);
00661 rotationf ry(to_radians(-rotate_y), -1, 0, 0);
00662 matrix4f mx, my;
00663 rx.get_value(mx);
00664 ry.get_value(my);
00665 return my * mx;
00666 }
00667
00668 float rotate_x, rotate_y, scale;
00669 };
00670
00671 class glut_mouse_to_keyboard : public glut_simple_interactor
00672 {
00673 public:
00674 glut_mouse_to_keyboard()
00675 {
00676 keyboard_function = 0;
00677 pos_dx_key = neg_dx_key = pos_dy_key = neg_dy_key = 0;
00678 }
00679 void apply_transform() {}
00680
00681 void apply_inverse_transform() {}
00682
00683 matrix4f get_transform() {return matrix4f();}
00684
00685 matrix4f get_inverse_transform() {return matrix4f();}
00686
00687 void update()
00688 {
00689 if(!keyboard_function) return;
00690 if(dx > 0)
00691 keyboard_function(pos_dx_key, x, y);
00692 else if(dx < 0)
00693 keyboard_function(neg_dx_key, x, y);
00694 if(dy > 0)
00695 keyboard_function(pos_dy_key, x, y);
00696 else if(dy < 0)
00697 keyboard_function(neg_dy_key, x, y);
00698 }
00699 unsigned char pos_dx_key, neg_dx_key, pos_dy_key, neg_dy_key;
00700 void (*keyboard_function)(unsigned char, int, int);
00701 };
00702
00703 inline void glut_exit_on_escape(unsigned char k, int x = 0, int y = 0)
00704 { if(k==27) exit(0); }
00705
00706 struct glut_simple_mouse_interactor : public glut_interactor
00707 {
00708
00709 public:
00710 glut_simple_mouse_interactor(int num_buttons_to_use=3)
00711 {
00712 configure_buttons(num_buttons_to_use);
00713 camera_mode = false;
00714 }
00715
00716 void enable()
00717 {
00718 trackball.enable();
00719 pan.enable();
00720 dolly.enable();
00721 }
00722
00723 void disable()
00724 {
00725 trackball.disable();
00726 pan.disable();
00727 dolly.disable();
00728 }
00729
00730 void set_camera_mode(bool cam)
00731 {
00732 camera_mode = cam;
00733 if(camera_mode)
00734 {
00735 trackball.invert_increment = true;
00736 pan.invert_increment = true;
00737 dolly.invert_increment = true;
00738 pan.parent_rotation = & trackball.r;
00739 dolly.parent_rotation = & trackball.r;
00740 }
00741 else
00742 {
00743 trackball.invert_increment = false;
00744 pan.invert_increment = false;
00745 dolly.invert_increment = false;
00746 if(pan.parent_rotation == &trackball.r) pan.parent_rotation = 0;
00747 if(dolly.parent_rotation == &trackball.r) dolly.parent_rotation = 0;
00748 }
00749 }
00750 void configure_buttons(int num_buttons_to_use = 3)
00751 {
00752 switch(num_buttons_to_use)
00753 {
00754 case 1:
00755 trackball.activate_on = GLUT_LEFT_BUTTON;
00756 trackball.modifiers = 0;
00757
00758 pan.activate_on = GLUT_LEFT_BUTTON;
00759 pan.modifiers = GLUT_ACTIVE_SHIFT;
00760
00761
00762 dolly.activate_on = GLUT_LEFT_BUTTON;
00763 dolly.modifiers = GLUT_ACTIVE_CTRL;
00764
00765 break;
00766
00767 case 2:
00768 trackball.activate_on = GLUT_LEFT_BUTTON;
00769 trackball.modifiers = 0;
00770
00771 pan.activate_on = GLUT_MIDDLE_BUTTON;
00772 pan.modifiers = 0;
00773
00774
00775 dolly.activate_on = GLUT_LEFT_BUTTON;
00776 dolly.modifiers = GLUT_ACTIVE_CTRL;
00777
00778 break;
00779
00780 case 3:
00781 default:
00782 trackball.activate_on = GLUT_LEFT_BUTTON;
00783 trackball.modifiers = 0;
00784
00785 pan.activate_on = GLUT_MIDDLE_BUTTON;
00786 pan.modifiers = 0;
00787
00788 dolly.activate_on = GLUT_RIGHT_BUTTON;
00789 dolly.modifiers = 0;
00790
00791 break;
00792 }
00793 }
00794
00795 virtual void motion(int x, int y)
00796 {
00797
00798 trackball.motion(x,y);
00799
00800 pan.motion(x,y);
00801
00802 dolly.motion(x,y);
00803 }
00804 virtual void mouse(int button, int state, int x, int y)
00805 {
00806 trackball.mouse(button, state, x, y);
00807 pan.mouse(button, state, x, y);
00808 dolly.mouse(button, state, x, y);
00809 }
00810
00811 virtual void reshape(int x, int y)
00812 {
00813 trackball.reshape(x,y);
00814 pan.reshape(x,y);
00815 dolly.reshape(x,y);
00816 }
00817
00818 void apply_transform()
00819 {
00820 pan.apply_transform();
00821 dolly.apply_transform();
00822 trackball.apply_transform();
00823 }
00824
00825 void apply_inverse_transform()
00826 {
00827 trackball.apply_inverse_transform();
00828 dolly.apply_inverse_transform();
00829 pan.apply_inverse_transform();
00830 }
00831
00832 matrix4f get_transform()
00833 {
00834 return ( pan.get_transform() *
00835 dolly.get_transform() *
00836 trackball.get_transform() );
00837 }
00838
00839 matrix4f get_inverse_transform()
00840 {
00841 return ( trackball.get_inverse_transform() *
00842 dolly.get_inverse_transform() *
00843 pan.get_inverse_transform() );
00844 }
00845
00846 void set_parent_rotation(rotationf *rp)
00847 {
00848 trackball.parent_rotation = rp;
00849 dolly.parent_rotation = rp;
00850 pan.parent_rotation = rp;
00851 }
00852
00853 bool camera_mode;
00854 glut_trackball trackball;
00855 glut_pan pan;
00856 glut_dolly dolly;
00857 };
00858
00859 }
00860
00861 #endif