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/llsurface.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 '')
-rw-r--r-- | linden/indra/newview/llsurface.cpp | 1356 |
1 files changed, 1356 insertions, 0 deletions
diff --git a/linden/indra/newview/llsurface.cpp b/linden/indra/newview/llsurface.cpp new file mode 100644 index 0000000..c1b22c9 --- /dev/null +++ b/linden/indra/newview/llsurface.cpp | |||
@@ -0,0 +1,1356 @@ | |||
1 | /** | ||
2 | * @file llsurface.cpp | ||
3 | * @brief Implementation of LLSurface class | ||
4 | * | ||
5 | * Copyright (c) 2000-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 "llsurface.h" | ||
31 | |||
32 | #include "llviewerimagelist.h" | ||
33 | #include "llpatchvertexarray.h" | ||
34 | #include "patch_dct.h" | ||
35 | #include "patch_code.h" | ||
36 | #include "bitpack.h" | ||
37 | #include "llviewerobjectlist.h" | ||
38 | #include "llregionhandle.h" | ||
39 | #include "llagent.h" | ||
40 | #include "viewer.h" | ||
41 | #include "llworld.h" | ||
42 | #include "llviewercontrol.h" | ||
43 | #include "llviewerimage.h" | ||
44 | #include "llsurfacepatch.h" | ||
45 | #include "llvosurfacepatch.h" | ||
46 | #include "llvowater.h" | ||
47 | #include "pipeline.h" | ||
48 | #include "llviewerregion.h" | ||
49 | #include "llvlcomposition.h" | ||
50 | #include "noise.h" | ||
51 | #include "llviewercamera.h" | ||
52 | #include "llglheaders.h" | ||
53 | #include "lldrawpool.h" | ||
54 | #include "lldrawable.h" | ||
55 | |||
56 | extern LLPipeline gPipeline; | ||
57 | |||
58 | LLColor4U MAX_WATER_COLOR(0, 48, 96, 240); | ||
59 | |||
60 | |||
61 | S32 LLSurface::sTextureSize = 256; | ||
62 | S32 LLSurface::sTexelsUpdated = 0; | ||
63 | F32 LLSurface::sTextureUpdateTime = 0.f; | ||
64 | LLStat LLSurface::sTexelsUpdatedPerSecStat; | ||
65 | |||
66 | extern void bad_network_handler(); | ||
67 | |||
68 | // ---------------- LLSurface:: Public Members --------------- | ||
69 | |||
70 | LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) : | ||
71 | mGridsPerEdge(0), | ||
72 | mOOGridsPerEdge(0.f), | ||
73 | mPatchesPerEdge(0), | ||
74 | mType(type), | ||
75 | mOriginGlobal(0.0, 0.0, 0.0), | ||
76 | mSTexturep(NULL), | ||
77 | mWaterTexturep(NULL), | ||
78 | mGridsPerPatchEdge(0), | ||
79 | mMetersPerGrid(1.0f), | ||
80 | mMetersPerEdge(1.0f), | ||
81 | mRegionp(regionp) | ||
82 | { | ||
83 | // Surface data | ||
84 | mSurfaceZ = NULL; | ||
85 | mNorm = NULL; | ||
86 | |||
87 | // Patch data | ||
88 | mPatchList = NULL; | ||
89 | |||
90 | // One of each for each camera | ||
91 | mVisiblePatchCount = 0; | ||
92 | |||
93 | mHasZData = FALSE; | ||
94 | // "uninitialized" min/max z | ||
95 | mMinZ = 10000.f; | ||
96 | mMaxZ = -10000.f; | ||
97 | |||
98 | mWaterObjp = NULL; | ||
99 | |||
100 | // In here temporarily. | ||
101 | mSurfacePatchUpdateCount = 0; | ||
102 | |||
103 | for (S32 i = 0; i < 8; i++) | ||
104 | { | ||
105 | mNeighbors[i] = NULL; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | |||
110 | LLSurface::~LLSurface() | ||
111 | { | ||
112 | delete [] mSurfaceZ; | ||
113 | mSurfaceZ = NULL; | ||
114 | |||
115 | delete [] mNorm; | ||
116 | |||
117 | mGridsPerEdge = 0; | ||
118 | mGridsPerPatchEdge = 0; | ||
119 | mPatchesPerEdge = 0; | ||
120 | mNumberOfPatches = 0; | ||
121 | destroyPatchData(); | ||
122 | |||
123 | LLDrawPool *poolp = gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep); | ||
124 | if (!poolp) | ||
125 | { | ||
126 | llwarns << "No pool for terrain on destruction!" << llendl; | ||
127 | } | ||
128 | else if (poolp->mReferences.empty()) | ||
129 | { | ||
130 | gPipeline.removePool(poolp); | ||
131 | // Don't enable this until we blitz the draw pool for it as well. -- djs | ||
132 | if (mSTexturep) | ||
133 | { | ||
134 | gImageList.deleteImage(mSTexturep); | ||
135 | mSTexturep = NULL; | ||
136 | } | ||
137 | if (mWaterTexturep) | ||
138 | { | ||
139 | gImageList.deleteImage(mWaterTexturep); | ||
140 | mWaterTexturep = NULL; | ||
141 | } | ||
142 | } | ||
143 | else | ||
144 | { | ||
145 | llerrs << "Terrain pool not empty!" << llendl; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | void LLSurface::initClasses() | ||
150 | { | ||
151 | } | ||
152 | |||
153 | void LLSurface::setRegion(LLViewerRegion *regionp) | ||
154 | { | ||
155 | mRegionp = regionp; | ||
156 | } | ||
157 | |||
158 | // Assumes that arguments are powers of 2, and that | ||
159 | // grids_per_edge / grids_per_patch_edge = power of 2 | ||
160 | void LLSurface::create(const S32 grids_per_edge, | ||
161 | const S32 grids_per_patch_edge, | ||
162 | const LLVector3d &origin_global, | ||
163 | const F32 width) | ||
164 | { | ||
165 | // Initialize various constants for the surface | ||
166 | mGridsPerEdge = grids_per_edge + 1; // Add 1 for the east and north buffer | ||
167 | mOOGridsPerEdge = 1.f / mGridsPerEdge; | ||
168 | mGridsPerPatchEdge = grids_per_patch_edge; | ||
169 | mPatchesPerEdge = (mGridsPerEdge - 1) / mGridsPerPatchEdge; | ||
170 | mNumberOfPatches = mPatchesPerEdge * mPatchesPerEdge; | ||
171 | mMetersPerGrid = width / ((F32)(mGridsPerEdge - 1)); | ||
172 | mMetersPerEdge = mMetersPerGrid * (mGridsPerEdge - 1); | ||
173 | |||
174 | mOriginGlobal.setVec(origin_global); | ||
175 | |||
176 | mPVArray.create(mGridsPerEdge, mGridsPerPatchEdge, gWorldPointer->getRegionScale()); | ||
177 | |||
178 | S32 number_of_grids = mGridsPerEdge * mGridsPerEdge; | ||
179 | |||
180 | ///////////////////////////////////// | ||
181 | // | ||
182 | // Initialize data arrays for surface | ||
183 | /// | ||
184 | mSurfaceZ = new F32[number_of_grids]; | ||
185 | mNorm = new LLVector3[number_of_grids]; | ||
186 | |||
187 | // Reset the surface to be a flat square grid | ||
188 | for(S32 i=0; i < number_of_grids; i++) | ||
189 | { | ||
190 | // Surface is flat and zero | ||
191 | // Normals all point up | ||
192 | mSurfaceZ[i] = 0.0f; | ||
193 | mNorm[i].setVec(0.f, 0.f, 1.f); | ||
194 | } | ||
195 | |||
196 | |||
197 | mVisiblePatchCount = 0; | ||
198 | |||
199 | |||
200 | /////////////////////// | ||
201 | // | ||
202 | // Initialize textures | ||
203 | // | ||
204 | |||
205 | initTextures(); | ||
206 | |||
207 | // Has to be done after texture initialization | ||
208 | createPatchData(); | ||
209 | } | ||
210 | |||
211 | LLViewerImage* LLSurface::getSTexture() | ||
212 | { | ||
213 | if (mSTexturep.notNull() && !mSTexturep->getHasGLTexture()) | ||
214 | { | ||
215 | createSTexture(); | ||
216 | } | ||
217 | return mSTexturep; | ||
218 | } | ||
219 | |||
220 | LLViewerImage* LLSurface::getWaterTexture() | ||
221 | { | ||
222 | if (mWaterTexturep.notNull() && !mWaterTexturep->getHasGLTexture()) | ||
223 | { | ||
224 | createWaterTexture(); | ||
225 | } | ||
226 | return mWaterTexturep; | ||
227 | } | ||
228 | |||
229 | void LLSurface::createSTexture() | ||
230 | { | ||
231 | if (!mSTexturep) | ||
232 | { | ||
233 | // Fill with dummy gray data. | ||
234 | LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3); | ||
235 | U8 *default_texture = raw->getData(); | ||
236 | for (S32 i = 0; i < sTextureSize; i++) | ||
237 | { | ||
238 | for (S32 j = 0; j < sTextureSize; j++) | ||
239 | { | ||
240 | *(default_texture + (i*sTextureSize + j)*3) = 128; | ||
241 | *(default_texture + (i*sTextureSize + j)*3 + 1) = 128; | ||
242 | *(default_texture + (i*sTextureSize + j)*3 + 2) = 128; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | mSTexturep = new LLViewerImage(raw, FALSE); | ||
247 | mSTexturep->dontDiscard(); | ||
248 | mSTexturep->bind(); | ||
249 | mSTexturep->setClamp(TRUE, TRUE); | ||
250 | gImageList.addImage(mSTexturep); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | void LLSurface::createWaterTexture() | ||
255 | { | ||
256 | if (!mWaterTexturep) | ||
257 | { | ||
258 | // Create the water texture | ||
259 | LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4); | ||
260 | U8 *default_texture = raw->getData(); | ||
261 | for (S32 i = 0; i < sTextureSize/2; i++) | ||
262 | { | ||
263 | for (S32 j = 0; j < sTextureSize/2; j++) | ||
264 | { | ||
265 | *(default_texture + (i*sTextureSize/2 + j)*4) = MAX_WATER_COLOR.mV[0]; | ||
266 | *(default_texture + (i*sTextureSize/2 + j)*4 + 1) = MAX_WATER_COLOR.mV[1]; | ||
267 | *(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2]; | ||
268 | *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3]; | ||
269 | } | ||
270 | } | ||
271 | mWaterTexturep = new LLViewerImage(raw, FALSE); | ||
272 | mWaterTexturep->dontDiscard(); | ||
273 | mWaterTexturep->bind(); | ||
274 | mWaterTexturep->setClamp(TRUE, TRUE); | ||
275 | gImageList.addImage(mWaterTexturep); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | void LLSurface::initTextures() | ||
280 | { | ||
281 | /////////////////////// | ||
282 | // | ||
283 | // Main surface texture | ||
284 | // | ||
285 | createSTexture(); | ||
286 | |||
287 | /////////////////////// | ||
288 | // | ||
289 | // Water texture | ||
290 | // | ||
291 | if (gSavedSettings.getBOOL("RenderWater") ) | ||
292 | { | ||
293 | createWaterTexture(); | ||
294 | mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); | ||
295 | gPipeline.addObject(mWaterObjp); | ||
296 | LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle()); | ||
297 | water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT); | ||
298 | mWaterObjp->setPositionGlobal(water_pos_global); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | |||
303 | void LLSurface::setOriginGlobal(const LLVector3d &origin_global) | ||
304 | { | ||
305 | LLVector3d new_origin_global; | ||
306 | mOriginGlobal = origin_global; | ||
307 | LLSurfacePatch *patchp; | ||
308 | S32 i, j; | ||
309 | // Need to update the southwest corners of the patches | ||
310 | for (j=0; j<mPatchesPerEdge; j++) | ||
311 | { | ||
312 | for (i=0; i<mPatchesPerEdge; i++) | ||
313 | { | ||
314 | patchp = getPatch(i, j); | ||
315 | |||
316 | new_origin_global = patchp->getOriginGlobal(); | ||
317 | |||
318 | new_origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge; | ||
319 | new_origin_global.mdV[1] = mOriginGlobal.mdV[1] + j * mMetersPerGrid * mGridsPerPatchEdge; | ||
320 | patchp->setOriginGlobal(new_origin_global); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | // Hack! | ||
325 | if (mWaterObjp.notNull() && mWaterObjp->mDrawable.notNull()) | ||
326 | { | ||
327 | const F64 x = origin_global.mdV[VX] + 128.0; | ||
328 | const F64 y = origin_global.mdV[VY] + 128.0; | ||
329 | const F64 z = mWaterObjp->getPositionGlobal().mdV[VZ]; | ||
330 | |||
331 | LLVector3d water_origin_global(x, y, z); | ||
332 | |||
333 | mWaterObjp->setPositionGlobal(water_origin_global); | ||
334 | gPipeline.markMoved(mWaterObjp->mDrawable); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | |||
339 | void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction) | ||
340 | { | ||
341 | S32 i; | ||
342 | LLSurfacePatch *patchp, *neighbor_patchp; | ||
343 | |||
344 | if (gNoRender) | ||
345 | { | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | mNeighbors[direction] = neighborp; | ||
350 | neighborp->mNeighbors[gDirOpposite[direction]] = this; | ||
351 | |||
352 | // Connect patches | ||
353 | if (NORTHEAST == direction) | ||
354 | { | ||
355 | patchp = getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); | ||
356 | neighbor_patchp = neighborp->getPatch(0, 0); | ||
357 | |||
358 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
359 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
360 | |||
361 | patchp->updateNorthEdge(); // Only update one of north or east. | ||
362 | patchp->dirtyZ(); | ||
363 | } | ||
364 | else if (NORTHWEST == direction) | ||
365 | { | ||
366 | patchp = getPatch(0, mPatchesPerEdge - 1); | ||
367 | neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, 0); | ||
368 | |||
369 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
370 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
371 | } | ||
372 | else if (SOUTHWEST == direction) | ||
373 | { | ||
374 | patchp = getPatch(0, 0); | ||
375 | neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); | ||
376 | |||
377 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
378 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
379 | |||
380 | neighbor_patchp->updateNorthEdge(); // Only update one of north or east. | ||
381 | neighbor_patchp->dirtyZ(); | ||
382 | } | ||
383 | else if (SOUTHEAST == direction) | ||
384 | { | ||
385 | patchp = getPatch(mPatchesPerEdge - 1, 0); | ||
386 | neighbor_patchp = neighborp->getPatch(0, mPatchesPerEdge - 1); | ||
387 | |||
388 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
389 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
390 | } | ||
391 | else if (EAST == direction) | ||
392 | { | ||
393 | // Do east/west connections, first | ||
394 | for (i = 0; i < (S32)mPatchesPerEdge; i++) | ||
395 | { | ||
396 | patchp = getPatch(mPatchesPerEdge - 1, i); | ||
397 | neighbor_patchp = neighborp->getPatch(0, i); | ||
398 | |||
399 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
400 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
401 | |||
402 | patchp->updateEastEdge(); | ||
403 | patchp->dirtyZ(); | ||
404 | } | ||
405 | |||
406 | // Now do northeast/southwest connections | ||
407 | for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) | ||
408 | { | ||
409 | patchp = getPatch(mPatchesPerEdge - 1, i); | ||
410 | neighbor_patchp = neighborp->getPatch(0, i+1); | ||
411 | |||
412 | patchp->connectNeighbor(neighbor_patchp, NORTHEAST); | ||
413 | neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); | ||
414 | } | ||
415 | // Now do southeast/northwest connections | ||
416 | for (i = 1; i < (S32)mPatchesPerEdge; i++) | ||
417 | { | ||
418 | patchp = getPatch(mPatchesPerEdge - 1, i); | ||
419 | neighbor_patchp = neighborp->getPatch(0, i-1); | ||
420 | |||
421 | patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); | ||
422 | neighbor_patchp->connectNeighbor(patchp, NORTHWEST); | ||
423 | } | ||
424 | } | ||
425 | else if (NORTH == direction) | ||
426 | { | ||
427 | // Do north/south connections, first | ||
428 | for (i = 0; i < (S32)mPatchesPerEdge; i++) | ||
429 | { | ||
430 | patchp = getPatch(i, mPatchesPerEdge - 1); | ||
431 | neighbor_patchp = neighborp->getPatch(i, 0); | ||
432 | |||
433 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
434 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
435 | |||
436 | patchp->updateNorthEdge(); | ||
437 | patchp->dirtyZ(); | ||
438 | } | ||
439 | |||
440 | // Do northeast/southwest connections | ||
441 | for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) | ||
442 | { | ||
443 | patchp = getPatch(i, mPatchesPerEdge - 1); | ||
444 | neighbor_patchp = neighborp->getPatch(i+1, 0); | ||
445 | |||
446 | patchp->connectNeighbor(neighbor_patchp, NORTHEAST); | ||
447 | neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); | ||
448 | } | ||
449 | // Do southeast/northwest connections | ||
450 | for (i = 1; i < (S32)mPatchesPerEdge; i++) | ||
451 | { | ||
452 | patchp = getPatch(i, mPatchesPerEdge - 1); | ||
453 | neighbor_patchp = neighborp->getPatch(i-1, 0); | ||
454 | |||
455 | patchp->connectNeighbor(neighbor_patchp, NORTHWEST); | ||
456 | neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); | ||
457 | } | ||
458 | } | ||
459 | else if (WEST == direction) | ||
460 | { | ||
461 | // Do east/west connections, first | ||
462 | for (i = 0; i < mPatchesPerEdge; i++) | ||
463 | { | ||
464 | patchp = getPatch(0, i); | ||
465 | neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i); | ||
466 | |||
467 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
468 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
469 | |||
470 | neighbor_patchp->updateEastEdge(); | ||
471 | neighbor_patchp->dirtyZ(); | ||
472 | } | ||
473 | |||
474 | // Now do northeast/southwest connections | ||
475 | for (i = 1; i < mPatchesPerEdge; i++) | ||
476 | { | ||
477 | patchp = getPatch(0, i); | ||
478 | neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i - 1); | ||
479 | |||
480 | patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); | ||
481 | neighbor_patchp->connectNeighbor(patchp, NORTHEAST); | ||
482 | } | ||
483 | |||
484 | // Now do northwest/southeast connections | ||
485 | for (i = 0; i < mPatchesPerEdge - 1; i++) | ||
486 | { | ||
487 | patchp = getPatch(0, i); | ||
488 | neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i + 1); | ||
489 | |||
490 | patchp->connectNeighbor(neighbor_patchp, NORTHWEST); | ||
491 | neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); | ||
492 | } | ||
493 | } | ||
494 | else if (SOUTH == direction) | ||
495 | { | ||
496 | // Do north/south connections, first | ||
497 | for (i = 0; i < mPatchesPerEdge; i++) | ||
498 | { | ||
499 | patchp = getPatch(i, 0); | ||
500 | neighbor_patchp = neighborp->getPatch(i, mPatchesPerEdge - 1); | ||
501 | |||
502 | patchp->connectNeighbor(neighbor_patchp, direction); | ||
503 | neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); | ||
504 | |||
505 | neighbor_patchp->updateNorthEdge(); | ||
506 | neighbor_patchp->dirtyZ(); | ||
507 | } | ||
508 | |||
509 | // Now do northeast/southwest connections | ||
510 | for (i = 1; i < mPatchesPerEdge; i++) | ||
511 | { | ||
512 | patchp = getPatch(i, 0); | ||
513 | neighbor_patchp = neighborp->getPatch(i - 1, mPatchesPerEdge - 1); | ||
514 | |||
515 | patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); | ||
516 | neighbor_patchp->connectNeighbor(patchp, NORTHEAST); | ||
517 | } | ||
518 | // Now do northeast/southwest connections | ||
519 | for (i = 0; i < mPatchesPerEdge - 1; i++) | ||
520 | { | ||
521 | patchp = getPatch(i, 0); | ||
522 | neighbor_patchp = neighborp->getPatch(i + 1, mPatchesPerEdge - 1); | ||
523 | |||
524 | patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); | ||
525 | neighbor_patchp->connectNeighbor(patchp, NORTHWEST); | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | void LLSurface::disconnectNeighbor(LLSurface *surfacep) | ||
531 | { | ||
532 | S32 i; | ||
533 | for (i = 0; i < 8; i++) | ||
534 | { | ||
535 | if (surfacep == mNeighbors[i]) | ||
536 | { | ||
537 | mNeighbors[i] = NULL; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | // Iterate through surface patches, removing any connectivity to removed surface. | ||
542 | for (i = 0; i < mNumberOfPatches; i++) | ||
543 | { | ||
544 | (mPatchList + i)->disconnectNeighbor(surfacep); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | |||
549 | void LLSurface::disconnectAllNeighbors() | ||
550 | { | ||
551 | S32 i; | ||
552 | for (i = 0; i < 8; i++) | ||
553 | { | ||
554 | if (mNeighbors[i]) | ||
555 | { | ||
556 | mNeighbors[i]->disconnectNeighbor(this); | ||
557 | mNeighbors[i] = NULL; | ||
558 | } | ||
559 | } | ||
560 | } | ||
561 | |||
562 | |||
563 | |||
564 | const LLVector3d &LLSurface::getOriginGlobal() const | ||
565 | { | ||
566 | return mOriginGlobal; | ||
567 | } | ||
568 | |||
569 | LLVector3 LLSurface::getOriginAgent() const | ||
570 | { | ||
571 | return gAgent.getPosAgentFromGlobal(mOriginGlobal); | ||
572 | } | ||
573 | |||
574 | F32 LLSurface::getMetersPerGrid() const | ||
575 | { | ||
576 | return mMetersPerGrid; | ||
577 | } | ||
578 | |||
579 | S32 LLSurface::getGridsPerEdge() const | ||
580 | { | ||
581 | return mGridsPerEdge; | ||
582 | } | ||
583 | |||
584 | S32 LLSurface::getPatchesPerEdge() const | ||
585 | { | ||
586 | return mPatchesPerEdge; | ||
587 | } | ||
588 | |||
589 | S32 LLSurface::getGridsPerPatchEdge() const | ||
590 | { | ||
591 | return mGridsPerPatchEdge; | ||
592 | } | ||
593 | |||
594 | void LLSurface::moveZ(const S32 x, const S32 y, const F32 delta) | ||
595 | { | ||
596 | llassert(x >= 0); | ||
597 | llassert(y >= 0); | ||
598 | llassert(x < mGridsPerEdge); | ||
599 | llassert(y < mGridsPerEdge); | ||
600 | mSurfaceZ[x + y*mGridsPerEdge] += delta; | ||
601 | } | ||
602 | |||
603 | |||
604 | void LLSurface::updatePatchVisibilities(LLAgent &agent) | ||
605 | { | ||
606 | LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgent.getCameraPositionGlobal()); | ||
607 | |||
608 | LLSurfacePatch *patchp; | ||
609 | |||
610 | mVisiblePatchCount = 0; | ||
611 | for (S32 i=0; i<mNumberOfPatches; i++) | ||
612 | { | ||
613 | patchp = mPatchList + i; | ||
614 | |||
615 | patchp->updateVisibility(); | ||
616 | if (patchp->getVisible()) | ||
617 | { | ||
618 | mVisiblePatchCount++; | ||
619 | patchp->updateCameraDistanceRegion(pos_region); | ||
620 | } | ||
621 | } | ||
622 | } | ||
623 | |||
624 | |||
625 | |||
626 | BOOL LLSurface::idleUpdate() | ||
627 | { | ||
628 | if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN)) | ||
629 | { | ||
630 | return TRUE; | ||
631 | } | ||
632 | |||
633 | // Perform idle time update of non-critical stuff. | ||
634 | // In this case, texture and normal updates. | ||
635 | LLTimer update_timer; | ||
636 | LLSurfacePatch *patchp = NULL; | ||
637 | |||
638 | // If the Z height data has changed, we need to rebuild our | ||
639 | // property line vertex arrays. | ||
640 | if (mDirtyPatchList.count() > 0) | ||
641 | { | ||
642 | getRegion()->dirtyHeights(); | ||
643 | } | ||
644 | |||
645 | S32 i = 0; | ||
646 | while (i < mDirtyPatchList.count()) | ||
647 | { | ||
648 | patchp = mDirtyPatchList[i]; | ||
649 | patchp->updateNormals(); | ||
650 | patchp->updateVerticalStats(); | ||
651 | |||
652 | if ((update_timer.getElapsedTimeF32() < 0.05f) && patchp->updateTexture()) | ||
653 | { | ||
654 | patchp->clearDirty(); | ||
655 | mDirtyPatchList.remove(i); | ||
656 | } | ||
657 | else | ||
658 | { | ||
659 | i++; | ||
660 | } | ||
661 | } | ||
662 | return TRUE; | ||
663 | } | ||
664 | |||
665 | // TODO -- move this to LLViewerRegion class | ||
666 | void LLSurface::renderSurfaceBounds() | ||
667 | { | ||
668 | // Shows the edge of the surface, so that visibility across regions can be seen | ||
669 | LLVector3 origin_agent = getOriginAgent(); | ||
670 | |||
671 | glPushMatrix(); | ||
672 | LLGLSNoTexture no_texture; | ||
673 | |||
674 | F32 region_width_meters = gWorldPointer->getRegionWidthInMeters(); | ||
675 | glTranslatef(origin_agent.mV[VX] + (region_width_meters * 0.005f), | ||
676 | origin_agent.mV[VY] + (region_width_meters * 0.005f), 0.f); | ||
677 | |||
678 | glColor4ub(0, 128, 0, 64); | ||
679 | |||
680 | F32 length = region_width_meters * 0.995f; | ||
681 | F32 height = length/8.0f; | ||
682 | |||
683 | glBegin(GL_QUADS); | ||
684 | glVertex3f(length, 0, 0); | ||
685 | glVertex3f(0,0, 0); | ||
686 | glVertex3f(0,0, height); | ||
687 | glVertex3f(length,0, height); | ||
688 | |||
689 | glVertex3f(length,0, height); | ||
690 | glVertex3f(0,0, height); | ||
691 | glVertex3f(0,0, 0); | ||
692 | glVertex3f(length, 0, 0); | ||
693 | glEnd(); | ||
694 | |||
695 | glTranslatef(length, 0, 0); | ||
696 | glRotated(90, 0, 0, 1); | ||
697 | glBegin(GL_QUADS); | ||
698 | glVertex3f(length, 0, 0); | ||
699 | glVertex3f(0,0, 0); | ||
700 | glVertex3f(0,0, height); | ||
701 | glVertex3f(length,0, height); | ||
702 | |||
703 | glVertex3f(length,0, height); | ||
704 | glVertex3f(0,0, height); | ||
705 | glVertex3f(0,0, 0); | ||
706 | glVertex3f(length, 0, 0); | ||
707 | |||
708 | glEnd(); | ||
709 | glTranslatef(length, 0, 0); | ||
710 | glRotated(90, 0, 0, 1); | ||
711 | glBegin(GL_QUADS); | ||
712 | glVertex3f(length, 0, 0); | ||
713 | glVertex3f(0,0, 0); | ||
714 | glVertex3f(0,0, height); | ||
715 | glVertex3f(length,0, height); | ||
716 | |||
717 | glVertex3f(length,0, height); | ||
718 | glVertex3f(0,0, height); | ||
719 | glVertex3f(0,0, 0); | ||
720 | glVertex3f(length, 0, 0); | ||
721 | glEnd(); | ||
722 | glTranslatef(length, 0, 0); | ||
723 | glRotated(90, 0, 0, 1); | ||
724 | glBegin(GL_QUADS); | ||
725 | glVertex3f(length, 0, 0); | ||
726 | glVertex3f(0,0, 0); | ||
727 | glVertex3f(0,0, height); | ||
728 | glVertex3f(length,0, height); | ||
729 | |||
730 | glVertex3f(length,0, height); | ||
731 | glVertex3f(0,0, height); | ||
732 | glVertex3f(0,0, 0); | ||
733 | glVertex3f(length, 0, 0); | ||
734 | glEnd(); | ||
735 | glTranslatef(length, 0, 0); | ||
736 | glRotated(90, 0, 0, 1); | ||
737 | |||
738 | glPopMatrix(); | ||
739 | } | ||
740 | |||
741 | |||
742 | void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch) | ||
743 | { | ||
744 | |||
745 | LLPatchHeader ph; | ||
746 | S32 j, i; | ||
747 | S32 patch[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; | ||
748 | LLSurfacePatch *patchp; | ||
749 | |||
750 | init_patch_decompressor(gopp->patch_size); | ||
751 | gopp->stride = mGridsPerEdge; | ||
752 | set_group_of_patch_header(gopp); | ||
753 | |||
754 | while (1) | ||
755 | { | ||
756 | decode_patch_header(bitpack, &ph); | ||
757 | if (ph.quant_wbits == END_OF_PATCHES) | ||
758 | { | ||
759 | break; | ||
760 | } | ||
761 | |||
762 | i = ph.patchids >> 5; | ||
763 | j = ph.patchids & 0x1F; | ||
764 | |||
765 | if ((i >= mPatchesPerEdge) || (j >= mPatchesPerEdge)) | ||
766 | { | ||
767 | llwarns << "Received invalid terrain packet - patch header patch ID incorrect!" | ||
768 | << " patches per edge " << mPatchesPerEdge | ||
769 | << " i " << i | ||
770 | << " j " << j | ||
771 | << " dc_offset " << ph.dc_offset | ||
772 | << " range " << (S32)ph.range | ||
773 | << " quant_wbits " << (S32)ph.quant_wbits | ||
774 | << " patchids " << (S32)ph.patchids | ||
775 | << llendl; | ||
776 | bad_network_handler(); | ||
777 | return; | ||
778 | } | ||
779 | |||
780 | patchp = &mPatchList[j*mPatchesPerEdge + i]; | ||
781 | |||
782 | |||
783 | decode_patch(bitpack, patch); | ||
784 | decompress_patch(patchp->getDataZ(), patch, &ph); | ||
785 | |||
786 | // Update edges for neighbors. Need to guarantee that this gets done before we generate vertical stats. | ||
787 | patchp->updateNorthEdge(); | ||
788 | patchp->updateEastEdge(); | ||
789 | if (patchp->getNeighborPatch(WEST)) | ||
790 | { | ||
791 | patchp->getNeighborPatch(WEST)->updateEastEdge(); | ||
792 | } | ||
793 | if (patchp->getNeighborPatch(SOUTHWEST)) | ||
794 | { | ||
795 | patchp->getNeighborPatch(SOUTHWEST)->updateEastEdge(); | ||
796 | patchp->getNeighborPatch(SOUTHWEST)->updateNorthEdge(); | ||
797 | } | ||
798 | if (patchp->getNeighborPatch(SOUTH)) | ||
799 | { | ||
800 | patchp->getNeighborPatch(SOUTH)->updateNorthEdge(); | ||
801 | } | ||
802 | |||
803 | // Dirty patch statistics, and flag that the patch has data. | ||
804 | patchp->dirtyZ(); | ||
805 | patchp->setHasReceivedData(); | ||
806 | } | ||
807 | } | ||
808 | |||
809 | |||
810 | // Retrurns TRUE if "position" is within the bounds of surface. | ||
811 | // "position" is region-local | ||
812 | BOOL LLSurface::containsPosition(const LLVector3 &position) | ||
813 | { | ||
814 | if (position.mV[VX] < 0.0f || position.mV[VX] > mMetersPerEdge || | ||
815 | position.mV[VY] < 0.0f || position.mV[VY] > mMetersPerEdge) | ||
816 | { | ||
817 | return FALSE; | ||
818 | } | ||
819 | return TRUE; | ||
820 | } | ||
821 | |||
822 | |||
823 | F32 LLSurface::resolveHeightRegion(const F32 x, const F32 y) const | ||
824 | { | ||
825 | F32 height = 0.0f; | ||
826 | F32 oometerspergrid = 1.f/mMetersPerGrid; | ||
827 | |||
828 | // Check to see if v is actually above surface | ||
829 | // We use (mGridsPerEdge-1) below rather than (mGridsPerEdge) | ||
830 | // becuase of the east and north buffers | ||
831 | |||
832 | if (x >= 0.f && | ||
833 | x <= mMetersPerEdge && | ||
834 | y >= 0.f && | ||
835 | y <= mMetersPerEdge) | ||
836 | { | ||
837 | const S32 left = llfloor(x * oometerspergrid); | ||
838 | const S32 bottom = llfloor(y * oometerspergrid); | ||
839 | |||
840 | // Don't walk off the edge of the array! | ||
841 | const S32 right = ( left+1 < (S32)mGridsPerEdge-1 ? left+1 : left ); | ||
842 | const S32 top = ( bottom+1 < (S32)mGridsPerEdge-1 ? bottom+1 : bottom ); | ||
843 | |||
844 | // Figure out if v is in first or second triangle of the square | ||
845 | // and calculate the slopes accordingly | ||
846 | // | | | ||
847 | // -(i,j+1)---(i+1,j+1)-- | ||
848 | // | 1 / | ^ | ||
849 | // | / 2 | | | ||
850 | // | / | j | ||
851 | // --(i,j)----(i+1,j)-- | ||
852 | // | | | ||
853 | // | ||
854 | // i -> | ||
855 | // where N = mGridsPerEdge | ||
856 | |||
857 | const F32 left_bottom = getZ( left, bottom ); | ||
858 | const F32 right_bottom = getZ( right, bottom ); | ||
859 | const F32 left_top = getZ( left, top ); | ||
860 | const F32 right_top = getZ( right, top ); | ||
861 | |||
862 | // dx and dy are incremental steps from (mSurface + k) | ||
863 | F32 dx = x - left * mMetersPerGrid; | ||
864 | F32 dy = y - bottom * mMetersPerGrid; | ||
865 | |||
866 | if (dy > dx) | ||
867 | { | ||
868 | // triangle 1 | ||
869 | dy *= left_top - left_bottom; | ||
870 | dx *= right_top - left_top; | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | // triangle 2 | ||
875 | dx *= right_bottom - left_bottom; | ||
876 | dy *= right_top - right_bottom; | ||
877 | } | ||
878 | height = left_bottom + (dx + dy) * oometerspergrid; | ||
879 | } | ||
880 | return height; | ||
881 | } | ||
882 | |||
883 | |||
884 | F32 LLSurface::resolveHeightGlobal(const LLVector3d& v) const | ||
885 | { | ||
886 | if (!mRegionp) | ||
887 | { | ||
888 | return 0.f; | ||
889 | } | ||
890 | |||
891 | LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(v); | ||
892 | |||
893 | return resolveHeightRegion(pos_region); | ||
894 | } | ||
895 | |||
896 | |||
897 | LLVector3 LLSurface::resolveNormalGlobal(const LLVector3d& pos_global) const | ||
898 | { | ||
899 | if (!mSurfaceZ) | ||
900 | { | ||
901 | // Hmm. Uninitialized surface! | ||
902 | return LLVector3::z_axis; | ||
903 | } | ||
904 | // | ||
905 | // Returns the vector normal to a surface at location specified by vector v | ||
906 | // | ||
907 | F32 oometerspergrid = 1.f/mMetersPerGrid; | ||
908 | LLVector3 normal; | ||
909 | F32 dzx, dzy; | ||
910 | |||
911 | if (pos_global.mdV[VX] >= mOriginGlobal.mdV[VX] && | ||
912 | pos_global.mdV[VX] < mOriginGlobal.mdV[VX] + mMetersPerEdge && | ||
913 | pos_global.mdV[VY] >= mOriginGlobal.mdV[VY] && | ||
914 | pos_global.mdV[VY] < mOriginGlobal.mdV[VY] + mMetersPerEdge) | ||
915 | { | ||
916 | U32 i, j, k; | ||
917 | F32 dx, dy; | ||
918 | i = (U32) ((pos_global.mdV[VX] - mOriginGlobal.mdV[VX]) * oometerspergrid); | ||
919 | j = (U32) ((pos_global.mdV[VY] - mOriginGlobal.mdV[VY]) * oometerspergrid ); | ||
920 | k = i + j*mGridsPerEdge; | ||
921 | |||
922 | // Figure out if v is in first or second triangle of the square | ||
923 | // and calculate the slopes accordingly | ||
924 | // | | | ||
925 | // -(k+N)---(k+1+N)-- | ||
926 | // | 1 / | ^ | ||
927 | // | / 2 | | | ||
928 | // | / | j | ||
929 | // --(k)----(k+1)-- | ||
930 | // | | | ||
931 | // | ||
932 | // i -> | ||
933 | // where N = mGridsPerEdge | ||
934 | |||
935 | // dx and dy are incremental steps from (mSurface + k) | ||
936 | dx = (F32)(pos_global.mdV[VX] - i*mMetersPerGrid - mOriginGlobal.mdV[VX]); | ||
937 | dy = (F32)(pos_global.mdV[VY] - j*mMetersPerGrid - mOriginGlobal.mdV[VY]); | ||
938 | if (dy > dx) | ||
939 | { // triangle 1 | ||
940 | dzx = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + mGridsPerEdge); | ||
941 | dzy = *(mSurfaceZ + k) - *(mSurfaceZ + k + mGridsPerEdge); | ||
942 | normal.setVec(-dzx,dzy,1); | ||
943 | } | ||
944 | else | ||
945 | { // triangle 2 | ||
946 | dzx = *(mSurfaceZ + k) - *(mSurfaceZ + k + 1); | ||
947 | dzy = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + 1); | ||
948 | normal.setVec(dzx,-dzy,1); | ||
949 | } | ||
950 | } | ||
951 | normal.normVec(); | ||
952 | return normal; | ||
953 | |||
954 | |||
955 | } | ||
956 | |||
957 | LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const | ||
958 | { | ||
959 | // x and y should be region-local coordinates. | ||
960 | // If x and y are outside of the surface, then the returned | ||
961 | // index will be for the nearest boundary patch. | ||
962 | // | ||
963 | // 12 | 13| 14| 15 | ||
964 | // | | | | ||
965 | // +---+---+---+---+ | ||
966 | // | 12| 13| 14| 15| | ||
967 | // ----+---+---+---+---+----- | ||
968 | // 8 | 8 | 9 | 10| 11| 11 | ||
969 | // ----+---+---+---+---+----- | ||
970 | // 4 | 4 | 5 | 6 | 7 | 7 | ||
971 | // ----+---+---+---+---+----- | ||
972 | // | 0 | 1 | 2 | 3 | | ||
973 | // +---+---+---+---+ | ||
974 | // | | | | ||
975 | // 0 | 1 | 2 | 3 | ||
976 | // | ||
977 | |||
978 | // When x and y are not region-local do the following first | ||
979 | |||
980 | S32 i, j; | ||
981 | if (x < 0.0f) | ||
982 | { | ||
983 | i = 0; | ||
984 | } | ||
985 | else if (x >= mMetersPerEdge) | ||
986 | { | ||
987 | i = mPatchesPerEdge - 1; | ||
988 | } | ||
989 | else | ||
990 | { | ||
991 | i = (U32) (x / (mMetersPerGrid * mGridsPerPatchEdge)); | ||
992 | } | ||
993 | |||
994 | if (y < 0.0f) | ||
995 | { | ||
996 | j = 0; | ||
997 | } | ||
998 | else if (y >= mMetersPerEdge) | ||
999 | { | ||
1000 | j = mPatchesPerEdge - 1; | ||
1001 | } | ||
1002 | else | ||
1003 | { | ||
1004 | j = (U32) (y / (mMetersPerGrid * mGridsPerPatchEdge)); | ||
1005 | } | ||
1006 | |||
1007 | // *NOTE: Super paranoia code follows. | ||
1008 | S32 index = i + j * mPatchesPerEdge; | ||
1009 | if((index < 0) || (index >= mNumberOfPatches)) | ||
1010 | { | ||
1011 | if(0 == mNumberOfPatches) | ||
1012 | { | ||
1013 | llwarns << "No patches for current region!" << llendl; | ||
1014 | return NULL; | ||
1015 | } | ||
1016 | S32 old_index = index; | ||
1017 | index = llclamp(old_index, 0, (mNumberOfPatches - 1)); | ||
1018 | llwarns << "Clamping out of range patch index " << old_index | ||
1019 | << " to " << index << llendl; | ||
1020 | } | ||
1021 | return &(mPatchList[index]); | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | LLSurfacePatch *LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const | ||
1026 | { | ||
1027 | return resolvePatchRegion(pos_region.mV[VX], pos_region.mV[VY]); | ||
1028 | } | ||
1029 | |||
1030 | |||
1031 | LLSurfacePatch *LLSurface::resolvePatchGlobal(const LLVector3d &pos_global) const | ||
1032 | { | ||
1033 | LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(pos_global); | ||
1034 | return resolvePatchRegion(pos_region); | ||
1035 | } | ||
1036 | |||
1037 | |||
1038 | std::ostream& operator<<(std::ostream &s, const LLSurface &S) | ||
1039 | { | ||
1040 | s << "{ \n"; | ||
1041 | s << " mGridsPerEdge = " << S.mGridsPerEdge - 1 << " + 1\n"; | ||
1042 | s << " mGridsPerPatchEdge = " << S.mGridsPerPatchEdge << "\n"; | ||
1043 | s << " mPatchesPerEdge = " << S.mPatchesPerEdge << "\n"; | ||
1044 | s << " mOriginGlobal = " << S.mOriginGlobal << "\n"; | ||
1045 | s << " mMetersPerGrid = " << S.mMetersPerGrid << "\n"; | ||
1046 | s << " mVisiblePatchCount = " << S.mVisiblePatchCount << "\n"; | ||
1047 | s << "}"; | ||
1048 | return s; | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | // ---------------- LLSurface:: Protected ---------------- | ||
1053 | |||
1054 | void LLSurface::createPatchData() | ||
1055 | { | ||
1056 | // Assumes mGridsPerEdge, mGridsPerPatchEdge, and mPatchesPerEdge have been properly set | ||
1057 | // TODO -- check for create() called when surface is not empty | ||
1058 | S32 i, j; | ||
1059 | LLSurfacePatch *patchp; | ||
1060 | |||
1061 | // Allocate memory | ||
1062 | mPatchList = new LLSurfacePatch[mNumberOfPatches]; | ||
1063 | |||
1064 | // One of each for each camera | ||
1065 | mVisiblePatchCount = mNumberOfPatches; | ||
1066 | |||
1067 | for (j=0; j<mPatchesPerEdge; j++) | ||
1068 | { | ||
1069 | for (i=0; i<mPatchesPerEdge; i++) | ||
1070 | { | ||
1071 | patchp = getPatch(i, j); | ||
1072 | patchp->setSurface(this); | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | for (j=0; j<mPatchesPerEdge; j++) | ||
1077 | { | ||
1078 | for (i=0; i<mPatchesPerEdge; i++) | ||
1079 | { | ||
1080 | patchp = getPatch(i, j); | ||
1081 | patchp->mHasReceivedData = FALSE; | ||
1082 | patchp->mSTexUpdate = TRUE; | ||
1083 | |||
1084 | S32 data_offset = i * mGridsPerPatchEdge + j * mGridsPerPatchEdge * mGridsPerEdge; | ||
1085 | |||
1086 | patchp->setDataZ(mSurfaceZ + data_offset); | ||
1087 | patchp->setDataNorm(mNorm + data_offset); | ||
1088 | |||
1089 | |||
1090 | // We make each patch point to its neighbors so we can do resolution checking | ||
1091 | // when butting up different resolutions. Patches that don't have neighbors | ||
1092 | // somewhere will point to NULL on that side. | ||
1093 | if (i < mPatchesPerEdge-1) | ||
1094 | { | ||
1095 | patchp->setNeighborPatch(EAST,getPatch(i+1, j)); | ||
1096 | } | ||
1097 | else | ||
1098 | { | ||
1099 | patchp->setNeighborPatch(EAST, NULL); | ||
1100 | } | ||
1101 | |||
1102 | if (j < mPatchesPerEdge-1) | ||
1103 | { | ||
1104 | patchp->setNeighborPatch(NORTH, getPatch(i, j+1)); | ||
1105 | } | ||
1106 | else | ||
1107 | { | ||
1108 | patchp->setNeighborPatch(NORTH, NULL); | ||
1109 | } | ||
1110 | |||
1111 | if (i > 0) | ||
1112 | { | ||
1113 | patchp->setNeighborPatch(WEST, getPatch(i - 1, j)); | ||
1114 | } | ||
1115 | else | ||
1116 | { | ||
1117 | patchp->setNeighborPatch(WEST, NULL); | ||
1118 | } | ||
1119 | |||
1120 | if (j > 0) | ||
1121 | { | ||
1122 | patchp->setNeighborPatch(SOUTH, getPatch(i, j-1)); | ||
1123 | } | ||
1124 | else | ||
1125 | { | ||
1126 | patchp->setNeighborPatch(SOUTH, NULL); | ||
1127 | } | ||
1128 | |||
1129 | if (i < (mPatchesPerEdge-1) && j < (mPatchesPerEdge-1)) | ||
1130 | { | ||
1131 | patchp->setNeighborPatch(NORTHEAST, getPatch(i + 1, j + 1)); | ||
1132 | } | ||
1133 | else | ||
1134 | { | ||
1135 | patchp->setNeighborPatch(NORTHEAST, NULL); | ||
1136 | } | ||
1137 | |||
1138 | if (i > 0 && j < (mPatchesPerEdge-1)) | ||
1139 | { | ||
1140 | patchp->setNeighborPatch(NORTHWEST, getPatch(i - 1, j + 1)); | ||
1141 | } | ||
1142 | else | ||
1143 | { | ||
1144 | patchp->setNeighborPatch(NORTHWEST, NULL); | ||
1145 | } | ||
1146 | |||
1147 | if (i > 0 && j > 0) | ||
1148 | { | ||
1149 | patchp->setNeighborPatch(SOUTHWEST, getPatch(i - 1, j - 1)); | ||
1150 | } | ||
1151 | else | ||
1152 | { | ||
1153 | patchp->setNeighborPatch(SOUTHWEST, NULL); | ||
1154 | } | ||
1155 | |||
1156 | if (i < (mPatchesPerEdge-1) && j > 0) | ||
1157 | { | ||
1158 | patchp->setNeighborPatch(SOUTHEAST, getPatch(i + 1, j - 1)); | ||
1159 | } | ||
1160 | else | ||
1161 | { | ||
1162 | patchp->setNeighborPatch(SOUTHEAST, NULL); | ||
1163 | } | ||
1164 | |||
1165 | LLVector3d origin_global; | ||
1166 | origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge; | ||
1167 | origin_global.mdV[1] = mOriginGlobal.mdV[0] + j * mMetersPerGrid * mGridsPerPatchEdge; | ||
1168 | origin_global.mdV[2] = 0.f; | ||
1169 | patchp->setOriginGlobal(origin_global); | ||
1170 | } | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | |||
1175 | void LLSurface::destroyPatchData() | ||
1176 | { | ||
1177 | // Delete all of the cached patch data for these patches. | ||
1178 | |||
1179 | delete [] mPatchList; | ||
1180 | mPatchList = NULL; | ||
1181 | mVisiblePatchCount = 0; | ||
1182 | } | ||
1183 | |||
1184 | |||
1185 | void LLSurface::setTextureSize(const S32 texture_size) | ||
1186 | { | ||
1187 | sTextureSize = texture_size; | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | U32 LLSurface::getRenderLevel(const U32 render_stride) const | ||
1192 | { | ||
1193 | return mPVArray.mRenderLevelp[render_stride]; | ||
1194 | } | ||
1195 | |||
1196 | |||
1197 | U32 LLSurface::getRenderStride(const U32 render_level) const | ||
1198 | { | ||
1199 | return mPVArray.mRenderStridep[render_level]; | ||
1200 | } | ||
1201 | |||
1202 | |||
1203 | LLSurfacePatch *LLSurface::getPatch(const S32 x, const S32 y) const | ||
1204 | { | ||
1205 | if ((x < 0) || (x >= mPatchesPerEdge)) | ||
1206 | { | ||
1207 | llerrs << "Asking for patch out of bounds" << llendl; | ||
1208 | return NULL; | ||
1209 | } | ||
1210 | if ((y < 0) || (y >= mPatchesPerEdge)) | ||
1211 | { | ||
1212 | llerrs << "Asking for patch out of bounds" << llendl; | ||
1213 | return NULL; | ||
1214 | } | ||
1215 | |||
1216 | return mPatchList + x + y*mPatchesPerEdge; | ||
1217 | } | ||
1218 | |||
1219 | |||
1220 | void LLSurface::dirtyAllPatches() | ||
1221 | { | ||
1222 | S32 i; | ||
1223 | for (i = 0; i < mNumberOfPatches; i++) | ||
1224 | { | ||
1225 | mPatchList[i].dirtyZ(); | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | void LLSurface::dirtySurfacePatch(LLSurfacePatch *patchp) | ||
1230 | { | ||
1231 | // Put surface patch on dirty surface patch list | ||
1232 | if (-1 == mDirtyPatchList.find(patchp)) | ||
1233 | { | ||
1234 | mDirtyPatchList.put(patchp); | ||
1235 | } | ||
1236 | } | ||
1237 | |||
1238 | |||
1239 | void LLSurface::setWaterHeight(F32 height) | ||
1240 | { | ||
1241 | if (!mWaterObjp.isNull()) | ||
1242 | { | ||
1243 | LLVector3 water_pos_region = mWaterObjp->getPositionRegion(); | ||
1244 | water_pos_region.mV[VZ] = height; | ||
1245 | mWaterObjp->setPositionRegion(water_pos_region); | ||
1246 | } | ||
1247 | else | ||
1248 | { | ||
1249 | llwarns << "LLSurface::setWaterHeight with no water object!" << llendl; | ||
1250 | } | ||
1251 | } | ||
1252 | |||
1253 | F32 LLSurface::getWaterHeight() const | ||
1254 | { | ||
1255 | if (!mWaterObjp.isNull()) | ||
1256 | { | ||
1257 | // we have a water object, the usual case | ||
1258 | return mWaterObjp->getPositionRegion().mV[VZ]; | ||
1259 | } | ||
1260 | else | ||
1261 | { | ||
1262 | return DEFAULT_WATER_HEIGHT; | ||
1263 | } | ||
1264 | } | ||
1265 | |||
1266 | |||
1267 | BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y, | ||
1268 | const F32 width, const F32 height) | ||
1269 | { | ||
1270 | if (!getWaterTexture()) | ||
1271 | { | ||
1272 | return FALSE; | ||
1273 | } | ||
1274 | |||
1275 | S32 tex_width = mWaterTexturep->getWidth(); | ||
1276 | S32 tex_height = mWaterTexturep->getHeight(); | ||
1277 | S32 tex_comps = mWaterTexturep->getComponents(); | ||
1278 | S32 tex_stride = tex_width * tex_comps; | ||
1279 | LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps); | ||
1280 | U8 *rawp = raw->getData(); | ||
1281 | |||
1282 | F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width; | ||
1283 | F32 scale_inv = 1.f / scale; | ||
1284 | |||
1285 | S32 x_begin, y_begin, x_end, y_end; | ||
1286 | |||
1287 | x_begin = llround(x * scale_inv); | ||
1288 | y_begin = llround(y * scale_inv); | ||
1289 | x_end = llround((x + width) * scale_inv); | ||
1290 | y_end = llround((y + width) * scale_inv); | ||
1291 | |||
1292 | if (x_end > tex_width) | ||
1293 | { | ||
1294 | x_end = tex_width; | ||
1295 | } | ||
1296 | if (y_end > tex_width) | ||
1297 | { | ||
1298 | y_end = tex_width; | ||
1299 | } | ||
1300 | |||
1301 | LLVector3d origin_global = from_region_handle(getRegion()->getHandle()); | ||
1302 | |||
1303 | // OK, for now, just have the composition value equal the height at the point. | ||
1304 | LLVector3 location; | ||
1305 | LLColor4U coloru; | ||
1306 | |||
1307 | const F32 WATER_HEIGHT = getWaterHeight(); | ||
1308 | |||
1309 | S32 i, j, offset; | ||
1310 | for (j = y_begin; j < y_end; j++) | ||
1311 | { | ||
1312 | for (i = x_begin; i < x_end; i++) | ||
1313 | { | ||
1314 | //F32 nv[2]; | ||
1315 | //nv[0] = i/256.f; | ||
1316 | //nv[1] = j/256.f; | ||
1317 | // const S32 modulation = noise2(nv)*40; | ||
1318 | offset = j*tex_stride + i*tex_comps; | ||
1319 | location.mV[VX] = i*scale; | ||
1320 | location.mV[VY] = j*scale; | ||
1321 | |||
1322 | // Sample multiple points | ||
1323 | const F32 height = resolveHeightRegion(location); | ||
1324 | |||
1325 | if (height > WATER_HEIGHT) | ||
1326 | { | ||
1327 | // Above water... | ||
1328 | coloru = MAX_WATER_COLOR; | ||
1329 | coloru.mV[3] = ABOVE_WATERLINE_ALPHA; | ||
1330 | *(rawp + offset++) = coloru.mV[0]; | ||
1331 | *(rawp + offset++) = coloru.mV[1]; | ||
1332 | *(rawp + offset++) = coloru.mV[2]; | ||
1333 | *(rawp + offset++) = coloru.mV[3]; | ||
1334 | } | ||
1335 | else | ||
1336 | { | ||
1337 | // Want non-linear curve for transparency gradient | ||
1338 | coloru = MAX_WATER_COLOR; | ||
1339 | const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT)); | ||
1340 | S32 alpha = 64 + llround((255-64)*frac); | ||
1341 | |||
1342 | alpha = llmin(llround((F32)MAX_WATER_COLOR.mV[3]), alpha); | ||
1343 | alpha = llmax(64, alpha); | ||
1344 | |||
1345 | coloru.mV[3] = alpha; | ||
1346 | *(rawp + offset++) = coloru.mV[0]; | ||
1347 | *(rawp + offset++) = coloru.mV[1]; | ||
1348 | *(rawp + offset++) = coloru.mV[2]; | ||
1349 | *(rawp + offset++) = coloru.mV[3]; | ||
1350 | } | ||
1351 | } | ||
1352 | } | ||
1353 | |||
1354 | mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin); | ||
1355 | return TRUE; | ||
1356 | } | ||