aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llsurfacepatch.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llsurfacepatch.cpp
parentREADME.txt (diff)
downloadmeta-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.cpp993
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
47extern U64 gFrameTime;
48extern LLPipeline gPipeline;
49
50LLSurfacePatch::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
85LLSurfacePatch::~LLSurfacePatch()
86{
87 mVObjp = NULL;
88}
89
90
91void 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
115void 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
129void 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
175LLVector3 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
187LLVector2 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
202void 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
237void 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
349const 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
356void 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
363F32 LLSurfacePatch::getDistance() const
364{
365 return mVisInfo.mDistance;
366}
367
368
369// Called when a patch has changed its height field
370// data.
371void 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
433void 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
595void 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
628void 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
659BOOL 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
719void 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
750const U64 &LLSurfacePatch::getLastUpdateTime() const
751{
752 return mLastUpdateTime;
753}
754
755F32 LLSurfacePatch::getMaxZ() const
756{
757 return mMaxZ;
758}
759
760F32 LLSurfacePatch::getMinZ() const
761{
762 return mMinZ;
763}
764
765void 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
783void 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
814void 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
882const LLVector3d &LLSurfacePatch::getOriginGlobal() const
883{
884 return mOriginGlobal;
885}
886
887LLVector3 LLSurfacePatch::getOriginAgent() const
888{
889 return gAgent.getPosAgentFromGlobal(mOriginGlobal);
890}
891
892BOOL LLSurfacePatch::getVisible() const
893{
894 return mVisInfo.mbIsVisible;
895}
896
897U32 LLSurfacePatch::getRenderStride() const
898{
899 return mVisInfo.mRenderStride;
900}
901
902S32 LLSurfacePatch::getRenderLevel() const
903{
904 return mVisInfo.mRenderLevel;
905}
906
907void LLSurfacePatch::setHasReceivedData()
908{
909 mHasReceivedData = TRUE;
910}
911
912BOOL LLSurfacePatch::getHasReceivedData() const
913{
914 return mHasReceivedData;
915}
916
917const LLVector3 &LLSurfacePatch::getCenterRegion() const
918{
919 return mCenterRegion;
920}
921
922
923void 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
959F32 LLSurfacePatch::getMeanComposition() const
960{
961 return mMeanComposition;
962}
963
964F32 LLSurfacePatch::getMinComposition() const
965{
966 return mMinComposition;
967}
968
969F32 LLSurfacePatch::getMaxComposition() const
970{
971 return mMaxComposition;
972}
973
974void 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
985LLSurfacePatch *LLSurfacePatch::getNeighborPatch(const U32 direction) const
986{
987 return mNeighborPatches[direction];
988}
989
990void LLSurfacePatch::clearVObj()
991{
992 mVObjp = NULL;
993}