00001 #include <X11/Xlib.h>
00002
00003 #include <GL/gl.h>
00004 #include <GL/glu.h>
00005
00006 #include <string>
00007 #include <iostream>
00008
00009 #include <archon/math/vector.H>
00010
00011 #include <archon/util/options.H>
00012 #include <archon/util/text.H>
00013 #include <archon/util/thread.H>
00014
00015 #include <archon/display/window.H>
00016 #include <archon/display/context.H>
00017
00018 #include <archon/render/exception.H>
00019 #include <archon/render/conductor.H>
00020
00021 namespace Archon
00022 {
00023 namespace Render
00024 {
00025 namespace Test
00026 {
00027 bool opt_help = false;
00028 int opt_viewMode = 2;
00029 double opt_frameRate = 30;
00030 double opt_windowSize = 1;
00031 double opt_detailLevel = 1;
00032 bool opt_directRendering = true;
00033
00034 unsigned adjust(unsigned val, unsigned min, double f)
00035 {
00036 return std::max(static_cast<unsigned>(f*val), min);
00037 }
00038
00039 unsigned adjustDetail(unsigned val, unsigned min)
00040 {
00041 return adjust(val, min, opt_detailLevel);
00042 }
00043
00044 Ref<Conductor> oneThreadMono(Ref<Display::Visual> visual, Ref<Renderer> renderer)
00045 {
00046 Ref<Display::Window> window = visual->newWindow(100, 100,
00047 adjust(1000, 10, opt_windowSize),
00048 adjust(1000, 10, opt_windowSize),
00049 "One thread monoscopic view");
00050
00051 Ref<View> view = View::create(renderer);
00052
00053 Ref<Viewport> viewport = Viewport::create(view);
00054 Ref<Screen > screen = Screen ::create(view);
00055 Ref<Eye > eye = Eye ::create(view);
00056 Ref<Clip > clip = Clip ::create(view);
00057
00058 screen->set(Vector3(0, 0, -2),
00059 Vector3(1, 0, 0), Vector3(0, 1, 0), 1, 1);
00060
00061 Ref<Conductor> conductor = Conductor::create();
00062 Ref<Pipe> pipe = conductor->addPipe(visual);
00063 pipe->addChannel(conductor, view, window,
00064 viewport, screen, eye, clip);
00065 return conductor;
00066 }
00067
00068
00069 Ref<Conductor> twoThreadMono(Ref<Display::Visual> visual, Ref<Renderer> renderer)
00070 {
00071 Ref<Display::Window> window = visual->newWindow(100, 100,
00072 adjust(1000, 10, opt_windowSize),
00073 adjust(1000, 10, opt_windowSize),
00074 "Two thread monoscopic view");
00075
00076 Ref<View> view = View::create(renderer);
00077
00078 Ref<Viewport> leftViewport = Viewport::create(view);
00079 Ref<Viewport> rightViewport = Viewport::create(view);
00080 Ref<Screen> leftScreen = Screen::create(view);
00081 Ref<Screen> rightScreen = Screen::create(view);
00082 Ref<Eye> eye = Eye::create(view);
00083 Ref<Clip> clip = Clip::create(view);
00084
00085 leftViewport->set(0, 0, 0.5, 1);
00086 rightViewport->set(0.5, 0, 0.5, 1);
00087
00088 leftScreen->set(Vector3(-0.5, 0, -2),
00089 Vector3(1, 0, 0), Vector3(0, 1, 0), 0.5, 1);
00090 rightScreen->set(Vector3(0.5, 0, -2),
00091 Vector3(1, 0, 0), Vector3(0, 1, 0), 0.5, 1);
00092
00093 Ref<Conductor> conductor = Conductor::create();
00094
00095 Ref<Pipe> leftPipe = conductor->addPipe(visual);
00096 Ref<Pipe> rightPipe = conductor->addPipe(visual);
00097
00098 leftPipe->addChannel(conductor, view, window,
00099 leftViewport, leftScreen, eye, clip);
00100 rightPipe->addChannel(conductor, view, window,
00101 rightViewport, rightScreen, eye, clip);
00102
00103 return conductor;
00104 }
00105
00106
00107 Ref<Conductor> oneThreadPaperStereo(Ref<Display::Visual> visual, Ref<Renderer> renderer)
00108 {
00109 Ref<Display::Window> window = visual->newWindow(100, 100,
00110 adjust(1500, 10, opt_windowSize),
00111 adjust(750, 10, opt_windowSize),
00112 "One thread paper stereo: Use a piece of paper");
00113
00114 Ref<View> view = View::create(renderer);
00115
00116 Ref<Viewport> leftViewport = Viewport::create(view);
00117 Ref<Viewport> rightViewport = Viewport::create(view);
00118 Ref<Screen> leftScreen = Screen::create(view);
00119 Ref<Screen> rightScreen = Screen::create(view);
00120 Ref<Eye> leftEye = Eye::create(view);
00121 Ref<Eye> rightEye = Eye::create(view);
00122 Ref<Clip> clip = Clip::create(view);
00123
00124 leftViewport->set(0, 0, 0.5, 1);
00125 rightViewport->set(0.5, 0, 0.5, 1);
00126
00127 leftEye->set(Vector3(-1.5/7, 0, 0));
00128 rightEye->set(Vector3(+1.5/7, 0, 0));
00129
00130 leftScreen->set(Vector3(-0.5, 0, -2),
00131 Vector3(1, 0, 0), Vector3(0, 1, 0), 0.5, 0.5);
00132 rightScreen->set(Vector3(0.5, 0, -2),
00133 Vector3(1, 0, 0), Vector3(0, 1, 0), 0.5, 0.5);
00134
00135 Ref<Conductor> conductor = Conductor::create();
00136
00137 Ref<Pipe> pipe = conductor->addPipe(visual);
00138
00139 pipe->addChannel(conductor, view, window,
00140 leftViewport, leftScreen, leftEye, clip);
00141 pipe->addChannel(conductor, view, window,
00142 rightViewport, rightScreen, rightEye, clip);
00143
00144 return conductor;
00145 }
00146
00147 Ref<Conductor> twoThreadPaperStereo(Ref<Display::Visual> visual, Ref<Renderer> renderer)
00148 {
00149 Ref<Display::Window> window = visual->newWindow(100, 100,
00150 adjust(1500, 10, opt_windowSize),
00151 adjust(750, 10, opt_windowSize),
00152 "Two thread paper stereo: Use a piece of paper");
00153
00154 Ref<View> view = View::create(renderer);
00155
00156 Ref<Viewport> leftViewport = Viewport::create(view);
00157 Ref<Viewport> rightViewport = Viewport::create(view);
00158 Ref<Screen> leftScreen = Screen::create(view);
00159 Ref<Screen> rightScreen = Screen::create(view);
00160 Ref<Eye> leftEye = Eye::create(view);
00161 Ref<Eye> rightEye = Eye::create(view);
00162 Ref<Clip> clip = Clip::create(view);
00163
00164 leftViewport->set(0, 0, 0.5, 1);
00165 rightViewport->set(0.5, 0, 0.5, 1);
00166
00167 leftEye->set(Vector3(-1.5/7, 0, 0));
00168 rightEye->set(Vector3(+1.5/7, 0, 0));
00169
00170 leftScreen->set(Vector3(-0.5, 0, -2),
00171 Vector3(1, 0, 0), Vector3(0, 1, 0), 0.5, 0.5);
00172 rightScreen->set(Vector3(0.5, 0, -2),
00173 Vector3(1, 0, 0), Vector3(0, 1, 0), 0.5, 0.5);
00174
00175 Ref<Conductor> conductor = Conductor::create();
00176
00177 Ref<Pipe> leftPipe = conductor->addPipe(visual);
00178 Ref<Pipe> rightPipe = conductor->addPipe(visual);
00179
00180 leftPipe->addChannel(conductor, view, window,
00181 leftViewport, leftScreen, leftEye, clip);
00182 rightPipe->addChannel(conductor, view, window,
00183 rightViewport, rightScreen, rightEye, clip);
00184
00185 return conductor;
00186 }
00187
00188 Ref<Conductor> splitScreenStereo(Ref<Display::Visual> visual, Ref<Renderer> renderer)
00189 {
00190 Ref<Display::Window> window = visual->newWindow(100, 100,
00191 adjust(1000, 10, opt_windowSize),
00192 adjust(1000, 10, opt_windowSize),
00193 "Split screen stereoscopic view");
00194
00195 Ref<View> view = View::create(renderer);
00196
00197 Ref<Viewport> leftViewport = Viewport::create(view);
00198 Ref<Viewport> rightViewport = Viewport::create(view);
00199 Ref<Screen> screen = Screen::create(view);
00200 Ref<Eye> leftEye = Eye::create(view);
00201 Ref<Eye> rightEye = Eye::create(view);
00202 Ref<Clip> clip = Clip::create(view);
00203
00204 leftViewport->set(0, 0, 0.5, 1);
00205 rightViewport->set(0.5, 0, 0.5, 1);
00206
00207 leftEye->set(Vector3(-1.0/20, 0, 0));
00208 rightEye->set(Vector3(+1.0/20, 0, 0));
00209
00210 Ref<Conductor> conductor = Conductor::create();
00211
00212 Ref<Pipe> leftPipe = conductor->addPipe(visual);
00213 Ref<Pipe> rightPipe = conductor->addPipe(visual);
00214
00215 leftPipe->addChannel(conductor, view, window,
00216 leftViewport, screen, leftEye, clip);
00217 rightPipe->addChannel(conductor, view, window,
00218 rightViewport, screen, rightEye, clip);
00219
00220 return conductor;
00221 }
00222
00223 Ref<Conductor> dualWindowStereo(Ref<Display::Visual> visual, Ref<Renderer> renderer)
00224 {
00225 Ref<Display::Window> leftWindow = visual->newWindow(100, 100,
00226 adjust(500, 10, opt_windowSize),
00227 adjust(500, 10, opt_windowSize),
00228 "Left eye of stereoscopic view");
00229 Ref<Display::Window> rightWindow = visual->newWindow(100, 100,
00230 adjust(500, 10, opt_windowSize),
00231 adjust(500, 10, opt_windowSize),
00232 "Right eye of stereoscopic view");
00233
00234 Ref<View> view = View::create(renderer);
00235
00236 Ref<Viewport> viewport = Viewport::create(view);
00237 Ref<Screen> screen = Screen::create(view);
00238 Ref<Eye> leftEye = Eye::create(view);
00239 Ref<Eye> rightEye = Eye::create(view);
00240 Ref<Clip> clip = Clip::create(view);
00241
00242 leftEye->set(Vector3(-1.0/5, 0, 0));
00243 rightEye->set(Vector3(+1.0/5, 0, 0));
00244
00245 screen->set(1, M_PI/4, 10);
00246
00247 Ref<Conductor> conductor = Conductor::create();
00248
00249 Ref<Pipe> leftPipe = conductor->addPipe(visual);
00250 Ref<Pipe> rightPipe = conductor->addPipe(visual);
00251
00252 leftPipe->addChannel(conductor, view, leftWindow,
00253 viewport, screen, leftEye, clip);
00254 rightPipe->addChannel(conductor, view, rightWindow,
00255 viewport, screen, rightEye, clip);
00256
00257 return conductor;
00258 }
00259
00260
00261 struct MyRenderer: Renderer
00262 {
00263 MyRenderer(): w(0) {}
00264
00265 double w;
00266
00267 void initOpenGlContext()
00268 {
00269 GLfloat v[4];
00270 v[3] = 1;
00271
00272 glEnable(GL_LIGHTING);
00273 glEnable(GL_LIGHT0);
00274 glEnable(GL_DEPTH_TEST);
00275 glEnable(GL_COLOR_MATERIAL);
00276
00277 v[0] = v[1] = v[2] = 0.2;
00278 glLightfv(GL_LIGHT0, GL_AMBIENT, v);
00279
00280 v[0] = v[1] = v[2] = 0.9;
00281 glLightfv(GL_LIGHT0, GL_DIFFUSE, v);
00282
00283 v[0] = v[1] = v[2] = 0.8;
00284 glLightfv(GL_LIGHT0, GL_SPECULAR, v);
00285
00286 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
00287 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
00288 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
00289
00290 v[0] = 0.9; v[1] = 0.9; v[2] = 0.9;
00291 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
00292
00293 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32);
00294
00295 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
00296 }
00297
00298 void render()
00299 {
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 glTranslated(0, 0, -6);
00333 glRotated(10, 1, 0, 0);
00334
00335 GLfloat v[4];
00336 v[3] = 1;
00337
00338 v[0] = 5; v[1] = 20; v[2] = -5;
00339 glLightfv(GL_LIGHT0, GL_POSITION, v);
00340
00341 glRotated(w/M_PI*180, 0, 1, 0);
00342
00343 GLUquadric *quadric = gluNewQuadric();
00344
00345 glPushMatrix();
00346 glColor3f(0.1, 0.9, 0.9);
00347 glTranslated(0, 0, -16);
00348 gluCylinder(quadric, 0.2, 0.2, 1.6,
00349 adjustDetail(50, 3), adjustDetail(25, 1));
00350 glPopMatrix();
00351
00352 glPushMatrix();
00353 glColor3f(0.2, 0.2, 0.8);
00354 glTranslated(0, 0, -12.5);
00355 gluCylinder(quadric, 0.2, 0.2, 1.6,
00356 adjustDetail(50, 3), adjustDetail(25, 1));
00357 glPopMatrix();
00358
00359 glPushMatrix();
00360 glColor3f(0.9, 0.1, 0.9);
00361 glTranslated(0, 0, -9);
00362 gluCylinder(quadric, 0.2, 0.2, 1.6,
00363 adjustDetail(50, 3), adjustDetail(25, 1));
00364 glPopMatrix();
00365
00366 glPushMatrix();
00367 glColor3f(0.2, 0.2, 0.8);
00368 glTranslated(0, 0, -5.5);
00369 gluCylinder(quadric, 0.2, 0.2, 1.6,
00370 adjustDetail(50, 3), adjustDetail(25, 1));
00371 glPopMatrix();
00372
00373 glPushMatrix();
00374 glColor3f(0.9, 0.9, 0.1);
00375 glTranslated(0, 0, -2);
00376 gluCylinder(quadric, 0.2, 0.2, 1.6,
00377 adjustDetail(50, 3), adjustDetail(25, 1));
00378 glPopMatrix();
00379
00380 glPushMatrix();
00381 glColor3f(0.2, 0.2, 0.8);
00382 glTranslated(0, 0, 1.5);
00383 gluCylinder(quadric, 0.2, 0.2, 1.6,
00384 adjustDetail(50, 3), adjustDetail(25, 1));
00385 glPopMatrix();
00386
00387 glPushMatrix();
00388 glColor3f(0.8, 0.3, 0.3);
00389 glTranslated(-0.07, 0, -60.5);
00390 gluCylinder(quadric, 0.02, 0.02, 64,
00391 adjustDetail(25, 3), adjustDetail(200, 1));
00392 glPopMatrix();
00393
00394 glPushMatrix();
00395 glColor3f(0.8, 0.3, 0.3);
00396 glTranslated(+0.07, 0, -60.5);
00397 gluCylinder(quadric, 0.02, 0.02, 64,
00398 adjustDetail(25, 3), adjustDetail(200, 1));
00399 glPopMatrix();
00400
00401 gluDeleteQuadric(quadric);
00402 }
00403 };
00404
00405 void measureFrameRate()
00406 {
00407 static Time next = Time::now() + Time(10.0);
00408 static double frames = 0;
00409
00410 ++frames;
00411
00412 while(Time::now() >= next)
00413 {
00414 cerr << "Frame rate (f/s): " << frames/10 << "\n";
00415 frames = 0;
00416 next += Time(10.0);
00417 }
00418 }
00419
00420 int main(int argc, const char *argv[])
00421 {
00422 Options o;
00423
00424 o.addSwitch("h", "help", opt_help, true,
00425 "Describe the parameters");
00426 o.addConfig("m", "view-mode", opt_viewMode, opt_viewMode,
00427 "0 for one thread mono, 1 for two thread mono, "
00428 "2 for one thread paper stereo, 3 for two thread "
00429 "paper stereo, 4 for split screen stereo and 5 for "
00430 "dual window stereo.",
00431 Options::wantArg_always, Options::range(0, 6));
00432 o.addConfig("f", "frame-rate", opt_frameRate, opt_frameRate,
00433 "Upper limit on number of frames per second.",
00434 Options::wantArg_always);
00435 o.addConfig("s", "window-size", opt_windowSize, opt_windowSize,
00436 "A window size modifier 1 corresponds to normal size.",
00437 Options::wantArg_always);
00438 o.addConfig("d", "detail-level", opt_detailLevel, opt_detailLevel,
00439 "A detail level modifier, 1 corresponds to normal level of detail.",
00440 Options::wantArg_always);
00441 o.addConfig("D", "direct-rendering", opt_directRendering, opt_directRendering,
00442 "Attempt to establist direct rendering contexts to gain performance.",
00443 Options::wantArg_always);
00444
00445 if(o.processCommandLine(argc, argv))
00446 {
00447 cerr << "Try --help\n";
00448 return 1;
00449 }
00450
00451 if(opt_help)
00452 {
00453 cout <<
00454 "Test Application for the Archon::Render library\n"
00455 "by Brian Kristiansen & Kristian Spangsege\n"
00456 "\n"
00457 "Synopsis: " << argv[0] << "\n"
00458 "\n"
00459 "Available options:\n";
00460 cout << o.list();
00461 return 0;
00462 }
00463
00464 if(argc > 1)
00465 {
00466 cerr << "Too many aguments\n";
00467 cerr << "Try --help\n";
00468 return 1;
00469 }
00470
00471 Ref<Display::Implementation> implementation = Display::getDefaultImplementation();
00472 Ref<Display::Connection> connection = implementation->newConnection();
00473 Ref<Display::Screen> screen = connection->getDefaultScreen();
00474 Ref<Display::Visual> visual = screen->chooseVisual();
00475
00476 Ref<MyRenderer> myRenderer = new MyRenderer;
00477
00478 Ref<Conductor> conductor =
00479 opt_viewMode == 0 ? oneThreadMono(visual, myRenderer) :
00480 opt_viewMode == 1 ? twoThreadMono(visual, myRenderer) :
00481 opt_viewMode == 2 ? oneThreadPaperStereo(visual, myRenderer) :
00482 opt_viewMode == 3 ? twoThreadPaperStereo(visual, myRenderer) :
00483 opt_viewMode == 4 ? splitScreenStereo(visual, myRenderer) :
00484 dualWindowStereo(visual, myRenderer);
00485
00486 Time timePerFrame;
00487 timePerFrame.setNanoSeconds(long(1E9/opt_frameRate));
00488
00489 Time t = Time::now();
00490 for(;;)
00491 {
00492 measureFrameRate();
00493
00494 conductor->render();
00495
00496 myRenderer->w += 2*M_PI/opt_frameRate/10;
00497
00498 t += timePerFrame;
00499 Thread::sleepUntil(t);
00500 }
00501
00502 return 0;
00503 }
00504 }
00505 }
00506 }
00507
00508 int main(int argc, const char *argv[]) throw()
00509 {
00510 using namespace Archon::Utilities;
00511
00512 std::set_unexpected(Exception::terminal<Archon::Render::exceptionCatchInfo>);
00513 std::set_terminate (Exception::terminal<Archon::Render::exceptionCatchInfo>);
00514
00515 if(!XInitThreads()) ARCHON_THROW1(ResourceException, "Unable to enter thread safe X11 mode");
00516
00517 return Archon::Render::Test::main(argc, argv);
00518 }