contrib/brl/bbas/bgui3d/bgui3d_examiner_tableau.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/bgui3d/bgui3d_examiner_tableau.cxx
00002 #include "bgui3d_examiner_tableau.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_cassert.h>
00007 #include <vcl_algorithm.h>
00008 
00009 #include <vgui/vgui_menu.h>
00010 #include <vgui/vgui_command.h>
00011 #include <vgui/vgui_gl.h>
00012 
00013 #include <Inventor/actions/SoSearchAction.h>
00014 #include <Inventor/projectors/SbSphereSheetProjector.h>
00015 #include <Inventor/actions/SoRayPickAction.h>
00016 #include <Inventor/SoPickedPoint.h>
00017 
00018 #include <Inventor/SbLinear.h>
00019 #include <Inventor/sensors/SoTimerSensor.h>
00020 #include <Inventor/misc/SoChildList.h>
00021 #include <Inventor/actions/SoGetBoundingBoxAction.h>
00022 #include <Inventor/nodes/SoPerspectiveCamera.h>
00023 
00024 
00025 static void seeksensorCB(void * data, SoSensor * s);
00026 
00027 // Bitmap representations of an "X", a "Y" and a "Z" for the axis cross.
00028 static GLubyte xbmp[] = { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11 };
00029 static GLubyte ybmp[] = { 0x04,0x04,0x04,0x04,0x0a,0x11,0x11 };
00030 static GLubyte zbmp[] = { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f };
00031 
00032 int count = 0;
00033 SbVec3f d;
00034 
00035 //: Constructor
00036 bgui3d_examiner_tableau::bgui3d_examiner_tableau(SoNode * scene_root)
00037  : bgui3d_fullviewer_tableau(scene_root),
00038    last_down_button_(vgui_BUTTON_NULL), last_timestamp_(0), seek_distance_(SEEK_HALF),
00039    scale_(1.0f),
00040    axis_visible_(true)
00041 {
00042   interaction_type_ = CAMERA;
00043   spin_projector_ = new SbSphereSheetProjector(SbSphere(SbVec3f(0, 0, 0), 0.8f));
00044   SbViewVolume volume;
00045   volume.ortho(-1, 1, -1, 1, -1, 1);
00046   spin_projector_->setViewVolume( volume );
00047   seekSensor_ = new SoTimerSensor( seeksensorCB, this );
00048   find_scale();
00049 }
00050 
00051 
00052 //: Destructor
00053 bgui3d_examiner_tableau::~bgui3d_examiner_tableau()
00054 {
00055   // Ming: no need to delete the SbSphereSheetProjector object
00056   // delete spin_projector_;
00057 }
00058 
00059 
00060 vcl_string bgui3d_examiner_tableau::type_name() const {return "bgui3d_examiner_tableau";}
00061 
00062 //: Handle the events coming in
00063 // - Left mouse = spin
00064 // - Middle mouse = pan
00065 // - Middle mouse with control = zoom (dolly)
00066 // - 's' and then click = seeks 2/3 of the distance to the object
00067 // - 'i' toggles idle events
00068 // - 'h' puts camera to the current view
00069 // - 'h' with control sets the home view to the current view
00070 // - 'v' views the entire scene
00071 // - 'n' go to the next camera
00072 // - 'p' go to the previous camera
00073 // - The cursors pan
00074 // - The cursors with 'control' spin
00075 // - The up and down cursors with shift zoom (dolly)
00076 
00077 bool bgui3d_examiner_tableau::handle(const vgui_event& e)
00078 {
00079   // to deal with multiple tableaux in a grid
00080   if ( e.type == vgui_LEAVE )
00081     reset_log();
00082   if ( e.type == vgui_ENTER )
00083     post_idle_request();
00084 
00085   // ALWAYS DO KEYPRESSES
00086   if ( e.type == vgui_KEY_PRESS )
00087   {
00088     SbVec2f middle(0.5f, 0.5f);
00089     SbVec2f left(0.4f, 0.5f);
00090     SbVec2f right(0.6f, 0.5f);
00091     SbVec2f up(0.5f, 0.6f);
00092     SbVec2f down(0.5f, 0.4f);
00093     switch (e.key)
00094     {
00095      case 'v':
00096       find_scale();
00097       view_all();
00098       break;
00099 
00100      case 'h':
00101       if (e.modifier == vgui_CTRL)
00102         save_home_position();
00103       else
00104         reset_to_home_position();
00105       break;
00106 
00107      case 'n': {
00108       int next = camera_group_->whichChild.getValue()+1;
00109       if (next < camera_group_->getChildren()->getLength()) {
00110         camera_group_->whichChild.setValue(next);
00111         set_camera((SoCamera*)(*camera_group_->getChildren())[next]);
00112       }
00113       break; }
00114 
00115      case 'p': {
00116       int prev = camera_group_->whichChild.getValue()-1;
00117       if (prev>=0) {
00118         camera_group_->whichChild.setValue(prev);
00119         set_camera((SoCamera*)(*camera_group_->getChildren())[prev]);
00120       }
00121       break; }
00122 
00123      case vgui_CURSOR_LEFT:
00124       if (e.modifier == vgui_CTRL)
00125         spin(left, middle);
00126       else if (e.modifier == vgui_MODIFIER_NULL) // rotate left
00127       {
00128         SbRotation camrot = scene_camera_->orientation.getValue();
00129         SbVec3f upvec(0, 1, 0); // init to default up vector
00130         camrot.multVec(upvec, upvec);
00131         SbRotation rotation(upvec, 0.025f );
00132         scene_camera_->orientation = camrot*rotation;
00133       }
00134       break;
00135 
00136      case vgui_CURSOR_RIGHT:
00137       if (e.modifier == vgui_CTRL)
00138         spin(right, middle);
00139       else if (e.modifier == vgui_MODIFIER_NULL) // rotate right
00140       {
00141         SbRotation camrot = scene_camera_->orientation.getValue();
00142         SbVec3f upvec(0, 1, 0); // init to default up vector
00143         camrot.multVec(upvec, upvec);
00144         SbRotation rotation(upvec, -0.025f );
00145         scene_camera_->orientation = camrot*rotation;
00146       }
00147       break;
00148 
00149      case vgui_CURSOR_UP:
00150       if (e.modifier == vgui_CTRL)
00151         spin(up, middle);
00152       else if (e.modifier == vgui_MODIFIER_NULL) // move forward
00153       {
00154         SbRotation camrot = scene_camera_->orientation.getValue();
00155         SbVec3f lookat(0, 0, -1); // init to default view direction vector
00156         camrot.multVec(lookat, lookat);
00157         lookat *= scale_*0.025f;
00158         SbVec3f pos = scene_camera_->position.getValue();
00159         pos += lookat;
00160         scene_camera_->position = pos;
00161         float foc = scene_camera_->focalDistance.getValue();
00162         foc -= lookat.length();
00163         scene_camera_->focalDistance = foc;
00164       }
00165       else if (e.modifier == vgui_SHIFT)
00166         zoom(0.025f*scale_);
00167       break;
00168 
00169      case vgui_CURSOR_DOWN:
00170       if (e.modifier == vgui_CTRL)
00171         spin(down, middle);
00172       else if (e.modifier == vgui_MODIFIER_NULL) // move backward
00173       {
00174         SbRotation camrot = scene_camera_->orientation.getValue();
00175         SbVec3f lookat(0, 0, -1); // init to default view direction vector
00176         camrot.multVec(lookat, lookat);
00177         SbVec3f pos = scene_camera_->position.getValue();
00178         pos -= lookat;
00179         scene_camera_->position = pos;
00180         float foc = scene_camera_->focalDistance.getValue();
00181         foc += lookat.length();
00182         scene_camera_->focalDistance = foc;
00183       }
00184       else if (e.modifier == vgui_SHIFT)
00185         zoom(-0.025f*scale_);
00186       break;
00187      default:
00188       break;
00189     }
00190   }
00191 
00192   // ONLY IF CAMERA INTERACTION MODE
00193   if ( interaction_type_ == CAMERA )
00194   {
00195     const SbVec2s viewport_size(get_viewport_region().getViewportSizePixels());
00196     const SbVec2s viewport_origin(get_viewport_region().getViewportOriginPixels());
00197     const SbVec2s curr_pos = SbVec2s(e.wx, e.wy) - viewport_origin;
00198     float aspect_ratio = get_viewport_region().getViewportAspectRatio();
00199 
00200     if ( e.type == vgui_KEY_PRESS && e.key == 's' )
00201     {
00202       last_process_ = SEEK;
00203     }
00204     // SEEK
00205     else if ( last_process_ == SEEK && e.type == vgui_MOUSE_DOWN )
00206     {
00207       reset_log();
00208       seek_to_point(curr_pos);
00209       last_process_ = IDLE;
00210     }
00211     // MOUSE DOWN
00212     else if ( e.type == vgui_MOUSE_DOWN )
00213     {
00214       reset_log();
00215       last_down_button_ = e.button;
00216       if ( e.modifier == vgui_CTRL)
00217       {
00218         interaction_type_ = SCENEGRAPH;
00219         bool b = bgui3d_fullviewer_tableau::handle(e);
00220         interaction_type_ = CAMERA;
00221         return b;
00222       }
00223     }
00224 
00225     // MOUSE UP
00226     else if ( e.type == vgui_MOUSE_UP )
00227     {
00228       last_down_button_ = vgui_BUTTON_NULL;
00229       last_process_ = IDLE;
00230       if ( e.timestamp - last_timestamp_ > 100 )
00231         reset_log();
00232 
00233       if ( e.modifier == vgui_CTRL)
00234       {
00235         interaction_type_ = SCENEGRAPH;
00236         bool b = bgui3d_fullviewer_tableau::handle(e);
00237         interaction_type_ = CAMERA;
00238         return b;
00239       }
00240     }
00241 
00242     // MOUSE MOTION
00243     else if ( e.type == vgui_MOUSE_MOTION )
00244     {
00245       if ( e.modifier == vgui_CTRL && last_down_button_ == vgui_LEFT)
00246       {
00247         interaction_type_ = SCENEGRAPH;
00248         //bool b =
00249         bgui3d_fullviewer_tableau::handle(e);
00250         interaction_type_ = CAMERA;
00251         //return b;
00252       }
00253       const SbVec2f last_pos_norm = last_pos_;
00254       const SbVec2s curr_pos = SbVec2s(e.wx, e.wy) - viewport_origin;
00255       const SbVec2f curr_pos_norm((float) curr_pos[0] / (float) vcl_max((int)(viewport_size[0] - 1), 1),
00256                                   (float) curr_pos[1] / (float) vcl_max((int)(viewport_size[1] - 1), 1));
00257 
00258       last_pos_ = curr_pos_norm;
00259 
00260       // MOUSE DOWN HANDLING
00261       switch (last_down_button_)
00262       {
00263        case vgui_LEFT:
00264         if ( e.modifier != vgui_CTRL )
00265         {
00266           spin(curr_pos_norm, last_pos_norm);
00267           update_log( curr_pos_norm );
00268 
00269           last_process_ = DRAG;
00270         }
00271         break;
00272 
00273        case vgui_MIDDLE:
00274         if (e.modifier == vgui_CTRL)
00275         {
00276           zoom( (curr_pos_norm[1] - last_pos_norm[1]) * scale_);
00277           last_process_ = ZOOM;
00278         }
00279         else
00280         {
00281           pan(curr_pos_norm, last_pos_norm, aspect_ratio);
00282           last_process_ = PAN;
00283         }
00284         break;
00285 
00286        default:
00287         break;
00288       }
00289 
00290       last_timestamp_ = e.timestamp;
00291     }
00292     if ( idle_enabled_ )
00293     {
00294       idle();
00295     }
00296   }
00297   set_clipping_planes();
00298   return bgui3d_fullviewer_tableau::handle(e);
00299 }
00300 
00301 
00302 //: Determine the scale of the scene
00303 void bgui3d_examiner_tableau::find_scale()
00304 {
00305   SoGetBoundingBoxAction action( get_viewport_region() );
00306   action.apply( scene_root_ );
00307   SbBox3f box = action.getBoundingBox();
00308 
00309   float dx, dy, dz;
00310   box.getSize(dx,dy,dz);
00311 
00312   scale_ = dx;
00313   if (dy > scale_) scale_ = dy;
00314   if (dz > scale_) scale_ = dz;
00315 }
00316 
00317 
00318 //: When idle, spin the scene based on the log
00319 bool bgui3d_examiner_tableau::idle()
00320 {
00321   if ( idle_enabled_ && last_process_ == IDLE && log_.size >2  )
00322   {
00323     SbVec2f p = log_.pos3 + (log_.pos1 - log_.pos3)/5.0;
00324     spin(p, log_.pos3);
00325     request_render();
00326   }
00327   return bgui3d_fullviewer_tableau::idle();
00328 }
00329 
00330 //----------------------------------------------------------------------------
00331 //: A vgui command used to toggle axis visibility
00332 class bgui3d_axis_visible_command : public vgui_command
00333 {
00334  public:
00335   bgui3d_axis_visible_command(bgui3d_examiner_tableau* tab)
00336    : bgui3d_examiner_tab(tab) {}
00337   void execute()
00338   {
00339     bool visible = bgui3d_examiner_tab->axis_visible();
00340     bgui3d_examiner_tab->set_axis_visible(!visible);
00341   }
00342 
00343   bgui3d_examiner_tableau *bgui3d_examiner_tab;
00344 };
00345 
00346 
00347 //----------------------------------------------------------------------------
00348 //: A vgui command used to toggle interaction type
00349 class bgui3d_seek_distance_command : public vgui_command
00350 {
00351  public:
00352   bgui3d_seek_distance_command(bgui3d_examiner_tableau* tab,
00353                                bgui3d_examiner_tableau::SeekDistance seek)
00354     : bgui3d_examiner_tab(tab), seek_distance(seek) {}
00355   void execute()
00356   {
00357     bgui3d_examiner_tab->set_seek_distance(seek_distance);
00358   }
00359 
00360   bgui3d_examiner_tableau *bgui3d_examiner_tab;
00361   bgui3d_examiner_tableau::SeekDistance seek_distance;
00362 };
00363 
00364 //: Builds a popup menu
00365 void bgui3d_examiner_tableau::get_popup(const vgui_popup_params& params,
00366                                         vgui_menu &menu)
00367 {
00368   bgui3d_fullviewer_tableau::get_popup(params, menu);
00369 
00370   vcl_string axis_item;
00371   if ( this->axis_visible() )
00372     axis_item = "Disable Axis";
00373   else
00374     axis_item = "Enable Axis";
00375 
00376   menu.add(axis_item, new bgui3d_axis_visible_command(this));
00377 
00378   vcl_string check_on = "[x]";
00379   vcl_string check_off = "[ ]";
00380 
00381   vgui_menu seek_menu;
00382   SeekDistance seek = seek_distance_;
00383 
00384   seek_menu.add(((seek==SEEK_FAR)?check_on:check_off) + " 3/4 ",
00385                 new bgui3d_seek_distance_command(this,SEEK_FAR));
00386   seek_menu.add(((seek==SEEK_HALF)?check_on:check_off) + " 1/2",
00387                 new bgui3d_seek_distance_command(this,SEEK_HALF));
00388   seek_menu.add(((seek==SEEK_NEAR)?check_on:check_off) + " 1/4",
00389                 new bgui3d_seek_distance_command(this,SEEK_NEAR));
00390   seek_menu.add(((seek==SEEK_ZERO)?check_on:check_off) + " 0 (focus)",
00391                 new bgui3d_seek_distance_command(this,SEEK_ZERO));
00392 
00393   menu.add( "Seek Distance", seek_menu );
00394 }
00395 
00396 //: Pan the camera
00397 void bgui3d_examiner_tableau::pan(const SbVec2f& currpos, const SbVec2f &prevpos, const float aspect_ratio)
00398 {
00399   if (scene_camera_ == NULL) return; // can happen for empty scenegraph
00400 
00401   if (currpos == prevpos) return; // useless invocation
00402 
00403   SbViewVolume vv = scene_camera_->getViewVolume(aspect_ratio);
00404   SbPlane panningplane = vv.getPlane(scene_camera_->focalDistance.getValue());
00405 
00406   vv = scene_camera_->getViewVolume(aspect_ratio);
00407   SbLine line;
00408   vv.projectPointToLine(currpos, line);
00409   SbVec3f current_planept;
00410   panningplane.intersect(line, current_planept);
00411   vv.projectPointToLine(prevpos, line);
00412   SbVec3f old_planept;
00413   panningplane.intersect(line, old_planept);
00414 
00415   scene_camera_->position = scene_camera_->position.getValue() - (current_planept - old_planept);
00416 }
00417 
00418 
00419 //: Zoom (actually dolly) the camera
00420 void bgui3d_examiner_tableau::zoom(float diffvalue)
00421 {
00422   if (scene_camera_ == NULL) return; // can happen for empty scenegraph
00423 
00424   SbVec3f direction;
00425   scene_camera_->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00426   scene_camera_->position = diffvalue*direction + scene_camera_->position.getValue();
00427   scene_camera_->focalDistance = -diffvalue*direction.length() + scene_camera_->focalDistance.getValue();
00428 }
00429 
00430 //: Spin the scene based on the current mouse position and the last mouse position
00431 void bgui3d_examiner_tableau::spin(const SbVec2f& currpos, const SbVec2f &prevpos)
00432 {
00433   spin_projector_->project(prevpos);
00434   SbRotation r;
00435   spin_projector_->projectAndGetRotation(currpos, r);
00436   r.invert();
00437   reorient_camera(r);
00438 }
00439 
00440 //: Reorient the camera based on specified rotation
00441 void bgui3d_examiner_tableau::reorient_camera(const SbRotation & rot)
00442 {
00443   SoCamera * cam = scene_camera_;
00444   if (cam == NULL) return;
00445 
00446   // Find global coordinates of focal point.
00447   SbVec3f direction;
00448   cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00449   SbVec3f focalpoint = cam->position.getValue() +
00450                   cam->focalDistance.getValue() * direction;
00451 
00452   // Set new orientation value by accumulating the new rotation.
00453   cam->orientation = rot * cam->orientation.getValue();
00454   SbVec3f lookat(0, 0, -1); // init to default view direction vector
00455 
00456   cam->orientation.getValue().multVec(lookat, lookat);
00457 
00458   // Reposition camera so we are still pointing at the same old focal point.
00459   cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
00460   SbVec3f distance = cam->focalDistance.getValue() * direction;
00461 
00462   cam->position = focalpoint - distance;
00463 }
00464 
00465 
00466 //: Update the log so that it can keep track of where the mouse has been
00467 void bgui3d_examiner_tableau::update_log(SbVec2f pos)
00468 {
00469   log_.size++;
00470   log_.pos3 = log_.pos2;
00471   log_.pos2 = log_.pos1;
00472   log_.pos1 = pos;
00473 }
00474 
00475 //: Reset the log
00476 void bgui3d_examiner_tableau::reset_log()
00477 {
00478   log_.size = 0;
00479 }
00480 
00481 
00482 static void
00483 seeksensorCB(void * data, SoSensor * s)
00484 {
00485   SbTime currenttime = SbTime::getTimeOfDay();
00486 
00487   bgui3d_examiner_tableau * thisp = (bgui3d_examiner_tableau *)data;
00488   SoTimerSensor * sensor = (SoTimerSensor *)s;
00489 
00490   float t = float((currenttime - sensor->getBaseTime()).getValue()) / 1.0f;
00491   if ((t > 1.0f) || (t + sensor->getInterval().getValue() > 1.0f)) t = 1.0f;
00492   SbBool end = (t == 1.0f);
00493 
00494   t = float(1 - vcl_cos(M_PI*t)) * 0.5f;
00495 
00496   thisp->camera_node()->position = thisp->fromPos_ + (thisp->toPos_ - thisp->fromPos_) * t;
00497   thisp->camera_node()->orientation = SbRotation::slerp( thisp->fromRot_, thisp->toRot_, t);
00498   if ( end )
00499     s->unschedule();
00500 }
00501 
00502 // Seek to a specified point on the screen
00503 void bgui3d_examiner_tableau::seek_to_point( SbVec2s pos )
00504 {
00505   if (! scene_camera_)
00506     return;
00507 
00508   // SoRayPickAction needs the viewport to have origin (0,0)
00509   SbViewportRegion v = get_viewport_region();
00510   v.setViewportPixels( SbVec2s(0,0), v.getViewportSizePixels() );
00511 
00512   SoRayPickAction rpaction( v );
00513   rpaction.setPoint( pos );
00514   rpaction.setRadius( 1 );
00515   rpaction.apply( user_scene_root_ );
00516 
00517   SoPickedPoint * picked = rpaction.getPickedPoint();
00518   if (!picked)
00519     return;
00520   float factor;
00521   switch (seek_distance_)
00522   {
00523    case SEEK_FAR:
00524     factor = 0.75f;
00525     break;
00526    case SEEK_HALF:
00527     factor = 0.5f;
00528     break;
00529    case SEEK_NEAR:
00530    default:
00531     factor = 0.25f;
00532     break;
00533    case SEEK_ZERO:
00534     factor = 0.0f;
00535     break;
00536   }
00537 
00538   SbVec3f hitpoint = picked->getPoint();
00539   SbVec3f cameraposition = scene_camera_->position.getValue();
00540   SbVec3f diff = hitpoint - cameraposition;
00541   fromPos_ = cameraposition;
00542   toPos_ = cameraposition += factor*diff;
00543 
00544   SbRotation camrot = scene_camera_->orientation.getValue();
00545   SbVec3f lookat(0, 0, -1); // init to default view direction vector
00546   camrot.multVec(lookat, lookat);
00547   SbRotation rot(lookat, diff);
00548 
00549   fromRot_ = camrot;
00550   toRot_ = camrot*rot;
00551 
00552   scene_camera_->focalDistance = diff.length()*(1.0f-factor);
00553   seekSensor_->setBaseTime( SbTime::getTimeOfDay() );
00554   seekSensor_->schedule();
00555 }
00556 
00557 
00558 //: Set the visibility of the axis cross
00559 void
00560 bgui3d_examiner_tableau::set_axis_visible(bool state)
00561 {
00562   axis_visible_ = state;
00563 }
00564 
00565 
00566 //: Return true if the axis cross is visible
00567 bool
00568 bgui3d_examiner_tableau::axis_visible() const
00569 {
00570   return axis_visible_;
00571 }
00572 
00573 
00574 //: Changes the distance the viewer goes when seeking
00575 void
00576 bgui3d_examiner_tableau::set_seek_distance( SeekDistance seek )
00577 {
00578   seek_distance_ = seek;
00579 }
00580 
00581 
00582 //: Render the scene graph (called on draw events)
00583 bool
00584 bgui3d_examiner_tableau::render()
00585 {
00586   // call the super class method
00587   bool result = bgui3d_fullviewer_tableau::render();
00588   if (!result)
00589     return false;
00590 
00591   if (axis_visible_)
00592     this->draw_axis_cross();
00593 
00594   return true;
00595 }
00596 
00597 
00598 void
00599 bgui3d_examiner_tableau::draw_axis_cross()
00600 {
00601   // FIXME: convert this to a superimposition scenegraph instead of
00602   // OpenGL calls. 20020603 mortene.
00603 
00604   // Store GL state.
00605   glPushAttrib(GL_ALL_ATTRIB_BITS);
00606   GLfloat depthrange[2];
00607   glGetFloatv(GL_DEPTH_RANGE, depthrange);
00608   GLdouble projectionmatrix[16];
00609   glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
00610 
00611   glDepthFunc(GL_ALWAYS);
00612   glDepthMask(GL_TRUE);
00613   glDepthRange(0, 0);
00614   glEnable(GL_DEPTH_TEST);
00615   glDisable(GL_LIGHTING);
00616   glEnable(GL_COLOR_MATERIAL);
00617   glDisable(GL_BLEND); // Kills transparency.
00618 
00619   // Set the viewport in the OpenGL canvas. Dimensions are calculated
00620   // as a percentage of the total canvas size.
00621   GLint vp[4];
00622   glGetIntegerv(GL_VIEWPORT, vp);
00623   const int view_x = vp[2];
00624   const int view_y = vp[3];
00625   const int pixelarea = int(0.25f * vcl_min(view_x, view_y));
00626   // lower right of canvas
00627   glViewport(vp[0]+vp[2] - pixelarea, vp[1], pixelarea, pixelarea);
00628 
00629   // Set up the projection matrix.
00630   glMatrixMode(GL_PROJECTION);
00631   glLoadIdentity();
00632 
00633   const float NEARVAL = 0.1f;
00634   const float FARVAL = 10.0f;
00635   const float dim = NEARVAL * float(vcl_tan(M_PI / 8.0)); // FOV is 45 (45/360 = 1/8)
00636   glFrustum(-dim, dim, -dim, dim, NEARVAL, FARVAL);
00637 
00638   // Set up the model matrix.
00639   glMatrixMode(GL_MODELVIEW);
00640   glPushMatrix();
00641   SbMatrix mx;
00642   SoCamera * cam = this->camera_node();
00643 
00644   // If there is no camera (like for an empty scene, for instance),
00645   // just use an identity rotation.
00646   if (cam) { mx = cam->orientation.getValue(); }
00647   else { mx = SbMatrix::identity(); }
00648 
00649   mx = mx.inverse();
00650   mx[3][2] = -3.5; // Translate away from the projection point (along z axis).
00651   glLoadMatrixf((float *)mx);
00652 
00653   // Find unit vector end points.
00654   SbMatrix px;
00655   glGetFloatv(GL_PROJECTION_MATRIX, (float *)px);
00656   SbMatrix comb = mx.multRight(px);
00657 
00658   SbVec3f xpos;
00659   comb.multVecMatrix(SbVec3f(1,0,0), xpos);
00660   xpos[0] = (1 + xpos[0]) * view_x/2;
00661   xpos[1] = (1 + xpos[1]) * view_y/2;
00662   SbVec3f ypos;
00663   comb.multVecMatrix(SbVec3f(0,1,0), ypos);
00664   ypos[0] = (1 + ypos[0]) * view_x/2;
00665   ypos[1] = (1 + ypos[1]) * view_y/2;
00666   SbVec3f zpos;
00667   comb.multVecMatrix(SbVec3f(0,0,1), zpos);
00668   zpos[0] = (1 + zpos[0]) * view_x/2;
00669   zpos[1] = (1 + zpos[1]) * view_y/2;
00670 
00671   // Render the cross.
00672   {
00673     glLineWidth(2.0);
00674 
00675     enum { XAXIS, YAXIS, ZAXIS };
00676     int idx[3] = { XAXIS, YAXIS, ZAXIS };
00677     float val[3] = { xpos[2], ypos[2], zpos[2] };
00678 
00679     // Bubble sort.. :-}
00680     if (val[0] < val[1]) { vcl_swap(val[0], val[1]); vcl_swap(idx[0], idx[1]); }
00681     if (val[1] < val[2]) { vcl_swap(val[1], val[2]); vcl_swap(idx[1], idx[2]); }
00682     if (val[0] < val[1]) { vcl_swap(val[0], val[1]); vcl_swap(idx[0], idx[1]); }
00683     assert((val[0] >= val[1]) && (val[1] >= val[2])); // Just checking..
00684 
00685     for (int i=0; i < 3; i++) {
00686       glPushMatrix();
00687       if (idx[i] == XAXIS) {                     // X axis.
00688         glColor3f(0.500f, 0.125f, 0.125f);
00689       }
00690       else if (idx[i] == YAXIS) {                // Y axis.
00691         glRotatef(90, 0, 0, 1);
00692         glColor3f(0.125f, 0.500f, 0.125f);
00693       }
00694       else {                                     // Z axis.
00695         glRotatef(-90, 0, 1, 0);
00696         glColor3f(0.125f, 0.125f, 0.500f);
00697       }
00698       this->draw_arrow();
00699       glPopMatrix();
00700     }
00701   }
00702 
00703   // Render axis notation letters ("X", "Y", "Z").
00704   glMatrixMode(GL_PROJECTION);
00705   glLoadIdentity();
00706   glOrtho(0, view_x, 0, view_y, -1, 1);
00707 
00708   glMatrixMode(GL_MODELVIEW);
00709   glLoadIdentity();
00710 
00711   GLint unpack;
00712   glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
00713   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00714 
00715   glColor3fv(SbVec3f(0.8f, 0.8f, 0.0f).getValue());
00716 
00717   glRasterPos2d(xpos[0], xpos[1]);
00718   glBitmap(8, 7, 0, 0, 0, 0, xbmp);
00719   glRasterPos2d(ypos[0], ypos[1]);
00720   glBitmap(8, 7, 0, 0, 0, 0, ybmp);
00721   glRasterPos2d(zpos[0], zpos[1]);
00722   glBitmap(8, 7, 0, 0, 0, 0, zbmp);
00723 
00724   glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
00725   glPopMatrix();
00726 
00727   // Reset original state.
00728 
00729   // FIXME: are these 3 lines really necessary, as we push
00730   // GL_ALL_ATTRIB_BITS at the start? 20000604 mortene.
00731   glDepthRange(depthrange[0], depthrange[1]);
00732   glMatrixMode(GL_PROJECTION);
00733   glLoadMatrixd(projectionmatrix);
00734 
00735   glPopAttrib();
00736 }
00737 
00738 //: Draw an arrow for the axis representation directly through OpenGL.
00739 void
00740 bgui3d_examiner_tableau::draw_arrow()
00741 {
00742   glBegin(GL_LINES);
00743   glVertex3f(0.0f, 0.0f, 0.0f);
00744   glVertex3f(1.0f, 0.0f, 0.0f);
00745   glEnd();
00746   glDisable(GL_CULL_FACE);
00747   glBegin(GL_TRIANGLES);
00748   glVertex3f(1.0f, 0.0f, 0.0f);
00749   glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f);
00750   glVertex3f(1.0f - 1.0f / 3.0f, -0.5f / 4.0f, 0.0f);
00751   glVertex3f(1.0f, 0.0f, 0.0f);
00752   glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, +0.5f / 4.0f);
00753   glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, -0.5f / 4.0f);
00754   glEnd();
00755   glBegin(GL_QUADS);
00756   glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f);
00757   glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, +0.5f / 4.0f);
00758   glVertex3f(1.0f - 1.0f / 3.0f, -0.5f / 4.0f, 0.0f);
00759   glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, -0.5f / 4.0f);
00760   glEnd();
00761 }
00762