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

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