00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "glut-demo.h"
00034
00035 #include <iostream>
00036 #include <math.h>
00037
00038 #include "glut/glut_2d.h"
00039 #include "glut-font/glut-font.h"
00040 #include "perf/perf.h"
00041 #include "util/date.h"
00042
00043
00044 namespace glut {
00045
00046
00047
00048 DisplayLine::~DisplayLine(void) throw() { }
00049
00050
00051
00052 static const int s_maxBufferSize = 256;
00053 static const int s_maxLighting = 3;
00054 static const float s_dRot = 0.25;
00055 static const float s_2 = sqrt(0.5);
00056
00057 static const float s_radiansPerDegree = M_PI / 180.0;
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 class FpsDisplay : public DisplayLine {
00075 public:
00076
00077 FpsDisplay(void) throw() : m_fps(perf::getNow()) { }
00078 ~FpsDisplay(void) throw() { }
00079
00080
00081 void tick(void) throw() {
00082 m_fps.tick(perf::getNow());
00083 }
00084
00085
00086 ePosition getPosition(void) { return eTopLeft; }
00087 const char * getText(void) {
00088 int fps = (int) (m_fps.getFPS() + 0.5);
00089 sprintf(m_buffer, "%d fps", fps);
00090 return m_buffer;
00091 }
00092
00093 private:
00094
00095 char m_buffer[s_maxBufferSize];
00096 fps_t m_fps;
00097 };
00098
00099
00100
00101 class WireDisplay : public DisplayLine {
00102 public:
00103
00104 WireDisplay(void) throw() : m_wire(false) { }
00105 ~WireDisplay(void) throw() { }
00106
00107
00108 void setWireframe(IN bool wireframe) throw() { m_wire = wireframe; }
00109
00110
00111 ePosition getPosition(void) { return eTopLeft; }
00112 const char * getText(void) {
00113 sprintf(m_buffer, "(w)ireframe: %s",
00114 m_wire ? "yes" : "no");
00115 return m_buffer;
00116 }
00117
00118 private:
00119
00120 char m_buffer[s_maxBufferSize];
00121 bool m_wire;
00122 };
00123
00124
00125
00126 class LightingDisplay : public DisplayLine {
00127 public:
00128
00129 LightingDisplay(void) throw() : m_light(0) { }
00130 ~LightingDisplay(void) throw() { }
00131
00132
00133 void setLighting(IN int level) throw() { m_light = level; }
00134
00135
00136 ePosition getPosition(void) { return eTopRight; }
00137 const char * getText(void) {
00138 const char * txt = "(unknown?)";
00139 switch (m_light) {
00140 case 0: txt = "none"; break;
00141 case 1: txt = "ambient only"; break;
00142 case 2: txt = "ambient and directed"; break;
00143 }
00144 sprintf(m_buffer, "(l)ighting: %s", txt);
00145 return m_buffer;
00146 }
00147
00148 private:
00149
00150 char m_buffer[s_maxBufferSize];
00151 int m_light;
00152 };
00153
00154
00155
00156 class PositionDisplay : public DisplayLine {
00157 public:
00158
00159 ~PositionDisplay(void) throw() { }
00160
00161
00162 void setPosition(IN const point3d_t& pos) { m_pos = pos; }
00163
00164
00165 ePosition getPosition(void) { return eTopRight; }
00166 const char * getText(void) {
00167 sprintf(m_buffer, "position: (%.1f, %.1f, %.1f)",
00168 m_pos.x, m_pos.y, m_pos.z);
00169 return m_buffer;
00170 }
00171
00172 private:
00173
00174 char m_buffer[s_maxBufferSize];
00175 point3d_t m_pos;
00176 };
00177
00178
00179
00180 class RotateDisplay : public DisplayLine {
00181 public:
00182
00183 ~RotateDisplay(void) throw() { }
00184
00185
00186 void setRotate(IN float dRot) throw() { m_rot = dRot; }
00187
00188
00189 ePosition getPosition(void) { return eBottomRight; }
00190 const char * getText(void) {
00191 sprintf(m_buffer, "(r/R)otate: %.2f degrees/frame",
00192 m_rot);
00193 return m_buffer;
00194 }
00195
00196 private:
00197
00198 char m_buffer[s_maxBufferSize];
00199 float m_rot;
00200 };
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 class Demo : public Host {
00211 public:
00212
00213 Demo(void);
00214 ~Demo(void) throw();
00215
00216
00217 void initialize(IN DemoHost * host);
00218
00219
00220 void init(void);
00221 void display(IN int w, IN int h);
00222 eBehavior mouseMove(IN int x, IN int y);
00223 eBehavior mouseButton(IN int button, IN int state, IN int x, IN int y);
00224 eBehavior keyboard(IN int key, IN int mods);
00225 eBehavior specialKey(IN int key, IN int mods);
00226 int shutdown(void);
00227
00228 private:
00229
00230 void setLighting(void);
00231 void renderLines(IN int x, IN int y, IN int dy,
00232 IN DisplayLine::ePosition pos);
00233
00234
00235 DemoHost * m_host;
00236 bool m_wireframe;
00237 int m_light;
00238 float m_rot;
00239 float m_angle;
00240 float m_delta;
00241 Viewer m_viewer;
00242 vec_display_lines_t m_lines;
00243 smart_ptr<glut::RenderQueue> m_rQueue;
00244 smart_ptr<perf::Timer> m_demoTimer;
00245 smart_ptr<FpsDisplay> m_fps;
00246 smart_ptr<WireDisplay> m_wire;
00247 smart_ptr<LightingDisplay> m_lighting;
00248 smart_ptr<PositionDisplay> m_position;
00249 smart_ptr<RotateDisplay> m_rotate;
00250 };
00251
00252
00253
00254 Demo::Demo(void)
00255 :
00256 m_host(NULL),
00257 m_wireframe(false),
00258 m_light(0),
00259 m_rot(0.0),
00260 m_angle(0.0)
00261 {
00262 }
00263
00264
00265
00266 Demo::~Demo(void)
00267 throw()
00268 {
00269 }
00270
00271
00272
00273 void
00274 Demo::initialize
00275 (
00276 IN DemoHost * host
00277 )
00278 {
00279 ASSERT(host, "null");
00280 m_host = host;
00281
00282 m_demoTimer = new perf::Timer("glut demo overall timer");
00283 THROW(m_demoTimer, "null");
00284
00285 m_viewer.setPosition(point3d_t(0, 0, -10));
00286
00287
00288 m_delta = host->getDelta();
00289 ASSERT(m_delta > 0.0, "Bad step size: %f", m_delta);
00290
00291
00292 m_fps = new FpsDisplay;
00293 THROW(m_fps, "out of memory");
00294 m_lines.push_back(m_fps);
00295
00296 m_wire = new WireDisplay;
00297 THROW(m_wire, "out of memory");
00298 m_lines.push_back(m_wire);
00299
00300 m_lighting = new LightingDisplay;
00301 THROW(m_lighting, "out of memory");
00302 m_lines.push_back(m_lighting);
00303
00304 m_position = new PositionDisplay;
00305 THROW(m_position, "out of memory");
00306 m_lines.push_back(m_position);
00307
00308 m_rotate = new RotateDisplay;
00309 THROW(m_rotate, "out of memory");
00310 m_lines.push_back(m_rotate);
00311
00312
00313 vec_display_lines_t lines;
00314 m_host->getDisplayLines(lines);
00315 m_lines.insert(m_lines.end(), lines.begin(), lines.end());
00316 DPRINTF("I have %d display lines", (int) m_lines.size());
00317
00318
00319 int nSlots = 1024;
00320 m_rQueue = glut::RenderQueue::create(nSlots);
00321 ASSERT(m_rQueue, "failed to create render queue");
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 void
00333 Demo::init
00334 (
00335 void
00336 )
00337 {
00338
00339 m_host->onInit();
00340 }
00341
00342
00343
00344 void
00345 Demo::display
00346 (
00347 IN int w,
00348 IN int h
00349 )
00350 {
00351 perf::Timer timer("Demo::display");
00352 ASSERT(m_rQueue, "null");
00353
00354
00355 m_delta = m_host->getDelta();
00356
00357
00358 m_fps->tick();
00359 m_wire->setWireframe(m_wireframe);
00360 m_lighting->setLighting(m_light);
00361 m_rotate->setRotate(m_rot);
00362 m_position->setPosition(m_viewer.getPosition());
00363
00364
00365 glEnable(GL_DEPTH_TEST);
00366 glFrontFace(GL_CCW);
00367
00368
00369 if (m_wireframe) {
00370 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00371 glColor3f(1.0, 1.0, 1.0);
00372 glDisable(GL_CULL_FACE);
00373 } else {
00374 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00375 glCullFace(GL_BACK);
00376 glEnable(GL_CULL_FACE);
00377 }
00378
00379
00380 glClearColor(0.0, 0.0, 0.0, 0.0);
00381 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00382
00383
00384 m_angle += m_rot;
00385 m_viewer.setYRotation(m_angle * s_radiansPerDegree);
00386
00387
00388 render_context_t rc;
00389 rc.viewport.left = 0;
00390 rc.viewport.top = 0;
00391 rc.viewport.right = w;
00392 rc.viewport.bottom = h;
00393 rc.camera.setAspect(w, h);
00394 rc.viewer = m_viewer;
00395
00396
00397 setOpenGLProjection(rc.camera);
00398 setOpenGLViewer(rc.viewer);
00399
00400
00401 this->setLighting();
00402
00403
00404 {
00405 perf::Timer timer("host::display3D");
00406 m_host->display3D(rc, m_rQueue);
00407 }
00408
00409
00410 if (m_host->displayAxes()) {
00411 glDisable(GL_LIGHTING);
00412 glColor3f(0, 0, 1);
00413 glBegin(GL_LINES);
00414 glVertex3f(0, 1, 0);
00415 glVertex3f(0, 2, 0);
00416 glEnd();
00417
00418 glColor3f(1, 0, 0);
00419 glBegin(GL_LINES);
00420 glVertex3f(1, 0, 0);
00421 glVertex3f(2, 0, 0);
00422 glEnd();
00423
00424 glColor3f(0, 1, 0);
00425 glBegin(GL_LINES);
00426 glVertex3f(0, 0, 1);
00427 glVertex3f(0, 0, 2);
00428 glEnd();
00429 }
00430
00431
00432 glEnable(GL_BLEND);
00433 glEnable(GL_LIGHTING);
00434 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00435 glEnable(GL_TEXTURE_2D);
00436
00437
00438
00439 glMatrixMode(GL_MODELVIEW);
00440 glPushMatrix();
00441 glLoadIdentity();
00442
00443
00444 if (m_host->displayQueuedPolys()) {
00445 perf::Timer timer("queued polygons");
00446 while (glut::poly_request_t * pr = m_rQueue->popRequest()) {
00447 if (pr->nVertices < 3 || pr->textureId < 1) {
00448 DPRINTF("Skipping invalid request");
00449 continue;
00450 }
00451
00452
00453 glBindTexture(GL_TEXTURE_2D, pr->textureId);
00454 glNormal3fv((GLfloat *) &pr->normal.x);
00455
00456
00457 glBegin(GL_POLYGON);
00458 for (int i = 0; i < pr->nVertices; ++i) {
00459 glTexCoord2f(pr->u[i], pr->v[i]);
00460 glVertex3fv((GLfloat *) &pr->vertex[i].x);
00461 }
00462 glEnd();
00463 }
00464 }
00465
00466
00467 glDisable(GL_TEXTURE_2D);
00468 glDisable(GL_LIGHTING);
00469 glDisable(GL_LIGHT0);
00470 glDisable(GL_BLEND);
00471 glDisable(GL_CULL_FACE);
00472 glPopMatrix();
00473
00474
00475 glDisable(GL_DEPTH_TEST);
00476
00477 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00478
00479
00480 perf::Timer timer2d("demo--2D drawing");
00481 push2D(w, h);
00482
00483
00484 {
00485 perf::Timer timer("host::display2D");
00486 m_host->display2D(w, h);
00487 }
00488
00489
00490 glColor3f(1, 1, 1);
00491 int textHeight = 14;
00492 int lineSpace = 2;
00493 int lineHeight = textHeight + lineSpace;
00494 int rightMargin = 300;
00495 this->renderLines(1, lineHeight, lineHeight,
00496 DisplayLine::eTopLeft);
00497 this->renderLines(w - rightMargin, lineHeight, lineHeight,
00498 DisplayLine::eTopRight);
00499 this->renderLines(1, h - lineSpace, -lineHeight,
00500 DisplayLine::eBottomLeft);
00501 this->renderLines(w - rightMargin, h - lineSpace, -lineHeight,
00502 DisplayLine::eBottomRight);
00503
00504
00505 pop2D();
00506 }
00507
00508
00509
00510 int
00511 Demo::shutdown
00512 (
00513 void
00514 )
00515 {
00516
00517 m_host->onShutdown();
00518
00519
00520 m_demoTimer = NULL;
00521 perf::dumpTimingSummary(std::cerr);
00522 return 0;
00523 }
00524
00525
00526
00527 Host::eBehavior
00528 Demo::mouseMove
00529 (
00530 IN int x,
00531 IN int y
00532 )
00533 {
00534 m_host->onCursor(x, y);
00535 return eContinue;
00536 }
00537
00538
00539
00540 Host::eBehavior
00541 Demo::mouseButton
00542 (
00543 IN int button,
00544 IN int state,
00545 IN int x,
00546 IN int y
00547 )
00548 {
00549 m_host->onButton(button, state, x, y);
00550 return eContinue;
00551 }
00552
00553
00554
00555 Host::eBehavior
00556 Demo::keyboard
00557 (
00558 IN int key,
00559 IN int mods
00560 )
00561 {
00562 switch (key) {
00563 case 'l': m_light = (m_light + 1) % s_maxLighting; break;
00564
00565 case 'q':
00566 case 27:
00567 return eExit;
00568
00569 case 'r': m_rot += s_dRot; break;
00570
00571 case 'R': m_rot -= s_dRot; break;
00572
00573 case 'w': m_wireframe = !m_wireframe; break;
00574
00575 case '+':
00576 case '=':
00577 m_viewer.move(m_delta, 0, 0); break;
00578
00579 case '-':
00580 m_viewer.move(-m_delta, 0, 0); break;
00581 }
00582
00583
00584 m_host->onKey(key, mods);
00585
00586
00587 return eContinue;
00588 }
00589
00590
00591
00592 Host::eBehavior
00593 Demo::specialKey
00594 (
00595 IN int key,
00596 IN int mods
00597 )
00598 {
00599
00600 bool shiftDown = (1 & mods);
00601
00602 const float s_up = 0.03;
00603
00604 switch (key) {
00605 case GLUT_KEY_UP:
00606 if (shiftDown)
00607 m_viewer.rotateUp(-s_up);
00608 else
00609 m_viewer.move(0, 0, m_delta);
00610 break;
00611 case GLUT_KEY_DOWN:
00612 if (shiftDown)
00613 m_viewer.rotateUp(+s_up);
00614 else
00615 m_viewer.move(0, 0, -m_delta);
00616 break;
00617 case GLUT_KEY_LEFT: m_viewer.move(0, -m_delta, 0); break;
00618 case GLUT_KEY_RIGHT: m_viewer.move(0, m_delta, 0); break;
00619 }
00620
00621 return eContinue;
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632 void
00633 Demo::setLighting
00634 (
00635 void
00636 )
00637 {
00638
00639 if (m_light < 1) {
00640 glDisable(GL_LIGHTING);
00641 glDisable(GL_LIGHT0);
00642 glDisable(GL_LIGHT1);
00643 return;
00644 }
00645
00646
00647 glEnable(GL_LIGHTING);
00648 glEnable(GL_LIGHT0);
00649 glShadeModel(GL_SMOOTH);
00650
00651
00652 float lightModelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
00653 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
00654 if (m_light < 2)
00655 return;
00656
00657
00658 glEnable(GL_LIGHT1);
00659 float lightDirection[] = { s_2, 0, s_2, 0 };
00660 glLightfv(GL_LIGHT1, GL_POSITION, lightDirection);
00661
00662 float lightDiffuse[] = { 1, 1, 1, 1 };
00663 glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDiffuse);
00664 glLightfv(GL_LIGHT1, GL_SPECULAR, lightDiffuse);
00665
00666 float lightAmbient[] = { 0.2, 0, 0.2, 1 };
00667 glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmbient);
00668 }
00669
00670
00671
00672 void
00673 Demo::renderLines
00674 (
00675 IN int x,
00676 IN int y,
00677 IN int dy,
00678 IN DisplayLine::ePosition pos
00679 )
00680 {
00681 glut::Font * font = glut::getDefaultFont();
00682 for (vec_display_lines_t::iterator i = m_lines.begin();
00683 i != m_lines.end(); ++i) {
00684 DisplayLine * pdl = *i;
00685 ASSERT(pdl, "null display line in vector");
00686
00687 if (pdl->getPosition() != pos)
00688 continue;
00689
00690 const char * txt = pdl->getText();
00691 font->display(x, y, 0, txt);
00692 y += dy;
00693 }
00694 }
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704 DemoHost::~DemoHost(void)
00705 throw()
00706 {
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717 void
00718 startDemo
00719 (
00720 IN int argc,
00721 IN const char * argv[],
00722 IN const char * title,
00723 IN DemoHost * host
00724 )
00725 {
00726 ASSERT(argc >= 0, "Bad argument count: %d", argc);
00727 IMPLIES(argc, argv, "null");
00728 ASSERT(title, "null");
00729 ASSERT(host, "null");
00730
00731
00732 smart_ptr<Demo> demo = new Demo;
00733 THROW(demo, "out of memory");
00734 demo->initialize(host);
00735
00736 int width = host->getWidth();
00737 int height = host->getHeight();
00738
00739
00740 smart_ptr<Host> glutHost = demo;
00741 THROW(glutHost, "failed to downcast");
00742 glut::start(argc, argv, width, height, title, NULL, glutHost);
00743 }
00744
00745
00746
00747 };
00748