00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00042 static const int s_delay = 100;
00043 static int s_ignoreInput = s_delay;
00044
00045
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
00060
00061
00062
00063 static void
00064 onExit
00065 (
00066 void
00067 )
00068 {
00069
00070 glutDestroyWindow(s_winid);
00071
00072
00073 std::string summary;
00074 perf::getTimingSummary(summary);
00075 DPRINTF("Timers:\n%s\n", summary.c_str());
00076
00077
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;
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
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;
00131 float yScale = 1;
00132
00133 const char * hfield_files[] = { pgm_file };
00134 const char * texture_files[] = { ppm_file };
00135
00136
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
00149 float dim = (width - 1) * xzScale;
00150
00151
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
00207 float lightAmbient[] = { 0.5, 0.5, 0.5, 1.0 };
00208 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightAmbient);
00209
00210
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
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 if (s_ignoreInput) {
00278 s_ignoreInput--;
00279 return;
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
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
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
00333
00334 viewer.rotateY(0.5 * dt);
00335
00336
00337 static glut::fps_t myFps(perf::getNow());
00338 myFps.tick(perf::getNow());
00339
00340
00341
00342 glEnable(GL_DEPTH_TEST);
00343 glEnable(GL_COLOR_MATERIAL);
00344
00345
00346 glClearColor(0.2, 0.4, 0.8, 1.0);
00347 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00348
00349
00350 glut::setOpenGLProjection(camera);
00351 glut::setOpenGLViewer(viewer);
00352
00353
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
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
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
00380 s_cache->rendercache();
00381
00382
00383
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
00393 glDisable(GL_COLOR_MATERIAL);
00394 glDisable(GL_DEPTH_TEST);
00395
00396
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
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
00497 glutInit(&argc, (char **) argv);
00498
00499
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
00506 glutDisplayFunc(onDisplay);
00507 glutIdleFunc(onIdle);
00508 glutKeyboardFunc(onKeys);
00509 glutSpecialFunc(onSpecial);
00510 glutReshapeFunc(onReshape);
00511 glutCloseFunc(onExit);
00512
00513
00514
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
00526
00527
00528 glutMainLoop();
00529
00530 return 0;
00531 }
00532