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-font/glut-font.h"
00039 #include "perf/perf.h"
00040 #include "util/date.h"
00041 #include "wave-glut/glut_2d.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 eBehavior tick(IN float dt);
00222 void display(IN int w, IN int h);
00223 eBehavior mouseMove(IN int x, IN int y);
00224 eBehavior mouseButton(IN int button, IN int state, IN int x, IN int y);
00225 eBehavior keyboard(IN int key, IN int mods);
00226 eBehavior specialKey(IN int key, IN int mods);
00227 int shutdown(void);
00228
00229 private:
00230
00231 void setLighting(void);
00232 void renderLines(IN int x, IN int y, IN int dy,
00233 IN DisplayLine::ePosition pos);
00234
00235
00236 DemoHost * m_host;
00237 bool m_wireframe;
00238 int m_light;
00239 float m_rot;
00240 float m_angle;
00241 float m_delta;
00242 Viewer m_viewer;
00243 vec_display_lines_t m_lines;
00244 smart_ptr<glut::RenderQueue> m_rQueue;
00245 smart_ptr<perf::Timer> m_demoTimer;
00246 smart_ptr<FpsDisplay> m_fps;
00247 smart_ptr<WireDisplay> m_wire;
00248 smart_ptr<LightingDisplay> m_lighting;
00249 smart_ptr<PositionDisplay> m_position;
00250 smart_ptr<RotateDisplay> m_rotate;
00251 };
00252
00253
00254
00255 Demo::Demo(void)
00256 :
00257 m_host(NULL),
00258 m_wireframe(false),
00259 m_light(0),
00260 m_rot(0.0),
00261 m_angle(0.0)
00262 {
00263 }
00264
00265
00266
00267 Demo::~Demo(void)
00268 throw()
00269 {
00270 }
00271
00272
00273
00274 void
00275 Demo::initialize
00276 (
00277 IN DemoHost * host
00278 )
00279 {
00280 ASSERT(host, "null");
00281 m_host = host;
00282
00283 m_demoTimer = new perf::Timer("glut demo overall timer");
00284 THROW(m_demoTimer, "null");
00285
00286 m_viewer.setPosition(point3d_t(0, 0, -10));
00287
00288
00289 m_delta = host->getDelta();
00290 ASSERT(m_delta > 0.0, "Bad step size: %f", m_delta);
00291
00292
00293 m_fps = new FpsDisplay;
00294 THROW(m_fps, "out of memory");
00295 m_lines.push_back(m_fps);
00296
00297 m_wire = new WireDisplay;
00298 THROW(m_wire, "out of memory");
00299 m_lines.push_back(m_wire);
00300
00301 m_lighting = new LightingDisplay;
00302 THROW(m_lighting, "out of memory");
00303 m_lines.push_back(m_lighting);
00304
00305 m_position = new PositionDisplay;
00306 THROW(m_position, "out of memory");
00307 m_lines.push_back(m_position);
00308
00309 m_rotate = new RotateDisplay;
00310 THROW(m_rotate, "out of memory");
00311 m_lines.push_back(m_rotate);
00312
00313
00314 vec_display_lines_t lines;
00315 m_host->getDisplayLines(lines);
00316 m_lines.insert(m_lines.end(), lines.begin(), lines.end());
00317 DPRINTF("I have %d display lines", (int) m_lines.size());
00318
00319
00320 int nSlots = 1024;
00321 m_rQueue = glut::RenderQueue::create(nSlots);
00322 ASSERT(m_rQueue, "failed to create render queue");
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 void
00334 Demo::init
00335 (
00336 void
00337 )
00338 {
00339
00340 m_host->onInit();
00341 }
00342
00343
00344
00345 Host::eBehavior
00346 Demo::tick
00347 (
00348 IN float dt
00349 )
00350 {
00351 ASSERT(dt >= 0.0, "bad time delta between frames: %f seconds", dt);
00352
00353 m_host->onIdle(dt);
00354
00355 return eContinue;
00356 }
00357
00358
00359
00360 void
00361 Demo::display
00362 (
00363 IN int w,
00364 IN int h
00365 )
00366 {
00367 perf::Timer timer("Demo::display");
00368 ASSERT(m_rQueue, "null");
00369
00370
00371 m_delta = m_host->getDelta();
00372
00373
00374 m_fps->tick();
00375 m_wire->setWireframe(m_wireframe);
00376 m_lighting->setLighting(m_light);
00377 m_rotate->setRotate(m_rot);
00378 m_position->setPosition(m_viewer.getPosition());
00379
00380
00381 glEnable(GL_DEPTH_TEST);
00382 glFrontFace(GL_CCW);
00383
00384
00385 if (m_wireframe) {
00386 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00387 glColor3f(1.0, 1.0, 1.0);
00388 glDisable(GL_CULL_FACE);
00389 } else {
00390 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00391 glCullFace(GL_BACK);
00392 glEnable(GL_CULL_FACE);
00393 }
00394
00395
00396 glClearColor(0.0, 0.0, 0.0, 0.0);
00397 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00398
00399
00400 m_angle += m_rot;
00401 m_viewer.setYRotation(m_angle * s_radiansPerDegree);
00402
00403
00404 render_context_t rc;
00405 rc.viewport.left = 0;
00406 rc.viewport.top = 0;
00407 rc.viewport.right = w;
00408 rc.viewport.bottom = h;
00409 rc.camera.setAspect(w, h);
00410 rc.viewer = m_viewer;
00411
00412
00413 setOpenGLProjection(rc.camera);
00414 setOpenGLViewer(rc.viewer);
00415
00416
00417 this->setLighting();
00418
00419
00420 {
00421 perf::Timer timer("host::display3D");
00422 m_host->display3D(rc, m_rQueue);
00423 }
00424
00425
00426 if (m_host->displayAxes()) {
00427 glDisable(GL_LIGHTING);
00428 glColor3f(0, 0, 1);
00429 glBegin(GL_LINES);
00430 glVertex3f(0, 1, 0);
00431 glVertex3f(0, 2, 0);
00432 glEnd();
00433
00434 glColor3f(1, 0, 0);
00435 glBegin(GL_LINES);
00436 glVertex3f(1, 0, 0);
00437 glVertex3f(2, 0, 0);
00438 glEnd();
00439
00440 glColor3f(0, 1, 0);
00441 glBegin(GL_LINES);
00442 glVertex3f(0, 0, 1);
00443 glVertex3f(0, 0, 2);
00444 glEnd();
00445 }
00446
00447
00448 glEnable(GL_BLEND);
00449 glEnable(GL_LIGHTING);
00450 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00451 glEnable(GL_TEXTURE_2D);
00452
00453
00454
00455 glMatrixMode(GL_MODELVIEW);
00456 glPushMatrix();
00457 glLoadIdentity();
00458
00459
00460 if (m_host->displayQueuedPolys()) {
00461 perf::Timer timer("queued polygons");
00462 while (glut::poly_request_t * pr = m_rQueue->popRequest()) {
00463 if (pr->nVertices < 3 || pr->textureId < 1) {
00464 DPRINTF("Skipping invalid request");
00465 continue;
00466 }
00467
00468
00469 glBindTexture(GL_TEXTURE_2D, pr->textureId);
00470 glNormal3fv((GLfloat *) &pr->normal.x);
00471
00472
00473 glBegin(GL_POLYGON);
00474 for (int i = 0; i < pr->nVertices; ++i) {
00475 glTexCoord2f(pr->u[i], pr->v[i]);
00476 glVertex3fv((GLfloat *) &pr->vertex[i].x);
00477 }
00478 glEnd();
00479 }
00480 }
00481
00482
00483 glDisable(GL_TEXTURE_2D);
00484 glDisable(GL_LIGHTING);
00485 glDisable(GL_LIGHT0);
00486 glDisable(GL_BLEND);
00487 glDisable(GL_CULL_FACE);
00488 glPopMatrix();
00489
00490
00491 glDisable(GL_DEPTH_TEST);
00492
00493 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00494
00495
00496 perf::Timer timer2d("demo--2D drawing");
00497 push2D(w, h);
00498
00499
00500 {
00501 perf::Timer timer("host::display2D");
00502 m_host->display2D(w, h);
00503 }
00504
00505
00506 glColor3f(1, 1, 1);
00507 int textHeight = 14;
00508 int lineSpace = 2;
00509 int lineHeight = textHeight + lineSpace;
00510 int rightMargin = 300;
00511 this->renderLines(1, lineHeight, lineHeight,
00512 DisplayLine::eTopLeft);
00513 this->renderLines(w - rightMargin, lineHeight, lineHeight,
00514 DisplayLine::eTopRight);
00515 this->renderLines(1, h - lineSpace, -lineHeight,
00516 DisplayLine::eBottomLeft);
00517 this->renderLines(w - rightMargin, h - lineSpace, -lineHeight,
00518 DisplayLine::eBottomRight);
00519
00520
00521 pop2D();
00522 }
00523
00524
00525
00526 int
00527 Demo::shutdown
00528 (
00529 void
00530 )
00531 {
00532
00533 m_host->onShutdown();
00534
00535
00536 m_demoTimer = NULL;
00537 perf::dumpTimingSummary(std::cerr);
00538 return 0;
00539 }
00540
00541
00542
00543 Host::eBehavior
00544 Demo::mouseMove
00545 (
00546 IN int x,
00547 IN int y
00548 )
00549 {
00550 m_host->onCursor(x, y);
00551 return eContinue;
00552 }
00553
00554
00555
00556 Host::eBehavior
00557 Demo::mouseButton
00558 (
00559 IN int button,
00560 IN int state,
00561 IN int x,
00562 IN int y
00563 )
00564 {
00565 m_host->onButton(button, state, x, y);
00566 return eContinue;
00567 }
00568
00569
00570
00571 Host::eBehavior
00572 Demo::keyboard
00573 (
00574 IN int key,
00575 IN int mods
00576 )
00577 {
00578 switch (key) {
00579 case 'l': m_light = (m_light + 1) % s_maxLighting; break;
00580
00581 case 'q':
00582 case 27:
00583 return eExit;
00584
00585 case 'r': m_rot += s_dRot; break;
00586
00587 case 'R': m_rot -= s_dRot; break;
00588
00589 case 'w': m_wireframe = !m_wireframe; break;
00590
00591 case '+':
00592 case '=':
00593 m_viewer.move(m_delta, 0, 0); break;
00594
00595 case '-':
00596 m_viewer.move(-m_delta, 0, 0); break;
00597 }
00598
00599
00600 m_host->onKey(key, mods);
00601
00602
00603 return eContinue;
00604 }
00605
00606
00607
00608 Host::eBehavior
00609 Demo::specialKey
00610 (
00611 IN int key,
00612 IN int mods
00613 )
00614 {
00615
00616 bool shiftDown = (1 & mods);
00617
00618 const float s_up = 0.03;
00619
00620 switch (key) {
00621 case GLUT_KEY_UP:
00622 if (shiftDown)
00623 m_viewer.rotateUp(-s_up);
00624 else
00625 m_viewer.move(0, 0, m_delta);
00626 break;
00627 case GLUT_KEY_DOWN:
00628 if (shiftDown)
00629 m_viewer.rotateUp(+s_up);
00630 else
00631 m_viewer.move(0, 0, -m_delta);
00632 break;
00633 case GLUT_KEY_LEFT: m_viewer.move(0, -m_delta, 0); break;
00634 case GLUT_KEY_RIGHT: m_viewer.move(0, m_delta, 0); break;
00635 }
00636
00637 return eContinue;
00638 }
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 void
00649 Demo::setLighting
00650 (
00651 void
00652 )
00653 {
00654
00655 if (m_light < 1) {
00656 glDisable(GL_LIGHTING);
00657 glDisable(GL_LIGHT0);
00658 glDisable(GL_LIGHT1);
00659 return;
00660 }
00661
00662
00663 glEnable(GL_LIGHTING);
00664 glEnable(GL_LIGHT0);
00665 glShadeModel(GL_SMOOTH);
00666
00667
00668 float lightModelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
00669 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightModelAmbient);
00670 if (m_light < 2)
00671 return;
00672
00673
00674 glEnable(GL_LIGHT1);
00675 float lightDirection[] = { s_2, 0, s_2, 0 };
00676 glLightfv(GL_LIGHT1, GL_POSITION, lightDirection);
00677
00678 float lightDiffuse[] = { 1, 1, 1, 1 };
00679 glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDiffuse);
00680 glLightfv(GL_LIGHT1, GL_SPECULAR, lightDiffuse);
00681
00682 float lightAmbient[] = { 0.2, 0, 0.2, 1 };
00683 glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmbient);
00684 }
00685
00686
00687
00688 void
00689 Demo::renderLines
00690 (
00691 IN int x,
00692 IN int y,
00693 IN int dy,
00694 IN DisplayLine::ePosition pos
00695 )
00696 {
00697 glut::Font * font = glut::getDefaultFont();
00698 for (vec_display_lines_t::iterator i = m_lines.begin();
00699 i != m_lines.end(); ++i) {
00700 DisplayLine * pdl = *i;
00701 ASSERT(pdl, "null display line in vector");
00702
00703 if (pdl->getPosition() != pos)
00704 continue;
00705
00706 const char * txt = pdl->getText();
00707 font->display(x, y, 0, txt);
00708 y += dy;
00709 }
00710 }
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720 DemoHost::~DemoHost(void)
00721 throw()
00722 {
00723 }
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733 void
00734 startDemo
00735 (
00736 IN int argc,
00737 IN const char * argv[],
00738 IN const char * title,
00739 IN DemoHost * host
00740 )
00741 {
00742 ASSERT(argc >= 0, "Bad argument count: %d", argc);
00743 IMPLIES(argc, argv, "null");
00744 ASSERT(title, "null");
00745 ASSERT(host, "null");
00746
00747
00748 smart_ptr<Demo> demo = new Demo;
00749 THROW(demo, "out of memory");
00750 demo->initialize(host);
00751
00752 int width = host->getWidth();
00753 int height = host->getHeight();
00754
00755
00756 smart_ptr<Host> glutHost = demo;
00757 THROW(glutHost, "failed to downcast");
00758 glut::start(argc, argv, width, height, title, NULL, glutHost);
00759 }
00760
00761
00762
00763 };
00764