00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <fstream>
00012 #include <math.h>
00013
00014 #include "common/wave_ex.h"
00015 #include "glut-font/glut-font.h"
00016 #include "perf/perf.h"
00017 #include "terrain/terrain.h"
00018 #include "util/file.h"
00019 #include "wave-glut/glut-state.h"
00020 #include "wave-glut/glut_2d.h"
00021 #include "wave-glut/wave-glut.h"
00022
00023
00024 static const int s_defaultWidth = 800;
00025 static const int s_defaultHeight = 600;
00026
00027 static int s_screenWidth = s_defaultWidth;
00028 static int s_screenHeight = s_defaultHeight;
00029
00030 static const float s_twoPi = 2.0 * M_PI;
00031
00032 typedef short int height_t;
00033
00034 static int s_winid = -1;
00035
00036
00037
00038 static const int s_delay = 100;
00039
00040 static int s_wmode = 0;
00041
00042
00043 static point3d_t s_lightPosition(0.0, 0.0, 0.0);
00044 static point3d_t s_lightVelocity(0.0, 0.0, -0.01);
00045
00046 static int s_retval = 0;
00047
00048
00049 static smart_ptr<hfield::Heightfield> s_hfield;
00050 static smart_ptr<glut::Renderable> s_terrain;
00051
00052
00053
00054
00055
00056
00057
00058
00059 static void
00060 onExit
00061 (
00062 void
00063 )
00064 {
00065
00066 glutDestroyWindow(s_winid);
00067
00068
00069 std::string summary;
00070 perf::getTimingSummary(summary);
00071 DPRINTF("Timers:\n%s\n", summary.c_str());
00072
00073
00074 exit(s_retval);
00075 }
00076
00077
00078
00079 static void
00080 setTerrain
00081 (
00082 IN const char * hfield_file
00083 )
00084 {
00085 perf::Timer timer("setTerrain");
00086 ASSERT(hfield_file, "null");
00087
00088
00089 smart_ptr<nstream::Manager> mgr =
00090 nstream::getFilesystemManager("");
00091 ASSERT(mgr, "null");
00092
00093
00094 smart_ptr<nstream::Stream> stream =
00095 nstream::openNamedStream(mgr, hfield_file);
00096 ASSERT(stream, "null");
00097 s_hfield = hfield::Heightfield::create(stream);
00098 ASSERT(s_hfield, "Failed to load heightfield from file");
00099 s_hfield->dump(hfield_file);
00100
00101
00102 s_terrain = glut::createTerrain(s_hfield);
00103 ASSERT(s_terrain, "failed to create terrain object");
00104 }
00105
00106
00107
00108 static void
00109 setLight
00110 (
00111 IN float t
00112 )
00113 {
00114 glEnable(GL_LIGHTING);
00115 glEnable(GL_LIGHT0);
00116 glShadeModel(GL_SMOOTH);
00117
00118
00119 float lightModel[] = { 0.2, 0.2, 0.2, 1.0 };
00120 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightModel);
00121
00122 float lightPos[] = { sin(t), cos(t), 0, 0 };
00123 glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
00124
00125 float lightAmbient[] = { 0, 0, 0, 1 };
00126 glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
00127
00128 float lightDiffuse[] = { 1, 1, 1, 1 };
00129 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
00130 glLightfv(GL_LIGHT0, GL_SPECULAR, lightDiffuse);
00131 }
00132
00133
00134
00135 static void
00136 onDisplay
00137 (
00138 IN glut::RenderQueue * rq
00139 )
00140 {
00141 perf::Timer timer("onDisplay");
00142 ASSERT(rq, "null");
00143
00144 static float t = 0.0;
00145 const float dt = 0.002;
00146 t += dt;
00147
00148 float xzScale = s_hfield->getXZScale();
00149 float W = xzScale * s_hfield->getWidth();
00150 float H = xzScale * s_hfield->getLength();
00151
00152 float T = s_hfield->getMaxHeight() - s_hfield->getMinHeight();
00153
00154
00155 float K = 2;
00156 point3d_t pos(sin(K * t), 0, sin((37 / 17) * K * (t + 0.2)));
00157 pos = 0.8 * W * pos;
00158
00159
00160 glut::render_context_t rc;
00161 rc.viewer.setPosition(pos);
00162 point3d_t vpos = rc.viewer.getPosition();
00163
00164
00165 float hX = vpos.x + 0.5 * W;
00166 float hZ = vpos.z + 0.5 * H;
00167 float min_y = s_hfield->getHeight(hX, hZ) + 0.1 * (1.0 + sin(0.8773 * t)) * (W + 0.25 * T);
00168 float dy = (min_y - vpos.y);
00169 rc.viewer.move(0, 0, dy);
00170
00171
00172
00173
00174 vpos = rc.viewer.getPosition();
00175 float R2 = dotProduct(vpos, vpos);
00176 float R = sqrt(R2);
00177
00178
00179 float phi = atan2(-vpos.x, -vpos.z);
00180 while (phi < 0.0) {
00181 phi += s_twoPi;
00182 }
00183 while (phi > s_twoPi) {
00184 phi -= s_twoPi;
00185 }
00186
00187 float rho = asin(-vpos.y / R);
00188
00189
00190
00191
00192 rc.viewer.setYRotation(phi);
00193 rc.viewer.setUpRotation(rho);
00194
00195
00196
00197
00198
00199 static glut::fps_t myFps(perf::getNow());
00200 myFps.tick(perf::getNow());
00201
00202
00203
00204 glEnable(GL_DEPTH_TEST);
00205
00206
00207 glClearColor(0.2, 0.4, 0.8, 1.0);
00208 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
00209
00210 if (s_wmode) {
00211 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00212 } else {
00213 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00214 }
00215
00216
00217 glut::setOpenGLProjection(rc.camera);
00218 glut::setOpenGLViewer(rc.viewer);
00219
00220
00221 glColor3f(1.0, 1.0, 1.0);
00222 setLight(t);
00223
00224
00225 glEnable(GL_COLOR_MATERIAL);
00226 s_terrain->render(rc, rq);
00227 glDisable(GL_COLOR_MATERIAL);
00228
00229
00230 glDisable(GL_LIGHTING);
00231 glDisable(GL_DEPTH_TEST);
00232 {
00233 perf::Timer timer("display-2d");
00234
00235
00236 glut::push2D(s_screenWidth, s_screenHeight);
00237 glColor3f(0, 0, 0);
00238 glut::Font * font = glut::getDefaultFont();
00239 char buffer[1024];
00240 sprintf(buffer, "%5.1f FPS", myFps.getFPS());
00241 font->display(10, 15, 0.0, buffer);
00242 glut::pop2D();
00243 }
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 class TestHost : public glut::Host {
00272 public:
00273 virtual ~TestHost(void) throw() { }
00274
00275
00276 void init(void) {
00277 setTerrain(m_hfieldFilename.c_str());
00278
00279 int nSlots = 8;
00280 m_rQueue = glut::RenderQueue::create(nSlots);
00281 ASSERT(m_rQueue, "null");
00282 }
00283 void display(IN int w, IN int h) {
00284 onDisplay(m_rQueue);
00285 }
00286 int shutdown(void) {
00287 onExit();
00288 return 0;
00289 }
00290 eBehavior keyboard(IN int key, IN int mods) {
00291 switch (key) {
00292 case 'w':
00293 s_wmode = 1 - s_wmode;
00294 break;
00295
00296 case 27:
00297 case 'q':
00298 return eExit;
00299 }
00300
00301 return eContinue;
00302 }
00303
00304
00305 static smart_ptr<glut::Host> create(IN const char * hfieldFilename) {
00306 ASSERT(hfieldFilename, "null");
00307
00308 smart_ptr<TestHost> local = new TestHost;
00309 ASSERT(local, "out of memory");
00310
00311 local->m_hfieldFilename = hfieldFilename;
00312
00313 return local;
00314 }
00315
00316 private:
00317
00318 std::string m_hfieldFilename;
00319 smart_ptr<glut::RenderQueue> m_rQueue;
00320 };
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 int
00331 main
00332 (
00333 IN int argc,
00334 IN const char * argv[]
00335 )
00336 {
00337 ASSERT(2 == argc,
00338 "usage: terrain-test <hfield-file>");
00339
00340 const char * hfield_file = argv[1];
00341
00342 try {
00343
00344 smart_ptr<glut::Host> host = TestHost::create(hfield_file);
00345 ASSERT(host, "NULL");
00346
00347 std::string title = "Terrain Test: ";
00348 title += GetFilename(hfield_file);
00349
00350 glut::start(argc, argv, s_defaultWidth, s_defaultHeight,
00351 title.c_str(), NULL, host);
00352
00353 } catch (std::exception& e) {
00354 DPRINTF("Exception: %s", e.what());
00355 s_retval = 1;
00356 onExit();
00357 }
00358
00359 return 0;
00360 }
00361