00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00036 #define M_LOG2E 1.4426950408889634073599246810018922
00037 #define M_LOG10E 0.4342944819032518276511289189166051
00038 #define M_LN2 0.6931471805599453094172321214581766
00039 #define M_LN10 2.3025850929940456840179914546843642
00040 #define M_PI 3.1415926535897932384626433832795029
00041 #define M_PI_2 1.5707963267948966192313216916397514
00042 #define M_PI_4 0.7853981633974483096156608458198757
00043 #define M_1_PI 0.3183098861837906715377675267450287
00044 #define M_2_PI 0.6366197723675813430755350534900574
00045 #define M_2_SQRTPI 1.1283791670955125738961589031215452
00046 #define M_SQRT2 1.4142135623730950488016887242096981
00047 #define M_SQRT1_2 0.7071067811865475244008443621048490
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
00100 " 32 32 3 1",
00101
00102 "X c #000000",
00103 ". c #ffffff",
00104 " c None",
00105
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
00144 " 32 32 3 1",
00145
00146 "X c #000000",
00147 ". c #ffffff",
00148 " c None",
00149
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
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 }