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/llsurfacepatch.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/llsurfacepatch.cpp')
-rw-r--r-- | linden/indra/newview/llsurfacepatch.cpp | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/linden/indra/newview/llsurfacepatch.cpp b/linden/indra/newview/llsurfacepatch.cpp new file mode 100644 index 0000000..d19d930 --- /dev/null +++ b/linden/indra/newview/llsurfacepatch.cpp | |||
@@ -0,0 +1,993 @@ | |||
1 | /** | ||
2 | * @file llsurfacepatch.cpp | ||
3 | * @brief LLSurfacePatch class implementation | ||
4 | * | ||
5 | * Copyright (c) 2001-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 "llsurfacepatch.h" | ||
31 | #include "llpatchvertexarray.h" | ||
32 | #include "llviewerobjectlist.h" | ||
33 | #include "llvosurfacepatch.h" | ||
34 | #include "llsurface.h" | ||
35 | #include "pipeline.h" | ||
36 | #include "llagent.h" | ||
37 | #include "timing.h" | ||
38 | #include "llsky.h" | ||
39 | #include "llviewercamera.h" | ||
40 | |||
41 | // For getting composition values | ||
42 | #include "llviewerregion.h" | ||
43 | #include "llvlcomposition.h" | ||
44 | #include "lldrawpool.h" | ||
45 | #include "noise.h" | ||
46 | |||
47 | extern U64 gFrameTime; | ||
48 | extern LLPipeline gPipeline; | ||
49 | |||
50 | LLSurfacePatch::LLSurfacePatch() : | ||
51 | mDataZ(NULL), | ||
52 | mVObjp(NULL), | ||
53 | mLastUpdateTime(0), | ||
54 | mSurfacep(NULL) | ||
55 | { | ||
56 | // This flag is used to communicate between adjacent surfaces and is set | ||
57 | // to non-zero values by higher classes. | ||
58 | mConnectedEdge = NO_EDGE; | ||
59 | mCenterRegion = LLVector3(0.f, 0.f, 0.f); | ||
60 | mOriginRegion = LLVector3(0.f, 0.f, 0.f); | ||
61 | mHasReceivedData = FALSE; | ||
62 | mMinZ = 0.0f; | ||
63 | mMaxZ = 0.0f; | ||
64 | mMeanZ = 0.0f; | ||
65 | mMinComposition = 0.f; | ||
66 | mMeanComposition = 0.f; | ||
67 | mMaxComposition = 0.f; | ||
68 | mRadius = 0.f; | ||
69 | mDirty = FALSE; | ||
70 | mDirtyZStats = TRUE; | ||
71 | mHeightsGenerated = FALSE; | ||
72 | |||
73 | S32 i; | ||
74 | for (i = 0; i < 8; i++) | ||
75 | { | ||
76 | setNeighborPatch(i, NULL); | ||
77 | } | ||
78 | for (i = 0; i < 9; i++) | ||
79 | { | ||
80 | mNormalsInvalid[i] = TRUE; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | |||
85 | LLSurfacePatch::~LLSurfacePatch() | ||
86 | { | ||
87 | mVObjp = NULL; | ||
88 | } | ||
89 | |||
90 | |||
91 | void LLSurfacePatch::dirty() | ||
92 | { | ||
93 | // These are outside of the loop in case we're still waiting for a dirty from the | ||
94 | // texture being updated... | ||
95 | if (mVObjp) | ||
96 | { | ||
97 | mVObjp->dirtyGeom(); | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | llwarns << "No viewer object for this surface patch!" << llendl; | ||
102 | } | ||
103 | |||
104 | mDirtyZStats = TRUE; | ||
105 | mHeightsGenerated = FALSE; | ||
106 | |||
107 | if (!mDirty) | ||
108 | { | ||
109 | mDirty = TRUE; | ||
110 | mSurfacep->dirtySurfacePatch(this); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | |||
115 | void LLSurfacePatch::setSurface(LLSurface *surfacep) | ||
116 | { | ||
117 | mSurfacep = surfacep; | ||
118 | if (mVObjp == (LLVOSurfacePatch *)NULL) | ||
119 | { | ||
120 | llassert(mSurfacep->mType == 'l'); | ||
121 | |||
122 | mVObjp = (LLVOSurfacePatch *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SURFACE_PATCH, mSurfacep->getRegion()); | ||
123 | mVObjp->setPatch(this); | ||
124 | mVObjp->setPositionRegion(mCenterRegion); | ||
125 | gPipeline.addObject(mVObjp); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | void LLSurfacePatch::disconnectNeighbor(LLSurface *surfacep) | ||
130 | { | ||
131 | U32 i; | ||
132 | for (i = 0; i < 8; i++) | ||
133 | { | ||
134 | if (getNeighborPatch(i)) | ||
135 | { | ||
136 | if (getNeighborPatch(i)->mSurfacep == surfacep) | ||
137 | { | ||
138 | setNeighborPatch(i, NULL); | ||
139 | mNormalsInvalid[i] = TRUE; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | // Clean up connected edges | ||
145 | if (getNeighborPatch(EAST)) | ||
146 | { | ||
147 | if (getNeighborPatch(EAST)->mSurfacep == surfacep) | ||
148 | { | ||
149 | mConnectedEdge &= ~EAST_EDGE; | ||
150 | } | ||
151 | } | ||
152 | if (getNeighborPatch(NORTH)) | ||
153 | { | ||
154 | if (getNeighborPatch(NORTH)->mSurfacep == surfacep) | ||
155 | { | ||
156 | mConnectedEdge &= ~NORTH_EDGE; | ||
157 | } | ||
158 | } | ||
159 | if (getNeighborPatch(WEST)) | ||
160 | { | ||
161 | if (getNeighborPatch(WEST)->mSurfacep == surfacep) | ||
162 | { | ||
163 | mConnectedEdge &= ~WEST_EDGE; | ||
164 | } | ||
165 | } | ||
166 | if (getNeighborPatch(SOUTH)) | ||
167 | { | ||
168 | if (getNeighborPatch(SOUTH)->mSurfacep == surfacep) | ||
169 | { | ||
170 | mConnectedEdge &= ~SOUTH_EDGE; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | LLVector3 LLSurfacePatch::getPointAgent(const U32 x, const U32 y) const | ||
176 | { | ||
177 | U32 surface_stride = mSurfacep->getGridsPerEdge(); | ||
178 | U32 point_offset = x + y*surface_stride; | ||
179 | LLVector3 pos; | ||
180 | pos = getOriginAgent(); | ||
181 | pos.mV[VX] += x * mSurfacep->getMetersPerGrid(); | ||
182 | pos.mV[VY] += y * mSurfacep->getMetersPerGrid(); | ||
183 | pos.mV[VZ] = *(mDataZ + point_offset); | ||
184 | return pos; | ||
185 | } | ||
186 | |||
187 | LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const | ||
188 | { | ||
189 | U32 surface_stride = mSurfacep->getGridsPerEdge(); | ||
190 | U32 point_offset = x + y*surface_stride; | ||
191 | LLVector3 pos, rel_pos; | ||
192 | pos = getOriginAgent(); | ||
193 | pos.mV[VX] += x * mSurfacep->getMetersPerGrid(); | ||
194 | pos.mV[VY] += y * mSurfacep->getMetersPerGrid(); | ||
195 | pos.mV[VZ] = *(mDataZ + point_offset); | ||
196 | rel_pos = pos - mSurfacep->getOriginAgent(); | ||
197 | rel_pos *= 1.f/surface_stride; | ||
198 | return LLVector2(rel_pos.mV[VX], rel_pos.mV[VY]); | ||
199 | } | ||
200 | |||
201 | |||
202 | void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal, | ||
203 | LLVector2 *tex0, LLVector2 *tex1) | ||
204 | { | ||
205 | U32 surface_stride = mSurfacep->getGridsPerEdge(); | ||
206 | U32 point_offset = x + y*surface_stride; | ||
207 | |||
208 | *normal = getNormal(x, y); | ||
209 | |||
210 | LLVector3 pos_agent = getOriginAgent(); | ||
211 | pos_agent.mV[VX] += x * mSurfacep->getMetersPerGrid(); | ||
212 | pos_agent.mV[VY] += y * mSurfacep->getMetersPerGrid(); | ||
213 | pos_agent.mV[VZ] = *(mDataZ + point_offset); | ||
214 | *vertex = pos_agent; | ||
215 | |||
216 | LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent(); | ||
217 | LLVector3 tex_pos = rel_pos * (1.f/surface_stride); | ||
218 | tex0->mV[0] = tex_pos.mV[0]; | ||
219 | tex0->mV[1] = tex_pos.mV[1]; | ||
220 | tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y); | ||
221 | |||
222 | const F32 xyScale = 4.9215f*7.f; //0.93284f; | ||
223 | const F32 xyScaleInv = (1.f / xyScale)*(0.2222222222f); | ||
224 | |||
225 | F32 vec[3] = { | ||
226 | fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), | ||
227 | fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f), | ||
228 | 0.f | ||
229 | }; | ||
230 | F32 rand_val = llclamp(noise2(vec)* 0.75f + 0.5f, 0.f, 1.f); | ||
231 | tex1->mV[1] = rand_val; | ||
232 | |||
233 | |||
234 | } | ||
235 | |||
236 | |||
237 | void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) | ||
238 | { | ||
239 | U32 patch_width = mSurfacep->mPVArray.mPatchWidth; | ||
240 | U32 surface_stride = mSurfacep->getGridsPerEdge(); | ||
241 | |||
242 | const F32 mpg = mSurfacep->getMetersPerGrid() * stride; | ||
243 | |||
244 | S32 poffsets[2][2][2]; | ||
245 | poffsets[0][0][0] = x - stride; | ||
246 | poffsets[0][0][1] = y - stride; | ||
247 | |||
248 | poffsets[0][1][0] = x - stride; | ||
249 | poffsets[0][1][1] = y + stride; | ||
250 | |||
251 | poffsets[1][0][0] = x + stride; | ||
252 | poffsets[1][0][1] = y - stride; | ||
253 | |||
254 | poffsets[1][1][0] = x + stride; | ||
255 | poffsets[1][1][1] = y + stride; | ||
256 | |||
257 | const LLSurfacePatch *ppatches[2][2]; | ||
258 | |||
259 | // LLVector3 p1, p2, p3, p4; | ||
260 | |||
261 | ppatches[0][0] = this; | ||
262 | ppatches[0][1] = this; | ||
263 | ppatches[1][0] = this; | ||
264 | ppatches[1][1] = this; | ||
265 | |||
266 | U32 i, j; | ||
267 | for (i = 0; i < 2; i++) | ||
268 | { | ||
269 | for (j = 0; j < 2; j++) | ||
270 | { | ||
271 | if (poffsets[i][j][0] < 0) | ||
272 | { | ||
273 | if (!ppatches[i][j]->getNeighborPatch(WEST)) | ||
274 | { | ||
275 | poffsets[i][j][0] = 0; | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | poffsets[i][j][0] += patch_width; | ||
280 | ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST); | ||
281 | } | ||
282 | } | ||
283 | if (poffsets[i][j][1] < 0) | ||
284 | { | ||
285 | if (!ppatches[i][j]->getNeighborPatch(SOUTH)) | ||
286 | { | ||
287 | poffsets[i][j][1] = 0; | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | poffsets[i][j][1] += patch_width; | ||
292 | ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH); | ||
293 | } | ||
294 | } | ||
295 | if (poffsets[i][j][0] >= (S32)patch_width) | ||
296 | { | ||
297 | if (!ppatches[i][j]->getNeighborPatch(EAST)) | ||
298 | { | ||
299 | poffsets[i][j][0] = patch_width - 1; | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | poffsets[i][j][0] -= patch_width; | ||
304 | ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST); | ||
305 | } | ||
306 | } | ||
307 | if (poffsets[i][j][1] >= (S32)patch_width) | ||
308 | { | ||
309 | if (!ppatches[i][j]->getNeighborPatch(NORTH)) | ||
310 | { | ||
311 | poffsets[i][j][1] = patch_width - 1; | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | poffsets[i][j][1] -= patch_width; | ||
316 | ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH); | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | LLVector3 p00(-mpg,-mpg, | ||
323 | *(ppatches[0][0]->mDataZ | ||
324 | + poffsets[0][0][0] | ||
325 | + poffsets[0][0][1]*surface_stride)); | ||
326 | LLVector3 p01(-mpg,+mpg, | ||
327 | *(ppatches[0][1]->mDataZ | ||
328 | + poffsets[0][1][0] | ||
329 | + poffsets[0][1][1]*surface_stride)); | ||
330 | LLVector3 p10(+mpg,-mpg, | ||
331 | *(ppatches[1][0]->mDataZ | ||
332 | + poffsets[1][0][0] | ||
333 | + poffsets[1][0][1]*surface_stride)); | ||
334 | LLVector3 p11(+mpg,+mpg, | ||
335 | *(ppatches[1][1]->mDataZ | ||
336 | + poffsets[1][1][0] | ||
337 | + poffsets[1][1][1]*surface_stride)); | ||
338 | |||
339 | LLVector3 c1 = p11 - p00; | ||
340 | LLVector3 c2 = p01 - p10; | ||
341 | |||
342 | LLVector3 normal = c1; | ||
343 | normal %= c2; | ||
344 | normal.normVec(); | ||
345 | |||
346 | *(mDataNorm + surface_stride * y + x) = normal; | ||
347 | } | ||
348 | |||
349 | const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const | ||
350 | { | ||
351 | U32 surface_stride = mSurfacep->getGridsPerEdge(); | ||
352 | return *(mDataNorm + surface_stride * y + x); | ||
353 | } | ||
354 | |||
355 | |||
356 | void LLSurfacePatch::updateCameraDistanceRegion(const LLVector3 &pos_region) | ||
357 | { | ||
358 | LLVector3 dv = pos_region; | ||
359 | dv -= mCenterRegion; | ||
360 | mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius)); | ||
361 | } | ||
362 | |||
363 | F32 LLSurfacePatch::getDistance() const | ||
364 | { | ||
365 | return mVisInfo.mDistance; | ||
366 | } | ||
367 | |||
368 | |||
369 | // Called when a patch has changed its height field | ||
370 | // data. | ||
371 | void LLSurfacePatch::updateVerticalStats() | ||
372 | { | ||
373 | if (!mDirtyZStats) | ||
374 | { | ||
375 | return; | ||
376 | } | ||
377 | |||
378 | U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); | ||
379 | U32 grids_per_edge = mSurfacep->getGridsPerEdge(); | ||
380 | F32 meters_per_grid = mSurfacep->getMetersPerGrid(); | ||
381 | |||
382 | U32 i, j, k; | ||
383 | F32 z, total; | ||
384 | |||
385 | z = *(mDataZ); | ||
386 | |||
387 | mMinZ = z; | ||
388 | mMaxZ = z; | ||
389 | |||
390 | k = 0; | ||
391 | total = 0.0f; | ||
392 | |||
393 | // Iterate to +1 because we need to do the edges correctly. | ||
394 | for (j=0; j<(grids_per_patch_edge+1); j++) | ||
395 | { | ||
396 | for (i=0; i<(grids_per_patch_edge+1); i++) | ||
397 | { | ||
398 | z = *(mDataZ + i + j*grids_per_edge); | ||
399 | |||
400 | if (z < mMinZ) | ||
401 | { | ||
402 | mMinZ = z; | ||
403 | } | ||
404 | if (z > mMaxZ) | ||
405 | { | ||
406 | mMaxZ = z; | ||
407 | } | ||
408 | total += z; | ||
409 | k++; | ||
410 | } | ||
411 | } | ||
412 | mMeanZ = total / (F32) k; | ||
413 | mCenterRegion.mV[VZ] = 0.5f * (mMinZ + mMaxZ); | ||
414 | |||
415 | LLVector3 diam_vec(meters_per_grid*grids_per_patch_edge, | ||
416 | meters_per_grid*grids_per_patch_edge, | ||
417 | mMaxZ - mMinZ); | ||
418 | mRadius = diam_vec.magVec() * 0.5f; | ||
419 | |||
420 | mSurfacep->mMaxZ = llmax(mMaxZ, mSurfacep->mMaxZ); | ||
421 | mSurfacep->mMinZ = llmin(mMinZ, mSurfacep->mMinZ); | ||
422 | mSurfacep->mHasZData = TRUE; | ||
423 | mSurfacep->getRegion()->calculateCenterGlobal(); | ||
424 | |||
425 | if (mVObjp) | ||
426 | { | ||
427 | mVObjp->dirtyPatch(); | ||
428 | } | ||
429 | mDirtyZStats = FALSE; | ||
430 | } | ||
431 | |||
432 | |||
433 | void LLSurfacePatch::updateNormals() | ||
434 | { | ||
435 | if (mSurfacep->mType == 'w') | ||
436 | { | ||
437 | return; | ||
438 | } | ||
439 | U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); | ||
440 | U32 grids_per_edge = mSurfacep->getGridsPerEdge(); | ||
441 | |||
442 | BOOL dirty_patch = FALSE; | ||
443 | |||
444 | U32 i, j; | ||
445 | // update the east edge | ||
446 | if (mNormalsInvalid[EAST] || mNormalsInvalid[NORTHEAST] || mNormalsInvalid[SOUTHEAST]) | ||
447 | { | ||
448 | for (j = 0; j <= grids_per_patch_edge; j++) | ||
449 | { | ||
450 | calcNormal(grids_per_patch_edge, j, 2); | ||
451 | calcNormal(grids_per_patch_edge - 1, j, 2); | ||
452 | calcNormal(grids_per_patch_edge - 2, j, 2); | ||
453 | } | ||
454 | |||
455 | dirty_patch = TRUE; | ||
456 | } | ||
457 | |||
458 | // update the north edge | ||
459 | if (mNormalsInvalid[NORTHEAST] || mNormalsInvalid[NORTH] || mNormalsInvalid[NORTHWEST]) | ||
460 | { | ||
461 | for (i = 0; i <= grids_per_patch_edge; i++) | ||
462 | { | ||
463 | calcNormal(i, grids_per_patch_edge, 2); | ||
464 | calcNormal(i, grids_per_patch_edge - 1, 2); | ||
465 | calcNormal(i, grids_per_patch_edge - 2, 2); | ||
466 | } | ||
467 | |||
468 | dirty_patch = TRUE; | ||
469 | } | ||
470 | |||
471 | // update the west edge | ||
472 | if (mNormalsInvalid[NORTHWEST] || mNormalsInvalid[WEST] || mNormalsInvalid[SOUTHWEST]) | ||
473 | { | ||
474 | for (j = 0; j < grids_per_patch_edge; j++) | ||
475 | { | ||
476 | calcNormal(0, j, 2); | ||
477 | calcNormal(1, j, 2); | ||
478 | } | ||
479 | dirty_patch = TRUE; | ||
480 | } | ||
481 | |||
482 | // update the south edge | ||
483 | if (mNormalsInvalid[SOUTHWEST] || mNormalsInvalid[SOUTH] || mNormalsInvalid[SOUTHEAST]) | ||
484 | { | ||
485 | for (i = 0; i < grids_per_patch_edge; i++) | ||
486 | { | ||
487 | calcNormal(i, 0, 2); | ||
488 | calcNormal(i, 1, 2); | ||
489 | } | ||
490 | dirty_patch = TRUE; | ||
491 | } | ||
492 | |||
493 | // Invalidating the northeast corner is different, because depending on what the adjacent neighbors are, | ||
494 | // we'll want to do different things. | ||
495 | if (mNormalsInvalid[NORTHEAST]) | ||
496 | { | ||
497 | if (!getNeighborPatch(NORTHEAST)) | ||
498 | { | ||
499 | if (!getNeighborPatch(NORTH)) | ||
500 | { | ||
501 | if (!getNeighborPatch(EAST)) | ||
502 | { | ||
503 | // No north or east neighbors. Pull from the diagonal in your own patch. | ||
504 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
505 | *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); | ||
506 | } | ||
507 | else | ||
508 | { | ||
509 | if (getNeighborPatch(EAST)->getHasReceivedData()) | ||
510 | { | ||
511 | // East, but not north. Pull from your east neighbor's northwest point. | ||
512 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
513 | *(getNeighborPatch(EAST)->mDataZ + (grids_per_patch_edge - 1)*grids_per_edge); | ||
514 | } | ||
515 | else | ||
516 | { | ||
517 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
518 | *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | // We have a north. | ||
525 | if (getNeighborPatch(EAST)) | ||
526 | { | ||
527 | // North and east neighbors, but not northeast. | ||
528 | // Pull from diagonal in your own patch. | ||
529 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
530 | *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | if (getNeighborPatch(NORTH)->getHasReceivedData()) | ||
535 | { | ||
536 | // North, but not east. Pull from your north neighbor's southeast corner. | ||
537 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
538 | *(getNeighborPatch(NORTH)->mDataZ + (grids_per_patch_edge - 1)); | ||
539 | } | ||
540 | else | ||
541 | { | ||
542 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
543 | *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge); | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | else if (getNeighborPatch(NORTHEAST)->mSurfacep != mSurfacep) | ||
549 | { | ||
550 | if ( | ||
551 | (!getNeighborPatch(NORTH) || (getNeighborPatch(NORTH)->mSurfacep != mSurfacep)) | ||
552 | && | ||
553 | (!getNeighborPatch(EAST) || (getNeighborPatch(EAST)->mSurfacep != mSurfacep))) | ||
554 | { | ||
555 | *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = | ||
556 | *(getNeighborPatch(NORTHEAST)->mDataZ); | ||
557 | } | ||
558 | } | ||
559 | else | ||
560 | { | ||
561 | // We've got a northeast patch in the same surface. | ||
562 | // The z and normals will be handled by that patch. | ||
563 | } | ||
564 | calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2); | ||
565 | calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2); | ||
566 | calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2); | ||
567 | calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2); | ||
568 | dirty_patch = TRUE; | ||
569 | } | ||
570 | |||
571 | // update the middle normals | ||
572 | if (mNormalsInvalid[MIDDLE]) | ||
573 | { | ||
574 | for (j=2; j < grids_per_patch_edge - 2; j++) | ||
575 | { | ||
576 | for (i=2; i < grids_per_patch_edge - 2; i++) | ||
577 | { | ||
578 | calcNormal(i, j, 2); | ||
579 | } | ||
580 | } | ||
581 | dirty_patch = TRUE; | ||
582 | } | ||
583 | |||
584 | if (dirty_patch) | ||
585 | { | ||
586 | mSurfacep->dirtySurfacePatch(this); | ||
587 | } | ||
588 | |||
589 | for (i = 0; i < 9; i++) | ||
590 | { | ||
591 | mNormalsInvalid[i] = FALSE; | ||
592 | } | ||
593 | } | ||
594 | |||
595 | void LLSurfacePatch::updateEastEdge() | ||
596 | { | ||
597 | U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); | ||
598 | U32 grids_per_edge = mSurfacep->getGridsPerEdge(); | ||
599 | |||
600 | U32 j, k; | ||
601 | F32 *west_surface, *east_surface; | ||
602 | |||
603 | if (!getNeighborPatch(EAST)) | ||
604 | { | ||
605 | west_surface = mDataZ + grids_per_patch_edge; | ||
606 | east_surface = mDataZ + grids_per_patch_edge - 1; | ||
607 | } | ||
608 | else if (mConnectedEdge & EAST_EDGE) | ||
609 | { | ||
610 | west_surface = mDataZ + grids_per_patch_edge; | ||
611 | east_surface = getNeighborPatch(EAST)->mDataZ; | ||
612 | } | ||
613 | else | ||
614 | { | ||
615 | return; | ||
616 | } | ||
617 | |||
618 | // If patchp is on the east edge of its surface, then we update the east | ||
619 | // side buffer | ||
620 | for (j=0; j < grids_per_patch_edge; j++) | ||
621 | { | ||
622 | k = j * grids_per_edge; | ||
623 | *(west_surface + k) = *(east_surface + k); // update buffer Z | ||
624 | } | ||
625 | } | ||
626 | |||
627 | |||
628 | void LLSurfacePatch::updateNorthEdge() | ||
629 | { | ||
630 | U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); | ||
631 | U32 grids_per_edge = mSurfacep->getGridsPerEdge(); | ||
632 | |||
633 | U32 i; | ||
634 | F32 *south_surface, *north_surface; | ||
635 | |||
636 | if (!getNeighborPatch(NORTH)) | ||
637 | { | ||
638 | south_surface = mDataZ + grids_per_patch_edge*grids_per_edge; | ||
639 | north_surface = mDataZ + (grids_per_patch_edge - 1) * grids_per_edge; | ||
640 | } | ||
641 | else if (mConnectedEdge & NORTH_EDGE) | ||
642 | { | ||
643 | south_surface = mDataZ + grids_per_patch_edge*grids_per_edge; | ||
644 | north_surface = getNeighborPatch(NORTH)->mDataZ; | ||
645 | } | ||
646 | else | ||
647 | { | ||
648 | return; | ||
649 | } | ||
650 | |||
651 | // Update patchp's north edge ... | ||
652 | for (i=0; i<grids_per_patch_edge; i++) | ||
653 | { | ||
654 | *(south_surface + i) = *(north_surface + i); // update buffer Z | ||
655 | } | ||
656 | } | ||
657 | |||
658 | |||
659 | BOOL LLSurfacePatch::updateTexture() | ||
660 | { | ||
661 | if (mSTexUpdate) // Update texture as needed | ||
662 | { | ||
663 | F32 meters_per_grid = getSurface()->getMetersPerGrid(); | ||
664 | F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge(); | ||
665 | |||
666 | if ((!getNeighborPatch(EAST) || getNeighborPatch(EAST)->getHasReceivedData()) | ||
667 | && (!getNeighborPatch(WEST) || getNeighborPatch(WEST)->getHasReceivedData()) | ||
668 | && (!getNeighborPatch(SOUTH) || getNeighborPatch(SOUTH)->getHasReceivedData()) | ||
669 | && (!getNeighborPatch(NORTH) || getNeighborPatch(NORTH)->getHasReceivedData())) | ||
670 | { | ||
671 | LLViewerRegion *regionp = getSurface()->getRegion(); | ||
672 | LLVector3d origin_region = getOriginGlobal() - getSurface()->getOriginGlobal(); | ||
673 | |||
674 | // Have to figure out a better way to deal with these edge conditions... | ||
675 | LLVLComposition* comp = regionp->getComposition(); | ||
676 | if (!mHeightsGenerated) | ||
677 | { | ||
678 | F32 patch_size = meters_per_grid*(grids_per_patch_edge+1); | ||
679 | if (comp->generateHeights((F32)origin_region[VX], (F32)origin_region[VY], | ||
680 | patch_size, patch_size)) | ||
681 | { | ||
682 | mHeightsGenerated = TRUE; | ||
683 | } | ||
684 | else | ||
685 | { | ||
686 | return FALSE; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | if (comp->generateComposition()) | ||
691 | { | ||
692 | if (mVObjp) | ||
693 | { | ||
694 | mVObjp->dirtyGeom(); | ||
695 | } | ||
696 | updateCompositionStats(); | ||
697 | F32 tex_patch_size = meters_per_grid*grids_per_patch_edge; | ||
698 | if (comp->generateTexture((F32)origin_region[VX], (F32)origin_region[VY], | ||
699 | tex_patch_size, tex_patch_size)) | ||
700 | { | ||
701 | mSTexUpdate = FALSE; | ||
702 | |||
703 | // Also generate the water texture | ||
704 | mSurfacep->generateWaterTexture((F32)origin_region.mdV[VX], (F32)origin_region.mdV[VY], | ||
705 | tex_patch_size, tex_patch_size); | ||
706 | return TRUE; | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | return FALSE; | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | return TRUE; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | |||
719 | void LLSurfacePatch::dirtyZ() | ||
720 | { | ||
721 | mSTexUpdate = TRUE; | ||
722 | |||
723 | // Invalidate all normals in this patch | ||
724 | U32 i; | ||
725 | for (i = 0; i < 9; i++) | ||
726 | { | ||
727 | mNormalsInvalid[i] = TRUE; | ||
728 | } | ||
729 | |||
730 | // Invalidate normals in this and neighboring patches | ||
731 | for (i = 0; i < 8; i++) | ||
732 | { | ||
733 | if (getNeighborPatch(i)) | ||
734 | { | ||
735 | getNeighborPatch(i)->mNormalsInvalid[gDirOpposite[i]] = TRUE; | ||
736 | getNeighborPatch(i)->dirty(); | ||
737 | if (i < 4) | ||
738 | { | ||
739 | getNeighborPatch(i)->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][0]] = TRUE; | ||
740 | getNeighborPatch(i)->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][1]] = TRUE; | ||
741 | } | ||
742 | } | ||
743 | } | ||
744 | |||
745 | dirty(); | ||
746 | mLastUpdateTime = gFrameTime; | ||
747 | } | ||
748 | |||
749 | |||
750 | const U64 &LLSurfacePatch::getLastUpdateTime() const | ||
751 | { | ||
752 | return mLastUpdateTime; | ||
753 | } | ||
754 | |||
755 | F32 LLSurfacePatch::getMaxZ() const | ||
756 | { | ||
757 | return mMaxZ; | ||
758 | } | ||
759 | |||
760 | F32 LLSurfacePatch::getMinZ() const | ||
761 | { | ||
762 | return mMinZ; | ||
763 | } | ||
764 | |||
765 | void LLSurfacePatch::setOriginGlobal(const LLVector3d &origin_global) | ||
766 | { | ||
767 | mOriginGlobal = origin_global; | ||
768 | |||
769 | LLVector3 origin_region; | ||
770 | origin_region.setVec(mOriginGlobal - mSurfacep->getOriginGlobal()); | ||
771 | |||
772 | mOriginRegion = origin_region; | ||
773 | mCenterRegion.mV[VX] = origin_region.mV[VX] + 0.5f*mSurfacep->getGridsPerPatchEdge()*mSurfacep->getMetersPerGrid(); | ||
774 | mCenterRegion.mV[VY] = origin_region.mV[VY] + 0.5f*mSurfacep->getGridsPerPatchEdge()*mSurfacep->getMetersPerGrid(); | ||
775 | |||
776 | mVisInfo.mbIsVisible = FALSE; | ||
777 | mVisInfo.mDistance = 512.0f; | ||
778 | mVisInfo.mRenderLevel = 0; | ||
779 | mVisInfo.mRenderStride = mSurfacep->getGridsPerPatchEdge(); | ||
780 | |||
781 | } | ||
782 | |||
783 | void LLSurfacePatch::connectNeighbor(LLSurfacePatch *neighbor_patchp, const U32 direction) | ||
784 | { | ||
785 | llassert(neighbor_patchp); | ||
786 | mNormalsInvalid[direction] = TRUE; | ||
787 | neighbor_patchp->mNormalsInvalid[gDirOpposite[direction]] = TRUE; | ||
788 | |||
789 | setNeighborPatch(direction, neighbor_patchp); | ||
790 | neighbor_patchp->setNeighborPatch(gDirOpposite[direction], this); | ||
791 | |||
792 | if (EAST == direction) | ||
793 | { | ||
794 | mConnectedEdge |= EAST_EDGE; | ||
795 | neighbor_patchp->mConnectedEdge |= WEST_EDGE; | ||
796 | } | ||
797 | else if (NORTH == direction) | ||
798 | { | ||
799 | mConnectedEdge |= NORTH_EDGE; | ||
800 | neighbor_patchp->mConnectedEdge |= SOUTH_EDGE; | ||
801 | } | ||
802 | else if (WEST == direction) | ||
803 | { | ||
804 | mConnectedEdge |= WEST_EDGE; | ||
805 | neighbor_patchp->mConnectedEdge |= EAST_EDGE; | ||
806 | } | ||
807 | else if (SOUTH == direction) | ||
808 | { | ||
809 | mConnectedEdge |= SOUTH_EDGE; | ||
810 | neighbor_patchp->mConnectedEdge |= NORTH_EDGE; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | void LLSurfacePatch::updateVisibility() | ||
815 | { | ||
816 | if (mVObjp == (LLVOSurfacePatch*)NULL) | ||
817 | { | ||
818 | return; | ||
819 | } | ||
820 | |||
821 | const F32 DEFAULT_DELTA_ANGLE = (0.15f); | ||
822 | U32 old_render_stride, max_render_stride; | ||
823 | U32 new_render_level; | ||
824 | F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid(); | ||
825 | U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); | ||
826 | |||
827 | // sphere in frustum on global coordinates | ||
828 | if (gCamera->sphereInFrustum(mCenterRegion + mSurfacep->getOriginAgent(), mRadius) ) | ||
829 | { | ||
830 | // We now need to calculate the render stride based on patchp's distance | ||
831 | // from LLCamera render_stride is governed by a relation something like this... | ||
832 | // | ||
833 | // delta_angle * patch.distance | ||
834 | // render_stride <= ---------------------------------------- | ||
835 | // mMetersPerGrid | ||
836 | // | ||
837 | // where 'delta_angle' is the desired solid angle of the average polgon on a patch. | ||
838 | // | ||
839 | // Any render_stride smaller than the RHS would be 'satisfactory'. Smaller | ||
840 | // strides give more resolution, but efficiency suggests that we use the largest | ||
841 | // of the render_strides that obey the relation. Flexibility is achieved by | ||
842 | // modulating 'delta_angle' until we have an acceptable number of triangles. | ||
843 | |||
844 | old_render_stride = mVisInfo.mRenderStride; | ||
845 | |||
846 | // Calculate the render_stride using information in agent | ||
847 | max_render_stride = lltrunc(mVisInfo.mDistance * stride_per_distance); | ||
848 | max_render_stride = llmin(max_render_stride , 2*grids_per_patch_edge); | ||
849 | |||
850 | // We only use render_strides that are powers of two, so we use look-up tables to figure out | ||
851 | // the render_level and corresponding render_stride | ||
852 | new_render_level = mVisInfo.mRenderLevel = mSurfacep->getRenderLevel(max_render_stride); | ||
853 | mVisInfo.mRenderStride = mSurfacep->getRenderStride(new_render_level); | ||
854 | |||
855 | if ((mVisInfo.mRenderStride != old_render_stride)) | ||
856 | // The reason we check !mbIsVisible is because non-visible patches normals | ||
857 | // are not updated when their data is changed. When this changes we can get | ||
858 | // rid of mbIsVisible altogether. | ||
859 | { | ||
860 | if (mVObjp) | ||
861 | { | ||
862 | mVObjp->dirtyGeom(); | ||
863 | if (getNeighborPatch(WEST)) | ||
864 | { | ||
865 | getNeighborPatch(WEST)->mVObjp->dirtyGeom(); | ||
866 | } | ||
867 | if (getNeighborPatch(SOUTH)) | ||
868 | { | ||
869 | getNeighborPatch(SOUTH)->mVObjp->dirtyGeom(); | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | mVisInfo.mbIsVisible = TRUE; | ||
874 | } | ||
875 | else | ||
876 | { | ||
877 | mVisInfo.mbIsVisible = FALSE; | ||
878 | } | ||
879 | } | ||
880 | |||
881 | |||
882 | const LLVector3d &LLSurfacePatch::getOriginGlobal() const | ||
883 | { | ||
884 | return mOriginGlobal; | ||
885 | } | ||
886 | |||
887 | LLVector3 LLSurfacePatch::getOriginAgent() const | ||
888 | { | ||
889 | return gAgent.getPosAgentFromGlobal(mOriginGlobal); | ||
890 | } | ||
891 | |||
892 | BOOL LLSurfacePatch::getVisible() const | ||
893 | { | ||
894 | return mVisInfo.mbIsVisible; | ||
895 | } | ||
896 | |||
897 | U32 LLSurfacePatch::getRenderStride() const | ||
898 | { | ||
899 | return mVisInfo.mRenderStride; | ||
900 | } | ||
901 | |||
902 | S32 LLSurfacePatch::getRenderLevel() const | ||
903 | { | ||
904 | return mVisInfo.mRenderLevel; | ||
905 | } | ||
906 | |||
907 | void LLSurfacePatch::setHasReceivedData() | ||
908 | { | ||
909 | mHasReceivedData = TRUE; | ||
910 | } | ||
911 | |||
912 | BOOL LLSurfacePatch::getHasReceivedData() const | ||
913 | { | ||
914 | return mHasReceivedData; | ||
915 | } | ||
916 | |||
917 | const LLVector3 &LLSurfacePatch::getCenterRegion() const | ||
918 | { | ||
919 | return mCenterRegion; | ||
920 | } | ||
921 | |||
922 | |||
923 | void LLSurfacePatch::updateCompositionStats() | ||
924 | { | ||
925 | LLViewerLayer *vlp = mSurfacep->getRegion()->getComposition(); | ||
926 | |||
927 | F32 x, y, width, height, mpg, min, mean, max; | ||
928 | |||
929 | LLVector3 origin = getOriginAgent() - mSurfacep->getOriginAgent(); | ||
930 | mpg = mSurfacep->getMetersPerGrid(); | ||
931 | x = origin.mV[VX]; | ||
932 | y = origin.mV[VY]; | ||
933 | width = mpg*(mSurfacep->getGridsPerPatchEdge()+1); | ||
934 | height = mpg*(mSurfacep->getGridsPerPatchEdge()+1); | ||
935 | |||
936 | mean = 0.f; | ||
937 | min = vlp->getValueScaled(x, y); | ||
938 | max= min; | ||
939 | U32 count = 0; | ||
940 | F32 i, j; | ||
941 | for (j = 0; j < height; j += mpg) | ||
942 | { | ||
943 | for (i = 0; i < width; i += mpg) | ||
944 | { | ||
945 | F32 comp = vlp->getValueScaled(x + i, y + j); | ||
946 | mean += comp; | ||
947 | min = llmin(min, comp); | ||
948 | max = llmax(max, comp); | ||
949 | count++; | ||
950 | } | ||
951 | } | ||
952 | mean /= count; | ||
953 | |||
954 | mMinComposition = min; | ||
955 | mMeanComposition = mean; | ||
956 | mMaxComposition = max; | ||
957 | } | ||
958 | |||
959 | F32 LLSurfacePatch::getMeanComposition() const | ||
960 | { | ||
961 | return mMeanComposition; | ||
962 | } | ||
963 | |||
964 | F32 LLSurfacePatch::getMinComposition() const | ||
965 | { | ||
966 | return mMinComposition; | ||
967 | } | ||
968 | |||
969 | F32 LLSurfacePatch::getMaxComposition() const | ||
970 | { | ||
971 | return mMaxComposition; | ||
972 | } | ||
973 | |||
974 | void LLSurfacePatch::setNeighborPatch(const U32 direction, LLSurfacePatch *neighborp) | ||
975 | { | ||
976 | mNeighborPatches[direction] = neighborp; | ||
977 | mNormalsInvalid[direction] = TRUE; | ||
978 | if (direction < 4) | ||
979 | { | ||
980 | mNormalsInvalid[gDirAdjacent[direction][0]] = TRUE; | ||
981 | mNormalsInvalid[gDirAdjacent[direction][1]] = TRUE; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | LLSurfacePatch *LLSurfacePatch::getNeighborPatch(const U32 direction) const | ||
986 | { | ||
987 | return mNeighborPatches[direction]; | ||
988 | } | ||
989 | |||
990 | void LLSurfacePatch::clearVObj() | ||
991 | { | ||
992 | mVObjp = NULL; | ||
993 | } | ||