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
00034 #include "terrain.h"
00035
00036 #include "common/wave_ex.h"
00037 #include "nstream/nstream.h"
00038 #include "perf/perf.h"
00039 #include "util/file.h"
00040 #include "wave-glut/glut-state.h"
00041 #include "wave-glut/wave-glut.h"
00042
00043
00044 #include "mini.h"
00045
00046
00047 namespace glut {
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 class Terrain : public Renderable {
00059 public:
00060
00061 Terrain(void) throw() { }
00062 ~Terrain(void) throw() { }
00063
00064
00065 void initialize(IN hfield::Heightfield * hfield);
00066
00067
00068 void render(IN const render_context_t& rc,
00069 IN RenderQueue * rq);
00070 rect3d_t getBoundingBox(void) const throw() { return m_boundingBox; }
00071
00072 private:
00073
00074 smart_ptr<minitile> m_tileset;
00075 smart_ptr<minicache> m_cache;
00076 point3d_t m_offset;
00077 rect3d_t m_boundingBox;
00078 float m_yOffset;
00079 };
00080
00081
00082
00083 void
00084 Terrain::initialize
00085 (
00086 IN hfield::Heightfield * hfield
00087 )
00088 {
00089 perf::Timer timer("Terrain::initialize");
00090 ASSERT(hfield, "null");
00091
00092 hfield->dump("Creating terrain rendering object");
00093
00094
00095 glPushMatrix();
00096 glMatrixMode(GL_PROJECTION);
00097 glLoadIdentity();
00098 glMatrixMode(GL_MODELVIEW);
00099 glLoadIdentity();
00100
00101
00102 glNormal3f(0, 0, 1.0);
00103
00104
00105 glBindTexture(GL_TEXTURE_2D, 0);
00106
00107 int iOldMode;
00108 glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &iOldMode);
00109 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00110
00111 int iOldMinFilter;
00112 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &iOldMinFilter);
00113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 int nRows = 1;
00125 int nCols = 1;
00126
00127 const char * pgmFile = hfield->getHeightfieldPath();
00128 ASSERT(pgmFile, "null heightfield file?");
00129
00130 const char * ppmFile = hfield->getTexturePath();
00131 ASSERT(ppmFile, "null texture file?");
00132
00133
00134 smart_ptr<nstream::Manager> mgr = hfield->getStreamManager();
00135 ASSERT_THROW(mgr, "null");
00136 std::string pgmAbs = mgr->getFullName(pgmFile);
00137 std::string ppmAbs = mgr->getFullName(ppmFile);
00138
00139 DPRINTF("height file: %s", pgmAbs.c_str());
00140 DPRINTF("texture file: %s", ppmAbs.c_str());
00141
00142 const char * hfield_files[] = { pgmAbs.c_str() };
00143 const char * texture_files[] = { ppmAbs.c_str() };
00144
00145 int width = hfield->getWidth();
00146 int length = hfield->getLength();
00147 ASSERT(width > 0 && length > 0,
00148 "Bad width or length? w=%d, h=%d", width, length);
00149
00150 ASSERT(width == length, "libmini requires width = length!");
00151
00152 float xzScale = hfield->getXZScale();
00153 ASSERT(xzScale > 0, "Bad xz-scale: %f", xzScale);
00154
00155 float xSize = (width - 1) * xzScale;
00156 float zSize = (length - 1) * xzScale;
00157
00158 float yScale = hfield->getYScale();
00159 ASSERT(yScale > 0, "Bad y-scale: %f", yScale);
00160
00161
00162 ASSERT(!m_tileset, "Already have a tileset?");
00163 m_tileset = new minitile((const unsigned char **) hfield_files,
00164 (const unsigned char **) texture_files,
00165 nRows, nCols, xSize, zSize, yScale);
00166 ASSERT(m_tileset, "out of memory");
00167
00168
00169 ASSERT(!m_cache, "already have a cache?");
00170 m_cache = new minicache();
00171 ASSERT(m_cache, "out of memory");
00172
00173
00174 m_cache->attach(m_tileset);
00175 m_cache->usevtxshader(0);
00176
00177
00178 m_boundingBox.clear();
00179 m_boundingBox.x1 = xSize;
00180 m_boundingBox.z1 = zSize;
00181 m_boundingBox.y0 = hfield->getMinHeight() * yScale;
00182 m_boundingBox.y1 = hfield->getMaxHeight() * yScale;
00183 m_boundingBox.dump("Raw bounding box (from native heightfield)");
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 m_offset.x = 0.5 * (m_boundingBox.x0 + m_boundingBox.x1);
00198 m_offset.y = 0.5 * (m_boundingBox.y0 + m_boundingBox.y1);
00199 m_offset.z = 0.5 * (m_boundingBox.z0 + m_boundingBox.z1);
00200 m_offset.dump("Calculated offset");
00201
00202 m_boundingBox.translate(-m_offset);
00203 m_boundingBox.dump("Offset bounding box");
00204
00205
00206 DPRINTF("Height at (0,0): %lf", hfield->getHeight(0, 0));
00207 DPRINTF("Height at (%f, %f): %f", -m_offset.x, -m_offset.z, hfield->getHeight(-m_offset.x, -m_offset.z));
00208
00209 float yMax = hfield->getMaxHeight() * yScale;
00210 float yMin = hfield->getMinHeight() * yScale;
00211 float yAvg = 0.5 * (yMax + yMin);
00212 DPRINTF("y-value at center: %f", yAvg);
00213 m_yOffset = -yAvg;
00214
00215
00216 glPopMatrix();
00217 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, iOldMode);
00218 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, iOldMinFilter);
00219
00220
00221
00222
00223 }
00224
00225
00226
00227 void
00228 Terrain::render
00229 (
00230 IN const render_context_t& rc,
00231 IN RenderQueue * rq
00232 )
00233 {
00234 perf::Timer timer("Terrain::render");
00235 ASSERT(rq, "null");
00236 ASSERT(m_tileset, "null");
00237 ASSERT(m_cache, "null");
00238
00239
00240
00241
00242
00243
00244 point3d_t view = rc.viewer.getFacing();
00245 point3d_t eye = rc.viewer.getPosition();
00246 point3d_t up = rc.viewer.getUp();
00247
00248
00249
00250
00251 glPushMatrix();
00252
00253
00254
00255 eye = eye - rc.placement.position;
00256 eye.y = eye.y - m_yOffset;
00257
00258 static int s_counter = 0;
00259 if (!(s_counter % 1000)) {
00260 DPRINTF("Rendering heightfield!");
00261 rc.viewer.getPosition().dump(" viewer");
00262 rc.placement.position.dump(" placement");
00263 eye.dump(" eye");
00264 m_offset.dump(" offset");
00265 DPRINTF(" y-offset: %f", m_yOffset);
00266 }
00267 ++s_counter;
00268
00269 Viewer local = rc.viewer;
00270 local.setPosition(eye);
00271 setOpenGLViewer(local);
00272
00273
00274
00275
00276
00277
00278
00279 float resolution = 400.0;
00280 int updates = 5;
00281
00282
00283
00284 int iTexMode;
00285 glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &iTexMode);
00286 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00287
00288
00289 int oldColorMaterial;
00290 glGetIntegerv(GL_COLOR_MATERIAL, &oldColorMaterial);
00291 glEnable(GL_COLOR_MATERIAL);
00292
00293
00294 int oldTexMinFilter;
00295 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00296 &oldTexMinFilter);
00297
00298
00299 float oldAmbient[4];
00300 float oldDiffuse[4];
00301 glGetMaterialfv(GL_FRONT, GL_AMBIENT, oldAmbient);
00302 glGetMaterialfv(GL_FRONT, GL_DIFFUSE, oldDiffuse);
00303
00304
00305
00306
00307
00308
00309
00310 m_cache->makecurrent();
00311
00312
00313 {
00314 perf::Timer timer("minitile::draw");
00315 m_tileset->draw(resolution,
00316 eye.x, eye.y, eye.z,
00317 view.x, view.y, view.z,
00318 up.x, up.y, up.z,
00319 rc.camera.getFovy(),
00320 rc.camera.getAspect(),
00321 rc.camera.getZNear(),
00322 rc.camera.getZFar(),
00323 updates);
00324 }
00325
00326
00327 {
00328 perf::Timer timer("minicache::draw");
00329 m_cache->rendercache();
00330 }
00331
00332
00333
00334
00335
00336 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, iTexMode);
00337 if (!oldColorMaterial) {
00338 glDisable(GL_COLOR_MATERIAL);
00339 }
00340
00341
00342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, oldTexMinFilter);
00343
00344
00345 glMaterialfv(GL_FRONT, GL_AMBIENT, oldAmbient);
00346 glMaterialfv(GL_FRONT, GL_DIFFUSE, oldDiffuse);
00347
00348
00349 glPopMatrix();
00350 }
00351
00352
00353
00354 class LoadTerrain : public Task {
00355 public:
00356 LoadTerrain(IN Terrain * terrain, IN hfield::Heightfield * hfield) {
00357 ASSERT(terrain, "null");
00358 ASSERT(hfield, "null");
00359 m_terrain = terrain;
00360 m_hfield = hfield;
00361 }
00362 void doTask(void) {
00363 ASSERT(m_terrain, "null");
00364 ASSERT(m_hfield, "null");
00365 m_terrain->initialize(m_hfield);
00366 }
00367
00368 private:
00369 Terrain * m_terrain;
00370 hfield::Heightfield * m_hfield;
00371 };
00372
00373
00374
00375
00376
00377
00378
00379
00380 smart_ptr<Renderable>
00381 createTerrain
00382 (
00383 IN hfield::Heightfield * hfield
00384 )
00385 {
00386 ASSERT(hfield, "null");
00387
00388 smart_ptr<Terrain> local = new Terrain;
00389 ASSERT(local, "out of memory");
00390
00391
00392
00393 LoadTerrain task(local, hfield);
00394 requestTask(&task);
00395 return local;
00396 }
00397
00398
00399
00400 };
00401