Main Page | Namespace List | Class List | File List | Class Members | File Members

heightfield.cpp File Reference

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <map>
#include <vector>
#include "config.h"
#include "heightfield.h"
#include "texture.h"
#include "water.h"

Go to the source code of this file.

Namespaces

namespace  std

Classes

struct  _S_VertexData
struct  _S_TexData

Functions

float gethf (int x, int y)
 Get value of the height field at certain coordinate.

_S_VertexData gethfData (int x, int y)
 Get data of the height field vertex at certain coordinate.

float diffuseLighting (const float &nx, const float &ny, const float &nz)
 Compute diffuse lighting for a vertex of the height field.

void computeNormal (int x, int y, float &nx, float &ny, float &nz)
 Compute normal to the height field at certain position.

float averageHeight (int x, int y)
TEXTURE hftexture (float h)
void initHeightField (int W, int H, const char *filename)
 Initialize the height field.

_S_VertexData averageVertex (const _S_VertexData &v1, const _S_VertexData &v2, const _S_VertexData &v3, const _S_VertexData &v4)
void streamVertex (const _S_VertexData &V, float alpha=1.0f)
void drawMultipassQuad (const _S_VertexData &v1, const _S_VertexData &v2, const _S_VertexData &v3, const _S_VertexData &v4)
void gethfVertexData (float x, float y, int xc, int yc, _S_VertexData &V)
void initGLState ()
 Initialize OpenGL state for height field rendering.

void drawHeightField (float x, float y, int w, int h)
 Draw the height field.


Variables

float g_texcoord []
float g_fLightVectorNorm = 1.0f
float * g_hf = NULL
_S_VertexDatag_hfData = NULL
int g_W = 0
int g_H = 0


Function Documentation

float averageHeight int  x,
int  y
 

Definition at line 105 of file heightfield.cpp.

References gethf().

Referenced by drawHeightField().

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 }

_S_VertexData averageVertex const _S_VertexData v1,
const _S_VertexData v2,
const _S_VertexData v3,
const _S_VertexData v4
 

Definition at line 208 of file heightfield.cpp.

References _S_VertexData::nx, _S_VertexData::ny, _S_VertexData::nz, _S_VertexData::tx, _S_VertexData::ty, _S_VertexData::x, _S_VertexData::y, and _S_VertexData::z.

Referenced by drawMultipassQuad().

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 }

void computeNormal int  x,
int  y,
float &  nx,
float &  ny,
float &  nz
[inline, static]
 

Compute normal to the height field at certain position.

Definition at line 88 of file heightfield.cpp.

References g_cellsize, g_H, g_W, and gethf().

00089 {
00090   assert( x>=0 && x<g_W );
00091   assert( y>=0 && y<g_H );
00092 
00093   // Compute normal using forward/backward differences
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   // Normalize
00098   float len = (float)sqrt( nx*nx + ny*ny + nz*nz );
00099   assert( len != 0 );
00100   nx /= len; ny /= len; nz /= len;
00101 }

float diffuseLighting const float &  nx,
const float &  ny,
const float &  nz
[inline]
 

Compute diffuse lighting for a vertex of the height field.

Definition at line 75 of file heightfield.cpp.

References colorDarkGrey, colorWhite, g_bLighting, g_fLightVectorNorm, and g_lightPos.

Referenced by streamVertex().

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 }

void drawHeightField float  x,
float  y,
int  w,
int  h
 

Draw the height field.

The field is placed in the XY plane centered in (0,0,0). The height field position (x,y) lies in the origin, and w x h tiles around this position are drawn. Each tile covers 1 square unit in OpenGL coordinates.

Definition at line 363 of file heightfield.cpp.

References averageHeight(), _S_VertexData::bShadow, _S_VertexData::bWater, drawMultipassQuad(), drawWaterQuads(), g_bBlending, gethfVertexData(), hftexture(), initGLState(), _S_VertexData::nTex, streamVertex(), TEX_N, TEXTURE, texture(), _S_WaterQuad::x, _S_VertexData::x, _S_WaterQuad::xp, _S_WaterQuad::y, _S_WaterQuad::yp, and _S_VertexData::z.

Referenced by renderScene().

00364 {
00365   // List of the water quads (rendered after field)
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       // Get correct textures for all four vertices of the next quad
00382       TEXTURE t1 = v1.nTex;
00383       TEXTURE t2 = v2.nTex;
00384       TEXTURE t3 = v3.nTex;
00385       TEXTURE t4 = v4.nTex;
00386       // Check if all are equal
00387       bool bAllEqual = false;
00388       if (t1==t2 && t2==t3 && t3==t4) {
00389         bAllEqual = true;
00390       }
00391       // Check if shadow quad
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         // Continue current triangle strip
00404         assert( t1 != TEX_N );
00405         streamVertex( v1 );
00406         streamVertex( v2 );
00407       }
00408       else {
00409         // The current texture changes. Stop the triangle strip,
00410         // if one is currently active.
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           // Only one pass is required. Start a new active
00420           // triangle strip.
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             // Draw the current quad using multiple passes.
00430             // Get coordinates for next vertices in the strip
00431               drawMultipassQuad( v1,v2,v3,v4 );
00432           }
00433           else {
00434             // Just use the texture for the average height
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 }

void drawMultipassQuad const _S_VertexData v1,
const _S_VertexData v2,
const _S_VertexData v3,
const _S_VertexData v4
 

Definition at line 245 of file heightfield.cpp.

References averageVertex(), g_bSmoothing, _S_VertexData::nTex, streamVertex(), and texture().

Referenced by drawHeightField().

00247 {
00248     // Init textures which are used for the quad
00249     // This function is not called too frequently, so it is
00250     // not heavily optimized. The map yields very
00251     // elegant code, but it's a bit slow.
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     // Draw all textures used by vertices in the quad
00259     // Should be more than 1
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           // Draw some extra geometry to improve the
00271           // boundaries between the blended textures
00272           // You can see it directly when you turn polygon fill off
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           // Standard quad version
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         // Blend from the second texture on
00300         glEnable( GL_BLEND );
00301         it++;
00302     }
00303     glDisable( GL_BLEND );
00304 }

float gethf int  x,
int  y
 

Get value of the height field at certain coordinate.

Definition at line 52 of file heightfield.cpp.

References g_H, g_hf, and g_W.

00052                             {
00053   // Not exactly as in the previous assignment, but looks 
00054   // better than modulo.
00055      x = abs(x); y=abs(y);
00056 //    while (x<0) x += g_hfW;
00057 //    while (y<0) y += g_hfH;
00058     
00059   // Tile HF over full plane
00060   return g_hf[ (x%g_W) + (y%g_H)*g_W ];
00061 }

_S_VertexData gethfData int  x,
int  y
[inline]
 

Get data of the height field vertex at certain coordinate.

Definition at line 65 of file heightfield.cpp.

References g_H, g_hfData, and g_W.

Referenced by gethfVertexData().

00065                                                {
00066   // Not exactly as in the previous assignment, but looks 
00067   // better than modulo.
00068   x = abs(x); y=abs(y);
00069   // Tile HF over full plane
00070   return g_hfData[ (x%g_W) + (y%g_H)*g_W ];
00071 }

void gethfVertexData float  x,
float  y,
int  xc,
int  yc,
_S_VertexData V
[inline]
 

Definition at line 311 of file heightfield.cpp.

References _S_VertexData::bWater, g_cellsize, g_fHeightScale, g_waterlevel, gethf(), gethfData(), _S_VertexData::x, and _S_VertexData::z.

Referenced by drawHeightField().

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 }

TEXTURE hftexture float  h  ) 
 

Definition at line 112 of file heightfield.cpp.

References g_fHeightScale, TEX_GRASS, TEX_ROCK, TEX_SAND, TEX_SNOW, and TEXTURE.

Referenced by drawHeightField(), and initHeightField().

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 }

void initGLState  ) 
 

Initialize OpenGL state for height field rendering.

Definition at line 323 of file heightfield.cpp.

References g_fLightVectorNorm, and g_lightPos.

Referenced by drawHeightField().

00324 {
00325   // Compute light vector normalization
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   // Use texture?
00331 //  if (g_bTexturing) {
00332     glEnable( GL_TEXTURE_2D );
00333 //  }
00334   // Own lighting computation
00335   glDisable( GL_LIGHTING );
00336   // Setup blending function
00337   glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00338 
00339     // MULTI-PASS RENDERING
00340 
00341     // Set up texture function for RGB and alpha channel
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     // Multiply the RGB components of the texture and the primary color
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     // Replace the alpha component
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     // Allow triangle overdrawing
00356     glDepthFunc( GL_LEQUAL );
00357 }

void initHeightField int  W,
int  H,
const char *  file
 

Initialize the height field.

The field data is loaded as W*H continuous raw floats from the file.

Definition at line 124 of file heightfield.cpp.

References computeNormal(), g_cellsize, g_fHeightScale, g_H, g_hf, g_hfData, g_strResourceDir, g_texcoord, g_tpt, g_W, gethf(), hftexture(), _S_VertexData::nTex, _S_VertexData::nx, _S_VertexData::ny, _S_VertexData::nz, _S_VertexData::tx, _S_VertexData::ty, _S_VertexData::x, _S_VertexData::y, and _S_VertexData::z.

Referenced by initGL().

00125 {
00126   // Validate params
00127   assert( W>0 && W*H > 0 );
00128   // Clear old data
00129   if (g_hf != NULL) {
00130     delete[] g_hf;
00131   }
00132   if (g_hfData != NULL) {
00133     delete[] g_hfData;
00134   }
00135 
00136   // Init new data
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   // Read data from file
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   // Init texture coords
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   // Init height field
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   // Init per vertex height field data
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 }

void streamVertex const _S_VertexData V,
float  alpha = 1.0f
[inline]
 

Definition at line 233 of file heightfield.cpp.

References diffuseLighting(), _S_VertexData::nx, _S_VertexData::ny, _S_VertexData::nz, _S_VertexData::tx, and _S_VertexData::x.

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 }


Variable Documentation

float g_fLightVectorNorm = 1.0f
 

Definition at line 20 of file heightfield.cpp.

Referenced by diffuseLighting(), and initGLState().

int g_H = 0 [static]
 

Definition at line 47 of file heightfield.cpp.

Referenced by computeNormal(), gethf(), gethfData(), and initHeightField().

float* g_hf = NULL [static]
 

Definition at line 44 of file heightfield.cpp.

Referenced by gethf(), and initHeightField().

_S_VertexData* g_hfData = NULL [static]
 

Definition at line 45 of file heightfield.cpp.

Referenced by gethfData(), and initHeightField().

float g_texcoord[]
 

Definition at line 18 of file heightfield.cpp.

Referenced by initHeightField().

int g_W = 0 [static]
 

Definition at line 46 of file heightfield.cpp.

Referenced by computeNormal(), gethf(), gethfData(), and initHeightField().


Generated on Thu Jan 20 02:46:58 2005 for Main_Demo by doxygen 1.3.6