wave-glut/lib/mini/test/test.cpp

Go to the documentation of this file.
00001 /*
00002  * test.cpp
00003  *
00004  * Copyright (C) 2008  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  * Program to test the libmini library (terrain).
00008  */
00009 
00010 // includes --------------------------------------------------------------------
00011 #include <fstream>
00012 #include <math.h>
00013 
00014 
00015 #include "glut/glut.h"
00016 #include "glut/glut_2d.h"
00017 #include "mini/mini.h"
00018 #include "glut/camera.h"
00019 
00020 #include "glut-font/glut-font.h"
00021 
00022 #include "perf/perf.h"
00023 
00024 #include "pgmppm/pgmppm.h"
00025 
00026 #include "common/wave_ex.h"
00027 
00028 
00029 static const int s_defaultWidth                 = 800;
00030 static const int s_defaultHeight                = 600;
00031 
00032 static int s_screenWidth                        = s_defaultWidth;
00033 static int s_screenHeight                       = s_defaultHeight;
00034 
00035 
00036 typedef short int height_t;
00037 
00038 static int s_winid                              = -1;
00039 static int s_wmode                              = 0;
00040 
00041 // input delay
00042 static const int s_delay                        = 100;
00043 static int s_ignoreInput                        = s_delay;
00044 
00045 // map data
00046 static minitile * s_tileset                     = NULL;
00047 static minicache * s_cache                      = NULL;
00048 static int s_updates                            = 5;
00049 
00050 
00051 static point3d_t s_lightPosition(0.0, 0.0, 0.0);
00052 static point3d_t s_lightVelocity(0.0, 0.0, -0.01);
00053 
00054 static int s_retval                             = 0;
00055 
00056 
00057 ////////////////////////////////////////////////////////////////////////////////
00058 //
00059 //      static helper methods
00060 //
00061 ////////////////////////////////////////////////////////////////////////////////
00062 
00063 static void
00064 onExit
00065 (
00066 void
00067 )
00068 {
00069         // shut down windows etc
00070         glutDestroyWindow(s_winid);
00071 
00072         // display timing information
00073         std::string summary;
00074         perf::getTimingSummary(summary);
00075         DPRINTF("Timers:\n%s\n", summary.c_str());
00076 
00077         // exit!
00078         exit(s_retval);
00079 }
00080 
00081 
00082 
00083 static bool
00084 notifyPgmSize
00085 (
00086 IN void * ctx,
00087 IN int width,
00088 IN int height,
00089 IN int max_val
00090 )
00091 {
00092         int * pWidth = (int *) ctx;
00093         ASSERT(pWidth, "bad context");
00094         ASSERT(width > 0, "Bad pgm width: %d", width);
00095         ASSERT(height == width, "require height == width!");
00096 
00097         *pWidth = width;
00098 
00099         return false;   // don't bother loading the rest of the file!
00100 }
00101 
00102 
00103 
00104 static void
00105 notifyPgmPixel
00106 (
00107 IN void * ctx,
00108 IN int x,
00109 IN int y,
00110 IN int height
00111 )
00112 {
00113         // nothing to do!
00114 }
00115 
00116 
00117 
00118 static void
00119 setTerrain
00120 (
00121 IN const char * pgm_file,
00122 IN const char * ppm_file
00123 )
00124 {
00125         perf::Timer timer("setTerrain");
00126         ASSERT(pgm_file, "null");
00127         ASSERT(ppm_file, "null");
00128 
00129         DPRINTF("About to init...");
00130         float xzScale = 10.0;           // 10m
00131         float yScale = 1;               // 1m
00132 
00133         const char * hfield_files[] = { pgm_file };
00134         const char * texture_files[] = { ppm_file };
00135 
00136         // load pgm to determine size
00137         std::ifstream infile(hfield_files[0]);
00138         if (!infile.good()) {
00139                 WAVE_EX(wex);
00140                 wex << "Failed to open terrain file for reading: ";
00141                 wex << hfield_files[0];
00142         }
00143         int width = -1;
00144         pgmppm::readPgm(infile, notifyPgmSize, notifyPgmPixel, &width);
00145         DPRINTF("PGM image width: %d pixels", width);
00146         ASSERT(width > 0, "Bad pgm width: %d", width);
00147 
00148         // dimension of heightfield?
00149         float dim = (width - 1) * xzScale;
00150 
00151         // okay, create minitile object
00152         int nRows = 1;
00153         int nCols = 1;
00154         s_tileset = new minitile((const unsigned char **) hfield_files,
00155                                  (const unsigned char **) texture_files,
00156                                  nRows, nCols,
00157                                  dim, dim, yScale);
00158         ASSERT(s_tileset, "null");
00159 
00160         s_cache = new minicache();
00161         ASSERT(s_cache, "out of memory");
00162         s_cache->attach(s_tileset);
00163 }
00164 
00165 
00166 
00167 static void
00168 addLight
00169 (
00170 IN int gl_enum,
00171 IN const point3d_t& position
00172 )
00173 {
00174         float x = position.x;
00175         float y = position.y;
00176         float z = position.z;
00177 
00178         float lightPos[] = { x, y, z, 1.0 };
00179         glLightfv(gl_enum, GL_POSITION, lightPos);
00180 
00181         float lightAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
00182         glLightfv(gl_enum, GL_AMBIENT, lightAmbient);
00183 
00184         float str = 1.0;
00185         float lightDiffuse[] = { str, str / 3, str / 9, 1.0 };
00186         glLightfv(gl_enum, GL_DIFFUSE, lightDiffuse);
00187         glLightfv(gl_enum, GL_SPECULAR, lightDiffuse);
00188 
00189         glLightf(gl_enum, GL_QUADRATIC_ATTENUATION, .02);
00190 
00191         glColor3f(str, str / 3, str / 9);
00192         glPushMatrix();
00193         glTranslatef(x, y, z);
00194         glutSolidSphere(0.5, 8, 8);
00195         glPopMatrix();
00196 }
00197 
00198 
00199 
00200 static void
00201 setLights
00202 (
00203 IN const glut::Viewer& walker
00204 )
00205 {
00206         // first light: ambient white light
00207         float lightAmbient[] = { 0.5, 0.5, 0.5, 1.0 };
00208         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightAmbient);
00209 
00210         // other lights--moving
00211         s_lightPosition.increment(s_lightVelocity);
00212         s_lightPosition.y = mini::getheight(s_lightPosition.x, s_lightPosition.z);
00213         s_lightPosition.y += 5.0;
00214         addLight(GL_LIGHT0, s_lightPosition);
00215 
00216         addLight(GL_LIGHT1, walker.getPosition());
00217 
00218         glEnable(GL_LIGHTING);
00219         glEnable(GL_LIGHT0);
00220         glEnable(GL_LIGHT1);
00221 }
00222 
00223 
00224 
00225 static void
00226 debugInfo
00227 (
00228 IN const glut::Viewer& viewer
00229 )
00230 {
00231         DPRINTF("Debug Information");
00232         point3d_t v;
00233 
00234         v = viewer.getPosition();
00235         v.dump("  Viewer is at");
00236         DPRINTF("  mini says height at camera is: %f",
00237             mini::getheight(v.x, v.z));
00238 
00239         v = viewer.getFacing();
00240         v.dump("  Viewer is facing");
00241 }
00242 
00243 
00244 
00245 static void
00246 updatePosition
00247 (
00248 IO glut::Viewer& view
00249 )
00250 {
00251         // get the current state of the first joystick
00252 /*
00253         DPRINTF("stick1: (%4d, %4d)    stick2: (%4d, %4d)",
00254             joy.stick1.x, joy.stick1.y, joy.stick2.x, joy.stick2.y);
00255  */
00256 
00257 /*
00258         // first axis: viewpoint
00259         float dr = 0.02;
00260         float dy_rot = (-joy.stick1.x * dr) / lib3d::eInput_MaxAxis;
00261         float dz_rot = (joy.stick1.y * dr) / lib3d::eInput_MaxAxis;
00262         view.rotateY(dy_rot);
00263         view.rotateUp(dz_rot);
00264 
00265         // second axis: motion
00266         float step = 0.1;
00267         float forward = (joy.stick2.y * step) / lib3d::eInput_MaxAxis;
00268         float sideways = (joy.stick2.x * step) / lib3d::eInput_MaxAxis;
00269         view.move(forward, sideways, 0.0);
00270 
00271         // get new location
00272         point3d_t pos = view.getPosition();
00273 //      pos.dump("position");
00274 
00275 */
00276         // ignore input?
00277         if (s_ignoreInput) {
00278                 s_ignoreInput--;
00279                 return;
00280         }
00281 /*
00282         // shoot out light?
00283         if (lib3d::eInput_Bumper1Top & joy.buttons) {
00284                 s_lightPosition = pos;
00285                 s_lightVelocity = view.getFacing();
00286                 s_lightVelocity.scale(0.1);
00287                 s_ignoreInput = s_delay;
00288         }
00289 
00290         // shoot out cube?
00291         if (lib3d::eInput_Bumper1Bottom & joy.buttons) {
00292                 point3d_t pos = view.getPosition();
00293                 pos.y += 2.0;
00294                 point3d_t facing = view.getFacing();
00295                 shootCube(pos, facing);
00296                 s_ignoreInput = s_delay;
00297         }
00298 
00299 */
00300         // debug?
00301         if (0) {
00302                 debugInfo(view);
00303                 s_ignoreInput = s_delay;
00304         }
00305 }
00306 
00307 
00308 
00309 static void
00310 onDisplay
00311 (
00312 void
00313 )
00314 {
00315         perf::Timer timer("onDisplay");
00316 
00317         static glut::Viewer viewer;
00318         static glut::camera_t camera;
00319         static float t = 0.0;
00320         const float dt = 0.002;
00321         t += dt;
00322 
00323         // update position based on controller
00324         updatePosition(viewer);
00325         viewer.setPosition(point3d_t(1000.0 * sin(0.1 * t), 0, 1000.0 * cos(0.1 * t)));
00326         point3d_t vpos = viewer.getPosition();
00327         float min_y = mini::getheight(vpos.x, vpos.z) + 10.0;
00328         float dy = (min_y - vpos.y);
00329         if (dy > 0.0) {
00330                 viewer.move(0, 0, dy);
00331         }
00332 //      camera.dump("camera");
00333 
00334         viewer.rotateY(0.5 * dt);
00335 
00336         // fps
00337         static glut::fps_t myFps(perf::getNow());
00338         myFps.tick(perf::getNow());
00339 
00340         //DPRINTF("On display...");
00341         // capabilities
00342         glEnable(GL_DEPTH_TEST);
00343         glEnable(GL_COLOR_MATERIAL);
00344 
00345         // clear buffers (takes no effect until drawing much later)
00346         glClearColor(0.2, 0.4, 0.8, 1.0);
00347         glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00348 
00349         // set perspective viewing (camera + projection)
00350         glut::setOpenGLProjection(camera);
00351         glut::setOpenGLViewer(viewer);
00352 
00353         // set up the lights (use default modelview transformation)
00354         glColor3f(1.0, 1.0, 1.0);
00355         if (s_updates) {
00356                 glut::Viewer bogus = viewer;
00357                 bogus.move(100.0, 0, 0);
00358                 setLights(bogus);
00359         }
00360 
00361         // set up for drawing
00362         float resolution = 1000.0;
00363         point3d_t view = viewer.getFacing();
00364         point3d_t eye = viewer.getPosition();
00365         point3d_t up = viewer.getUp();
00366 
00367         glNormal3f(0.0, 1.0, 0.0);
00368         s_tileset->draw(resolution,
00369                             eye.x, eye.y, eye.z,
00370 //                          eye.x, eye.y, eye.z,
00371                             view.x, view.y, view.z,
00372                             up.x, up.y, up.z,
00373                             camera.getFovy(),
00374                             camera.getAspect(),
00375                             camera.getZNear(),
00376                             camera.getZFar(),
00377                             s_updates);
00378 
00379         // actually draw
00380         s_cache->rendercache();
00381 
00382         // draw text
00383         // first, switch to orthographic projection
00384         glut::push2D(s_screenWidth, s_screenHeight);
00385         glColor3f(0, 0, 0);
00386         glut::Font * font = glut::getDefaultFont();
00387         char buffer[1024];
00388         sprintf(buffer, "%5.1f FPS", myFps.getFPS());
00389         font->display(10, 15, 0.0, buffer);
00390         glut::pop2D();
00391 
00392         // clear capabilities (just before exit!)
00393         glDisable(GL_COLOR_MATERIAL);
00394         glDisable(GL_DEPTH_TEST);
00395 
00396         // last thing--swap the buffers out
00397         glutSwapBuffers();
00398 }
00399 
00400 
00401 
00402 static void
00403 onIdle
00404 (
00405 void
00406 )
00407 {
00408         glutPostRedisplay();
00409 }
00410 
00411 
00412 
00413 static void
00414 onKeys
00415 (
00416 IN byte_t key,
00417 IN int x,
00418 IN int y
00419 )
00420 {
00421         DPRINTF("Pressed %d = '%c' at (%d, %d)", key, key, x, y);
00422 
00423         int mods = glutGetModifiers();
00424         if (GLUT_ACTIVE_SHIFT & mods) {
00425                 DPRINTF("  'shift' is pressed");
00426         } else if (GLUT_ACTIVE_CTRL & mods) {
00427                 DPRINTF("  'ctrl' is pressed");
00428         } else if (GLUT_ACTIVE_ALT & mods) {
00429                 DPRINTF("  'alt' is pressed");
00430         }
00431 
00432         if ('w' == key) {
00433                 s_wmode = 1 - s_wmode;
00434                 if (s_wmode) {
00435                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00436                 } else {
00437                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00438                 }
00439         }
00440 
00441         if (27 == key || 'q' == key || 'Q' == key) {
00442                 onExit();
00443         }
00444 }
00445 
00446 
00447 
00448 static void
00449 onSpecial
00450 (
00451 IN int key,
00452 IN int x,
00453 IN int y
00454 )
00455 {
00456         DPRINTF("Pressed 0x%02x at (%d, %d)", key, x, y);
00457 }
00458 
00459 
00460 
00461 static void
00462 onReshape
00463 (
00464 IN int w,
00465 IN int h
00466 )
00467 {
00468         DPRINTF("Screen size: %d x %d", w, h);
00469         s_screenWidth = w;
00470         s_screenHeight = h;
00471 
00472         glViewport(0, 0, w, h);
00473 }
00474 
00475 
00476 
00477 ////////////////////////////////////////////////////////////////////////////////
00478 //
00479 //      entry point
00480 //
00481 ////////////////////////////////////////////////////////////////////////////////
00482 
00483 int
00484 main
00485 (
00486 IN int argc,
00487 IN const char * argv[]
00488 )
00489 {
00490         ASSERT(3 == argc,
00491             "usage: mini-test <pgm-file> <ppm-file>");
00492 
00493         const char * pgm_file = argv[1];
00494         const char * ppm_file = argv[2];
00495 
00496         // initialize GLUT
00497         glutInit(&argc, (char **) argv);
00498 
00499         // initialize windows etc.
00500         glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
00501         glutInitWindowSize(s_defaultWidth, s_defaultHeight);
00502         s_winid = glutCreateWindow("test_glut");
00503         ASSERT(s_winid > 0, "Bad window id: %d", s_winid);
00504 
00505         // callbacks
00506         glutDisplayFunc(onDisplay);
00507         glutIdleFunc(onIdle);
00508         glutKeyboardFunc(onKeys);
00509         glutSpecialFunc(onSpecial);
00510         glutReshapeFunc(onReshape);
00511         glutCloseFunc(onExit);
00512 
00513         // NOTE: libmini apparently requires glut to be initialized before
00514         //      some of its library calls!  So initialize GL/GLUT first.
00515         try {
00516 
00517                 setTerrain(pgm_file, ppm_file);
00518 
00519         } catch (std::exception& e) {
00520                 DPRINTF("Exception: %s", e.what());
00521                 s_retval = 1;
00522                 onExit();
00523         }
00524 
00525         // joysticks
00526 
00527         // main loop
00528         glutMainLoop();
00529 
00530         return 0;
00531 }
00532