Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Water.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2006. All Rights Reserved.
4 
5  SUBSYSTEM: nGen.lib
6  FILE: Water.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Water surface effect w/ reflection and caustics
13 */
14 
15 #include "MemDebug.h"
16 #include "Water.h"
17 #include "Random.h"
18 
19 // +--------------------------------------------------------------------+
20 
22 {
23  // Vrefract = (V + refract * N) * norm
24  float refract;
25  float refractNorm;
26  DWORD diffuse;
27 };
28 
30 {
31  float height;
33 };
34 
35 // +--------------------------------------------------------------------+
36 
37 #if defined(_X86) && !defined(_WIN64)
38 inline int f2i(float flt)
39 {
40  volatile int n;
41 
42  __asm
43  {
44  fld flt
45  fistp n
46  }
47 
48  return n;
49 }
50 #else
51 inline int f2i(float flt)
52 {
53  return (int) flt;
54 }
55 #endif
56 
57 
58 // +--------------------------------------------------------------------+
59 
60 static WATER_REFRACT RefractionTable[512];
61 static bool refractInit = false;
62 
63 static const int WAVE_SIZE = 256;
64 static const DWORD WAVE_MASK = 0xff;
65 
66 // +--------------------------------------------------------------------+
67 
69 : size(0), depth(0), scaleTex(1), avgHeight(0),
70 nVertices(0), surface(0), waves(0)
71 {
72 }
73 
75 {
76  delete [] surface;
77  delete [] waves;
78 }
79 
80 // +--------------------------------------------------------------------+
81 
82 void
83 Water::Init(int n, float s, float d)
84 {
85  size = s;
86  depth = d;
87  scaleTex = 1/size;
88 
89  // Calculate number of vertices
90  nVertices = n;
91 
92  // Create refraction table
93  if (!refractInit) {
94  WATER_REFRACT* refract = &RefractionTable[256];
95 
96  for (UINT u = 0; u < 256; u++) {
97  float fCos0 = (float) u / (float) 256.0f;
98  float f0 = acosf(fCos0);
99  float fSin0 = sinf(f0);
100 
101  float fSin1 = fSin0 / 1.333f; // water
102  float f1 = asinf(fSin1);
103  float fCos1 = cosf(f1);
104 
105  refract[u].refract = fSin0 / fSin1 * fCos1 - fCos0;
106  refract[u].refractNorm = - fSin1 / fSin0;
107  refract[u].diffuse = ((((0xff - u)*(0xff - u)*(0xff - u)) << 8) & 0xff000000);
108 
109  RefractionTable[u] = RefractionTable[256];
110  }
111 
112  refractInit = true;
113  }
114 
115  // Create maps
116  if (surface)
117  delete [] surface;
118 
119  surface = new(__FILE__,__LINE__) WATER_SURFACE[n*n];
120  ZeroMemory(surface, n*n * sizeof(WATER_SURFACE));
121 
122  if (waves)
123  delete [] waves;
124 
125  waves = new(__FILE__,__LINE__) float[WAVE_SIZE*4];
126 
127  double f = 1.0 / (double) WAVE_SIZE;
128  for (int i = 0; i < WAVE_SIZE; i++) {
129  double s0 = sin(2*PI*i*f);
130  double s1 = sin(4*PI*i*f);
131  double s2 = sin(6*PI*i*f);
132  double s3 = sin(8*PI*i*f);
133 
134  waves[0*WAVE_SIZE + i] = (float) (1.8 * s0*s0 - 0.9);
135  waves[1*WAVE_SIZE + i] = (float) (1.6 * s1*s1 - 0.8);
136  waves[2*WAVE_SIZE + i] = (float) (0.4 * s2);
137  waves[3*WAVE_SIZE + i] = (float) (0.8 * s3*s3 - 0.4);
138  }
139 
140  for (int i = 0; i < 4; i++) {
141  offsets[i] = (float) Random(0, WAVE_SIZE);
142  }
143 
144  offsets[4] = 12.45f;
145  offsets[5] = 14.23f;
146  offsets[6] = 16.72f;
147  offsets[7] = 20.31f;
148 }
149 
150 // +--------------------------------------------------------------------+
151 
152 void
153 Water::CalcWaves(double seconds)
154 {
155  int i, n[4];
156  UINT SIZE = nVertices;
157  UINT STEP = WAVE_SIZE / (SIZE-1);
158  UINT STEP2 = STEP/2;
159  UINT AREA = SIZE * SIZE;
160  UINT x, y;
161 
162  for (i = 0; i < 4; i++) {
163  n[i] = (int) offsets[i];
164  }
165 
166  WATER_SURFACE* pSurf = surface;
167 
168  // compute heights
169  for (y = 0; y < SIZE; y++) {
170  for (x = 0; x < SIZE; x++) {
171  float h = 0;
172  h += waves[ ((n[0] + x*STEP
173  - y*STEP2) & WAVE_MASK) + 0*WAVE_SIZE ];
174  h += waves[ ((n[1] + x*STEP2
175  + y*STEP) & WAVE_MASK) + 1*WAVE_SIZE ];
176  h += waves[ ((n[2] + x*STEP) & WAVE_MASK) + 2*WAVE_SIZE ];
177  h += waves[ ((n[3] + y*STEP) & WAVE_MASK) + 3*WAVE_SIZE ];
178 
179  pSurf->height = h * depth;
180  pSurf++;
181  }
182  }
183 
184  // compute normals
185  UINT uXN, uX0, uXP;
186  UINT uYN, uY0, uYP;
187 
188  uYP = AREA - SIZE;
189  uY0 = 0;
190  uYN = SIZE;
191 
192  for (y = 0; y < SIZE; y++) {
193  uXP = SIZE - 1;
194  uX0 = 0;
195  uXN = 1;
196 
197  for (x = 0; x < SIZE; x++) {
198  Vec3 vecN;
199  float f;
200 
201  f = surface[uXN + uYN].height - surface[uXP + uYP].height; vecN.x = vecN.z = f;
202  f = surface[uX0 + uYN].height - surface[uX0 + uYP].height; vecN.z += f;
203  f = surface[uXP + uYN].height - surface[uXN + uYP].height; vecN.x -= f; vecN.z += f;
204  f = surface[uXN + uY0].height - surface[uXP + uY0].height; vecN.x += f;
205 
206  vecN.y = -15.0f * depth;
207  vecN.Normalize();
208 
209  surface[uX0 + uY0].normal = vecN * -1.0f;
210 
211  uXP = uX0;
212  uX0 = uXN;
213  uXN = (uXN + 1) % SIZE;
214  }
215 
216  uYP = uY0;
217  uY0 = uYN;
218  uYN = (uYN + SIZE) % AREA;
219  }
220 
221  // update offsets
222  for (i = 0; i < 4; i++) {
223  offsets[i] += (float) (offsets[i+4] * seconds);
224 
225  if (offsets[i] > WAVE_SIZE)
226  offsets[i] -= WAVE_SIZE;
227  }
228 
229 }
230 
231 // +--------------------------------------------------------------------+
232 
233 void
235 {
236  UINT SIZE = nVertices;
237  UINT AREA = SIZE * SIZE;
238  UINT x, y;
239 
240  WATER_SURFACE* pSurf = surface;
241  Vec3* pLoc = vset->loc;
242  Vec3* pNorm = vset->nrm;
243  DWORD* pDiff = vset->diffuse;
244  float* pTu = vset->tu;
245  float* pTv = vset->tv;
246 
247  float fInc = 1.0f / (float) (SIZE-1);
248  float fx = 0.0f;
249  float fz = 0.0f;
250 
251  for (y = 0; y < SIZE; y++) {
252  for (x = 0; x < SIZE; x++) {
253  // update vertex height and normal
254  pLoc->y += pSurf->height;
255  *pNorm = pSurf->normal;
256 
257  /*
258  // Update texture coords and diffuse based upon refraction
259  Vec3 vec = eyePos - *pLoc;
260  vec.Normalize();
261 
262  WATER_REFRACT *pRefract;
263  pRefract = RefractionTable + 256 + f2i(vec.dot(*pNorm) * 255.0f);
264 
265  *pDiff = pRefract->diffuse;
266 
267  // compute apparent displacement
268  Vec3 vecD = (pSurf->normal * pRefract->refract + vec) * pRefract->refractNorm;
269  Vec3 vecP = *pLoc;
270  vecP.y -= depth;
271 
272  // perturb texture coords
273  float fB = vecD * vecP * 2.0f;
274  float fD = fB * fB - depth;
275  float fScale = (-fB + sqrtf(fD)) * 0.5f;
276 
277  *pTu = vecD.x * fScale + fx;
278  *pTv = vecD.z * fScale + fz;
279  */
280 
281  fx += fInc;
282  pSurf++;
283  pLoc++;
284  pNorm++;
285  pDiff++;
286  pTu++;
287  pTv++;
288  }
289 
290  fx = 0.0f;
291  fz += fInc;
292  }
293 }
294 
295