00001 #include <GL/gl.h>
00002 #include <assert.h>
00003 #include <math.h>
00004 #include <string.h>
00005 #include <stdio.h>
00006 #include <complex>
00007
00008 #include "config.h"
00009 #include "water.h"
00010
00011
00012 using namespace std;
00013
00014
00015
00016
00017 typedef float normal[3];
00018 static float *g_hf = NULL;
00019 static normal *g_hf_normals = NULL;
00020 static float *g_hf_fc_re = NULL;
00021 static float *g_hf_fc_im = NULL;
00022 static int g_W = 0;
00023 static int g_H = 0;
00024
00025 static float g_xe, g_ye, g_ze;
00026
00027
00029 static inline float gethf( int x, int y ) {
00030 while (x<0) x += g_W;
00031 while (y<0) y += g_H;
00032 return g_hf[ (x%g_W) + (y%g_H)*g_W ];
00033 }
00034
00035 static inline const normal& getnormal( int x, int y )
00036 {
00037 while (x<0) x += g_W;
00038 while (y<0) y += g_H;
00039 return g_hf_normals[ (x%g_W) + (y%g_H)*g_W ];
00040 }
00041
00042
00043
00045 static inline void computeNormal( int x, int y, float &nx, float &ny, float &nz )
00046 {
00047 assert( x>=0 && x<g_W );
00048 assert( y>=0 && y<g_H );
00049
00050
00051 nx = 0.5f * (gethf( x+1,y ) - gethf( x-1,y )) / g_cellsize;
00052 ny = -1;
00053 nz = 0.5f * (gethf( x,y+1 ) - gethf( x,y-1 )) / g_cellsize;
00054
00055 float len = (float)sqrt( nx*nx + ny*ny + nz*nz );
00056 assert( len != 0 );
00057 nx /= len; ny /= len; nz /= len;
00058 }
00059
00060
00061
00062
00064 double gauss_rand()
00065 {
00066 int nSum = 0;
00067 for (unsigned i=0; i<100; i++) {
00068 nSum += (rand()%2);
00069 }
00070 return double(nSum-50) / 25.0;
00071 }
00072
00073
00074
00075 complex<float> fourier( float x, float y )
00076 {
00077 const float windx = 1.0;
00078 const float windy = 0.8;
00079 const float gravity = 9.81;
00080 float wind_speed2 = windx*windx + windy*windy;
00081
00082 float k2 = x*x + y*y;;
00083 float f1 = exp( -0.5*gravity*gravity / (k2 * wind_speed2 * wind_speed2) );
00084 float f2 = abs(x*windx + y*windy) / k2;
00085 float phillips = f1*f2;
00086
00087 return float(1.0 / sqrt(2.0)) * complex<float>( gauss_rand(), gauss_rand() ) * phillips;
00088 }
00089
00090
00091
00093 void initWater( int W, int H )
00094 {
00095
00096 assert( W>0 && W*H > 0 );
00097
00098 delete[] g_hf;
00099 delete[] g_hf_normals;
00100 delete[] g_hf_fc_re;
00101 delete[] g_hf_fc_im;
00102
00103
00104 g_W = W;
00105 g_H = H;
00106 g_hf = new float[W*H];
00107 g_hf_normals = new normal[W*H];
00108 g_hf_fc_re = new float[W*H];
00109 g_hf_fc_im = new float[W*H];
00110
00111 for (int x=0; x<g_W; x++) {
00112 for (int y=0; y<g_H; y++) {
00113 complex<float> fc = fourier( x,y );
00114 g_hf_fc_re[x+y*g_W] = real(fc);
00115 g_hf_fc_im[x+y*g_W] = imag(fc);
00116 }
00117 }
00118 g_hf_fc_re[0] = 0;
00119 g_hf_fc_im[0] = 0;
00120
00121 computeWater( 0.0f );
00122 }
00123
00125 float computeHeight( int x, int y, float t )
00126 {
00127 float tOff = t*0.1f;
00128 float re = 0.0f;
00129
00130 const int N = 8;
00131 for (int xc=1; xc<N; xc++) {
00132 for (int yc=1; yc<N; yc++) {
00133 float xp = x/float(g_W);
00134 float yp = y/float(g_H);
00135 float p = 2*M_PI* (xc*(xp+tOff) + yc*(yp+tOff));
00136 int i = xc + yc*g_W;
00137 re += g_hf_fc_re[i]*cos(p) - g_hf_fc_im[i]*sin(p);
00138 }
00139 }
00140 return g_fWaterScale * re / N*N;
00141 }
00142
00144
00145 void computeWater( float fTime )
00146 {
00147
00148 g_xe = g_CameraX;
00149 g_ze = g_CameraZ;
00150 g_ye = g_CameraY;
00151
00152
00153 float *p = g_hf;
00154 for (int y=0; y<g_H; y++) {
00155 for (int x=0; x<g_W; x++) {
00156 *p = computeHeight( x,y, fTime );
00157 p++;
00158 }
00159 }
00160
00161
00162 normal *pN = g_hf_normals;
00163 for (int y=0; y<g_H; y++) {
00164 for (int x=0; x<g_W; x++) {
00165 computeNormal( x,y, (*pN)[0], (*pN)[1], (*pN)[2] );
00166 pN++;
00167 }
00168 }
00169 }
00170
00171
00172
00173 inline float fresnelTerm( float a )
00174 {
00175
00176 float b = 1.0f / (1.0f+a);
00177 return b*b;
00178 }
00179
00180
00181 inline void streamVertex( int x, int y, float xp, float yp, float zoff )
00182 {
00183
00184 const normal& n = getnormal( x,y );
00185
00186 float col[4];
00187
00188
00189
00190
00191
00192
00193 if (day)
00194 {
00195 col[0] = colorSky[0];
00196 col[1] = colorSky[1];
00197 col[2] = colorSky[2];
00198 }
00199 else
00200 {
00201 col[0] = colorWaterGreen[0];
00202 col[1] = colorWaterGreen[1];
00203 col[2] = colorWaterGreen[2];
00204 }
00205
00206 float zp = zoff + gethf(x,y);
00207
00208 float ex = g_xe-xp; float ez = g_ye-yp; float ey = g_ze-zp;
00209 float l = sqrt( ex*ex + ey*ey + ez*ez );
00210 ex /= l; ey /= l; ez /= l;
00211 float a = ex*n[0] + ey*n[1] + ez*n[2];
00212 if (g_bFresnel) {
00213 col[3] = fresnelTerm( a );
00214 }
00215 else {
00216 col[3] = 0.5f;
00217 }
00218
00219
00220
00221 float rx = -ex + 2*a*n[0];
00222 float ry = -ey + 2*a*n[1];
00223 float rz = -ez + 2*a*n[2];
00224 glTexCoord3f( rx,ry,rz );
00225
00226 glColor4fv( col );
00227 glNormal3fv( n );
00228 glVertex3f( xp, zp, yp );
00229 }
00230
00231
00232
00233 void drawWaterQuad( int x, int y, float xp, float yp )
00234 {
00235
00236 float zOff = g_waterlevel * g_fHeightScale;
00237 streamVertex( x ,y+1, xp , yp+g_cellsize,zOff );
00238 streamVertex( x+1,y+1, xp+g_cellsize, yp+g_cellsize,zOff );
00239 streamVertex( x+1,y , xp+g_cellsize, yp ,zOff );
00240 streamVertex( x ,y , xp , yp ,zOff );
00241 }
00242
00243
00244 void drawWaterQuads( const vector<_S_WaterQuad> &water )
00245 {
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 glEnable( GL_BLEND );
00268
00269
00270 vector<_S_WaterQuad>::const_iterator it = water.begin();
00271 glBegin( GL_QUADS );
00272 while ( it != water.end() ) {
00273 drawWaterQuad( (*it).x, (*it).y, (*it).xp, (*it).yp );
00274 it++;
00275 }
00276 glEnd();
00277
00278
00279 glDisable( GL_BLEND );
00280 glDisable( GL_TEXTURE_CUBE_MAP );
00281 }