#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_VertexData * | g_hfData = NULL |
int | g_W = 0 |
int | g_H = 0 |
|
Definition at line 105 of file heightfield.cpp. References gethf(). Referenced by drawHeightField().
|
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
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.
|
|
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().
|
|
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 } |
|
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 } |
|
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 } |
|
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 } |
|
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.
|
|
Definition at line 20 of file heightfield.cpp. Referenced by diffuseLighting(), and initGLState(). |
|
Definition at line 47 of file heightfield.cpp. Referenced by computeNormal(), gethf(), gethfData(), and initHeightField(). |
|
Definition at line 44 of file heightfield.cpp. Referenced by gethf(), and initHeightField(). |
|
Definition at line 45 of file heightfield.cpp. Referenced by gethfData(), and initHeightField(). |
|
Definition at line 18 of file heightfield.cpp. Referenced by initHeightField(). |
|
Definition at line 46 of file heightfield.cpp. Referenced by computeNormal(), gethf(), gethfData(), and initHeightField(). |