llsurface.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llsurface.h"
00035 
00036 #include "llviewerimagelist.h"
00037 #include "llpatchvertexarray.h"
00038 #include "patch_dct.h"
00039 #include "patch_code.h"
00040 #include "bitpack.h"
00041 #include "llviewerobjectlist.h"
00042 #include "llregionhandle.h"
00043 #include "llagent.h"
00044 #include "viewer.h"
00045 #include "llworld.h"
00046 #include "llviewercontrol.h"
00047 #include "llviewerimage.h"
00048 #include "llsurfacepatch.h"
00049 #include "llvosurfacepatch.h"
00050 #include "llvowater.h"
00051 #include "pipeline.h"
00052 #include "llviewerregion.h"
00053 #include "llvlcomposition.h"
00054 #include "noise.h"
00055 #include "llviewercamera.h"
00056 #include "llglheaders.h"
00057 #include "lldrawpoolterrain.h"
00058 #include "lldrawable.h"
00059 
00060 extern LLPipeline gPipeline;
00061 
00062 LLColor4U MAX_WATER_COLOR(0, 48, 96, 240);
00063 
00064 
00065 S32 LLSurface::sTextureSize = 256;
00066 S32 LLSurface::sTexelsUpdated = 0;
00067 F32 LLSurface::sTextureUpdateTime = 0.f;
00068 LLStat LLSurface::sTexelsUpdatedPerSecStat;
00069 
00070 extern void bad_network_handler();
00071 
00072 // ---------------- LLSurface:: Public Members ---------------
00073 
00074 LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) :
00075         mGridsPerEdge(0),
00076         mOOGridsPerEdge(0.f),
00077         mPatchesPerEdge(0),
00078         mType(type),
00079         mOriginGlobal(0.0, 0.0, 0.0),
00080         mSTexturep(NULL),
00081         mWaterTexturep(NULL),
00082         mGridsPerPatchEdge(0),
00083         mMetersPerGrid(1.0f),
00084         mMetersPerEdge(1.0f),
00085         mRegionp(regionp)
00086 {
00087         // Surface data
00088         mSurfaceZ = NULL;
00089         mNorm = NULL;
00090 
00091         // Patch data
00092         mPatchList = NULL;
00093 
00094         // One of each for each camera
00095         mVisiblePatchCount = 0;
00096 
00097         mHasZData = FALSE;
00098         // "uninitialized" min/max z
00099         mMinZ = 10000.f;
00100         mMaxZ = -10000.f;
00101 
00102         mWaterObjp = NULL;
00103 
00104         // In here temporarily.
00105         mSurfacePatchUpdateCount = 0;
00106 
00107         for (S32 i = 0; i < 8; i++)
00108         {
00109                 mNeighbors[i] = NULL;
00110         }
00111 }
00112 
00113 
00114 LLSurface::~LLSurface()
00115 {
00116         delete [] mSurfaceZ;
00117         mSurfaceZ = NULL;
00118 
00119         delete [] mNorm;
00120 
00121         mGridsPerEdge = 0;
00122         mGridsPerPatchEdge = 0;
00123         mPatchesPerEdge = 0;
00124         mNumberOfPatches = 0;
00125         destroyPatchData();
00126 
00127         LLDrawPoolTerrain *poolp = (LLDrawPoolTerrain*) gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep);
00128         if (!poolp)
00129         {
00130                 llwarns << "No pool for terrain on destruction!" << llendl;
00131         }
00132         else if (poolp->mReferences.empty())
00133         {
00134                 gPipeline.removePool(poolp);
00135                 // Don't enable this until we blitz the draw pool for it as well.  -- djs
00136                 if (mSTexturep)
00137                 {
00138                         gImageList.deleteImage(mSTexturep);
00139                         mSTexturep = NULL;
00140                 }
00141                 if (mWaterTexturep)
00142                 {
00143                         gImageList.deleteImage(mWaterTexturep);
00144                         mWaterTexturep = NULL;
00145                 }
00146         }
00147         else
00148         {
00149                 llerrs << "Terrain pool not empty!" << llendl;
00150         }
00151 }
00152 
00153 void LLSurface::initClasses()
00154 {
00155 }
00156 
00157 void LLSurface::setRegion(LLViewerRegion *regionp)
00158 {
00159         mRegionp = regionp;
00160 }
00161 
00162 // Assumes that arguments are powers of 2, and that
00163 // grids_per_edge / grids_per_patch_edge = power of 2 
00164 void LLSurface::create(const S32 grids_per_edge,
00165                                            const S32 grids_per_patch_edge,
00166                                            const LLVector3d &origin_global,
00167                                            const F32 width) 
00168 {
00169         // Initialize various constants for the surface
00170         mGridsPerEdge = grids_per_edge + 1;  // Add 1 for the east and north buffer
00171         mOOGridsPerEdge = 1.f / mGridsPerEdge;
00172         mGridsPerPatchEdge = grids_per_patch_edge;
00173         mPatchesPerEdge = (mGridsPerEdge - 1) / mGridsPerPatchEdge;
00174         mNumberOfPatches = mPatchesPerEdge * mPatchesPerEdge;
00175         mMetersPerGrid = width / ((F32)(mGridsPerEdge - 1));
00176         mMetersPerEdge = mMetersPerGrid * (mGridsPerEdge - 1);
00177 
00178         mOriginGlobal.setVec(origin_global);
00179 
00180         mPVArray.create(mGridsPerEdge, mGridsPerPatchEdge, gWorldPointer->getRegionScale());
00181 
00182         S32 number_of_grids = mGridsPerEdge * mGridsPerEdge;
00183 
00185         //
00186         // Initialize data arrays for surface
00188         mSurfaceZ = new F32[number_of_grids];
00189         mNorm = new LLVector3[number_of_grids];
00190 
00191         // Reset the surface to be a flat square grid
00192         for(S32 i=0; i < number_of_grids; i++) 
00193         {
00194                 // Surface is flat and zero
00195                 // Normals all point up
00196                 mSurfaceZ[i] = 0.0f;
00197                 mNorm[i].setVec(0.f, 0.f, 1.f);
00198         }
00199 
00200 
00201         mVisiblePatchCount = 0;
00202 
00203 
00205         //
00206         // Initialize textures
00207         //
00208 
00209         initTextures();
00210 
00211         // Has to be done after texture initialization
00212         createPatchData();
00213 }
00214 
00215 LLViewerImage* LLSurface::getSTexture()
00216 {
00217         if (mSTexturep.notNull() && !mSTexturep->getHasGLTexture())
00218         {
00219                 createSTexture();
00220         }
00221         return mSTexturep;
00222 }
00223 
00224 LLViewerImage* LLSurface::getWaterTexture()
00225 {
00226         if (mWaterTexturep.notNull() && !mWaterTexturep->getHasGLTexture())
00227         {
00228                 createWaterTexture();
00229         }
00230         return mWaterTexturep;
00231 }
00232 
00233 void LLSurface::createSTexture()
00234 {
00235         if (!mSTexturep)
00236         {
00237                 // Fill with dummy gray data.
00238                 LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3);
00239                 U8 *default_texture = raw->getData();
00240                 for (S32 i = 0; i < sTextureSize; i++)
00241                 {
00242                         for (S32 j = 0; j < sTextureSize; j++)
00243                         {
00244                                 *(default_texture + (i*sTextureSize + j)*3) = 128;
00245                                 *(default_texture + (i*sTextureSize + j)*3 + 1) = 128;
00246                                 *(default_texture + (i*sTextureSize + j)*3 + 2) = 128;
00247                         }
00248                 }
00249 
00250                 mSTexturep = new LLViewerImage(raw, FALSE);
00251                 mSTexturep->dontDiscard();
00252                 mSTexturep->bind();
00253                 mSTexturep->setClamp(TRUE, TRUE);
00254                 gImageList.addImage(mSTexturep);
00255         }
00256 }
00257 
00258 void LLSurface::createWaterTexture()
00259 {
00260         if (!mWaterTexturep)
00261         {
00262                 // Create the water texture
00263                 LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4);
00264                 U8 *default_texture = raw->getData();
00265                 for (S32 i = 0; i < sTextureSize/2; i++)
00266                 {
00267                         for (S32 j = 0; j < sTextureSize/2; j++)
00268                         {
00269                                 *(default_texture + (i*sTextureSize/2 + j)*4) = MAX_WATER_COLOR.mV[0];
00270                                 *(default_texture + (i*sTextureSize/2 + j)*4 + 1) = MAX_WATER_COLOR.mV[1];
00271                                 *(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2];
00272                                 *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3];
00273                         }
00274                 }
00275                 mWaterTexturep = new LLViewerImage(raw, FALSE);
00276                 mWaterTexturep->dontDiscard();
00277                 mWaterTexturep->bind();
00278                 mWaterTexturep->setClamp(TRUE, TRUE);
00279                 gImageList.addImage(mWaterTexturep);
00280         }
00281 }
00282 
00283 void LLSurface::initTextures()
00284 {
00286         //
00287         // Main surface texture
00288         //
00289         createSTexture();
00290 
00292         //
00293         // Water texture
00294         //
00295         if (gSavedSettings.getBOOL("RenderWater") )
00296         {
00297                 createWaterTexture();
00298                 mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp);
00299                 gPipeline.addObject(mWaterObjp);
00300                 LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle());
00301                 water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT);
00302                 mWaterObjp->setPositionGlobal(water_pos_global);
00303         }
00304 }
00305 
00306 
00307 void LLSurface::setOriginGlobal(const LLVector3d &origin_global) 
00308 {
00309         LLVector3d new_origin_global;
00310         mOriginGlobal = origin_global;
00311         LLSurfacePatch *patchp;
00312         S32 i, j;
00313         // Need to update the southwest corners of the patches
00314         for (j=0; j<mPatchesPerEdge; j++) 
00315         {
00316                 for (i=0; i<mPatchesPerEdge; i++) 
00317                 {
00318                         patchp = getPatch(i, j);
00319 
00320                         new_origin_global = patchp->getOriginGlobal();
00321                         
00322                         new_origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge;
00323                         new_origin_global.mdV[1] = mOriginGlobal.mdV[1] + j * mMetersPerGrid * mGridsPerPatchEdge;
00324                         patchp->setOriginGlobal(new_origin_global);
00325                 }
00326         }
00327 
00328         // Hack!
00329         if (mWaterObjp.notNull() && mWaterObjp->mDrawable.notNull())
00330         {
00331                 const F64 x = origin_global.mdV[VX] + 128.0;
00332                 const F64 y = origin_global.mdV[VY] + 128.0;
00333                 const F64 z = mWaterObjp->getPositionGlobal().mdV[VZ];
00334 
00335                 LLVector3d water_origin_global(x, y, z);
00336 
00337                 mWaterObjp->setPositionGlobal(water_origin_global);
00338         }
00339 }
00340 
00341 
00342 void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction)
00343 {
00344         S32 i;
00345         LLSurfacePatch *patchp, *neighbor_patchp;
00346 
00347         if (gNoRender)
00348         {
00349                 return;
00350         }
00351 
00352         mNeighbors[direction] = neighborp;
00353         neighborp->mNeighbors[gDirOpposite[direction]] = this;
00354 
00355         // Connect patches
00356         if (NORTHEAST == direction)
00357         {
00358                 patchp = getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1);
00359                 neighbor_patchp = neighborp->getPatch(0, 0);
00360 
00361                 patchp->connectNeighbor(neighbor_patchp, direction);
00362                 neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00363 
00364                 patchp->updateNorthEdge(); // Only update one of north or east.
00365                 patchp->dirtyZ();
00366         }
00367         else if (NORTHWEST == direction)
00368         {
00369                 patchp = getPatch(0, mPatchesPerEdge - 1);
00370                 neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, 0);
00371 
00372                 patchp->connectNeighbor(neighbor_patchp, direction);
00373                 neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00374         }
00375         else if (SOUTHWEST == direction)
00376         {
00377                 patchp = getPatch(0, 0);
00378                 neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1);
00379 
00380                 patchp->connectNeighbor(neighbor_patchp, direction);
00381                 neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00382 
00383                 neighbor_patchp->updateNorthEdge(); // Only update one of north or east.
00384                 neighbor_patchp->dirtyZ();
00385         }
00386         else if (SOUTHEAST == direction)
00387         {
00388                 patchp = getPatch(mPatchesPerEdge - 1, 0);
00389                 neighbor_patchp = neighborp->getPatch(0, mPatchesPerEdge - 1);
00390 
00391                 patchp->connectNeighbor(neighbor_patchp, direction);
00392                 neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00393         }
00394         else if (EAST == direction)
00395         {
00396                 // Do east/west connections, first
00397                 for (i = 0; i < (S32)mPatchesPerEdge; i++)
00398                 {
00399                         patchp = getPatch(mPatchesPerEdge - 1, i);
00400                         neighbor_patchp = neighborp->getPatch(0, i);
00401 
00402                         patchp->connectNeighbor(neighbor_patchp, direction);
00403                         neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00404 
00405                         patchp->updateEastEdge();
00406                         patchp->dirtyZ();
00407                 }
00408 
00409                 // Now do northeast/southwest connections
00410                 for (i = 0; i < (S32)mPatchesPerEdge - 1; i++)
00411                 {
00412                         patchp = getPatch(mPatchesPerEdge - 1, i);
00413                         neighbor_patchp = neighborp->getPatch(0, i+1);
00414 
00415                         patchp->connectNeighbor(neighbor_patchp, NORTHEAST);
00416                         neighbor_patchp->connectNeighbor(patchp, SOUTHWEST);
00417                 }
00418                 // Now do southeast/northwest connections
00419                 for (i = 1; i < (S32)mPatchesPerEdge; i++)
00420                 {
00421                         patchp = getPatch(mPatchesPerEdge - 1, i);
00422                         neighbor_patchp = neighborp->getPatch(0, i-1);
00423 
00424                         patchp->connectNeighbor(neighbor_patchp, SOUTHEAST);
00425                         neighbor_patchp->connectNeighbor(patchp, NORTHWEST);
00426                 }
00427         }
00428         else if (NORTH == direction)
00429         {
00430                 // Do north/south connections, first
00431                 for (i = 0; i < (S32)mPatchesPerEdge; i++)
00432                 {
00433                         patchp = getPatch(i, mPatchesPerEdge - 1);
00434                         neighbor_patchp = neighborp->getPatch(i, 0);
00435 
00436                         patchp->connectNeighbor(neighbor_patchp, direction);
00437                         neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00438 
00439                         patchp->updateNorthEdge();
00440                         patchp->dirtyZ();
00441                 }
00442 
00443                 // Do northeast/southwest connections
00444                 for (i = 0; i < (S32)mPatchesPerEdge - 1; i++)
00445                 {
00446                         patchp = getPatch(i, mPatchesPerEdge - 1);
00447                         neighbor_patchp = neighborp->getPatch(i+1, 0);
00448 
00449                         patchp->connectNeighbor(neighbor_patchp, NORTHEAST);
00450                         neighbor_patchp->connectNeighbor(patchp, SOUTHWEST);
00451                 }
00452                 // Do southeast/northwest connections
00453                 for (i = 1; i < (S32)mPatchesPerEdge; i++)
00454                 {
00455                         patchp = getPatch(i, mPatchesPerEdge - 1);
00456                         neighbor_patchp = neighborp->getPatch(i-1, 0);
00457 
00458                         patchp->connectNeighbor(neighbor_patchp, NORTHWEST);
00459                         neighbor_patchp->connectNeighbor(patchp, SOUTHEAST);
00460                 }
00461         }
00462         else if (WEST == direction)
00463         {
00464                 // Do east/west connections, first
00465                 for (i = 0; i < mPatchesPerEdge; i++)
00466                 {
00467                         patchp = getPatch(0, i);
00468                         neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i);
00469 
00470                         patchp->connectNeighbor(neighbor_patchp, direction);
00471                         neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00472 
00473                         neighbor_patchp->updateEastEdge();
00474                         neighbor_patchp->dirtyZ();
00475                 }
00476 
00477                 // Now do northeast/southwest connections
00478                 for (i = 1; i < mPatchesPerEdge; i++)
00479                 {
00480                         patchp = getPatch(0, i);
00481                         neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i - 1);
00482 
00483                         patchp->connectNeighbor(neighbor_patchp, SOUTHWEST);
00484                         neighbor_patchp->connectNeighbor(patchp, NORTHEAST);
00485                 }
00486 
00487                 // Now do northwest/southeast connections
00488                 for (i = 0; i < mPatchesPerEdge - 1; i++)
00489                 {
00490                         patchp = getPatch(0, i);
00491                         neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i + 1);
00492 
00493                         patchp->connectNeighbor(neighbor_patchp, NORTHWEST);
00494                         neighbor_patchp->connectNeighbor(patchp, SOUTHEAST);
00495                 }
00496         }
00497         else if (SOUTH == direction)
00498         {
00499                 // Do north/south connections, first
00500                 for (i = 0; i < mPatchesPerEdge; i++)
00501                 {
00502                         patchp = getPatch(i, 0);
00503                         neighbor_patchp = neighborp->getPatch(i, mPatchesPerEdge - 1);
00504 
00505                         patchp->connectNeighbor(neighbor_patchp, direction);
00506                         neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]);
00507 
00508                         neighbor_patchp->updateNorthEdge();
00509                         neighbor_patchp->dirtyZ();
00510                 }
00511 
00512                 // Now do northeast/southwest connections
00513                 for (i = 1; i < mPatchesPerEdge; i++)
00514                 {
00515                         patchp = getPatch(i, 0);
00516                         neighbor_patchp = neighborp->getPatch(i - 1, mPatchesPerEdge - 1);
00517 
00518                         patchp->connectNeighbor(neighbor_patchp, SOUTHWEST);
00519                         neighbor_patchp->connectNeighbor(patchp, NORTHEAST);
00520                 }
00521                 // Now do northeast/southwest connections
00522                 for (i = 0; i < mPatchesPerEdge - 1; i++)
00523                 {
00524                         patchp = getPatch(i, 0);
00525                         neighbor_patchp = neighborp->getPatch(i + 1, mPatchesPerEdge - 1);
00526 
00527                         patchp->connectNeighbor(neighbor_patchp, SOUTHEAST);
00528                         neighbor_patchp->connectNeighbor(patchp, NORTHWEST);
00529                 }
00530         }               
00531 }
00532 
00533 void LLSurface::disconnectNeighbor(LLSurface *surfacep)
00534 {
00535         S32 i;
00536         for (i = 0; i < 8; i++)
00537         {
00538                 if (surfacep == mNeighbors[i])
00539                 {
00540                         mNeighbors[i] = NULL;
00541                 }
00542         }
00543 
00544         // Iterate through surface patches, removing any connectivity to removed surface.
00545         for (i = 0; i < mNumberOfPatches; i++)
00546         {
00547                 (mPatchList + i)->disconnectNeighbor(surfacep);
00548         }
00549 }
00550 
00551 
00552 void LLSurface::disconnectAllNeighbors()
00553 {
00554         S32 i;
00555         for (i = 0; i < 8; i++)
00556         {
00557                 if (mNeighbors[i])
00558                 {
00559                         mNeighbors[i]->disconnectNeighbor(this);
00560                         mNeighbors[i] = NULL;
00561                 }
00562         }
00563 }
00564 
00565 
00566 
00567 const LLVector3d &LLSurface::getOriginGlobal() const
00568 {
00569         return mOriginGlobal;
00570 }
00571 
00572 LLVector3 LLSurface::getOriginAgent() const
00573 {
00574         return gAgent.getPosAgentFromGlobal(mOriginGlobal);
00575 }
00576 
00577 F32 LLSurface::getMetersPerGrid() const
00578 {
00579         return mMetersPerGrid;
00580 }
00581 
00582 S32 LLSurface::getGridsPerEdge() const
00583 {
00584         return mGridsPerEdge;
00585 }
00586 
00587 S32 LLSurface::getPatchesPerEdge() const
00588 {
00589         return mPatchesPerEdge;
00590 }
00591 
00592 S32 LLSurface::getGridsPerPatchEdge() const
00593 {
00594         return mGridsPerPatchEdge;
00595 }
00596 
00597 void LLSurface::moveZ(const S32 x, const S32 y, const F32 delta)
00598 {
00599         llassert(x >= 0);
00600         llassert(y >= 0);
00601         llassert(x < mGridsPerEdge);
00602         llassert(y < mGridsPerEdge);
00603         mSurfaceZ[x + y*mGridsPerEdge] += delta;
00604 }
00605 
00606 
00607 void LLSurface::updatePatchVisibilities(LLAgent &agent) 
00608 {
00609         LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgent.getCameraPositionGlobal());
00610 
00611         LLSurfacePatch *patchp;
00612         
00613         mVisiblePatchCount = 0;
00614         for (S32 i=0; i<mNumberOfPatches; i++) 
00615         {
00616                 patchp = mPatchList + i;
00617 
00618                 patchp->updateVisibility();
00619                 if (patchp->getVisible())
00620                 {
00621                         mVisiblePatchCount++;
00622                         patchp->updateCameraDistanceRegion(pos_region);
00623                 }
00624         }
00625 }
00626 
00627 BOOL LLSurface::idleUpdate(F32 max_update_time)
00628 {
00629         if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN))
00630         {
00631                 return FALSE;
00632         }
00633         
00634         // Perform idle time update of non-critical stuff.
00635         // In this case, texture and normal updates.
00636         LLTimer update_timer;
00637         BOOL did_update = FALSE;
00638 
00639         // If the Z height data has changed, we need to rebuild our
00640         // property line vertex arrays.
00641         if (mDirtyPatchList.size() > 0)
00642         {
00643                 getRegion()->dirtyHeights();
00644         }
00645 
00646         // Always call updateNormals() / updateVerticalStats()
00647         //  every frame to avoid artifacts
00648         for(std::set<LLSurfacePatch *>::iterator iter = mDirtyPatchList.begin();
00649                 iter != mDirtyPatchList.end(); )
00650         {
00651                 std::set<LLSurfacePatch *>::iterator curiter = iter++;
00652                 LLSurfacePatch *patchp = *curiter;
00653                 patchp->updateNormals();
00654                 patchp->updateVerticalStats();
00655                 if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time)
00656                 {
00657                         if (patchp->updateTexture())
00658                         {
00659                                 did_update = TRUE;
00660                                 patchp->clearDirty();
00661                                 mDirtyPatchList.erase(curiter);
00662                         }
00663                 }
00664         }
00665         return did_update;
00666 }
00667 
00668 // TODO -- move this to LLViewerRegion class
00669 void LLSurface::renderSurfaceBounds()
00670 {
00671         //  Shows the edge of the surface, so that visibility across regions can be seen
00672         LLVector3 origin_agent = getOriginAgent();
00673         
00674         glPushMatrix();
00675         LLGLSNoTexture no_texture;
00676         
00677         F32 region_width_meters = gWorldPointer->getRegionWidthInMeters();
00678         glTranslatef(origin_agent.mV[VX] + (region_width_meters * 0.005f),
00679                                         origin_agent.mV[VY] + (region_width_meters * 0.005f), 0.f);
00680 
00681         glColor4ub(0, 128, 0, 64); 
00682 
00683         F32 length = region_width_meters * 0.995f;
00684         F32 height = length/8.0f;
00685 
00686         glBegin(GL_QUADS);
00687                 glVertex3f(length, 0, 0);
00688                 glVertex3f(0,0, 0);
00689                 glVertex3f(0,0, height);
00690                 glVertex3f(length,0, height);
00691 
00692                 glVertex3f(length,0, height);
00693                 glVertex3f(0,0, height);
00694                 glVertex3f(0,0, 0);
00695                 glVertex3f(length, 0, 0);
00696         glEnd();
00697 
00698         glTranslatef(length, 0, 0);
00699         glRotated(90, 0, 0, 1);
00700         glBegin(GL_QUADS);
00701                 glVertex3f(length, 0, 0);
00702                 glVertex3f(0,0, 0);
00703                 glVertex3f(0,0, height);
00704                 glVertex3f(length,0, height);
00705 
00706                 glVertex3f(length,0, height);
00707                 glVertex3f(0,0, height);
00708                 glVertex3f(0,0, 0);
00709                 glVertex3f(length, 0, 0);
00710 
00711         glEnd();
00712         glTranslatef(length, 0, 0);
00713         glRotated(90, 0, 0, 1);
00714         glBegin(GL_QUADS);
00715                 glVertex3f(length, 0, 0);
00716                 glVertex3f(0,0, 0);
00717                 glVertex3f(0,0, height);
00718                 glVertex3f(length,0, height);
00719 
00720                 glVertex3f(length,0, height);
00721                 glVertex3f(0,0, height);
00722                 glVertex3f(0,0, 0);
00723                 glVertex3f(length, 0, 0);
00724         glEnd();
00725         glTranslatef(length, 0, 0);
00726         glRotated(90, 0, 0, 1);
00727         glBegin(GL_QUADS);
00728                 glVertex3f(length, 0, 0);
00729                 glVertex3f(0,0, 0);
00730                 glVertex3f(0,0, height);
00731                 glVertex3f(length,0, height);
00732 
00733                 glVertex3f(length,0, height);
00734                 glVertex3f(0,0, height);
00735                 glVertex3f(0,0, 0);
00736                 glVertex3f(length, 0, 0);
00737         glEnd();
00738         glTranslatef(length, 0, 0);
00739         glRotated(90, 0, 0, 1);
00740  
00741         glPopMatrix();
00742 }
00743 
00744 
00745 void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch) 
00746 {
00747 
00748         LLPatchHeader  ph;
00749         S32 j, i;
00750         S32 patch[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE];
00751         LLSurfacePatch *patchp;
00752 
00753         init_patch_decompressor(gopp->patch_size);
00754         gopp->stride = mGridsPerEdge;
00755         set_group_of_patch_header(gopp);
00756 
00757         while (1)
00758         {
00759                 decode_patch_header(bitpack, &ph);
00760                 if (ph.quant_wbits == END_OF_PATCHES)
00761                 {
00762                         break;
00763                 }
00764 
00765                 i = ph.patchids >> 5;
00766                 j = ph.patchids & 0x1F;
00767 
00768                 if ((i >= mPatchesPerEdge) || (j >= mPatchesPerEdge))
00769                 {
00770                         llwarns << "Received invalid terrain packet - patch header patch ID incorrect!" 
00771                                 << " patches per edge " << mPatchesPerEdge
00772                                 << " i " << i
00773                                 << " j " << j
00774                                 << " dc_offset " << ph.dc_offset
00775                                 << " range " << (S32)ph.range
00776                                 << " quant_wbits " << (S32)ph.quant_wbits
00777                                 << " patchids " << (S32)ph.patchids
00778                                 << llendl;
00779                         bad_network_handler();
00780                         return;
00781                 }
00782 
00783                 patchp = &mPatchList[j*mPatchesPerEdge + i];
00784 
00785 
00786                 decode_patch(bitpack, patch);
00787                 decompress_patch(patchp->getDataZ(), patch, &ph);
00788 
00789                 // Update edges for neighbors.  Need to guarantee that this gets done before we generate vertical stats.
00790                 patchp->updateNorthEdge();
00791                 patchp->updateEastEdge();
00792                 if (patchp->getNeighborPatch(WEST))
00793                 {
00794                         patchp->getNeighborPatch(WEST)->updateEastEdge();
00795                 }
00796                 if (patchp->getNeighborPatch(SOUTHWEST))
00797                 {
00798                         patchp->getNeighborPatch(SOUTHWEST)->updateEastEdge();
00799                         patchp->getNeighborPatch(SOUTHWEST)->updateNorthEdge();
00800                 }
00801                 if (patchp->getNeighborPatch(SOUTH))
00802                 {
00803                         patchp->getNeighborPatch(SOUTH)->updateNorthEdge();
00804                 }
00805 
00806                 // Dirty patch statistics, and flag that the patch has data.
00807                 patchp->dirtyZ();
00808                 patchp->setHasReceivedData();
00809         }
00810 }
00811 
00812 
00813 // Retrurns TRUE if "position" is within the bounds of surface.
00814 // "position" is region-local
00815 BOOL LLSurface::containsPosition(const LLVector3 &position)
00816 {
00817         if (position.mV[VX] < 0.0f  ||  position.mV[VX] > mMetersPerEdge ||
00818                 position.mV[VY] < 0.0f  ||  position.mV[VY] > mMetersPerEdge)
00819         {
00820                 return FALSE;
00821         }
00822         return TRUE;
00823 }
00824 
00825 
00826 F32 LLSurface::resolveHeightRegion(const F32 x, const F32 y) const
00827 {
00828         F32 height = 0.0f;
00829         F32 oometerspergrid = 1.f/mMetersPerGrid;
00830 
00831         // Check to see if v is actually above surface 
00832         // We use (mGridsPerEdge-1) below rather than (mGridsPerEdge) 
00833         // becuase of the east and north buffers 
00834 
00835         if (x >= 0.f  &&  
00836                 x <= mMetersPerEdge  &&
00837                 y >= 0.f  &&  
00838                 y <= mMetersPerEdge)
00839         {
00840                 const S32 left   = llfloor(x * oometerspergrid);
00841                 const S32 bottom = llfloor(y * oometerspergrid);
00842 
00843                 // Don't walk off the edge of the array!
00844                 const S32 right  = ( left+1   < (S32)mGridsPerEdge-1 ? left+1   : left );
00845                 const S32 top    = ( bottom+1 < (S32)mGridsPerEdge-1 ? bottom+1 : bottom );
00846 
00847                 // Figure out if v is in first or second triangle of the square
00848                 // and calculate the slopes accordingly
00849                 //    |       |
00850                 // -(i,j+1)---(i+1,j+1)--   
00851                 //    |  1   /  |          ^
00852                 //    |    /  2 |          |
00853                 //    |  /      |          j
00854                 // --(i,j)----(i+1,j)--
00855                 //    |       |
00856                 // 
00857                 //      i ->
00858                 // where N = mGridsPerEdge
00859 
00860                 const F32 left_bottom  = getZ( left,  bottom );
00861                 const F32 right_bottom = getZ( right, bottom );
00862                 const F32 left_top     = getZ( left,  top );
00863                 const F32 right_top    = getZ( right, top );
00864 
00865                 // dx and dy are incremental steps from (mSurface + k)
00866                 F32 dx = x - left   * mMetersPerGrid;
00867                 F32 dy = y - bottom * mMetersPerGrid;
00868 
00869                 if (dy > dx) 
00870                 {
00871                         // triangle 1
00872                         dy *= left_top  - left_bottom;
00873                         dx *= right_top - left_top;
00874                 }
00875                 else 
00876                 {
00877                         // triangle 2
00878                         dx *= right_bottom - left_bottom;
00879                         dy *= right_top    - right_bottom;
00880                 }
00881                 height = left_bottom + (dx + dy) * oometerspergrid;
00882         }
00883         return height;
00884 }
00885 
00886 
00887 F32 LLSurface::resolveHeightGlobal(const LLVector3d& v) const
00888 {
00889         if (!mRegionp)
00890         {
00891                 return 0.f;
00892         }
00893         
00894         LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(v);
00895 
00896         return resolveHeightRegion(pos_region);
00897 }
00898 
00899 
00900 LLVector3 LLSurface::resolveNormalGlobal(const LLVector3d& pos_global) const
00901 {
00902         if (!mSurfaceZ)
00903         {
00904                 // Hmm.  Uninitialized surface!
00905                 return LLVector3::z_axis;
00906         }
00907         //
00908         // Returns the vector normal to a surface at location specified by vector v
00909         //
00910         F32 oometerspergrid = 1.f/mMetersPerGrid;
00911         LLVector3 normal;
00912         F32 dzx, dzy;
00913 
00914         if (pos_global.mdV[VX] >= mOriginGlobal.mdV[VX]  &&  
00915                 pos_global.mdV[VX] < mOriginGlobal.mdV[VX] + mMetersPerEdge  &&
00916                 pos_global.mdV[VY] >= mOriginGlobal.mdV[VY]  &&  
00917                 pos_global.mdV[VY] < mOriginGlobal.mdV[VY] + mMetersPerEdge)
00918         {
00919                 U32 i, j, k;
00920                 F32 dx, dy;
00921                 i = (U32) ((pos_global.mdV[VX] - mOriginGlobal.mdV[VX]) * oometerspergrid);
00922                 j = (U32) ((pos_global.mdV[VY] - mOriginGlobal.mdV[VY]) * oometerspergrid );
00923                 k = i + j*mGridsPerEdge;
00924 
00925                 // Figure out if v is in first or second triangle of the square
00926                 // and calculate the slopes accordingly
00927                 //    |       |
00928                 // -(k+N)---(k+1+N)--   
00929                 //    |  1 /  |          ^
00930                 //    |   / 2 |          |
00931                 //    |  /    |          j
00932                 // --(k)----(k+1)--
00933                 //    |       |
00934                 // 
00935                 //      i ->
00936                 // where N = mGridsPerEdge
00937 
00938                 // dx and dy are incremental steps from (mSurface + k)
00939                 dx = (F32)(pos_global.mdV[VX] - i*mMetersPerGrid - mOriginGlobal.mdV[VX]);
00940                 dy = (F32)(pos_global.mdV[VY] - j*mMetersPerGrid - mOriginGlobal.mdV[VY]);
00941                 if (dy > dx) 
00942                 {  // triangle 1
00943                         dzx = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + mGridsPerEdge);
00944                         dzy = *(mSurfaceZ + k) - *(mSurfaceZ + k + mGridsPerEdge);
00945                         normal.setVec(-dzx,dzy,1);
00946                 }
00947                 else 
00948                 {       // triangle 2
00949                         dzx = *(mSurfaceZ + k) - *(mSurfaceZ + k + 1);
00950                         dzy = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + 1);
00951                         normal.setVec(dzx,-dzy,1);
00952                 }
00953         }
00954         normal.normVec();
00955         return normal;
00956 
00957 
00958 }
00959 
00960 LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const
00961 {
00962 // x and y should be region-local coordinates. 
00963 // If x and y are outside of the surface, then the returned
00964 // index will be for the nearest boundary patch.
00965 //
00966 // 12      | 13| 14|       15
00967 //         |   |   |    
00968 //     +---+---+---+---+
00969 //     | 12| 13| 14| 15|
00970 // ----+---+---+---+---+-----
00971 // 8   | 8 | 9 | 10| 11|   11
00972 // ----+---+---+---+---+-----
00973 // 4   | 4 | 5 | 6 | 7 |    7
00974 // ----+---+---+---+---+-----
00975 //     | 0 | 1 | 2 | 3 |
00976 //     +---+---+---+---+
00977 //         |   |   |    
00978 // 0       | 1 | 2 |        3
00979 //
00980 
00981 // When x and y are not region-local do the following first
00982 
00983         S32 i, j;
00984         if (x < 0.0f)
00985         {
00986                 i = 0;
00987         }
00988         else if (x >= mMetersPerEdge)
00989         {
00990                 i = mPatchesPerEdge - 1;
00991         }
00992         else
00993         {
00994                 i = (U32) (x / (mMetersPerGrid * mGridsPerPatchEdge));
00995         }
00996 
00997         if (y < 0.0f)
00998         {
00999                 j = 0;
01000         }
01001         else if (y >= mMetersPerEdge)
01002         {
01003                 j = mPatchesPerEdge - 1;
01004         }
01005         else
01006         {
01007                 j = (U32) (y / (mMetersPerGrid * mGridsPerPatchEdge));
01008         }
01009 
01010         // *NOTE: Super paranoia code follows.
01011         S32 index = i + j * mPatchesPerEdge;
01012         if((index < 0) || (index >= mNumberOfPatches))
01013         {
01014                 if(0 == mNumberOfPatches)
01015                 {
01016                         llwarns << "No patches for current region!" << llendl;
01017                         return NULL;
01018                 }
01019                 S32 old_index = index;
01020                 index = llclamp(old_index, 0, (mNumberOfPatches - 1));
01021                 llwarns << "Clamping out of range patch index " << old_index
01022                                 << " to " << index << llendl;
01023         }
01024         return &(mPatchList[index]);
01025 }
01026 
01027 
01028 LLSurfacePatch *LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const
01029 {
01030         return resolvePatchRegion(pos_region.mV[VX], pos_region.mV[VY]);
01031 }
01032 
01033 
01034 LLSurfacePatch *LLSurface::resolvePatchGlobal(const LLVector3d &pos_global) const
01035 {
01036         LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(pos_global);
01037         return resolvePatchRegion(pos_region);
01038 }
01039 
01040 
01041 std::ostream& operator<<(std::ostream &s, const LLSurface &S) 
01042 {
01043         s << "{ \n";
01044         s << "  mGridsPerEdge = " << S.mGridsPerEdge - 1 << " + 1\n";
01045         s << "  mGridsPerPatchEdge = " << S.mGridsPerPatchEdge << "\n";
01046         s << "  mPatchesPerEdge = " << S.mPatchesPerEdge << "\n";
01047         s << "  mOriginGlobal = " << S.mOriginGlobal << "\n";
01048         s << "  mMetersPerGrid = " << S.mMetersPerGrid << "\n";
01049         s << "  mVisiblePatchCount = " << S.mVisiblePatchCount << "\n";
01050         s << "}";
01051         return s;
01052 }
01053 
01054 
01055 // ---------------- LLSurface:: Protected ----------------
01056 
01057 void LLSurface::createPatchData() 
01058 {
01059         // Assumes mGridsPerEdge, mGridsPerPatchEdge, and mPatchesPerEdge have been properly set
01060         // TODO -- check for create() called when surface is not empty
01061         S32 i, j;
01062         LLSurfacePatch *patchp;
01063 
01064         // Allocate memory
01065         mPatchList = new LLSurfacePatch[mNumberOfPatches];
01066 
01067         // One of each for each camera
01068         mVisiblePatchCount = mNumberOfPatches;
01069 
01070         for (j=0; j<mPatchesPerEdge; j++) 
01071         {
01072                 for (i=0; i<mPatchesPerEdge; i++) 
01073                 {
01074                         patchp = getPatch(i, j);
01075                         patchp->setSurface(this);
01076                 }
01077         }
01078 
01079         for (j=0; j<mPatchesPerEdge; j++) 
01080         {
01081                 for (i=0; i<mPatchesPerEdge; i++) 
01082                 {
01083                         patchp = getPatch(i, j);
01084                         patchp->mHasReceivedData = FALSE;
01085                         patchp->mSTexUpdate = TRUE;
01086 
01087                         S32 data_offset = i * mGridsPerPatchEdge + j * mGridsPerPatchEdge * mGridsPerEdge;
01088 
01089                         patchp->setDataZ(mSurfaceZ + data_offset);
01090                         patchp->setDataNorm(mNorm + data_offset);
01091 
01092 
01093                         // We make each patch point to its neighbors so we can do resolution checking 
01094                         // when butting up different resolutions.  Patches that don't have neighbors
01095                         // somewhere will point to NULL on that side.
01096                         if (i < mPatchesPerEdge-1)  
01097                         {
01098                                 patchp->setNeighborPatch(EAST,getPatch(i+1, j));
01099                         }
01100                         else 
01101                         {
01102                                 patchp->setNeighborPatch(EAST, NULL);
01103                         }
01104 
01105                         if (j < mPatchesPerEdge-1)  
01106                         {
01107                                 patchp->setNeighborPatch(NORTH, getPatch(i, j+1));
01108                         }
01109                         else 
01110                         {
01111                                 patchp->setNeighborPatch(NORTH, NULL);
01112                         }
01113 
01114                         if (i > 0) 
01115                         {
01116                                 patchp->setNeighborPatch(WEST, getPatch(i - 1, j));
01117                         }
01118                         else 
01119                         {
01120                                 patchp->setNeighborPatch(WEST, NULL);
01121                         }
01122 
01123                         if (j > 0)  
01124                         {
01125                                 patchp->setNeighborPatch(SOUTH, getPatch(i, j-1));
01126                         }
01127                         else 
01128                         {
01129                                 patchp->setNeighborPatch(SOUTH, NULL);
01130                         }
01131 
01132                         if (i < (mPatchesPerEdge-1)  &&  j < (mPatchesPerEdge-1)) 
01133                         {
01134                                 patchp->setNeighborPatch(NORTHEAST, getPatch(i + 1, j + 1));
01135                         }
01136                         else 
01137                         {
01138                                 patchp->setNeighborPatch(NORTHEAST, NULL);              
01139                         }
01140 
01141                         if (i > 0  &&  j < (mPatchesPerEdge-1)) 
01142                         {
01143                                 patchp->setNeighborPatch(NORTHWEST, getPatch(i - 1, j + 1));
01144                         }
01145                         else 
01146                         {
01147                                 patchp->setNeighborPatch(NORTHWEST, NULL);
01148                         }
01149 
01150                         if (i > 0  &&  j > 0) 
01151                         {
01152                                 patchp->setNeighborPatch(SOUTHWEST, getPatch(i - 1, j - 1));
01153                         }
01154                         else 
01155                         {
01156                                 patchp->setNeighborPatch(SOUTHWEST, NULL);
01157                         }
01158 
01159                         if (i < (mPatchesPerEdge-1)  &&  j > 0) 
01160                         {
01161                                 patchp->setNeighborPatch(SOUTHEAST, getPatch(i + 1, j - 1));
01162                         }
01163                         else 
01164                         {
01165                                 patchp->setNeighborPatch(SOUTHEAST, NULL);
01166                         }
01167 
01168                         LLVector3d origin_global;
01169                         origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge;
01170                         origin_global.mdV[1] = mOriginGlobal.mdV[0] + j * mMetersPerGrid * mGridsPerPatchEdge;
01171                         origin_global.mdV[2] = 0.f;
01172                         patchp->setOriginGlobal(origin_global);
01173                 }
01174         }
01175 }
01176 
01177 
01178 void LLSurface::destroyPatchData()
01179 {
01180         // Delete all of the cached patch data for these patches.
01181 
01182         delete [] mPatchList;
01183         mPatchList = NULL;
01184         mVisiblePatchCount = 0;
01185 }
01186 
01187 
01188 void LLSurface::setTextureSize(const S32 texture_size)
01189 {
01190         sTextureSize = texture_size;
01191 }
01192 
01193 
01194 U32 LLSurface::getRenderLevel(const U32 render_stride) const
01195 {
01196         return mPVArray.mRenderLevelp[render_stride];
01197 }
01198 
01199 
01200 U32 LLSurface::getRenderStride(const U32 render_level) const
01201 {
01202         return mPVArray.mRenderStridep[render_level];
01203 }
01204 
01205 
01206 LLSurfacePatch *LLSurface::getPatch(const S32 x, const S32 y) const
01207 {
01208         if ((x < 0) || (x >= mPatchesPerEdge))
01209         {
01210                 llerrs << "Asking for patch out of bounds" << llendl;
01211                 return NULL;
01212         }
01213         if ((y < 0) || (y >= mPatchesPerEdge))
01214         {
01215                 llerrs << "Asking for patch out of bounds" << llendl;
01216                 return NULL;
01217         }
01218 
01219         return mPatchList + x + y*mPatchesPerEdge;
01220 }
01221 
01222 
01223 void LLSurface::dirtyAllPatches()
01224 {
01225         S32 i;
01226         for (i = 0; i < mNumberOfPatches; i++)
01227         {
01228                 mPatchList[i].dirtyZ();
01229         }
01230 }
01231 
01232 void LLSurface::dirtySurfacePatch(LLSurfacePatch *patchp)
01233 {
01234         // Put surface patch on dirty surface patch list
01235         mDirtyPatchList.insert(patchp);
01236 }
01237 
01238 
01239 void LLSurface::setWaterHeight(F32 height)
01240 {
01241         if (!mWaterObjp.isNull())
01242         {
01243                 LLVector3 water_pos_region = mWaterObjp->getPositionRegion();
01244                 water_pos_region.mV[VZ] = height;
01245                 mWaterObjp->setPositionRegion(water_pos_region);
01246         }
01247         else
01248         {
01249                 llwarns << "LLSurface::setWaterHeight with no water object!" << llendl;
01250         }
01251 }
01252 
01253 F32 LLSurface::getWaterHeight() const
01254 {
01255         if (!mWaterObjp.isNull())
01256         {
01257                 // we have a water object, the usual case
01258                 return mWaterObjp->getPositionRegion().mV[VZ];
01259         }
01260         else
01261         {
01262                 return DEFAULT_WATER_HEIGHT;
01263         }
01264 }
01265 
01266 
01267 BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y,
01268                                                                          const F32 width, const F32 height)
01269 {
01270         if (!getWaterTexture())
01271         {
01272                 return FALSE;
01273         }
01274 
01275         S32 tex_width = mWaterTexturep->getWidth();
01276         S32 tex_height = mWaterTexturep->getHeight();
01277         S32 tex_comps = mWaterTexturep->getComponents();
01278         S32 tex_stride = tex_width * tex_comps;
01279         LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps);
01280         U8 *rawp = raw->getData();
01281 
01282         F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width;
01283         F32 scale_inv = 1.f / scale;
01284 
01285         S32 x_begin, y_begin, x_end, y_end;
01286 
01287         x_begin = llround(x * scale_inv);
01288         y_begin = llround(y * scale_inv);
01289         x_end = llround((x + width) * scale_inv);
01290         y_end = llround((y + width) * scale_inv);
01291 
01292         if (x_end > tex_width)
01293         {
01294                 x_end = tex_width;
01295         }
01296         if (y_end > tex_width)
01297         {
01298                 y_end = tex_width;
01299         }
01300 
01301         LLVector3d origin_global = from_region_handle(getRegion()->getHandle());
01302 
01303         // OK, for now, just have the composition value equal the height at the point.
01304         LLVector3 location;
01305         LLColor4U coloru;
01306 
01307         const F32 WATER_HEIGHT = getWaterHeight();
01308 
01309         S32 i, j, offset;
01310         for (j = y_begin; j < y_end; j++)
01311         {
01312                 for (i = x_begin; i < x_end; i++)
01313                 {
01314                         //F32 nv[2];
01315                         //nv[0] = i/256.f;
01316                         //nv[1] = j/256.f;
01317                         // const S32 modulation = noise2(nv)*40;
01318                         offset = j*tex_stride + i*tex_comps;
01319                         location.mV[VX] = i*scale;
01320                         location.mV[VY] = j*scale;
01321 
01322                         // Sample multiple points
01323                         const F32 height = resolveHeightRegion(location);
01324 
01325                         if (height > WATER_HEIGHT)
01326                         {
01327                                 // Above water...
01328                                 coloru = MAX_WATER_COLOR;
01329                                 coloru.mV[3] = ABOVE_WATERLINE_ALPHA;
01330                                 *(rawp + offset++) = coloru.mV[0];
01331                                 *(rawp + offset++) = coloru.mV[1];
01332                                 *(rawp + offset++) = coloru.mV[2];
01333                                 *(rawp + offset++) = coloru.mV[3];
01334                         }
01335                         else
01336                         {
01337                                 // Want non-linear curve for transparency gradient
01338                                 coloru = MAX_WATER_COLOR;
01339                                 const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT));
01340                                 S32 alpha = 64 + llround((255-64)*frac);
01341 
01342                                 alpha = llmin(llround((F32)MAX_WATER_COLOR.mV[3]), alpha);
01343                                 alpha = llmax(64, alpha);
01344 
01345                                 coloru.mV[3] = alpha;
01346                                 *(rawp + offset++) = coloru.mV[0];
01347                                 *(rawp + offset++) = coloru.mV[1];
01348                                 *(rawp + offset++) = coloru.mV[2];
01349                                 *(rawp + offset++) = coloru.mV[3];
01350                         }
01351                 }
01352         }
01353 
01354         mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin);
01355         return TRUE;
01356 }

Generated on Thu Jul 1 06:09:14 2010 for Second Life Viewer by  doxygen 1.4.7