llsurfacepatch.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llsurfacepatch.h"
00035 #include "llpatchvertexarray.h"
00036 #include "llviewerobjectlist.h"
00037 #include "llvosurfacepatch.h"
00038 #include "llsurface.h"
00039 #include "pipeline.h"
00040 #include "llagent.h"
00041 #include "timing.h"
00042 #include "llsky.h"
00043 #include "llviewercamera.h"
00044 
00045 // For getting composition values
00046 #include "llviewerregion.h"
00047 #include "llvlcomposition.h"
00048 #include "lldrawpool.h"
00049 #include "noise.h"
00050 
00051 extern U64 gFrameTime;
00052 extern LLPipeline gPipeline;
00053 
00054 LLSurfacePatch::LLSurfacePatch() :
00055                                                 mDataZ(NULL),
00056                                                 mVObjp(NULL),
00057                                                 mLastUpdateTime(0),
00058                                                 mSurfacep(NULL)
00059 {
00060         // This flag is used to communicate between adjacent surfaces and is set
00061         // to non-zero values by higher classes.  
00062         mConnectedEdge = NO_EDGE;
00063         mCenterRegion = LLVector3(0.f, 0.f, 0.f);
00064         mOriginRegion = LLVector3(0.f, 0.f, 0.f);
00065         mHasReceivedData = FALSE;
00066         mMinZ = 0.0f;
00067         mMaxZ = 0.0f;
00068         mMeanZ = 0.0f;
00069         mMinComposition = 0.f;
00070         mMeanComposition = 0.f;
00071         mMaxComposition = 0.f;
00072         mRadius = 0.f;
00073         mDirty = FALSE;
00074         mDirtyZStats = TRUE;
00075         mHeightsGenerated = FALSE;
00076         
00077         S32 i;
00078         for (i = 0; i < 8; i++)
00079         {
00080                 setNeighborPatch(i, NULL);
00081         }
00082         for (i = 0; i < 9; i++)
00083         {
00084                 mNormalsInvalid[i] = TRUE;
00085         }
00086 }
00087 
00088 
00089 LLSurfacePatch::~LLSurfacePatch()
00090 {
00091         mVObjp = NULL;
00092 }
00093 
00094 
00095 void LLSurfacePatch::dirty()
00096 {
00097         // These are outside of the loop in case we're still waiting for a dirty from the
00098         // texture being updated...
00099         if (mVObjp)
00100         {
00101                 mVObjp->dirtyGeom();
00102         }
00103         else
00104         {
00105                 llwarns << "No viewer object for this surface patch!" << llendl;
00106         }
00107 
00108         mDirtyZStats = TRUE;
00109         mHeightsGenerated = FALSE;
00110         
00111         if (!mDirty)
00112         {
00113                 mDirty = TRUE;
00114                 mSurfacep->dirtySurfacePatch(this);
00115         }
00116 }
00117 
00118 
00119 void LLSurfacePatch::setSurface(LLSurface *surfacep)
00120 {
00121         mSurfacep = surfacep;
00122         if (mVObjp == (LLVOSurfacePatch *)NULL)
00123         {
00124                 llassert(mSurfacep->mType == 'l');
00125 
00126                 mVObjp = (LLVOSurfacePatch *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SURFACE_PATCH, mSurfacep->getRegion());
00127                 mVObjp->setPatch(this);
00128                 mVObjp->setPositionRegion(mCenterRegion);
00129                 gPipeline.addObject(mVObjp);
00130         }
00131 } 
00132 
00133 void LLSurfacePatch::disconnectNeighbor(LLSurface *surfacep)
00134 {
00135         U32 i;
00136         for (i = 0; i < 8; i++)
00137         {
00138                 if (getNeighborPatch(i))
00139                 {
00140                         if (getNeighborPatch(i)->mSurfacep == surfacep)
00141                         {
00142                                 setNeighborPatch(i, NULL);
00143                                 mNormalsInvalid[i] = TRUE;
00144                         }
00145                 }
00146         }
00147 
00148         // Clean up connected edges
00149         if (getNeighborPatch(EAST))
00150         {
00151                 if (getNeighborPatch(EAST)->mSurfacep == surfacep)
00152                 {
00153                         mConnectedEdge &= ~EAST_EDGE;
00154                 }
00155         }
00156         if (getNeighborPatch(NORTH))
00157         {
00158                 if (getNeighborPatch(NORTH)->mSurfacep == surfacep)
00159                 {
00160                         mConnectedEdge &= ~NORTH_EDGE;
00161                 }
00162         }
00163         if (getNeighborPatch(WEST))
00164         {
00165                 if (getNeighborPatch(WEST)->mSurfacep == surfacep)
00166                 {
00167                         mConnectedEdge &= ~WEST_EDGE;
00168                 }
00169         }
00170         if (getNeighborPatch(SOUTH))
00171         {
00172                 if (getNeighborPatch(SOUTH)->mSurfacep == surfacep)
00173                 {
00174                         mConnectedEdge &= ~SOUTH_EDGE;
00175                 }
00176         }
00177 }
00178 
00179 LLVector3 LLSurfacePatch::getPointAgent(const U32 x, const U32 y) const
00180 {
00181         U32 surface_stride = mSurfacep->getGridsPerEdge();
00182         U32 point_offset = x + y*surface_stride;
00183         LLVector3 pos;
00184         pos = getOriginAgent();
00185         pos.mV[VX] += x * mSurfacep->getMetersPerGrid();
00186         pos.mV[VY] += y * mSurfacep->getMetersPerGrid();
00187         pos.mV[VZ] = *(mDataZ + point_offset);
00188         return pos;
00189 }
00190 
00191 LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const
00192 {
00193         U32 surface_stride = mSurfacep->getGridsPerEdge();
00194         U32 point_offset = x + y*surface_stride;
00195         LLVector3 pos, rel_pos;
00196         pos = getOriginAgent();
00197         pos.mV[VX] += x * mSurfacep->getMetersPerGrid();
00198         pos.mV[VY] += y * mSurfacep->getMetersPerGrid();
00199         pos.mV[VZ] = *(mDataZ + point_offset);
00200         rel_pos = pos - mSurfacep->getOriginAgent();
00201         rel_pos *= 1.f/surface_stride;
00202         return LLVector2(rel_pos.mV[VX], rel_pos.mV[VY]);
00203 }
00204 
00205 
00206 void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal,
00207                                                   LLVector2 *tex0, LLVector2 *tex1)
00208 {
00209         if (!mSurfacep || !mSurfacep->getRegion())
00210         {
00211                 return; // failsafe
00212         }
00213         
00214         U32 surface_stride = mSurfacep->getGridsPerEdge();
00215         U32 point_offset = x + y*surface_stride;
00216 
00217         *normal = getNormal(x, y);
00218 
00219         LLVector3 pos_agent = getOriginAgent();
00220         pos_agent.mV[VX] += x * mSurfacep->getMetersPerGrid();
00221         pos_agent.mV[VY] += y * mSurfacep->getMetersPerGrid();
00222         pos_agent.mV[VZ]  = *(mDataZ + point_offset);
00223         *vertex     = pos_agent;
00224 
00225         LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent();
00226         LLVector3 tex_pos = rel_pos * (1.f/surface_stride);
00227         tex0->mV[0]  = tex_pos.mV[0];
00228         tex0->mV[1]  = tex_pos.mV[1];
00229         tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y);
00230 
00231         const F32 xyScale = 4.9215f*7.f; //0.93284f;
00232         const F32 xyScaleInv = (1.f / xyScale)*(0.2222222222f);
00233 
00234         F32 vec[3] = {
00235                                         fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f),
00236                                         fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f),
00237                                         0.f
00238                                 };
00239         F32 rand_val = llclamp(noise2(vec)* 0.75f + 0.5f, 0.f, 1.f);
00240         tex1->mV[1] = rand_val;
00241 
00242 
00243 }
00244 
00245 
00246 void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
00247 {
00248         U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
00249         U32 surface_stride = mSurfacep->getGridsPerEdge();
00250 
00251         const F32 mpg = mSurfacep->getMetersPerGrid() * stride;
00252 
00253         S32 poffsets[2][2][2];
00254         poffsets[0][0][0] = x - stride;
00255         poffsets[0][0][1] = y - stride;
00256 
00257         poffsets[0][1][0] = x - stride;
00258         poffsets[0][1][1] = y + stride;
00259 
00260         poffsets[1][0][0] = x + stride;
00261         poffsets[1][0][1] = y - stride;
00262 
00263         poffsets[1][1][0] = x + stride;
00264         poffsets[1][1][1] = y + stride;
00265 
00266         const LLSurfacePatch *ppatches[2][2];
00267 
00268         // LLVector3 p1, p2, p3, p4;
00269 
00270         ppatches[0][0] = this;
00271         ppatches[0][1] = this;
00272         ppatches[1][0] = this;
00273         ppatches[1][1] = this;
00274 
00275         U32 i, j;
00276         for (i = 0; i < 2; i++)
00277         {
00278                 for (j = 0; j < 2; j++)
00279                 {
00280                         if (poffsets[i][j][0] < 0)
00281                         {
00282                                 if (!ppatches[i][j]->getNeighborPatch(WEST))
00283                                 {
00284                                         poffsets[i][j][0] = 0;
00285                                 }
00286                                 else
00287                                 {
00288                                         poffsets[i][j][0] += patch_width;
00289                                         ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST);
00290                                 }
00291                         }
00292                         if (poffsets[i][j][1] < 0)
00293                         {
00294                                 if (!ppatches[i][j]->getNeighborPatch(SOUTH))
00295                                 {
00296                                         poffsets[i][j][1] = 0;
00297                                 }
00298                                 else
00299                                 {
00300                                         poffsets[i][j][1] += patch_width;
00301                                         ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH);
00302                                 }
00303                         }
00304                         if (poffsets[i][j][0] >= (S32)patch_width)
00305                         {
00306                                 if (!ppatches[i][j]->getNeighborPatch(EAST))
00307                                 {
00308                                         poffsets[i][j][0] = patch_width - 1;
00309                                 }
00310                                 else
00311                                 {
00312                                         poffsets[i][j][0] -= patch_width;
00313                                         ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST);
00314                                 }
00315                         }
00316                         if (poffsets[i][j][1] >= (S32)patch_width)
00317                         {
00318                                 if (!ppatches[i][j]->getNeighborPatch(NORTH))
00319                                 {
00320                                         poffsets[i][j][1] = patch_width - 1;
00321                                 }
00322                                 else
00323                                 {
00324                                         poffsets[i][j][1] -= patch_width;
00325                                         ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH);
00326                                 }
00327                         }
00328                 }
00329         }
00330 
00331         LLVector3 p00(-mpg,-mpg,
00332                                   *(ppatches[0][0]->mDataZ
00333                                   + poffsets[0][0][0]
00334                                   + poffsets[0][0][1]*surface_stride));
00335         LLVector3 p01(-mpg,+mpg,
00336                                   *(ppatches[0][1]->mDataZ
00337                                   + poffsets[0][1][0]
00338                                   + poffsets[0][1][1]*surface_stride));
00339         LLVector3 p10(+mpg,-mpg,
00340                                   *(ppatches[1][0]->mDataZ
00341                                   + poffsets[1][0][0]
00342                                   + poffsets[1][0][1]*surface_stride));
00343         LLVector3 p11(+mpg,+mpg,
00344                                   *(ppatches[1][1]->mDataZ
00345                                   + poffsets[1][1][0]
00346                                   + poffsets[1][1][1]*surface_stride));
00347 
00348         LLVector3 c1 = p11 - p00;
00349         LLVector3 c2 = p01 - p10;
00350 
00351         LLVector3 normal = c1;
00352         normal %= c2;
00353         normal.normVec();
00354 
00355         *(mDataNorm + surface_stride * y + x) = normal;
00356 }
00357 
00358 const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const
00359 {
00360         U32 surface_stride = mSurfacep->getGridsPerEdge();
00361         return *(mDataNorm + surface_stride * y + x);
00362 }
00363 
00364 
00365 void LLSurfacePatch::updateCameraDistanceRegion(const LLVector3 &pos_region)
00366 {
00367         if (LLPipeline::sDynamicLOD)
00368         {
00369                 LLVector3 dv = pos_region;
00370                 dv -= mCenterRegion;
00371                 mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius))/
00372                         llmax(LLVOSurfacePatch::sLODFactor, 0.1f);
00373         }
00374         else
00375         {
00376                 mVisInfo.mDistance = 0.f;
00377         }
00378 }
00379 
00380 F32 LLSurfacePatch::getDistance() const
00381 {
00382         return mVisInfo.mDistance;
00383 }
00384 
00385 
00386 // Called when a patch has changed its height field
00387 // data.
00388 void LLSurfacePatch::updateVerticalStats() 
00389 {
00390         if (!mDirtyZStats)
00391         {
00392                 return;
00393         }
00394 
00395         U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
00396         U32 grids_per_edge = mSurfacep->getGridsPerEdge();
00397         F32 meters_per_grid = mSurfacep->getMetersPerGrid();
00398 
00399         U32 i, j, k;
00400         F32 z, total;
00401 
00402         z = *(mDataZ);
00403 
00404         mMinZ = z;
00405         mMaxZ = z;
00406 
00407         k = 0;
00408         total = 0.0f;
00409 
00410         // Iterate to +1 because we need to do the edges correctly.
00411         for (j=0; j<(grids_per_patch_edge+1); j++) 
00412         {
00413                 for (i=0; i<(grids_per_patch_edge+1); i++) 
00414                 {
00415                         z = *(mDataZ + i + j*grids_per_edge);
00416 
00417                         if (z < mMinZ)
00418                         {
00419                                 mMinZ = z;
00420                         }
00421                         if (z > mMaxZ)
00422                         {
00423                                 mMaxZ = z;
00424                         }
00425                         total += z;
00426                         k++;
00427                 }
00428         }
00429         mMeanZ = total / (F32) k;
00430         mCenterRegion.mV[VZ] = 0.5f * (mMinZ + mMaxZ);
00431 
00432         LLVector3 diam_vec(meters_per_grid*grids_per_patch_edge,
00433                                                 meters_per_grid*grids_per_patch_edge,
00434                                                 mMaxZ - mMinZ);
00435         mRadius = diam_vec.magVec() * 0.5f;
00436 
00437         mSurfacep->mMaxZ = llmax(mMaxZ, mSurfacep->mMaxZ);
00438         mSurfacep->mMinZ = llmin(mMinZ, mSurfacep->mMinZ);
00439         mSurfacep->mHasZData = TRUE;
00440         mSurfacep->getRegion()->calculateCenterGlobal();
00441 
00442         if (mVObjp)
00443         {
00444                 mVObjp->dirtyPatch();
00445         }
00446         mDirtyZStats = FALSE;
00447 }
00448 
00449 
00450 void LLSurfacePatch::updateNormals() 
00451 {
00452         if (mSurfacep->mType == 'w')
00453         {
00454                 return;
00455         }
00456         U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
00457         U32 grids_per_edge = mSurfacep->getGridsPerEdge();
00458 
00459         BOOL dirty_patch = FALSE;
00460 
00461         U32 i, j;
00462         // update the east edge
00463         if (mNormalsInvalid[EAST] || mNormalsInvalid[NORTHEAST] || mNormalsInvalid[SOUTHEAST])
00464         {
00465                 for (j = 0; j <= grids_per_patch_edge; j++)
00466                 {
00467                         calcNormal(grids_per_patch_edge, j, 2);
00468                         calcNormal(grids_per_patch_edge - 1, j, 2);
00469                         calcNormal(grids_per_patch_edge - 2, j, 2);
00470                 }
00471 
00472                 dirty_patch = TRUE;
00473         }
00474 
00475         // update the north edge
00476         if (mNormalsInvalid[NORTHEAST] || mNormalsInvalid[NORTH] || mNormalsInvalid[NORTHWEST])
00477         {
00478                 for (i = 0; i <= grids_per_patch_edge; i++)
00479                 {
00480                         calcNormal(i, grids_per_patch_edge, 2);
00481                         calcNormal(i, grids_per_patch_edge - 1, 2);
00482                         calcNormal(i, grids_per_patch_edge - 2, 2);
00483                 }
00484 
00485                 dirty_patch = TRUE;
00486         }
00487 
00488         // update the west edge
00489         if (mNormalsInvalid[NORTHWEST] || mNormalsInvalid[WEST] || mNormalsInvalid[SOUTHWEST])
00490         {
00491                 for (j = 0; j < grids_per_patch_edge; j++)
00492                 {
00493                         calcNormal(0, j, 2);
00494                         calcNormal(1, j, 2);
00495                 }
00496                 dirty_patch = TRUE;
00497         }
00498 
00499         // update the south edge
00500         if (mNormalsInvalid[SOUTHWEST] || mNormalsInvalid[SOUTH] || mNormalsInvalid[SOUTHEAST])
00501         {
00502                 for (i = 0; i < grids_per_patch_edge; i++)
00503                 {
00504                         calcNormal(i, 0, 2);
00505                         calcNormal(i, 1, 2);
00506                 }
00507                 dirty_patch = TRUE;
00508         }
00509 
00510         // Invalidating the northeast corner is different, because depending on what the adjacent neighbors are,
00511         // we'll want to do different things.
00512         if (mNormalsInvalid[NORTHEAST])
00513         {
00514                 if (!getNeighborPatch(NORTHEAST))
00515                 {
00516                         if (!getNeighborPatch(NORTH))
00517                         {
00518                                 if (!getNeighborPatch(EAST))
00519                                 {
00520                                         // No north or east neighbors.  Pull from the diagonal in your own patch.
00521                                         *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00522                                                 *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge);
00523                                 }
00524                                 else
00525                                 {
00526                                         if (getNeighborPatch(EAST)->getHasReceivedData())
00527                                         {
00528                                                 // East, but not north.  Pull from your east neighbor's northwest point.
00529                                                 *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00530                                                         *(getNeighborPatch(EAST)->mDataZ + (grids_per_patch_edge - 1)*grids_per_edge);
00531                                         }
00532                                         else
00533                                         {
00534                                                 *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00535                                                         *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge);
00536                                         }
00537                                 }
00538                         }
00539                         else
00540                         {
00541                                 // We have a north.
00542                                 if (getNeighborPatch(EAST))
00543                                 {
00544                                         // North and east neighbors, but not northeast.
00545                                         // Pull from diagonal in your own patch.
00546                                         *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00547                                                 *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge);
00548                                 }
00549                                 else
00550                                 {
00551                                         if (getNeighborPatch(NORTH)->getHasReceivedData())
00552                                         {
00553                                                 // North, but not east.  Pull from your north neighbor's southeast corner.
00554                                                 *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00555                                                         *(getNeighborPatch(NORTH)->mDataZ + (grids_per_patch_edge - 1));
00556                                         }
00557                                         else
00558                                         {
00559                                                 *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00560                                                         *(mDataZ + grids_per_patch_edge - 1 + (grids_per_patch_edge - 1)*grids_per_edge);
00561                                         }
00562                                 }
00563                         }
00564                 }
00565                 else if (getNeighborPatch(NORTHEAST)->mSurfacep != mSurfacep)
00566                 {
00567                         if (
00568                                 (!getNeighborPatch(NORTH) || (getNeighborPatch(NORTH)->mSurfacep != mSurfacep))
00569                                 &&
00570                                 (!getNeighborPatch(EAST) || (getNeighborPatch(EAST)->mSurfacep != mSurfacep)))
00571                         {
00572                                 *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) =
00573                                                                                 *(getNeighborPatch(NORTHEAST)->mDataZ);
00574                         }
00575                 }
00576                 else
00577                 {
00578                         // We've got a northeast patch in the same surface.
00579                         // The z and normals will be handled by that patch.
00580                 }
00581                 calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2);
00582                 calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
00583                 calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
00584                 calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
00585                 dirty_patch = TRUE;
00586         }
00587 
00588         // update the middle normals
00589         if (mNormalsInvalid[MIDDLE])
00590         {
00591                 for (j=2; j < grids_per_patch_edge - 2; j++)
00592                 {
00593                         for (i=2; i < grids_per_patch_edge - 2; i++)
00594                         {
00595                                 calcNormal(i, j, 2);
00596                         }
00597                 }
00598                 dirty_patch = TRUE;
00599         }
00600 
00601         if (dirty_patch)
00602         {
00603                 mSurfacep->dirtySurfacePatch(this);
00604         }
00605 
00606         for (i = 0; i < 9; i++)
00607         {
00608                 mNormalsInvalid[i] = FALSE;
00609         }
00610 }
00611 
00612 void LLSurfacePatch::updateEastEdge()
00613 {
00614         U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
00615         U32 grids_per_edge = mSurfacep->getGridsPerEdge();
00616 
00617         U32 j, k;
00618         F32 *west_surface, *east_surface;
00619 
00620         if (!getNeighborPatch(EAST))
00621         {
00622                 west_surface = mDataZ + grids_per_patch_edge;
00623                 east_surface = mDataZ + grids_per_patch_edge - 1;
00624         }
00625         else if (mConnectedEdge & EAST_EDGE)
00626         {
00627                 west_surface = mDataZ + grids_per_patch_edge;
00628                 east_surface = getNeighborPatch(EAST)->mDataZ;
00629         }
00630         else
00631         {
00632                 return;
00633         }
00634 
00635         // If patchp is on the east edge of its surface, then we update the east
00636         // side buffer
00637         for (j=0; j < grids_per_patch_edge; j++)
00638         {
00639                 k = j * grids_per_edge;
00640                 *(west_surface + k) = *(east_surface + k);      // update buffer Z
00641         }
00642 }
00643 
00644 
00645 void LLSurfacePatch::updateNorthEdge()
00646 {
00647         U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
00648         U32 grids_per_edge = mSurfacep->getGridsPerEdge();
00649 
00650         U32 i;
00651         F32 *south_surface, *north_surface;
00652 
00653         if (!getNeighborPatch(NORTH))
00654         {
00655                 south_surface = mDataZ + grids_per_patch_edge*grids_per_edge;
00656                 north_surface = mDataZ + (grids_per_patch_edge - 1) * grids_per_edge;
00657         }
00658         else if (mConnectedEdge & NORTH_EDGE)
00659         {
00660                 south_surface = mDataZ + grids_per_patch_edge*grids_per_edge;
00661                 north_surface = getNeighborPatch(NORTH)->mDataZ;
00662         }
00663         else
00664         {
00665                 return;
00666         }
00667 
00668         // Update patchp's north edge ...
00669         for (i=0; i<grids_per_patch_edge; i++)
00670         {
00671                 *(south_surface + i) = *(north_surface + i);    // update buffer Z
00672         }
00673 }
00674 
00675 
00676 BOOL LLSurfacePatch::updateTexture()
00677 {
00678         if (mSTexUpdate)                //  Update texture as needed
00679         {
00680                 F32 meters_per_grid = getSurface()->getMetersPerGrid();
00681                 F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge();
00682 
00683                 if ((!getNeighborPatch(EAST) || getNeighborPatch(EAST)->getHasReceivedData())
00684                         && (!getNeighborPatch(WEST) || getNeighborPatch(WEST)->getHasReceivedData())
00685                         && (!getNeighborPatch(SOUTH) || getNeighborPatch(SOUTH)->getHasReceivedData())
00686                         && (!getNeighborPatch(NORTH) || getNeighborPatch(NORTH)->getHasReceivedData()))
00687                 {
00688                         LLViewerRegion *regionp = getSurface()->getRegion();
00689                         LLVector3d origin_region = getOriginGlobal() - getSurface()->getOriginGlobal();
00690 
00691                         // Have to figure out a better way to deal with these edge conditions...
00692                         LLVLComposition* comp = regionp->getComposition();
00693                         if (!mHeightsGenerated)
00694                         {
00695                                 F32 patch_size = meters_per_grid*(grids_per_patch_edge+1);
00696                                 if (comp->generateHeights((F32)origin_region[VX], (F32)origin_region[VY],
00697                                                                                   patch_size, patch_size))
00698                                 {
00699                                         mHeightsGenerated = TRUE;
00700                                 }
00701                                 else
00702                                 {
00703                                         return FALSE;
00704                                 }
00705                         }
00706                         
00707                         if (comp->generateComposition())
00708                         {
00709                                 if (mVObjp)
00710                                 {
00711                                         mVObjp->dirtyGeom();
00712                                 }
00713                                 updateCompositionStats();
00714                                 F32 tex_patch_size = meters_per_grid*grids_per_patch_edge;
00715                                 if (comp->generateTexture((F32)origin_region[VX], (F32)origin_region[VY],
00716                                                                                   tex_patch_size, tex_patch_size))
00717                                 {
00718                                         mSTexUpdate = FALSE;
00719 
00720                                         // Also generate the water texture
00721                                         mSurfacep->generateWaterTexture((F32)origin_region.mdV[VX], (F32)origin_region.mdV[VY],
00722                                                                                                         tex_patch_size, tex_patch_size);
00723                                         return TRUE;
00724                                 }
00725                         }
00726                 }
00727                 return FALSE;
00728         }
00729         else
00730         {
00731                 return TRUE;
00732         }
00733 }
00734 
00735 
00736 void LLSurfacePatch::dirtyZ()
00737 {
00738         mSTexUpdate = TRUE;
00739 
00740         // Invalidate all normals in this patch
00741         U32 i;
00742         for (i = 0; i < 9; i++)
00743         {
00744                 mNormalsInvalid[i] = TRUE;
00745         }
00746 
00747         // Invalidate normals in this and neighboring patches
00748         for (i = 0; i < 8; i++)
00749         {
00750                 if (getNeighborPatch(i))
00751                 {
00752                         getNeighborPatch(i)->mNormalsInvalid[gDirOpposite[i]] = TRUE;
00753                         getNeighborPatch(i)->dirty();
00754                         if (i < 4)
00755                         {
00756                                 getNeighborPatch(i)->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][0]] = TRUE;
00757                                 getNeighborPatch(i)->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][1]] = TRUE;
00758                         }
00759                 }
00760         }
00761 
00762         dirty();
00763         mLastUpdateTime = gFrameTime;
00764 }
00765 
00766 
00767 const U64 &LLSurfacePatch::getLastUpdateTime() const
00768 {
00769         return mLastUpdateTime;
00770 }
00771 
00772 F32 LLSurfacePatch::getMaxZ() const
00773 {
00774         return mMaxZ;
00775 }
00776 
00777 F32 LLSurfacePatch::getMinZ() const
00778 {
00779         return mMinZ;
00780 }
00781 
00782 void LLSurfacePatch::setOriginGlobal(const LLVector3d &origin_global)
00783 {
00784         mOriginGlobal = origin_global;
00785 
00786         LLVector3 origin_region;
00787         origin_region.setVec(mOriginGlobal - mSurfacep->getOriginGlobal());
00788 
00789         mOriginRegion = origin_region;
00790         mCenterRegion.mV[VX] = origin_region.mV[VX] + 0.5f*mSurfacep->getGridsPerPatchEdge()*mSurfacep->getMetersPerGrid();
00791         mCenterRegion.mV[VY] = origin_region.mV[VY] + 0.5f*mSurfacep->getGridsPerPatchEdge()*mSurfacep->getMetersPerGrid();
00792 
00793         mVisInfo.mbIsVisible = FALSE;
00794         mVisInfo.mDistance = 512.0f;
00795         mVisInfo.mRenderLevel = 0;
00796         mVisInfo.mRenderStride = mSurfacep->getGridsPerPatchEdge();
00797         
00798 }
00799 
00800 void LLSurfacePatch::connectNeighbor(LLSurfacePatch *neighbor_patchp, const U32 direction)
00801 {
00802         llassert(neighbor_patchp);
00803         mNormalsInvalid[direction] = TRUE;
00804         neighbor_patchp->mNormalsInvalid[gDirOpposite[direction]] = TRUE;
00805 
00806         setNeighborPatch(direction, neighbor_patchp);
00807         neighbor_patchp->setNeighborPatch(gDirOpposite[direction], this);
00808 
00809         if (EAST == direction)
00810         {
00811                 mConnectedEdge |= EAST_EDGE;
00812                 neighbor_patchp->mConnectedEdge |= WEST_EDGE;
00813         }
00814         else if (NORTH == direction)
00815         {
00816                 mConnectedEdge |= NORTH_EDGE;
00817                 neighbor_patchp->mConnectedEdge |= SOUTH_EDGE;
00818         }
00819         else if (WEST == direction)
00820         {
00821                 mConnectedEdge |= WEST_EDGE;
00822                 neighbor_patchp->mConnectedEdge |= EAST_EDGE;
00823         }
00824         else if (SOUTH == direction)
00825         {
00826                 mConnectedEdge |= SOUTH_EDGE;
00827                 neighbor_patchp->mConnectedEdge |= NORTH_EDGE;
00828         }
00829 }
00830 
00831 void LLSurfacePatch::updateVisibility()
00832 {
00833         if (mVObjp.isNull())
00834         {
00835                 return;
00836         }
00837 
00838         const F32 DEFAULT_DELTA_ANGLE   = (0.15f);
00839         U32 old_render_stride, max_render_stride;
00840         U32 new_render_level;
00841         F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid();
00842         U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
00843 
00844         LLVector3 center = mCenterRegion + mSurfacep->getOriginAgent();
00845         LLVector3 radius = LLVector3(mRadius, mRadius, mRadius);
00846 
00847         // sphere in frustum on global coordinates
00848         if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, radius))
00849         {
00850                 // We now need to calculate the render stride based on patchp's distance 
00851                 // from LLCamera render_stride is governed by a relation something like this...
00852                 //
00853                 //                       delta_angle * patch.distance
00854                 // render_stride <=  ----------------------------------------
00855                 //                           mMetersPerGrid
00856                 //
00857                 // where 'delta_angle' is the desired solid angle of the average polgon on a patch.
00858                 //
00859                 // Any render_stride smaller than the RHS would be 'satisfactory'.  Smaller 
00860                 // strides give more resolution, but efficiency suggests that we use the largest 
00861                 // of the render_strides that obey the relation.  Flexibility is achieved by 
00862                 // modulating 'delta_angle' until we have an acceptable number of triangles.
00863         
00864                 old_render_stride = mVisInfo.mRenderStride;
00865 
00866                 // Calculate the render_stride using information in agent
00867                 max_render_stride = lltrunc(mVisInfo.mDistance * stride_per_distance);
00868                 max_render_stride = llmin(max_render_stride , 2*grids_per_patch_edge);
00869 
00870                 // We only use render_strides that are powers of two, so we use look-up tables to figure out
00871                 // the render_level and corresponding render_stride
00872                 new_render_level = mVisInfo.mRenderLevel = mSurfacep->getRenderLevel(max_render_stride);
00873                 mVisInfo.mRenderStride = mSurfacep->getRenderStride(new_render_level);
00874 
00875                 if ((mVisInfo.mRenderStride != old_render_stride)) 
00876                         // The reason we check !mbIsVisible is because non-visible patches normals 
00877                         // are not updated when their data is changed.  When this changes we can get 
00878                         // rid of mbIsVisible altogether.
00879                 {
00880                         if (mVObjp)
00881                         {
00882                                 mVObjp->dirtyGeom();
00883                                 if (getNeighborPatch(WEST))
00884                                 {
00885                                         getNeighborPatch(WEST)->mVObjp->dirtyGeom();
00886                                 }
00887                                 if (getNeighborPatch(SOUTH))
00888                                 {
00889                                         getNeighborPatch(SOUTH)->mVObjp->dirtyGeom();
00890                                 }
00891                         }
00892                 }
00893                 mVisInfo.mbIsVisible = TRUE;
00894         }
00895         else
00896         {
00897                 mVisInfo.mbIsVisible = FALSE;
00898         }
00899 }
00900 
00901 
00902 const LLVector3d &LLSurfacePatch::getOriginGlobal() const
00903 {
00904         return mOriginGlobal;
00905 }
00906 
00907 LLVector3 LLSurfacePatch::getOriginAgent() const
00908 {
00909         return gAgent.getPosAgentFromGlobal(mOriginGlobal);
00910 }
00911 
00912 BOOL LLSurfacePatch::getVisible() const
00913 {
00914         return mVisInfo.mbIsVisible;
00915 }
00916 
00917 U32 LLSurfacePatch::getRenderStride() const
00918 {
00919         return mVisInfo.mRenderStride;
00920 }
00921 
00922 S32 LLSurfacePatch::getRenderLevel() const
00923 {
00924         return mVisInfo.mRenderLevel;
00925 }
00926 
00927 void LLSurfacePatch::setHasReceivedData()
00928 {
00929         mHasReceivedData = TRUE;
00930 }
00931 
00932 BOOL LLSurfacePatch::getHasReceivedData() const
00933 {
00934         return mHasReceivedData;
00935 }
00936 
00937 const LLVector3 &LLSurfacePatch::getCenterRegion() const
00938 {
00939         return mCenterRegion;
00940 }
00941 
00942 
00943 void LLSurfacePatch::updateCompositionStats()
00944 {
00945         LLViewerLayer *vlp = mSurfacep->getRegion()->getComposition();
00946 
00947         F32 x, y, width, height, mpg, min, mean, max;
00948 
00949         LLVector3 origin = getOriginAgent() - mSurfacep->getOriginAgent();
00950         mpg = mSurfacep->getMetersPerGrid();
00951         x = origin.mV[VX];
00952         y = origin.mV[VY];
00953         width = mpg*(mSurfacep->getGridsPerPatchEdge()+1);
00954         height = mpg*(mSurfacep->getGridsPerPatchEdge()+1);
00955 
00956         mean = 0.f;
00957         min = vlp->getValueScaled(x, y);
00958         max= min;
00959         U32 count = 0;
00960         F32 i, j;
00961         for (j = 0; j < height; j += mpg)
00962         {
00963                 for (i = 0; i < width; i += mpg)
00964                 {
00965                         F32 comp = vlp->getValueScaled(x + i, y + j);
00966                         mean += comp;
00967                         min = llmin(min, comp);
00968                         max = llmax(max, comp);
00969                         count++;
00970                 }
00971         }
00972         mean /= count;
00973 
00974         mMinComposition = min;
00975         mMeanComposition = mean;
00976         mMaxComposition = max;
00977 }
00978 
00979 F32 LLSurfacePatch::getMeanComposition() const
00980 {
00981         return mMeanComposition;
00982 }
00983 
00984 F32 LLSurfacePatch::getMinComposition() const
00985 {
00986         return mMinComposition;
00987 }
00988 
00989 F32 LLSurfacePatch::getMaxComposition() const
00990 {
00991         return mMaxComposition;
00992 }
00993 
00994 void LLSurfacePatch::setNeighborPatch(const U32 direction, LLSurfacePatch *neighborp)
00995 {
00996         mNeighborPatches[direction] = neighborp;
00997         mNormalsInvalid[direction] = TRUE;
00998         if (direction < 4)
00999         {
01000                 mNormalsInvalid[gDirAdjacent[direction][0]] = TRUE;
01001                 mNormalsInvalid[gDirAdjacent[direction][1]] = TRUE;
01002         }
01003 }
01004 
01005 LLSurfacePatch *LLSurfacePatch::getNeighborPatch(const U32 direction) const
01006 {
01007         return mNeighborPatches[direction];
01008 }
01009 
01010 void LLSurfacePatch::clearVObj()
01011 {
01012         mVObjp = NULL;
01013 }

Generated on Fri May 16 08:34:03 2008 for SecondLife by  doxygen 1.5.5