diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llvowater.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llvowater.cpp')
-rw-r--r-- | linden/indra/newview/llvowater.cpp | 1047 |
1 files changed, 1047 insertions, 0 deletions
diff --git a/linden/indra/newview/llvowater.cpp b/linden/indra/newview/llvowater.cpp new file mode 100644 index 0000000..55a7020 --- /dev/null +++ b/linden/indra/newview/llvowater.cpp | |||
@@ -0,0 +1,1047 @@ | |||
1 | /** | ||
2 | * @file llvowater.cpp | ||
3 | * @brief LLVOWater class implementation | ||
4 | * | ||
5 | * Copyright (c) 2005-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include "llvowater.h" | ||
31 | |||
32 | #include "imageids.h" | ||
33 | #include "llviewercontrol.h" | ||
34 | |||
35 | #include "llagent.h" | ||
36 | #include "lldrawable.h" | ||
37 | #include "lldrawpoolwater.h" | ||
38 | #include "llface.h" | ||
39 | #include "llsky.h" | ||
40 | #include "llsurface.h" | ||
41 | #include "llvosky.h" | ||
42 | #include "llviewercamera.h" | ||
43 | #include "llviewerimagelist.h" | ||
44 | #include "llviewerregion.h" | ||
45 | #include "llworld.h" | ||
46 | #include "pipeline.h" | ||
47 | |||
48 | const BOOL gUseRoam = FALSE; | ||
49 | |||
50 | |||
51 | /////////////////////////////////// | ||
52 | |||
53 | #include "randgauss.h" | ||
54 | |||
55 | template<class T> inline T LERP(T a, T b, F32 factor) | ||
56 | { | ||
57 | return a + (b - a) * factor; | ||
58 | } | ||
59 | |||
60 | const U32 N_RES_HALF = (N_RES >> 1); | ||
61 | |||
62 | const U32 WIDTH = (N_RES * WAVE_STEP); //128.f //64 // width of wave tile, in meters | ||
63 | const F32 WAVE_STEP_INV = (1. / WAVE_STEP); | ||
64 | |||
65 | const F32 g = 9.81f; // gravitational constant (m/s^2) | ||
66 | |||
67 | /////////////////////////////////// | ||
68 | |||
69 | LLWaterSurface::LLWaterSurface() : | ||
70 | mInitialized(FALSE), | ||
71 | mWind(9, 0, 0), | ||
72 | mA(0.2f), | ||
73 | mVisc(0.001f), | ||
74 | mShininess(8.0f) | ||
75 | {} | ||
76 | |||
77 | |||
78 | LLWaterGrid *LLVOWater::sGrid = 0; | ||
79 | |||
80 | |||
81 | LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) | ||
82 | : LLViewerObject(id, LL_VO_WATER, regionp) | ||
83 | { | ||
84 | // Terrain must draw during selection passes so it can block objects behind it. | ||
85 | mbCanSelect = FALSE; | ||
86 | setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility. | ||
87 | |||
88 | mUseTexture = TRUE; | ||
89 | } | ||
90 | |||
91 | |||
92 | void LLVOWater::markDead() | ||
93 | { | ||
94 | LLViewerObject::markDead(); | ||
95 | } | ||
96 | |||
97 | |||
98 | BOOL LLVOWater::isActive() const | ||
99 | { | ||
100 | return FALSE; | ||
101 | } | ||
102 | |||
103 | |||
104 | void LLVOWater::setPixelAreaAndAngle(LLAgent &agent) | ||
105 | { | ||
106 | mAppAngle = 50; | ||
107 | mPixelArea = 500*500; | ||
108 | } | ||
109 | |||
110 | |||
111 | // virtual | ||
112 | void LLVOWater::updateTextures(LLAgent &agent) | ||
113 | { | ||
114 | } | ||
115 | |||
116 | // virtual | ||
117 | void LLVOWater::updateDrawable(BOOL force_damped) | ||
118 | { | ||
119 | // Force an immediate rebuild on any update | ||
120 | if (mDrawable.notNull()) | ||
121 | { | ||
122 | gPipeline.updateMoveNormalAsync(mDrawable); | ||
123 | gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); | ||
124 | } | ||
125 | clearChanged(SHIFTED); | ||
126 | } | ||
127 | |||
128 | // Never gets called | ||
129 | BOOL LLVOWater::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) | ||
130 | { | ||
131 | if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER))) | ||
132 | { | ||
133 | return TRUE; | ||
134 | } | ||
135 | if (mDrawable) | ||
136 | { | ||
137 | gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); | ||
138 | } | ||
139 | return TRUE; | ||
140 | } | ||
141 | |||
142 | LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) | ||
143 | { | ||
144 | pipeline->allocDrawable(this); | ||
145 | mDrawable->setLit(FALSE); | ||
146 | mDrawable->setRenderType(LLPipeline::RENDER_TYPE_WATER); | ||
147 | |||
148 | LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); | ||
149 | |||
150 | if (mUseTexture) | ||
151 | { | ||
152 | mDrawable->setNumFaces(1, pool, mRegionp->getLand().getWaterTexture()); | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | mDrawable->setNumFaces(1, pool, gWorldp->getDefaultWaterTexture()); | ||
157 | } | ||
158 | |||
159 | return mDrawable; | ||
160 | } | ||
161 | |||
162 | BOOL LLVOWater::updateGeometry(LLDrawable *drawable) | ||
163 | { | ||
164 | return updateGeometryFlat(drawable); | ||
165 | } | ||
166 | |||
167 | |||
168 | BOOL LLVOWater::updateGeometryFlat(LLDrawable *drawable) | ||
169 | { | ||
170 | LLFace *face; | ||
171 | |||
172 | if (drawable->getNumFaces() < 1) | ||
173 | { | ||
174 | drawable->addFace(gPipeline.getPool(LLDrawPool::POOL_WATER), NULL); | ||
175 | } | ||
176 | face = drawable->getFace(0); | ||
177 | |||
178 | LLVector2 uvs[4]; | ||
179 | LLVector3 vtx[4]; | ||
180 | |||
181 | LLStrider<LLVector3> verticesp, normalsp; | ||
182 | LLStrider<LLVector2> texCoordsp; | ||
183 | U32 *indicesp; | ||
184 | S32 index_offset; | ||
185 | |||
186 | S32 size = 16; | ||
187 | |||
188 | S32 num_quads = size*size; | ||
189 | |||
190 | face->setPrimType(LLTriangles); | ||
191 | face->setSize(4*num_quads, 6*num_quads); | ||
192 | index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
193 | if (-1 == index_offset) | ||
194 | { | ||
195 | return TRUE; | ||
196 | } | ||
197 | |||
198 | LLVector3 position_agent; | ||
199 | position_agent = getPositionAgent(); | ||
200 | face->mCenterAgent = position_agent; | ||
201 | |||
202 | S32 x, y; | ||
203 | F32 step_x = getScale().mV[0] / size; | ||
204 | F32 step_y = getScale().mV[1] / size; | ||
205 | |||
206 | const LLVector3 up(0.f, step_y * 0.5f, 0.f); | ||
207 | const LLVector3 right(step_x * 0.5f, 0.f, 0.f); | ||
208 | const LLVector3 normal(0.f, 0.f, 1.f); | ||
209 | |||
210 | F32 size_inv = 1.f / size; | ||
211 | |||
212 | for (y = 0; y < size; y++) | ||
213 | { | ||
214 | for (x = 0; x < size; x++) | ||
215 | { | ||
216 | S32 toffset = index_offset + 4*(y*size + x); | ||
217 | position_agent = getPositionAgent() - getScale() * 0.5f; | ||
218 | position_agent.mV[VX] += (x + 0.5f) * step_x; | ||
219 | position_agent.mV[VY] += (y + 0.5f) * step_y; | ||
220 | |||
221 | vtx[0] = position_agent - right + up; | ||
222 | vtx[1] = position_agent - right - up; | ||
223 | vtx[2] = position_agent + right + up; | ||
224 | vtx[3] = position_agent + right - up; | ||
225 | |||
226 | *(verticesp++) = vtx[0]; | ||
227 | *(verticesp++) = vtx[1]; | ||
228 | *(verticesp++) = vtx[2]; | ||
229 | *(verticesp++) = vtx[3]; | ||
230 | |||
231 | uvs[0].setVec(x*size_inv, (y+1)*size_inv); | ||
232 | uvs[1].setVec(x*size_inv, y*size_inv); | ||
233 | uvs[2].setVec((x+1)*size_inv, (y+1)*size_inv); | ||
234 | uvs[3].setVec((x+1)*size_inv, y*size_inv); | ||
235 | |||
236 | *(texCoordsp) = uvs[0]; | ||
237 | texCoordsp++; | ||
238 | *(texCoordsp) = uvs[1]; | ||
239 | texCoordsp++; | ||
240 | *(texCoordsp) = uvs[2]; | ||
241 | texCoordsp++; | ||
242 | *(texCoordsp) = uvs[3]; | ||
243 | texCoordsp++; | ||
244 | |||
245 | *(normalsp++) = normal; | ||
246 | *(normalsp++) = normal; | ||
247 | *(normalsp++) = normal; | ||
248 | *(normalsp++) = normal; | ||
249 | |||
250 | *indicesp++ = toffset + 0; | ||
251 | *indicesp++ = toffset + 1; | ||
252 | *indicesp++ = toffset + 2; | ||
253 | |||
254 | *indicesp++ = toffset + 1; | ||
255 | *indicesp++ = toffset + 3; | ||
256 | *indicesp++ = toffset + 2; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | |||
261 | mDrawable->movePartition(); | ||
262 | LLPipeline::sCompiles++; | ||
263 | return TRUE; | ||
264 | } | ||
265 | |||
266 | |||
267 | BOOL LLVOWater::updateGeometryHeightFieldRoam(LLDrawable *drawable) | ||
268 | { | ||
269 | LLVector3 position_agent = getPositionAgent(); | ||
270 | const LLVector3 region_size = getScale(); | ||
271 | const LLVector3 region_origin = position_agent - region_size * 0.5f; | ||
272 | |||
273 | S32 patch_origx = llround(region_origin.mV[VX] - sGrid->mRegionOrigin.mV[VX]) / sGrid->mRegionWidth; | ||
274 | S32 patch_origy = llround(region_origin.mV[VY] - sGrid->mRegionOrigin.mV[VY]) / sGrid->mRegionWidth; | ||
275 | S32 patch_dimx = llround(region_size.mV[VX]) / sGrid->mRegionWidth; | ||
276 | S32 patch_dimy = llround(region_size.mV[VY]) / sGrid->mRegionWidth; | ||
277 | |||
278 | static S32 res = (S32)sGrid->mPatchRes; | ||
279 | if (patch_origx < 0) | ||
280 | { | ||
281 | patch_dimx -= - patch_origx; | ||
282 | if (patch_dimx < 1) | ||
283 | { | ||
284 | return TRUE; | ||
285 | } | ||
286 | patch_origx = 0; | ||
287 | } | ||
288 | if (patch_origy < 0) | ||
289 | { | ||
290 | patch_dimy -= - patch_origy; | ||
291 | if (patch_dimy < 1) | ||
292 | { | ||
293 | return TRUE; | ||
294 | } | ||
295 | patch_origy = 0; | ||
296 | } | ||
297 | if (patch_origx >= res) | ||
298 | { | ||
299 | return TRUE; | ||
300 | } | ||
301 | if (patch_origy >= res) | ||
302 | { | ||
303 | return TRUE; | ||
304 | } | ||
305 | |||
306 | patch_dimx = llmin<U32>(patch_dimx, res - patch_origx); | ||
307 | patch_dimy = llmin<U32>(patch_dimy, res - patch_origy); | ||
308 | |||
309 | U32 num_of_tris = 0; | ||
310 | S32 px, py; | ||
311 | for (py = patch_origy; py < patch_origy + patch_dimy; py++) | ||
312 | { | ||
313 | for (px = patch_origx; px < patch_origx + patch_dimx; px++) | ||
314 | { | ||
315 | const U32 ind = py * sGrid->mPatchRes + px; | ||
316 | if (sGrid->mPatches[ind].visible() && sGrid->mTab[px][py] == 0) | ||
317 | { | ||
318 | num_of_tris += sGrid->mPatches[ind].numTris(); | ||
319 | sGrid->mTab[px][py] = this; | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | |||
324 | if (num_of_tris == 0) | ||
325 | { | ||
326 | return TRUE; | ||
327 | } | ||
328 | |||
329 | if (drawable->getNumFaces() < 1) | ||
330 | { | ||
331 | drawable->addFace((LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER), | ||
332 | gWorldp->getDefaultWaterTexture()); | ||
333 | } | ||
334 | |||
335 | LLFace *face; | ||
336 | |||
337 | face = drawable->getFace(0); | ||
338 | face->mCenterAgent = position_agent; | ||
339 | |||
340 | LLStrider<LLVector3> verticesp, normalsp; | ||
341 | LLStrider<LLVector2> texCoordsp; | ||
342 | U32 *indicesp; | ||
343 | S32 index_offset; | ||
344 | |||
345 | const F32 water_height = getRegion()->getWaterHeight(); | ||
346 | |||
347 | |||
348 | face->setPrimType(LLTriangles); | ||
349 | face->setSize(3 * num_of_tris, 3 * num_of_tris); | ||
350 | index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
351 | if (-1 == index_offset) | ||
352 | { | ||
353 | return TRUE; | ||
354 | } | ||
355 | |||
356 | U32 num_of_vtx = 0; | ||
357 | |||
358 | for (py = patch_origy; py < patch_origy + patch_dimy; py++) | ||
359 | { | ||
360 | for (px = patch_origx; px < patch_origx + patch_dimx; px++) | ||
361 | { | ||
362 | for (U8 h = 0; h < 2; h++) | ||
363 | { | ||
364 | const U32 ind = py * sGrid->mPatchRes + px; | ||
365 | if (!sGrid->mPatches[ind].visible() || sGrid->mTab[px][py] != this) | ||
366 | continue; | ||
367 | LLWaterTri* half = (LLWaterTri*) sGrid->mPatches[ind].half(h); | ||
368 | for (const LLWaterTri* tri = (LLWaterTri*) half->getFirstLeaf(); | ||
369 | tri != NULL; | ||
370 | tri = (LLWaterTri*) tri->getNextLeaf()) | ||
371 | { | ||
372 | /////// check for coordinates | ||
373 | *(verticesp++) = sGrid->vtx(tri->Lvtx(), water_height); | ||
374 | *(verticesp++) = sGrid->vtx(tri->Rvtx(), water_height); | ||
375 | *(verticesp++) = sGrid->vtx(tri->Tvtx(), water_height); | ||
376 | |||
377 | *(normalsp++) = sGrid->norm(tri->Lvtx()); | ||
378 | *(normalsp++) = sGrid->norm(tri->Rvtx()); | ||
379 | *(normalsp++) = sGrid->norm(tri->Tvtx()); | ||
380 | |||
381 | *(indicesp++) = index_offset + num_of_vtx + 0; | ||
382 | *(indicesp++) = index_offset + num_of_vtx + 1; | ||
383 | *(indicesp++) = index_offset + num_of_vtx + 2; | ||
384 | num_of_vtx += 3; | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | |||
391 | LLPipeline::sCompiles++; | ||
392 | return TRUE; | ||
393 | } | ||
394 | |||
395 | |||
396 | |||
397 | BOOL LLVOWater::updateGeometryHeightFieldSimple(LLDrawable *drawable) | ||
398 | { | ||
399 | LLVector3 position_agent = getPositionAgent(); | ||
400 | const LLVector3 region_size = getScale(); | ||
401 | const LLVector3 region_origin = position_agent - region_size * 0.5f; | ||
402 | |||
403 | S32 patch_origx = llround(region_origin.mV[VX] - sGrid->mRegionOrigin.mV[VX]) / sGrid->mRegionWidth; | ||
404 | S32 patch_origy = llround(region_origin.mV[VY] - sGrid->mRegionOrigin.mV[VY]) / sGrid->mRegionWidth; | ||
405 | S32 patch_dimx = llround(region_size.mV[VX]) / sGrid->mRegionWidth; | ||
406 | S32 patch_dimy = llround(region_size.mV[VY]) / sGrid->mRegionWidth; | ||
407 | |||
408 | static S32 res = sGrid->mPatchRes; | ||
409 | if (patch_origx < 0) | ||
410 | { | ||
411 | patch_dimx -= - patch_origx; | ||
412 | if (patch_dimx < 1) | ||
413 | { | ||
414 | return TRUE; | ||
415 | } | ||
416 | patch_origx = 0; | ||
417 | } | ||
418 | if (patch_origy < 0) | ||
419 | { | ||
420 | patch_dimy -= - patch_origy; | ||
421 | if (patch_dimy < 1) | ||
422 | { | ||
423 | return TRUE; | ||
424 | } | ||
425 | patch_origy = 0; | ||
426 | } | ||
427 | if (patch_origx >= res) | ||
428 | { | ||
429 | return TRUE; | ||
430 | } | ||
431 | if (patch_origy >= res) | ||
432 | { | ||
433 | return TRUE; | ||
434 | } | ||
435 | |||
436 | patch_dimx = llmin<U32>(patch_dimx, res - patch_origx); | ||
437 | patch_dimy = llmin<U32>(patch_dimy, res - patch_origy); | ||
438 | |||
439 | |||
440 | U32 num_of_regions = 0; | ||
441 | S32 px, py; | ||
442 | |||
443 | for (py = patch_origy; py < patch_origy + patch_dimy; py++) | ||
444 | { | ||
445 | for (px = patch_origx; px < patch_origx + patch_dimx; px++) | ||
446 | { | ||
447 | // if (sGrid->mTab[px][py] != 0) | ||
448 | // bool stop = true; | ||
449 | if (sGrid->mPatches[py * sGrid->mPatchRes + px].visible() && sGrid->mTab[px][py] == 0) | ||
450 | { | ||
451 | num_of_regions++; | ||
452 | sGrid->mTab[px][py] = this; | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | if (num_of_regions == 0) | ||
458 | { | ||
459 | return TRUE; | ||
460 | } | ||
461 | |||
462 | if (drawable->getNumFaces() < 1) | ||
463 | { | ||
464 | drawable->addFace((LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER), | ||
465 | gWorldp->getDefaultWaterTexture()); | ||
466 | } | ||
467 | |||
468 | LLFace *face; | ||
469 | |||
470 | face = drawable->getFace(0); | ||
471 | face->mCenterAgent = position_agent; | ||
472 | |||
473 | LLStrider<LLVector3> verticesp, normalsp; | ||
474 | LLStrider<LLVector2> texCoordsp; | ||
475 | U32 *indicesp; | ||
476 | S32 index_offset; | ||
477 | |||
478 | const F32 water_height = getRegion()->getWaterHeight(); | ||
479 | |||
480 | const U32 steps_in_region = sGrid->mStepsInRegion / sGrid->mResDecrease; | ||
481 | const U32 num_quads = steps_in_region * steps_in_region * num_of_regions; | ||
482 | |||
483 | face->setPrimType(LLTriangles); | ||
484 | face->setSize(4*num_quads, 6*num_quads); | ||
485 | index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); | ||
486 | if (-1 == index_offset) | ||
487 | { | ||
488 | return TRUE; | ||
489 | } | ||
490 | |||
491 | U32 num_of_vtx = 0; | ||
492 | |||
493 | for (py = patch_origy; py < patch_origy + patch_dimy; py++) | ||
494 | { | ||
495 | for (px = patch_origx; px < patch_origx + patch_dimx; px++) | ||
496 | { | ||
497 | if (!sGrid->mPatches[py * sGrid->mPatchRes + px].visible() || sGrid->mTab[px][py] != this) | ||
498 | { | ||
499 | continue; | ||
500 | } | ||
501 | |||
502 | U32 orig_indx = px * sGrid->mStepsInRegion; | ||
503 | U32 orig_indy = py * sGrid->mStepsInRegion; | ||
504 | |||
505 | for (U32 qy = 0; qy < steps_in_region; qy++) | ||
506 | { | ||
507 | for (U32 qx = 0; qx < steps_in_region; qx++) | ||
508 | { | ||
509 | const S32 x0 = orig_indx + qx * sGrid->mResDecrease; | ||
510 | const S32 y0 = orig_indy + qy * sGrid->mResDecrease; | ||
511 | const S32 x1 = x0 + sGrid->mResDecrease; | ||
512 | const S32 y1 = y0 + sGrid->mResDecrease; | ||
513 | |||
514 | sGrid->setVertex(x0, y1, water_height, *(verticesp)); | ||
515 | verticesp++; | ||
516 | sGrid->setVertex(x0, y0, water_height, *(verticesp)); | ||
517 | verticesp++; | ||
518 | sGrid->setVertex(x1, y1, water_height, *(verticesp)); | ||
519 | verticesp++; | ||
520 | sGrid->setVertex(x1, y0, water_height, *(verticesp)); | ||
521 | verticesp++; | ||
522 | /* | ||
523 | *(verticesp++) = sGrid->vtx(x0, y1, water_height); | ||
524 | *(verticesp++) = sGrid->vtx(x0, y0, water_height); | ||
525 | *(verticesp++) = sGrid->vtx(x1, y1, water_height); | ||
526 | *(verticesp++) = sGrid->vtx(x1, y0, water_height); | ||
527 | */ | ||
528 | *(normalsp++) = sGrid->norm(x0, y1); | ||
529 | *(normalsp++) = sGrid->norm(x0, y0); | ||
530 | *(normalsp++) = sGrid->norm(x1, y1); | ||
531 | *(normalsp++) = sGrid->norm(x1, y0); | ||
532 | |||
533 | const S32 curr_index_offset = index_offset + num_of_vtx; | ||
534 | |||
535 | *indicesp++ = curr_index_offset + 0; | ||
536 | *indicesp++ = curr_index_offset + 1; | ||
537 | *indicesp++ = curr_index_offset + 2; | ||
538 | |||
539 | *indicesp++ = curr_index_offset + 1; | ||
540 | *indicesp++ = curr_index_offset + 3; | ||
541 | *indicesp++ = curr_index_offset + 2; | ||
542 | num_of_vtx += 4; | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | |||
548 | |||
549 | LLPipeline::sCompiles++; | ||
550 | return TRUE; | ||
551 | } | ||
552 | |||
553 | void LLVOWater::initClass() | ||
554 | { | ||
555 | sGrid = new LLWaterGrid; | ||
556 | } | ||
557 | |||
558 | void LLVOWater::cleanupClass() | ||
559 | { | ||
560 | if (sGrid) | ||
561 | { | ||
562 | sGrid->cleanup(); | ||
563 | delete sGrid; | ||
564 | sGrid = 0; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | |||
569 | LLWaterGrid::LLWaterGrid() : mResIncrease(1)//0.5) | ||
570 | { | ||
571 | init(); | ||
572 | } | ||
573 | |||
574 | |||
575 | void LLWaterGrid::init() | ||
576 | { | ||
577 | //mRegionOrigin = LLVector3(-2 * mRegionWidth, -2 * mRegionWidth, 0); | ||
578 | mRegionWidth = 256; | ||
579 | mPatchRes = 5; | ||
580 | mMaxGridSize = mPatchRes * mRegionWidth; | ||
581 | mMinStep = (U32)(WAVE_STEP * mResIncrease); | ||
582 | |||
583 | LLWaterTri::sMinStep = mMinStep; | ||
584 | LLWaterTri::sQueues = &mRoam; | ||
585 | |||
586 | setGridDim(mMaxGridSize / mMinStep); | ||
587 | |||
588 | mVtx = new LLVector3[mGridDim1 * mGridDim1]; | ||
589 | mNorms = new LLVector3[mGridDim1 * mGridDim1]; | ||
590 | |||
591 | mPatches = new LLWaterPatch[mPatchRes * mPatchRes]; | ||
592 | |||
593 | mStepsInRegion = mRegionWidth / mMinStep; | ||
594 | const U32 max_div_level = 2 * (U32)(log((F32)mStepsInRegion) / log(2.0f)); | ||
595 | |||
596 | for (U32 y = 0; y < mPatchRes; y++) | ||
597 | { | ||
598 | for (U32 x = 0; x < mPatchRes; x++) | ||
599 | { | ||
600 | LLVector3 patch_center(mRegionWidth * (x + 0.5f), mRegionWidth * (y + 0.5f), 0); | ||
601 | |||
602 | mPatches[y * mPatchRes + x].set(x * mStepsInRegion, y * mStepsInRegion, | ||
603 | mStepsInRegion, mRegionWidth, patch_center, max_div_level); | ||
604 | if (x > 0) | ||
605 | { | ||
606 | mPatches[y * mPatchRes + x].left()->setRight(mPatches[y * mPatchRes + x - 1].right()); | ||
607 | mPatches[y * mPatchRes + x - 1].right()->setRight(mPatches[y * mPatchRes + x].left()); | ||
608 | } | ||
609 | if (y > 0) | ||
610 | { | ||
611 | mPatches[y * mPatchRes + x].left()->setLeft(mPatches[(y - 1) * mPatchRes + x].right()); | ||
612 | mPatches[(y - 1) * mPatchRes + x].right()->setLeft(mPatches[y * mPatchRes + x].left()); | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | void LLWaterGrid::cleanup() | ||
619 | { | ||
620 | delete[] mVtx; | ||
621 | mVtx = NULL; | ||
622 | |||
623 | delete[] mNorms; | ||
624 | mNorms = NULL; | ||
625 | |||
626 | delete[] mPatches; | ||
627 | mPatches = NULL; | ||
628 | } | ||
629 | |||
630 | |||
631 | void setVecZ(LLVector3& v) | ||
632 | { | ||
633 | v.mV[VX] = 0; | ||
634 | v.mV[VY] = 0; | ||
635 | v.mV[VZ] = 1; | ||
636 | } | ||
637 | |||
638 | void LLWaterGrid::update() | ||
639 | { | ||
640 | static LLViewerRegion* prev_region = gAgent.getRegion(); | ||
641 | LLViewerRegion* region = gAgent.getRegion(); | ||
642 | |||
643 | mRegionOrigin = region->getOriginAgent(); | ||
644 | mRegionOrigin.mV[VX] -= 2 * mRegionWidth; | ||
645 | mRegionOrigin.mV[VY] -= 2 * mRegionWidth; | ||
646 | mRegionOrigin.mV[VZ] = 0; | ||
647 | |||
648 | const F32 clip_far = gCamera->getFar() - 31; | ||
649 | const F32 clip_far2 = clip_far * clip_far; | ||
650 | |||
651 | const LLVector3 camera_pos = gAgent.getCameraPositionAgent(); | ||
652 | const LLVector3 look_at = gCamera->getAtAxis(); | ||
653 | |||
654 | |||
655 | if (camera_pos.mV[VZ] > 200) | ||
656 | { | ||
657 | mResDecrease = 4; | ||
658 | } | ||
659 | else if (camera_pos.mV[VZ] > 100) | ||
660 | { | ||
661 | mResDecrease = 2; | ||
662 | } | ||
663 | else | ||
664 | { | ||
665 | mResDecrease = 1; | ||
666 | } | ||
667 | |||
668 | |||
669 | //U32 mResDecrease = res_decrease; | ||
670 | U32 res_decrease = 1; | ||
671 | |||
672 | const F32 res_change = mResIncrease;// * res_decrease ; | ||
673 | |||
674 | F32 height; | ||
675 | |||
676 | // Set the grid | ||
677 | |||
678 | //U32 fractions = 1; | ||
679 | U32 fractions_res = res_decrease; | ||
680 | if (res_change < 1) | ||
681 | { | ||
682 | //fractions = llround(1. / res_change); | ||
683 | fractions_res = llround(1.f / mResIncrease); | ||
684 | } | ||
685 | |||
686 | |||
687 | //const U32 fractions_res = fractions * res_decrease; | ||
688 | |||
689 | LLVector3 cur_pos; | ||
690 | U32 x, y; | ||
691 | U32 ind = 0; | ||
692 | for (y = 0; y < mGridDim1; y += fractions_res) | ||
693 | { | ||
694 | const F32 dispy = (F32)(y * mMinStep);//step; | ||
695 | for (x = 0; x < mGridDim1; x += fractions_res) | ||
696 | { | ||
697 | const F32 dispx = (F32)(x * mMinStep);//step; | ||
698 | cur_pos = mRegionOrigin; | ||
699 | cur_pos.mV[VX] += dispx; | ||
700 | cur_pos.mV[VY] += dispy; | ||
701 | |||
702 | const F32 x_dist = cur_pos.mV[VX] - camera_pos.mV[VX]; | ||
703 | const F32 y_dist = cur_pos.mV[VY] - camera_pos.mV[VY]; | ||
704 | |||
705 | if (x_dist * look_at.mV[VX] + y_dist * look_at.mV[VY] < 0) | ||
706 | { | ||
707 | mVtx[ind] = cur_pos; | ||
708 | setVecZ(mNorms[ind]); | ||
709 | ind++; | ||
710 | continue; | ||
711 | } | ||
712 | |||
713 | const F32 dist_to_vtx2 = x_dist * x_dist + y_dist * y_dist; | ||
714 | if (dist_to_vtx2 > .81 * clip_far2) | ||
715 | { | ||
716 | mVtx[ind] = cur_pos; | ||
717 | setVecZ(mNorms[ind]); | ||
718 | ind++; | ||
719 | continue; | ||
720 | } | ||
721 | |||
722 | mWater.getIntegerHeightAndNormal(llround(WAVE_STEP_INV * dispx), | ||
723 | llround(WAVE_STEP_INV * dispy), height, mNorms[ind]); | ||
724 | |||
725 | cur_pos.mV[VZ] += height; | ||
726 | mVtx[ind] = cur_pos; | ||
727 | ind++; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | if (res_change < 1) | ||
732 | { | ||
733 | U32 fractions = llround(1.f / mResIncrease); | ||
734 | for (y = 0; y < mGridDim1; y += fractions_res) | ||
735 | { | ||
736 | for (x = 0; x < mGridDim; x += fractions_res) | ||
737 | { | ||
738 | const U32 ind00 = index(x, y); | ||
739 | const U32 ind01 = ind00 + fractions_res; | ||
740 | for (U32 frx = 1; frx < fractions; frx += res_decrease) | ||
741 | { | ||
742 | const U32 ind = ind00 + frx; | ||
743 | mNorms[ind] = LERP(mNorms[ind00], mNorms[ind01], frx * res_change); | ||
744 | mVtx[ind] = LERP( mVtx[ind00], mVtx[ind01], frx * res_change); | ||
745 | } | ||
746 | } | ||
747 | } | ||
748 | for (x = 0; x < mGridDim1; x += res_decrease) | ||
749 | { | ||
750 | for (y = 0; y < mGridDim; y += fractions_res) | ||
751 | { | ||
752 | const U32 ind00 = index(x, y); | ||
753 | const U32 ind10 = ind00 + fractions_res * mGridDim1;//(y + fractions) * quad_resx1 + x; | ||
754 | for (U32 fry = 1; fry < fractions; fry += res_decrease) | ||
755 | { | ||
756 | const U32 ind = ind00 + fry * mGridDim1;//(y + fry) * quad_resx1 + x; | ||
757 | mNorms[ind] = LERP(mNorms[ind00], mNorms[ind10], fry * res_change); | ||
758 | mVtx[ind] = LERP( mVtx[ind00], mVtx[ind10], fry * res_change); | ||
759 | } | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | |||
764 | if (gUseRoam) | ||
765 | { | ||
766 | updateTree(camera_pos, look_at, clip_far, prev_region != region); | ||
767 | } | ||
768 | else | ||
769 | { | ||
770 | updateVisibility(camera_pos, look_at, clip_far); | ||
771 | } | ||
772 | |||
773 | prev_region = region; | ||
774 | |||
775 | |||
776 | //mTab[0][0] = 0; | ||
777 | for (y = 0; y < mPatchRes; y++) | ||
778 | { | ||
779 | for (x = 0; x < mPatchRes; x++) | ||
780 | mTab[x][y] = 0; | ||
781 | } | ||
782 | |||
783 | } | ||
784 | |||
785 | void LLWaterGrid::updateTree(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far, | ||
786 | BOOL restart = FALSE) | ||
787 | { | ||
788 | static S8 recalculate_frame = 0; | ||
789 | |||
790 | if (restart) | ||
791 | { | ||
792 | recalculate_frame = 0; | ||
793 | } | ||
794 | |||
795 | if (recalculate_frame == 0) | ||
796 | { | ||
797 | LLWaterTri::nextRound(); | ||
798 | setCamPosition(LLWaterTri::sCam, camera_pos); | ||
799 | LLWaterTri::sClipFar = clip_far; | ||
800 | |||
801 | |||
802 | const U32 step = (U32)(WAVE_STEP * mResIncrease * mResDecrease); | ||
803 | const U32 steps_in_region = mRegionWidth / step; | ||
804 | LLWaterTri::sMaxDivLevel = 2 * llround(log((F32)steps_in_region) / log(2.0f)); | ||
805 | |||
806 | for (U32 y = 0; y < mPatchRes; y++) | ||
807 | { | ||
808 | for (U32 x = 0; x < mPatchRes; x++) | ||
809 | { | ||
810 | U32 patch_ind = y * mPatchRes + x; | ||
811 | mPatches[patch_ind].updateTree(camera_pos, look_at, mRegionOrigin); | ||
812 | } | ||
813 | } | ||
814 | |||
815 | mRoam.process(); | ||
816 | |||
817 | // debug | ||
818 | /* | ||
819 | for (y = 0; y < mPatchRes; y++) | ||
820 | { | ||
821 | for (U32 x = 0; x < mPatchRes; x++) | ||
822 | { | ||
823 | //mPatches[y * mPatchRes + x].checkUpToDate(); | ||
824 | //mPatches[y * mPatchRes + x].checkConsistensy(); | ||
825 | mPatches[y * mPatchRes + x].checkCount(); | ||
826 | } | ||
827 | } | ||
828 | */ | ||
829 | } | ||
830 | ++recalculate_frame; | ||
831 | recalculate_frame = recalculate_frame % 2; | ||
832 | } | ||
833 | |||
834 | void LLWaterGrid::updateVisibility(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far) | ||
835 | { | ||
836 | for (U32 y = 0; y < mPatchRes; y++) | ||
837 | { | ||
838 | for (U32 x = 0; x < mPatchRes; x++) | ||
839 | { | ||
840 | mPatches[y * mPatchRes + x].updateVisibility(camera_pos, look_at, mRegionOrigin); | ||
841 | } | ||
842 | } | ||
843 | } | ||
844 | |||
845 | |||
846 | void LLVOWater::setUseTexture(const BOOL use_texture) | ||
847 | { | ||
848 | mUseTexture = use_texture; | ||
849 | } | ||
850 | |||
851 | F32 LLWaterSurface::agentDepth() const | ||
852 | { | ||
853 | const LLViewerRegion* region = gAgent.getRegion(); | ||
854 | LLVector3 position_agent = region->getOriginAgent();// getPositionAgent(); | ||
855 | const LLVector3 region_origin = position_agent; | ||
856 | const LLVector3 camera_pos = gAgent.getCameraPositionAgent(); | ||
857 | |||
858 | F32 height; | ||
859 | LLVector3 normal; | ||
860 | |||
861 | getHeightAndNormal(WAVE_STEP_INV * camera_pos.mV[VX], | ||
862 | WAVE_STEP_INV * camera_pos.mV[VY], height, normal); | ||
863 | F32 agent_water_height = gAgent.getRegion()->getWaterHeight(); | ||
864 | return camera_pos.mV[VZ] - (agent_water_height + height); | ||
865 | } | ||
866 | |||
867 | //////////////////////////////////////////////// | ||
868 | |||
869 | |||
870 | void LLWaterSurface::getHeightAndNormal(F32 i, F32 j, F32& wave_height, LLVector3& normal) const | ||
871 | { | ||
872 | S32 i_ind = llfloor(i); | ||
873 | S32 j_ind = llfloor(j); | ||
874 | F32 i_fr = i - i_ind; | ||
875 | F32 j_fr = j - j_ind; | ||
876 | |||
877 | i_ind = i_ind % N_RES; | ||
878 | j_ind = j_ind % N_RES; | ||
879 | |||
880 | S32 i_ind_next = i_ind + 1; | ||
881 | S32 j_ind_next = j_ind + 1; | ||
882 | if (i_ind_next == (S32)N_RES) i_ind_next = 0; | ||
883 | if (j_ind_next == (S32)N_RES) j_ind_next = 0; | ||
884 | |||
885 | const F32 i_fr1 = 1 - i_fr; | ||
886 | const F32 j_fr1 = 1 - j_fr; | ||
887 | |||
888 | const F32 hi0 = i_fr1 * height(i_ind, j_ind) + i_fr * height(i_ind_next, j_ind); | ||
889 | const F32 hi1 = i_fr1 * height(i_ind, j_ind_next) + i_fr * height(i_ind_next, j_ind_next); | ||
890 | wave_height = j_fr1 * hi0 + j_fr * hi1; | ||
891 | |||
892 | normal = i_fr1 * mNorms[i_ind][j_ind]; | ||
893 | normal += i_fr * mNorms[i_ind_next][j_ind]; | ||
894 | LLVector3 vi1 = i_fr1 * mNorms[i_ind][j_ind_next]; | ||
895 | vi1 += i_fr * mNorms[i_ind_next][j_ind_next]; | ||
896 | normal *= j_fr1; | ||
897 | normal += j_fr * vi1; | ||
898 | |||
899 | //normal.normVec(); | ||
900 | } | ||
901 | |||
902 | void LLWaterSurface::getIntegerHeightAndNormal(S32 i, S32 j, F32& wave_height, LLVector3& normal) const | ||
903 | { | ||
904 | S32 i_ind = i % N_RES; | ||
905 | S32 j_ind = j % N_RES; | ||
906 | |||
907 | wave_height = height(i_ind, j_ind); | ||
908 | normal = mNorms[i_ind][j_ind]; | ||
909 | } | ||
910 | |||
911 | F32 LLWaterSurface::phillips(const LLVector2& k, const LLVector2& wind_n, F32 L, F32 L_small) | ||
912 | { | ||
913 | F32 k2 = k * k; | ||
914 | F32 k_dot_wind = k * wind_n; | ||
915 | F32 spectrum = mA * (F32) exp(-1 / (L * L * k2)) / (k2 * k2) * (k_dot_wind * k_dot_wind / k2); | ||
916 | |||
917 | if (k_dot_wind < 0) spectrum *= .25f; // scale down waves that move opposite to the wind | ||
918 | |||
919 | F32 damp = (F32) exp(- k2 * L_small * L_small); | ||
920 | |||
921 | return (spectrum * damp); | ||
922 | } | ||
923 | |||
924 | |||
925 | |||
926 | void LLWaterSurface::initAmplitudes() | ||
927 | { | ||
928 | U16 i, j; | ||
929 | LLVector2 k; | ||
930 | F32 sqrtPhillips; | ||
931 | |||
932 | const LLVector2 wind(mWind.mV); | ||
933 | |||
934 | LLVector2 wind_n = wind; | ||
935 | const F32 wind_vel = wind_n.normVec(); | ||
936 | |||
937 | const F32 L = wind_vel * wind_vel / g; // largest wave arising from constant wind of speed wind_vel | ||
938 | |||
939 | const F32 L_small = L / 70; // eliminate waves with very small length (L_small << L) | ||
940 | |||
941 | |||
942 | for (i = 0; i <= N_RES; i++) | ||
943 | { | ||
944 | k.mV[VX] = (- (S32)N_RES_HALF + i) * (F_TWO_PI / WIDTH); | ||
945 | for (j = 0; j <= N_RES; j++) | ||
946 | { | ||
947 | k.mV[VY] = (- (S32)N_RES_HALF + j) * (F_TWO_PI / WIDTH); | ||
948 | |||
949 | const F32 k_mag = k.magVec(); | ||
950 | mOmega[i][j] = (F32) sqrt(g * k_mag); | ||
951 | |||
952 | if (k_mag < F_APPROXIMATELY_ZERO) | ||
953 | sqrtPhillips = 0; | ||
954 | else | ||
955 | sqrtPhillips = (F32) sqrt(phillips(k, wind_n, L, L_small)); | ||
956 | |||
957 | //const F32 r1 = rand() / (F32) RAND_MAX; | ||
958 | //const F32 r2 = rand() / (F32) RAND_MAX; | ||
959 | const F32 r1 = randGauss(0, 1); | ||
960 | const F32 r2 = randGauss(0, 1); | ||
961 | |||
962 | mHtilda0[i][j].re = sqrtPhillips * r1 * OO_SQRT2; | ||
963 | mHtilda0[i][j].im = sqrtPhillips * r2 * OO_SQRT2; | ||
964 | |||
965 | } | ||
966 | } | ||
967 | |||
968 | mPlan.init(N_RES, N_RES); | ||
969 | mInitialized = 1; // initialization complete | ||
970 | } | ||
971 | |||
972 | void LLWaterSurface::generateWaterHeightField(F64 t) | ||
973 | { | ||
974 | S32 i, j; | ||
975 | S32 mi, mj; // -K indices | ||
976 | COMPLEX plus, minus; | ||
977 | |||
978 | if (!mInitialized) initAmplitudes(); | ||
979 | |||
980 | for (i = 0; i < (S32)N_RES_HALF; i++) | ||
981 | { | ||
982 | mi = N_RES - i; | ||
983 | for (j = 0; j < (S32)N_RES ; j++) | ||
984 | { | ||
985 | mj = N_RES - j; | ||
986 | |||
987 | const F32 cos_wt = cosf(mOmega[i][j] * t); // = cos(-mOmega[i][j] * t) | ||
988 | const F32 sin_wt = sinf(mOmega[i][j] * t); // = -sin(-mOmega[i][j] * t) | ||
989 | plus.re = mHtilda0[i][j].re * cos_wt - mHtilda0[i][j].im * sin_wt; | ||
990 | plus.im = mHtilda0[i][j].re * sin_wt + mHtilda0[i][j].im * cos_wt; | ||
991 | minus.re = mHtilda0[mi][mj].re * cos_wt - mHtilda0[mi][mj].im * sin_wt; | ||
992 | minus.im = -mHtilda0[mi][mj].re * sin_wt - mHtilda0[mi][mj].im * cos_wt; | ||
993 | |||
994 | // now sum the plus and minus waves to get the total wave amplitude h | ||
995 | mHtilda[i * N_RES + j].re = plus.re + minus.re; | ||
996 | mHtilda[i * N_RES + j].im = plus.im + minus.im; | ||
997 | if (mi < (S32)N_RES && mj < (S32)N_RES) | ||
998 | { | ||
999 | mHtilda[mi * N_RES + mj].re = plus.re + minus.re; | ||
1000 | mHtilda[mi * N_RES + mj].im = -plus.im - minus.im; | ||
1001 | } | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | inverse_fft(mPlan, mHtilda, N_RES, N_RES); | ||
1006 | |||
1007 | calcNormals(); | ||
1008 | } | ||
1009 | |||
1010 | |||
1011 | /* | ||
1012 | * Computer normals by taking finite differences. | ||
1013 | */ | ||
1014 | |||
1015 | void LLWaterSurface::calcNormals() | ||
1016 | { | ||
1017 | LLVector3 n; | ||
1018 | |||
1019 | for (U32 i = 0; i < N_RES; i++) | ||
1020 | { | ||
1021 | for (U32 j = 0; j < N_RES; j++) | ||
1022 | { | ||
1023 | F32 px = heightWrapped(i + 1, j); | ||
1024 | F32 mx = heightWrapped(i - 1, j); | ||
1025 | F32 py = heightWrapped(i, j + 1); | ||
1026 | F32 my = heightWrapped(i, j - 1); | ||
1027 | F32 pxpy = heightWrapped(i + 1, j + 1); | ||
1028 | F32 pxmy = heightWrapped(i + 1, j - 1); | ||
1029 | F32 mxpy = heightWrapped(i - 1, j + 1); | ||
1030 | F32 mxmy = heightWrapped(i - 1, j - 1); | ||
1031 | |||
1032 | n.mV[VX] = -((2 * px + pxpy + pxmy) - (2 * mx + mxpy + mxmy)); | ||
1033 | n.mV[VY] = -((2 * py + pxpy + mxpy) - (2 * my + pxmy + mxmy)); | ||
1034 | n.mV[VZ] = 8 * WIDTH / (F32) N_RES; | ||
1035 | n.normVec(); | ||
1036 | |||
1037 | mNorms[i][j] = n; | ||
1038 | } | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | void LLVOWater::generateNewWaves(F64 time) | ||
1043 | { | ||
1044 | getWaterSurface()->generateWaterHeightField(time); | ||
1045 | sGrid->update(); | ||
1046 | } | ||
1047 | |||