00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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);
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);
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);
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
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
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 , vgui_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
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);
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
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);
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
00325
00326 double scalefactor = vcl_pow(5.0, dy);
00327 if (!lock_dolly)
00328 this->token.scale = static_cast<float>(lastpos.scale * scalefactor);
00329
00330
00331
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
00342 if (c_mouse_translate(button, modifier)) {
00343 GLint vp[4];
00344 glGetIntegerv(GL_VIEWPORT, vp);
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
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);
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
00394
00395 return true;
00396 }
00397 }
00398 return false;
00399 }
00400
00401 bool vgui_viewer3D_tableau::help()
00402 {
00403
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 }