scene_view.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <GL/gl.h>
00021 
00022 #include <archon/math/vector.H>
00023 #include <archon/util/time.H>
00024 #include <archon/util/thread.H>
00025 #include <archon/util/window.H>
00026 #include <archon/util/keyboard.H>
00027 #include <archon/util/mouse.H>
00028 #include <archon/util/color.H>
00029 
00030 #include "engine.H"
00031 #include "sceneloader.H"
00032 #include "scene_view.H"
00033 
00034 #if ! defined M_PI
00035 #define M_E           2.7182818284590452353602874713526625  /* e */
00036 #define M_LOG2E       1.4426950408889634073599246810018922  /* log_2 e */
00037 #define M_LOG10E      0.4342944819032518276511289189166051  /* log_10 e */
00038 #define M_LN2         0.6931471805599453094172321214581766  /* log_e 2 */
00039 #define M_LN10        2.3025850929940456840179914546843642  /* log_e 10 */
00040 #define M_PI          3.1415926535897932384626433832795029  /* pi */
00041 #define M_PI_2        1.5707963267948966192313216916397514  /* pi/2 */
00042 #define M_PI_4        0.7853981633974483096156608458198757  /* pi/4 */
00043 #define M_1_PI        0.3183098861837906715377675267450287  /* 1/pi */
00044 #define M_2_PI        0.6366197723675813430755350534900574  /* 2/pi */
00045 #define M_2_SQRTPI    1.1283791670955125738961589031215452  /* 2/sqrt(pi) */
00046 #define M_SQRT2       1.4142135623730950488016887242096981  /* sqrt(2) */
00047 #define M_SQRT1_2     0.7071067811865475244008443621048490  /* 1/sqrt(2) */
00048 #endif
00049 
00050 namespace Archon
00051 {
00052   using namespace Math;
00053   using namespace Utilities;
00054 
00055   namespace Raytracer
00056   {
00057     class WindowQuitHandler: public Window::WindowHandler
00058     {
00059       bool &quitFlag;
00060 
00061     public:
00062       WindowQuitHandler(bool &quitFlag): quitFlag(quitFlag) {}
00063 
00064       void quit()
00065       {
00066         quitFlag = true;
00067       }
00068     };
00069 
00070     void drawDepthMarker(double depth)
00071     {
00072       const double d = 20;
00073 
00074       glEnable(GL_POINT_SMOOTH);
00075       glEnable(GL_LINE_SMOOTH);
00076       glPointSize(1);
00077       glLineWidth(1);
00078       glColor3f(1, 1, 1);
00079 
00080       glBegin(GL_POINTS);
00081       glVertex3f(0, 0, -depth);
00082       glEnd();
00083 
00084       for(int i=0; i<10; ++i)
00085       {
00086         glBegin(GL_LINE_LOOP);
00087 
00088         glVertex3f(-d*i, -d*i, -depth);
00089         glVertex3f(-d*i, +d*i, -depth);
00090         glVertex3f(+d*i, +d*i, -depth);
00091         glVertex3f(+d*i, -d*i, -depth);
00092 
00093         glEnd();
00094       }
00095     }
00096 
00097     static const char *sensorMouseCursorData[] =
00098     {
00099       //width height num_colors chars_per_pixel
00100       "    32    32        3            1",
00101       //colors
00102       "X c #000000",
00103       ". c #ffffff",
00104       "  c None",
00105       //pixels
00106       "                                ",
00107       "                                ",
00108       "                                ",
00109       "                                ",
00110       "                                ",
00111       "                                ",
00112       "        XX             XX       ",
00113       "       X..X           X..X      ",
00114       "       X...X         X...X      ",
00115       "        X...X       X...X       ",
00116       "         X...X     X...X        ",
00117       "          X...X   X...X         ",
00118       "           X...X X...X          ",
00119       "            X..X X..X           ",
00120       "             XX   XX            ",
00121       "                                ",
00122       "             XX   XX            ",
00123       "            X..X X..X           ",
00124       "           X...X X...X          ",
00125       "          X...X   X...X         ",
00126       "         X...X     X...X        ",
00127       "        X...X       X...X       ",
00128       "       X...X         X...X      ",
00129       "       X..X           X..X      ",
00130       "        XX             XX       ",
00131       "                                ",
00132       "                                ",
00133       "                                ",
00134       "                                ",
00135       "                                ",
00136       "                                ",
00137       "                                ",
00138       "16,15"
00139     };
00140 
00141     static const char *overSensorMouseCursorData[] =
00142     {
00143       //width height num_colors chars_per_pixel
00144       "    32    32        3            1",
00145       //colors
00146       "X c #000000",
00147       ". c #ffffff",
00148       "  c None",
00149       //pixels
00150       "                                ",
00151       "                                ",
00152       "                                ",
00153       "                                ",
00154       "                                ",
00155       "              XXXXX             ",
00156       "            XX.....XX           ",
00157       "          XX..XXXXX..XX         ",
00158       "         X..X      XX..X        ",
00159       "        X..X         X..X       ",
00160       "        X.X           X.X       ",
00161       "       X.X             X.X      ",
00162       "       X.X             X.X      ",
00163       "      X.X       X       X.X     ",
00164       "      X.X      X.X      X.X     ",
00165       "      X.X     X...X     X.X     ",
00166       "      X.X      X.X      X.X     ",
00167       "      X.X       X       X.X     ",
00168       "       X.X             X.X      ",
00169       "       X.X             X.X      ",
00170       "        X.X           X.X       ",
00171       "        X..X         X..X       ",
00172       "         X..XX     XX..X        ",
00173       "          XX..XXXXX..XX         ",
00174       "            XX.....XX           ",
00175       "              XXXXX             ",
00176       "                                ",
00177       "                                ",
00178       "                                ",
00179       "                                ",
00180       "                                ",
00181       "                                ",
00182       "16,15"
00183     };
00184 
00185     struct ViewState
00186     {
00187       bool showDepthMarker;
00188       double markerDepth;    
00189 
00190       KeyboardEvents::Dispatcher *keybordDispatcher;
00191       MouseEvents::Dispatcher *mouseDispatcher;
00192       Window *window;
00193       View *view;
00194       Vector3 trackballPos;
00195       double trackballRadius;
00196       bool sensorMode;
00197       bool sensorUpdate;
00198       Ref<Window::MouseCursor> sensorMouseCursor;
00199       Ref<Window::MouseCursor> overSensorMouseCursor;
00200       bool pointingDeviceActive;
00201 
00202       ViewState(KeyboardEvents::Dispatcher *k,
00203                 MouseEvents::Dispatcher *m,
00204                 Window *w,
00205                 View *v):
00206         showDepthMarker(false),
00207         markerDepth(500),
00208         keybordDispatcher(k),
00209         mouseDispatcher(m),
00210         window(w),
00211         view(v),
00212         trackballRadius((window->getWidth() < window->getHeight() ? window->getWidth() : window->getHeight())/2-1),
00213         sensorMode(false),
00214         sensorUpdate(false),
00215         sensorMouseCursor(w->newMouseCursor(sensorMouseCursorData)),
00216         overSensorMouseCursor(w->newMouseCursor(overSensorMouseCursorData)),
00217         pointingDeviceActive(false)
00218       {}
00219 
00224       Vector3 findTrackballPos(unsigned x, unsigned y)
00225       {
00226         Vector3 p(x-window->getWidth()/2.0, window->getHeight()/2.0-y, 0);
00227         p /= trackballRadius;
00228         double s = p.squareSum();
00229 
00230         // Clamp to sphere
00231         if(s>1)
00232         {
00233           p /= sqrt(s);
00234           s = 1;
00235         }
00236 
00237         p[2] = sqrt(1-s);
00238         return p;
00239       }
00240 
00241       void depthMarkerModeOn()
00242       {
00243         showDepthMarker = true;
00244         mouseDispatcher->setMode(4);
00245       }
00246 
00247       void depthMarkerModeOff()
00248       {
00249         showDepthMarker = false;
00250         mouseDispatcher->setMode(0);
00251       }
00252 
00253       void trackballMode(unsigned x, unsigned y, bool press)
00254       {
00255         mouseDispatcher->setMode(press ? 1 : 0);
00256         trackballPos = findTrackballPos(x, y);
00257       }
00258 
00259       void trackballDepthMode(unsigned x, unsigned y, bool press)
00260       {
00261         if(press)
00262         {
00263           if(showDepthMarker)
00264           {
00265             showDepthMarker = false;
00266             mouseDispatcher->setMode(0);
00267           }
00268           else
00269           {
00270             showDepthMarker = true;
00271             mouseDispatcher->setMode(4);
00272           }
00273         }
00274       }
00275 
00276       void trackballChangeDepthMode(unsigned x, unsigned y, bool press)
00277       {
00278         mouseDispatcher->setMode(press ? 5 : 4);
00279       }
00280 
00281       void travelMode(unsigned, unsigned, bool press)
00282       {
00283         mouseDispatcher->setMode(press ? 2 : 0);
00284       }
00285 
00286       void yawAndPitchMode(unsigned, unsigned, bool press)
00287       {
00288         mouseDispatcher->setMode(press ? 3 : 0);
00289       }
00290 
00291       void changeDepth(unsigned xAbs, unsigned yAbs, int xRel, int yRel)
00292       {
00293         markerDepth += yRel;
00294       }
00295 
00300       void trackballRoll(unsigned xAbs, unsigned yAbs, int xRel, int yRel)
00301       {
00302         Vector3 p = findTrackballPos(xAbs, yAbs);
00303 
00304         if(p == trackballPos) return;
00305 
00306         Vector3 d = Vector3(0, 0, -markerDepth);
00307         view->coordSystem.translate(d);
00308         view->coordSystem.basis.rotate(Rotation3(normalize(trackballPos * p), -2*acos(dot(trackballPos, p))));
00309         view->coordSystem.translate(-d);
00310         trackballPos = p;
00311       }
00312 
00313       void travel(unsigned xAbs, unsigned yAbs, int xRel, int yRel)
00314       {
00315         markerDepth += yRel;
00316         view->coordSystem.translate(Vector3(0, 0, yRel));
00317       }
00318 
00319       void yawAndPitch(unsigned xAbs, unsigned yAbs, int xRel, int yRel)
00320       {
00321         view->coordSystem.basis.yaw(M_PI*xRel/1000);
00322         view->coordSystem.basis.pitch(M_PI*yRel/1000);
00323       }
00324 
00325       void sensorModeOn()
00326       {
00327         mouseDispatcher->setMode(6);
00328         mouseDispatcher->setMulticlickLimit(0, 1);
00329         sensorMode = true;
00330         window->setMouseCursor(sensorMouseCursor);
00331         sensorUpdate = true;
00332       }
00333 
00334       void sensorModeOff()
00335       {
00336         mouseDispatcher->setMode(0);
00337         mouseDispatcher->setMulticlickLimit(0, 2);
00338         sensorMode = false;
00339         window->setDefaultMouseCursor();
00340         sensorUpdate = true;
00341       }
00342 
00343       void sensorTrack(unsigned, unsigned, int, int)
00344       {
00345         sensorUpdate = true;
00346       }
00347 
00348       void sensorActivate(unsigned, unsigned, bool press)
00349       {
00350         pointingDeviceActive = press;
00351         sensorUpdate = true;
00352       }
00353     };
00354 
00355 
00356     void viewScene(X3D::Scene *scene,
00357                    string viewPointName,
00358                    View *view, const Vector4 &backgroundColor,
00359                    int xResolution, int yResolution,
00360                    bool fullScreen,
00361                    bool showLightSources,
00362                    bool headLight,
00363                    int subdivisionX,
00364                    int subdivisionY,
00365                    int frameRate,
00366                    Logger *logger)
00367     {
00368       const double nearClippingDist = 1;
00369       const double farClippingDist = 2000;
00370 
00371       {
00372         vector<View> views;
00373         get_scene(scene, 0, 0, &views, 0, logger);
00374 
00375         if(viewPointName.empty())
00376         {
00377           if(views.size()) *view = views[0];
00378         }
00379         else
00380         {
00381           unsigned i = 0;
00382           for(;i<views.size(); ++i) if(viewPointName == views[i].name)
00383           {
00384             *view = views[i];
00385             break;
00386           }
00387           if(i == views.size())
00388           {
00389             logger->log("Viewpoint '" + viewPointName + "' is unknown");
00390             if(views.size()) *view = views[0];
00391           }
00392         }
00393       }
00394 
00395       bool quit = false;
00396       KeyboardEvents::Dispatcher kDisp(1);
00397       MouseEvents::Dispatcher mDisp(3, 7, 2);
00398       WindowQuitHandler windowQuitHandler(quit);
00399       Window window(xResolution, yResolution, 32, fullScreen, true,
00400                     &kDisp, &mDisp, &windowQuitHandler);
00401 
00402       window.discardEventQueue();
00403 
00404       ViewState state(&kDisp, &mDisp, &window, view);
00405 
00406       KeyboardEvents::MethodCall<ViewState>
00407         kDepthMarker(&state,
00408                      &Raytracer::ViewState::depthMarkerModeOn,
00409                      &Raytracer::ViewState::depthMarkerModeOff);
00410       KeyboardEvents::VarAssign<bool> kQuit(quit, true, true);
00411       KeyboardEvents::MethodCall<ViewState> kSensor(&state, &ViewState::sensorModeOn, &ViewState::sensorModeOff);
00412       KeyboardEvents::Toggle kHeadLight(headLight);
00413       KeyboardEvents::Toggle kShowLightSources(showLightSources);
00414 
00415       kDisp.setHandler(key_z, &kDepthMarker, 0);
00416       kDisp.setHandler(key_escape, &kQuit, 0);
00417       kDisp.setHandler(key_space, &kSensor, 0);
00418       kDisp.setHandler(key_h, &kHeadLight, 0);
00419       kDisp.setHandler(key_l, &kShowLightSources, 0);
00420 
00421       MouseEvents::MotionMethod<ViewState>
00422         mTrackballRoll(&state, &Raytracer::ViewState::trackballRoll);
00423       MouseEvents::MotionMethod<ViewState>
00424         mTravel(&state, &Raytracer::ViewState::travel);
00425       MouseEvents::MotionMethod<ViewState>
00426         mYawAndPitch(&state, &Raytracer::ViewState::yawAndPitch);
00427       MouseEvents::MotionMethod<ViewState>
00428         mChangeDepth(&state, &Raytracer::ViewState::changeDepth);
00429       MouseEvents::MotionMethod<ViewState>
00430         mSensorTrack(&state, &Raytracer::ViewState::sensorTrack);
00431       MouseEvents::ButtonMethod<ViewState>
00432         mTrackballMode(&state, &Raytracer::ViewState::trackballMode);
00433       MouseEvents::ButtonMethod<ViewState>
00434         mTrackballDepthMode(&state, &Raytracer::ViewState::trackballDepthMode);
00435       MouseEvents::ButtonMethod<ViewState>
00436         mTrackballChangeDepthMode(&state, &Raytracer::ViewState::trackballChangeDepthMode);
00437       MouseEvents::ButtonMethod<ViewState>
00438         mTravelMode(&state, &Raytracer::ViewState::travelMode);
00439       MouseEvents::ButtonMethod<ViewState>
00440         mYawAndPitchMode(&state, &Raytracer::ViewState::yawAndPitchMode);
00441       MouseEvents::ButtonMethod<ViewState>
00442         mActivateSensor(&state, &Raytracer::ViewState::sensorActivate);
00443 
00444       mDisp.setMotionHandler(&mTrackballRoll, 1);
00445       mDisp.setMotionHandler(&mTravel, 2);
00446       mDisp.setMotionHandler(&mYawAndPitch, 3);
00447       mDisp.setMotionHandler(&mChangeDepth, 5);
00448       mDisp.setMotionHandler(&mSensorTrack, 6);
00449       mDisp.setMulticlickLimit(0, 2);
00450       mDisp.setButtonHandler(0, &mTrackballMode,            0, 1);
00451       mDisp.setButtonHandler(0, &mTrackballDepthMode,       0, 2);
00452       mDisp.setButtonHandler(0, &mTrackballChangeDepthMode, 4, 1);
00453       mDisp.setButtonHandler(0, &mTrackballDepthMode,       4, 2);
00454       mDisp.setButtonHandler(1, &mTravelMode,               0, 1);
00455       mDisp.setButtonHandler(2, &mYawAndPitchMode,          0, 1);
00456       mDisp.setButtonHandler(0, &mActivateSensor,           6, 1);
00457 
00458       const double aspect = double(xResolution) / yResolution;
00459       const double viewPlaneRadius = nearClippingDist*tan(view->fieldOfView/2);
00460 
00461       Vector2 viewPlane;
00462 
00463       if(aspect > 1)
00464       {
00465         viewPlane[0] = viewPlaneRadius * aspect;
00466         viewPlane[1] = viewPlaneRadius;
00467       }
00468       else
00469       {
00470         viewPlane[0] = viewPlaneRadius;
00471         viewPlane[1] = viewPlaneRadius / aspect;
00472       }
00473 
00474       glViewport(0, 0, xResolution, yResolution);
00475       glMatrixMode(GL_PROJECTION);
00476       glLoadIdentity();
00477       glFrustum(-viewPlane[0], viewPlane[0], -viewPlane[1], viewPlane[1],
00478                 nearClippingDist, farClippingDist);
00479       glMatrixMode(GL_MODELVIEW);
00480       glClearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], backgroundColor[3]);
00481       glDepthFunc(GL_LESS);
00482       glEnable(GL_DEPTH_TEST);                    
00483 
00484       X3D::Viewer viewer(scene, uriToComponentMap, subdivisionX, subdivisionY);
00485       bool wasOver = false;
00486 
00487       Time timePerFrame;
00488       timePerFrame.setNanoSeconds(1000000000l/frameRate);
00489 
00490       while(!quit)
00491       {
00492         Time start = Time::now();
00493 
00494         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
00495 
00496         glDisable(GL_LIGHTING);
00497         glDisable(GL_TEXTURE_2D);
00498 
00499         if(state.showDepthMarker)
00500         {
00501           glLoadIdentity();
00502           drawDepthMarker(state.markerDepth);
00503         }
00504 
00505         if(state.sensorMode && state.sensorUpdate)
00506         {
00507           Vector3 mousePoint;
00508           mousePoint[0] = viewPlane[0] * (2.0 * window.getMouseX() / xResolution - 1);
00509           mousePoint[1] = viewPlane[1] * (-2.0 * window.getMouseY() / yResolution + 1);
00510           mousePoint[2] = -nearClippingDist;
00511 
00512           bool isOver = viewer.view(view->coordSystem, headLight, showLightSources,
00513                                     state.pointingDeviceActive, &mousePoint);
00514           if(isOver && !wasOver)
00515             window.setMouseCursor(state.overSensorMouseCursor);
00516           else if(!isOver && wasOver)
00517             window.setMouseCursor(state.sensorMouseCursor);
00518           wasOver = isOver;
00519 
00520           state.sensorUpdate = false;
00521         }
00522         else viewer.view(view->coordSystem, headLight, showLightSources,
00523                          state.pointingDeviceActive, 0);
00524 
00525         window.swapBuffers();
00526         window.executeEventQueue(Time::now().getMilliSeconds());
00527 
00528         Time used = Time::now()-start;
00529         Thread::sleep(timePerFrame-used);
00530       }
00531     }
00532   }
00533 }

Generated on Sun Jul 30 22:55:41 2006 for Archon by  doxygen 1.4.4