core/vgui/vgui_viewer3D_tableau.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_viewer3D_tableau.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \brief  See vgui_viewer3D_tableau.h for a description of this file
00008 // \author Philip C. Pritchett, RRG, University of Oxford
00009 // \date   14-SEP-1999
00010 //
00011 // \verbatim
00012 //  Modifications
00013 //   14-SEP-1999 P.Pritchett - Initial version.
00014 // \endverbatim
00015 
00016 #include "vgui_viewer3D_tableau.h"
00017 
00018 #include <vcl_cmath.h>
00019 #include <vcl_iostream.h>
00020 #include <vbl/vbl_bool_ostream.h>
00021 
00022 #include <vgui/vgui_gl.h>
00023 #include <vgui/vgui_glu.h>
00024 #include <vgui/internals/trackball.h>
00025 #include <vgui/vgui.h>
00026 #include <vgui/vgui_event.h>
00027 
00028 struct vgui_viewer3D_tableau_spin
00029 {
00030   vgui_viewer3D_tableau *viewer;
00031   float delta_r[4];
00032   double delay;
00033 };
00034 
00035 const void * const vgui_viewer3D_tableau::SPIN_EVENT="x";
00036 
00037 //: Constructor - don't use this, use vgui_viewer3D_tableau_new.
00038 vgui_viewer3D_tableau::vgui_viewer3D_tableau(vgui_tableau_sptr const& s) :
00039   vgui_wrapper_tableau(s),
00040   c_mouse_rotate(vgui_LEFT),
00041   c_mouse_translate(vgui_RIGHT),
00042   c_mouse_zoom(vgui_MIDDLE),
00043   c_lock_dolly(vgui_key('D'), vgui_MODIFIER_NULL),
00044   c_lock_zoom(vgui_key('Z'), vgui_MODIFIER_NULL),
00045   c_lighting(vgui_key('l'), vgui_MODIFIER_NULL),
00046   c_shading(vgui_key('s'), vgui_MODIFIER_NULL),
00047   c_spinning(vgui_key('p'), vgui_MODIFIER_NULL),
00048   c_render_mode(vgui_key('r'), vgui_MODIFIER_NULL),
00049   c_niceness(vgui_key('n'), vgui_MODIFIER_NULL),
00050   c_headlight(vgui_key('h'), vgui_MODIFIER_NULL),
00051   c_save_home(vgui_key('>'), vgui_MODIFIER_NULL),
00052   c_restore_home(vgui_key('<'), vgui_MODIFIER_NULL),
00053   lock_dolly(false),
00054   lock_zoom(true),
00055   spin_data(0)
00056 {
00057   spinning = false;
00058   allow_spinning = true;
00059 
00060   trackball(token.quat , 0.0, 0.0, 0.0, 0.0);
00061   token.scale = 1.0;
00062 
00063   token.trans[0] = 0;
00064   token.trans[1] = 0;
00065   token.trans[2] = -10;
00066 
00067   home = token;
00068 
00069   gl_mode = textured;
00070   lighting = true;
00071   smooth_shading = true;
00072   high_quality = true;
00073   headlight = true;
00074 }
00075 
00076 vgui_viewer3D_tableau::~vgui_viewer3D_tableau()
00077 {
00078 }
00079 
00080 vcl_string vgui_viewer3D_tableau::type_name() const {return "vgui_viewer3D_tableau";}
00081 
00082 static void draw_headlight()
00083 {
00084 #if 0
00085   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00086 #endif // 0
00087   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
00088   GLfloat light0_pos[4]   = {  0.0, 0.0, 1.0, 0.0 };
00089 #if 0
00090   GLfloat light0_dir[4]   = {  0.0, 0.0, -1.0, 0.0 };
00091 #endif // 0
00092   GLfloat light0_diff[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
00093   GLfloat light0_amb[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
00094   GLfloat light0_spec[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
00095 
00096   glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
00097 #if 0
00098   glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0_dir);
00099   glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 1080.0);
00100 #endif // 0
00101   glLightfv(GL_LIGHT0, GL_AMBIENT,  light0_amb);
00102   glLightfv(GL_LIGHT0, GL_DIFFUSE,  light0_diff);
00103   glLightfv(GL_LIGHT0, GL_SPECULAR,  light0_spec);
00104 #if 0
00105   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
00106   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0);
00107   glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0);
00108 #endif // 0
00109 
00110   glEnable(GL_LIGHT0);
00111 }
00112 
00113 
00114 void vgui_viewer3D_tableau::setup_gl_matrices()
00115 {
00116   GLdouble vp[4];
00117   glGetDoublev(GL_VIEWPORT, vp); // ok
00118   double width = vp[2];
00119   double height = vp[3];
00120 
00121   glMatrixMode(GL_PROJECTION);
00122   glLoadIdentity();
00123   gluPerspective(token.fov, width / height, 1, 1000);
00124 #if 0
00125   glOrtho(-10,10,-10,10,-20000,10000);
00126 #endif // 0
00127 
00128   glMatrixMode(GL_MODELVIEW);
00129   glLoadIdentity();
00130 
00131   glTranslatef(0,0,-10);      // object position
00132 
00133   glTranslatef(token.trans[0], token.trans[1], token.trans[2]);
00134   glScalef(token.scale, token.scale, token.scale);
00135   GLfloat m[4][4];
00136   build_rotmatrix(m,token.quat); // rotation
00137   glMultMatrixf(&m[0][0]);
00138 
00139   if (headlight)
00140     draw_headlight();
00141   else
00142     glDisable(GL_LIGHT0);
00143 }
00144 
00145 
00146 void vgui_viewer3D_tableau::draw_before_child()
00147 {
00148 #ifdef DEBUG
00149   vcl_cerr << "vgui_viewer3D_tableau::draw_before_child\n";
00150 #endif
00151 
00152   // Setup OpenGL for 3D
00153   glEnable(GL_CULL_FACE);
00154   glEnable(GL_DEPTH_TEST);
00155   glDisable(GL_TEXTURE_2D);
00156 #if 0
00157   glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
00158   glEnable(GL_COLOR_MATERIAL);
00159 #endif // 0
00160 
00161   glEnable(GL_NORMALIZE);
00162 
00163   glDepthFunc(GL_LESS);
00164   glEnable(GL_DEPTH_TEST);
00165   glDepthRange(0.0, 1.0);
00166 
00167   if (lighting)
00168     glEnable(GL_LIGHTING);
00169   else
00170     glDisable(GL_LIGHTING);
00171 
00172   if (smooth_shading)
00173     glShadeModel(GL_SMOOTH);
00174   else
00175     glShadeModel(GL_FLAT);
00176 
00177   if (high_quality) {
00178     glEnable(GL_DITHER);
00179     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00180     glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
00181     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
00182     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
00183 
00184     glEnable(GL_POINT_SMOOTH);
00185     glEnable(GL_LINE_SMOOTH);
00186 
00187     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00188     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00189   }
00190   else {
00191     glDisable(GL_DITHER);
00192     glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
00193     glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
00194     glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
00195     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
00196 
00197     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00198     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00199   }
00200 
00201 #if 0
00202   glClear(GL_DEPTH_BUFFER_BIT);
00203 #endif // 0
00204   setup_gl_matrices();
00205 }
00206 
00207 
00208 bool vgui_viewer3D_tableau::handle(const vgui_event& e)
00209 {
00210   if (this->spinning && (c_mouse_rotate(e) || c_mouse_translate(e) || c_mouse_zoom(e)))
00211     this->spinning = false;
00212 
00213   if (this->allow_spinning && this->spinning && event.user == &vgui_viewer3D_tableau::SPIN_EVENT)
00214   {
00215     vgui_viewer3D_tableau_spin const* spindata = (vgui_viewer3D_tableau_spin const*)event.data;
00216 
00217     if (spindata->viewer == this)
00218     {
00219 #ifdef DEBUG
00220       vcl_cerr << "spinning\n"
00221                << "spin_data->delta_r = "
00222                << spindata->delta_r[0] << ' '
00223                << spindata->delta_r[1] << ' '
00224                << spindata->delta_r[2] << ' '
00225                << spindata->delta_r[3] << '\n';
00226 #endif
00227 
00228       add_quats(spindata->delta_r, lastpos.quat, this->token.quat);
00229 
00230       // lastpos.quat = this->token.quat; // SGI CC can't do this.
00231       for (unsigned i=0; i<4; ++i) lastpos.quat[i] = this->token.quat[i];
00232 
00233       this->post_redraw();
00234 
00235 #if 0
00236       Fl::add_idle(spin_callback,spindata);
00237 #endif // 0
00238     }
00239   }
00240 
00241   event = e;
00242 
00243   if (vgui_drag_mixin::handle(e))
00244     return true;
00245 
00246   if (vgui_tableau::handle(e))
00247     return true;
00248 
00249   if (e.type == vgui_DRAW) {
00250 #ifdef DEBUG
00251     vcl_cerr << "vgui_viewer3D_tableau vgui_DRAW\n";
00252 #endif
00253     draw_before_child();
00254 
00255     child && child->handle(e);
00256     return true;
00257   }
00258   else {
00259     setup_gl_matrices();
00260 
00261     bool used = child->handle(e);
00262     return used;
00263   }
00264 }
00265 
00266 bool vgui_viewer3D_tableau::mouse_down(int x, int y, vgui_button /*button*/, vgui_modifier /*modifier*/)
00267 {
00268   if (c_mouse_rotate(event) || c_mouse_translate(event) || c_mouse_zoom(event)) {
00269     beginx = x;
00270     beginy = y;
00271     lastpos = this->token;
00272     last = event;
00273     this->spinning = false;
00274     return true;
00275   }
00276 
00277   return false;
00278 }
00279 
00280 bool vgui_viewer3D_tableau::mouse_drag(int x, int y, vgui_button button, vgui_modifier modifier)
00281 {
00282   // SPINNING
00283   if (c_mouse_rotate(button, modifier))
00284   {
00285 #ifdef DEBUG
00286     vcl_cerr << "vgui_viewer3D_tableau::mouse_drag: left\n";
00287 #endif
00288 
00289     GLdouble vp[4];
00290     glGetDoublev(GL_VIEWPORT, vp); // ok
00291     float width  = (float)vp[2];
00292     float height = (float)vp[3];
00293 
00294     float wscale = 2.0f / width;
00295     float hscale = 2.0f / height;
00296     float delta_r[4];
00297     trackball(delta_r,
00298               wscale*beginx - 1, hscale*beginy - 1,
00299               wscale*x - 1, hscale*y - 1);
00300     add_quats(delta_r, lastpos.quat, this->token.quat);
00301 
00302     prevx = x;
00303     prevx = y;
00304 
00305     this->post_redraw();
00306     return true;
00307   }
00308 
00309   // ZOOMING
00310   if (c_mouse_zoom(button, modifier))
00311   {
00312 #ifdef DEBUG
00313     vcl_cerr << "vgui_viewer3D_tableau::mouse_drag: middle\n";
00314 #endif
00315 
00316     GLdouble vp[4];
00317     glGetDoublev(GL_VIEWPORT, vp); // ok
00318     double width = vp[2];
00319     double height = vp[3];
00320 
00321     double dx = (beginx - x) / width;
00322     double dy = (beginy - y) / height;
00323 
00324     // changed to vcl_pow(5,dy) to vcl_pow(5.0,dy)
00325     // the first version is ambiguous when overloads exist for vcl_pow
00326     double scalefactor = vcl_pow(5.0, dy);
00327     if (!lock_dolly)
00328       this->token.scale = static_cast<float>(lastpos.scale * scalefactor);
00329 
00330     // changed to vcl_pow(5,dy) to vcl_pow(5.0,dy)
00331     // the first version is ambiguous when overloads exist for vcl_pow
00332     double zoomfactor = vcl_pow(5.0,dx);
00333     if (!lock_zoom) {
00334       this->token.fov = static_cast<float>(lastpos.fov * zoomfactor);
00335       vgui::out << "viewer3D : fov " << this->token.fov << vcl_endl;
00336     }
00337     this->post_redraw();
00338     return true;
00339   }
00340 
00341   // TRANSLATION
00342   if (c_mouse_translate(button, modifier)) {
00343     GLint vp[4];
00344     glGetIntegerv(GL_VIEWPORT, vp); // ok
00345     double width = (double)vp[2];
00346     double height = (double)vp[3];
00347 
00348     double dx = (beginx - x) / width;
00349     double dy = (beginy - y) / height;
00350 
00351     this->token.trans[0] = static_cast<float>(lastpos.trans[0] - dx * 20);
00352     this->token.trans[1] = static_cast<float>(lastpos.trans[1] - dy * 20);
00353 
00354     this->post_redraw();
00355     return true;
00356   }
00357   return false;
00358 }
00359 
00360 bool vgui_viewer3D_tableau::mouse_up(int x, int y, vgui_button button, vgui_modifier modifier)
00361 {
00362   // SPINNING
00363   if (this->allow_spinning && c_mouse_rotate(button, modifier))
00364   {
00365 #ifdef DEBUG
00366     vcl_cerr << "vgui_viewer3D_tableau::mouse_up: left\n";
00367 #endif
00368 
00369     GLdouble vp[4];
00370     glGetDoublev(GL_VIEWPORT, vp); // ok
00371     double width = vp[2];
00372     double height = vp[3];
00373 
00374     double wscale = 2.0 / width;
00375     double hscale = 2.0 / height;
00376     float delta_r[4];
00377     trackball(delta_r,
00378               static_cast<float>(wscale*beginx - 1), static_cast<float>(hscale*beginy - 1),
00379               static_cast<float>(wscale*x - 1), static_cast<float>(hscale*y - 1));
00380 
00381     if (beginx != x && beginy != y)
00382     {
00383       this->spinning = true;
00384       double delay = event.secs_since(last);
00385 
00386       delete spin_data;
00387       spin_data = new vgui_viewer3D_tableau_spin;
00388       spin_data->viewer = this;
00389       spin_data->delay = delay;
00390       for (int i=0; i<4; ++i)
00391         spin_data->delta_r[i] = delta_r[i];
00392 
00393       // Fl::add_timeout(delay,spin_callback,(void*)spin_data);
00394 
00395       return true;
00396     }
00397   }
00398   return false;
00399 }
00400 
00401 bool vgui_viewer3D_tableau::help()
00402 {
00403   // awf FIXME these need to come from this->c_*
00404   vcl_cerr << "\n-- vgui_viewer3D_tableau ---------\n"
00405            << "  rotate:    " << c_mouse_rotate.as_string() << '\n'
00406            << "  translate: " << c_mouse_translate.as_string() << '\n'
00407            << "  zoom: " << c_mouse_zoom.as_string() << '\n'
00408            << "  lock dolly: " << c_lock_dolly.as_string() << '\n'
00409            << "  lock zoom: " << c_lock_zoom.as_string() << '\n'
00410            << "  lighting: " << c_lighting.as_string() << '\n'
00411            << "  shading: " << c_shading.as_string() << '\n'
00412            << "  spinning: " << c_spinning.as_string() << '\n'
00413            << "  render_mode: " << c_render_mode.as_string() << '\n'
00414            << "  niceness: " << c_niceness.as_string() << '\n'
00415            << "  headlight: " << c_headlight.as_string() << '\n'
00416            << "  save_home: " << c_save_home.as_string() << '\n'
00417            << "  restore_home: " << c_restore_home.as_string() << '\n';
00418 
00419   return false;
00420 }
00421 
00422 bool vgui_viewer3D_tableau::key_press(int, int, vgui_key key, vgui_modifier modifier)
00423 {
00424   if (c_lock_dolly(key, modifier)) {
00425     lock_dolly = !lock_dolly;
00426     vgui::out << "viewer3D : dolly lock " << vbl_bool_ostream::on_off(lock_dolly) << vcl_endl;
00427     return true;
00428   }
00429 
00430   if (c_lock_zoom(key, modifier)) {
00431     lock_zoom = !lock_zoom;
00432     vgui::out << "viewer3D : zoom lock " << vbl_bool_ostream::on_off(lock_zoom) << vcl_endl;
00433     return true;
00434   }
00435 
00436   if (c_lighting(key, modifier)) {
00437     this->lighting = !this->lighting;
00438     vgui::out << "viewer3D : lighting " << vbl_bool_ostream::on_off(this->lighting) << vcl_endl;
00439     this->post_redraw();
00440     return true;
00441   }
00442 
00443   if (c_shading(key, modifier)) {
00444     this->smooth_shading = !this->smooth_shading;
00445     vgui::out << "viewer3D : smooth shading " << vbl_bool_ostream::on_off(this->smooth_shading) << vcl_endl;
00446     this->post_redraw();
00447     return true;
00448   }
00449 
00450   if (c_spinning(key, modifier)) {
00451     this->allow_spinning = !this->allow_spinning;
00452     vgui::out << "viewer3D : allow spinning " << vbl_bool_ostream::on_off(this->allow_spinning) << vcl_endl;
00453     return true;
00454   }
00455 
00456   if (c_render_mode(key, modifier)) {
00457     if (this->gl_mode == vgui_viewer3D_tableau::wireframe) {
00458       vgui::out << "viewer3D : textured rendering\n";
00459       this->gl_mode = vgui_viewer3D_tableau::textured;
00460     }
00461     else if (this->gl_mode == vgui_viewer3D_tableau::textured) {
00462       vgui::out << "viewer3D : wireframe rendering\n";
00463       this->gl_mode = vgui_viewer3D_tableau::wireframe;
00464     }
00465     this->post_redraw();
00466     return true;
00467   }
00468 
00469   if (c_niceness(key, modifier)) {
00470     this->high_quality = !this->high_quality;
00471     vgui::out << "viewer3D : " << vbl_bool_ostream::high_low(this->high_quality) << " quality\n";
00472     this->post_redraw();
00473     return true;
00474   }
00475 
00476   if (c_headlight(key, modifier)) {
00477     this->headlight = !this->headlight;
00478     vgui::out << "viewer3D : headlight " << vbl_bool_ostream::on_off(this->headlight) << vcl_endl;
00479     this->post_redraw();
00480     return true;
00481   }
00482 
00483   if (c_save_home(key, modifier)) {
00484     this->home = this->token;
00485     vgui::out << "viewer3D : saving position to 'home'\n";
00486     return true;
00487   }
00488 
00489   if (c_restore_home(key, modifier)) {
00490     vgui::out << "viewer3D : restoring position 'home'\n";
00491     this->token = this->home;
00492     this->post_redraw();
00493     return true;
00494   }
00495 
00496   return false;
00497 }