00001 #include <assert.h>
00002 #include <string.h>
00003 #include <stdio.h>
00004 #include <math.h>
00005 #include <algorithm>
00006 #include <map>
00007 #include <vector>
00008
00009 #include "config.h"
00010 #include "heightfield.h"
00011 #include "texture.h"
00012 #include "water.h"
00013
00014
00015 using namespace std;
00016
00017
00018 extern float g_texcoord[];
00019
00020 float g_fLightVectorNorm = 1.0f;
00021
00022
00023 struct _S_VertexData
00024 {
00025
00026 float x,y,z;
00027
00028 float nx, ny, nz;
00029
00030 float tx,ty;
00031
00032 TEXTURE nTex;
00033
00034 float sx, sy;
00035
00036 bool bShadow;
00037
00038 bool bWater;
00039 };
00040
00041
00042
00043
00044 static float *g_hf = NULL;
00045 static _S_VertexData *g_hfData = NULL;
00046 static int g_W = 0;
00047 static int g_H = 0;
00048
00049
00050
00052 float gethf( int x, int y ) {
00053
00054
00055 x = abs(x); y=abs(y);
00056
00057
00058
00059
00060 return g_hf[ (x%g_W) + (y%g_H)*g_W ];
00061 }
00062
00063
00065 inline _S_VertexData gethfData( int x, int y ) {
00066
00067
00068 x = abs(x); y=abs(y);
00069
00070 return g_hfData[ (x%g_W) + (y%g_H)*g_W ];
00071 }
00072
00073
00075 inline float diffuseLighting( const float &nx, const float &ny, const float &nz )
00076 {
00077 if (g_bLighting) {
00078 float l = nx * g_lightPos[0] + ny * g_lightPos[1] + nz * g_lightPos[2];
00079 l = 0.5 - 0.5*l*g_fLightVectorNorm;
00080 return colorDarkGrey[0] + l * (colorWhite[0] - colorDarkGrey[0]);
00081 }
00082 return 1.0f;
00083 }
00084
00085
00086
00088 static inline void computeNormal( int x, int y, float &nx, float &ny, float &nz )
00089 {
00090 assert( x>=0 && x<g_W );
00091 assert( y>=0 && y<g_H );
00092
00093
00094 nx = 0.5f * (gethf( x+1,y ) - gethf( x-1,y )) / g_cellsize;
00095 ny = -1;
00096 nz = 0.5f * (gethf( x,y+1 ) - gethf( x,y-1 )) / g_cellsize;
00097
00098 float len = (float)sqrt( nx*nx + ny*ny + nz*nz );
00099 assert( len != 0 );
00100 nx /= len; ny /= len; nz /= len;
00101 }
00102
00103
00104
00105 float averageHeight( int x, int y )
00106 {
00107 float v = gethf( x,y ) + gethf( x+1, y ) + gethf( x,y+1 ) + gethf( x+1,y+1 );
00108 return v/4.0f;
00109 }
00110
00111
00112 TEXTURE hftexture( float h )
00113 {
00114 h /= g_fHeightScale;
00115 if (h > 0.8) return TEX_SNOW;
00116 if (h > 0.5) return TEX_ROCK;
00117 if (h > 0.2) return TEX_GRASS;
00118 return TEX_SAND;
00119 }
00120
00121
00122
00124 void initHeightField( int W, int H, const char *filename )
00125 {
00126
00127 assert( W>0 && W*H > 0 );
00128
00129 if (g_hf != NULL) {
00130 delete[] g_hf;
00131 }
00132 if (g_hfData != NULL) {
00133 delete[] g_hfData;
00134 }
00135
00136
00137 g_W = W;
00138 g_H = H;
00139 g_hf = new float[W*H];
00140 g_hfData = new _S_VertexData[W*H];
00141
00142
00143 if (filename != NULL) {
00144 int L = strlen( filename ) + strlen( g_strResourceDir );
00145 char fn[L+1];
00146 strcpy( fn, g_strResourceDir );
00147 strcat( fn, filename );
00148
00149 FILE *file = fopen( fn, "rb" );
00150 assert( file != NULL );
00151 int n;
00152 if ( (n=fread( g_hf, sizeof(float), W*H, file )) != W*H) {
00153 printf( "Error loading height field, only %i floats read.", n );
00154 }
00155 else {
00156 printf( "read %i floats ... ", n );
00157 }
00158 }
00159
00160
00161 for ( int i=0; i<=g_tpt; i++) {
00162 g_texcoord[i] = float(i) / float(g_tpt);
00163 }
00164 for ( int i=0; i<g_tpt; i++) {
00165 g_texcoord[i + g_tpt] = 1.0f - float(i) / float(g_tpt);
00166 }
00167
00168
00169 for (int x=0; x<g_W; x++) {
00170 for (int y=0; y<g_H; y++) {
00171 g_hf[ x+y*g_W ] *= g_fHeightScale;
00172 }
00173 }
00174
00175
00176 for (int x=0; x<g_W; x++) {
00177 for (int y=0; y<g_H; y++) {
00178
00179 _S_VertexData &V = g_hfData[ x+y*g_W ];
00180 V.x = x * g_cellsize;
00181 V.y = gethf( x,y );
00182 V.z = y * g_cellsize;
00183 computeNormal( x,y, V.nx, V.ny, V.nz );
00184 V.tx = g_texcoord[ abs(x) % (2*g_tpt) ];
00185 V.ty = g_texcoord[ abs(y) % (2*g_tpt) ];
00186 V.nTex = hftexture( V.y );
00187
00188 }
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 struct _S_TexData {
00199 _S_TexData() {
00200 _bv1 = _bv2 = _bv3 = _bv4 = 0;
00201 };
00202
00203 int _bv1, _bv2, _bv3, _bv4;
00204 };
00205
00206
00207
00208 _S_VertexData averageVertex( const _S_VertexData &v1, const _S_VertexData &v2,
00209 const _S_VertexData &v3, const _S_VertexData &v4 )
00210 {
00211 _S_VertexData V(v1);
00212 V.x += v2.x; V.x += v3.x; V.x += v4.x;
00213 V.y += v2.y; V.y += v3.y; V.y += v4.y;
00214 V.z += v2.z; V.z += v3.z; V.z += v4.z;
00215
00216 V.nx += v2.nx; V.nx += v3.nx; V.nx += v4.nx;
00217 V.ny += v2.ny; V.ny += v3.ny; V.ny += v4.ny;
00218 V.nz += v2.nz; V.nz += v3.nz; V.nz += v4.nz;
00219
00220 V.tx += v2.tx; V.tx += v3.tx; V.tx += v4.tx;
00221 V.ty += v2.ty; V.ty += v3.ty; V.ty += v4.ty;
00222
00223 V.x /= 4.0f; V.y /= 4.0f; V.z /= 4.0f;
00224 V.nx /= 4.0f; V.ny /= 4.0f; V.nz /= 4.0f;
00225 V.tx /= 4.0f; V.ty /= 4.0f;
00226
00227 return V;
00228 }
00229
00230
00231
00232
00233 inline void streamVertex( const _S_VertexData &V, float alpha = 1.0f )
00234 {
00235 float l = diffuseLighting( V.nx, V.ny, V.nz );
00236 glColor4f( l,l,l, alpha );
00237
00238 glTexCoord2fv( &V.tx );
00239 glNormal3fv( &V.nx );
00240 glVertex3fv( &V.x );
00241 }
00242
00243
00244
00245 void drawMultipassQuad( const _S_VertexData &v1, const _S_VertexData &v2,
00246 const _S_VertexData &v3, const _S_VertexData &v4 )
00247 {
00248
00249
00250
00251
00252 map<TEXTURE, _S_TexData> textures;
00253 textures[v1.nTex]._bv1 = 1;
00254 textures[v2.nTex]._bv2 = 1;
00255 textures[v3.nTex]._bv3 = 1;
00256 textures[v4.nTex]._bv4 = 1;
00257
00258
00259
00260 if ( textures.size() <= 1 ) {
00261 printf( "Wrong number of textures: %u\n", textures.size() );
00262 assert( false );
00263 }
00264
00265 map<TEXTURE, _S_TexData>::const_iterator it = textures.begin();
00266 while( it != textures.end() ) {
00267 glBindTexture( GL_TEXTURE_2D, texture((*it).first) );
00268
00269 if (g_bSmoothing) {
00270
00271
00272
00273 _S_VertexData V = averageVertex( v1,v2,v3,v4 );
00274 float c = (*it).second._bv1 + (*it).second._bv2 +
00275 (*it).second._bv3 + (*it).second._bv4;
00276 if (c<=1.0f) c=0.0f;
00277 else if (c==2.0f) c=0.5f;
00278 else c=1.0f;
00279
00280 glBegin( GL_TRIANGLE_FAN );
00281 streamVertex( V, c );
00282 streamVertex( v1, (*it).second._bv1 );
00283 streamVertex( v2, (*it).second._bv2 );
00284 streamVertex( v3, (*it).second._bv3 );
00285 streamVertex( v4, (*it).second._bv4 );
00286 streamVertex( v1, (*it).second._bv1 );
00287 glEnd();
00288 }
00289 else {
00290
00291 glBegin( GL_QUADS );
00292 streamVertex( v1, (*it).second._bv1 );
00293 streamVertex( v2, (*it).second._bv2 );
00294 streamVertex( v3, (*it).second._bv3 );
00295 streamVertex( v4, (*it).second._bv4 );
00296 glEnd();
00297 }
00298
00299
00300 glEnable( GL_BLEND );
00301 it++;
00302 }
00303 glDisable( GL_BLEND );
00304 }
00305
00306
00307
00308
00309
00310
00311 inline void gethfVertexData( float x, float y, int xc, int yc, _S_VertexData &V )
00312 {
00313 V = gethfData( xc,yc );
00314 V.x = (xc-x)*g_cellsize;
00315 V.z = (yc-y)*g_cellsize;
00316
00317 V.bWater = (gethf(xc,yc) < g_waterlevel * g_fHeightScale);
00318 }
00319
00320
00321
00323 void initGLState()
00324 {
00325
00326 float L = g_lightPos[0]*g_lightPos[0];
00327 L += g_lightPos[1]*g_lightPos[1];
00328 L += g_lightPos[2]*g_lightPos[2];
00329 g_fLightVectorNorm = 1.0f / sqrt(L);
00330
00331
00332 glEnable( GL_TEXTURE_2D );
00333
00334
00335 glDisable( GL_LIGHTING );
00336
00337 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00338
00339
00340
00341
00342 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
00343 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE );
00344 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE );
00345
00346 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT );
00347 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR );
00348 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE );
00349 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR );
00350
00351 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT );
00352 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA );
00353 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE );
00354 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, GL_SRC_ALPHA );
00355
00356 glDepthFunc( GL_LEQUAL );
00357 }
00358
00359
00360
00361
00363 void drawHeightField( float x, float y, int w, int h )
00364 {
00365
00366 vector<_S_WaterQuad> water;
00367
00368 initGLState();
00369 int xi = int(x);
00370 int yi = int(y);
00371 for (int xc=xi-w; xc <= xi+w; xc++ ) {
00372 TEXTURE nCurrentTexture = TEX_N;
00373 _S_VertexData v1, v2;
00374 gethfVertexData( x,y, xc+1, yi-h, v1 );
00375 gethfVertexData( x,y, xc, yi-h, v2 );
00376 for ( int yc=yi-h; yc <= yi+h; yc++ ) {
00377 _S_VertexData v3, v4;
00378 gethfVertexData( x,y, xc, yc+1, v3 );
00379 gethfVertexData( x,y, xc+1, yc+1, v4 );
00380
00381
00382 TEXTURE t1 = v1.nTex;
00383 TEXTURE t2 = v2.nTex;
00384 TEXTURE t3 = v3.nTex;
00385 TEXTURE t4 = v4.nTex;
00386
00387 bool bAllEqual = false;
00388 if (t1==t2 && t2==t3 && t3==t4) {
00389 bAllEqual = true;
00390 }
00391
00392 bool bShadow = false;
00393 if (v1.bShadow || v2.bShadow || v3.bShadow || v4.bShadow) {
00394 bShadow = true;
00395 }
00396
00397 bool bWater = false;
00398 if (v1.bWater || v2.bWater || v3.bWater || v4.bWater) {
00399 bWater = true;
00400 }
00401
00402 if (bAllEqual && t1==nCurrentTexture && !bShadow && !bWater) {
00403
00404 assert( t1 != TEX_N );
00405 streamVertex( v1 );
00406 streamVertex( v2 );
00407 }
00408 else {
00409
00410
00411 if ( nCurrentTexture != TEX_N ) {
00412 streamVertex( v1 );
00413 streamVertex( v2 );
00414 nCurrentTexture = TEX_N;
00415 glEnd();
00416 }
00417
00418 if (bAllEqual && !bShadow && !bWater) {
00419
00420
00421 glBindTexture( GL_TEXTURE_2D, texture(t1) );
00422 glBegin( GL_TRIANGLE_STRIP );
00423 nCurrentTexture = t1;
00424 streamVertex( v1 );
00425 streamVertex( v2 );
00426 }
00427 else {
00428 if ( g_bBlending && !bAllEqual ) {
00429
00430
00431 drawMultipassQuad( v1,v2,v3,v4 );
00432 }
00433 else {
00434
00435 TEXTURE tex = hftexture( averageHeight( xc,yc ));
00436 glBindTexture( GL_TEXTURE_2D, texture(tex) );
00437 glBegin( GL_QUADS );
00438 streamVertex( v1 );
00439 streamVertex( v2 );
00440 streamVertex( v3 );
00441 streamVertex( v4 );
00442 glEnd();
00443 }
00444
00445 if (bWater) {
00446 _S_WaterQuad W;
00447 W.x = xc; W.y = yc;
00448 W.xp = v2.x; W.yp = v2.z;
00449 water.push_back( W );
00450 }
00451 }
00452 }
00453 v1 = v4; v2 = v3;
00454 }
00455
00456 glEnd();
00457 }
00458 glDisable( GL_TEXTURE_2D );
00459
00460 drawWaterQuads( water );
00461 glEnable( GL_LIGHTING );
00462 }