diff options
Diffstat (limited to 'indra/newview/llsurface.cpp')
-rw-r--r-- | indra/newview/llsurface.cpp | 2018 |
1 files changed, 1009 insertions, 1009 deletions
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 804afe6266..55ecc7ccc5 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsurface.cpp * @brief Implementation of LLSurface class * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -66,82 +66,82 @@ S32 LLSurface::sTextureSize = 256; // ---------------- LLSurface:: Public Members --------------- LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) : - mGridsPerEdge(0), - mOOGridsPerEdge(0.f), - mPatchesPerEdge(0), - mNumberOfPatches(0), - mType(type), - mDetailTextureScale(0.f), - mOriginGlobal(0.0, 0.0, 0.0), - mSTexturep(NULL), - mWaterTexturep(NULL), - mGridsPerPatchEdge(0), - mMetersPerGrid(1.0f), - mMetersPerEdge(1.0f), - mRegionp(regionp) + mGridsPerEdge(0), + mOOGridsPerEdge(0.f), + mPatchesPerEdge(0), + mNumberOfPatches(0), + mType(type), + mDetailTextureScale(0.f), + mOriginGlobal(0.0, 0.0, 0.0), + mSTexturep(NULL), + mWaterTexturep(NULL), + mGridsPerPatchEdge(0), + mMetersPerGrid(1.0f), + mMetersPerEdge(1.0f), + mRegionp(regionp) { - // Surface data - mSurfaceZ = NULL; - mNorm = NULL; + // Surface data + mSurfaceZ = NULL; + mNorm = NULL; - // Patch data - mPatchList = NULL; + // Patch data + mPatchList = NULL; - // One of each for each camera - mVisiblePatchCount = 0; + // One of each for each camera + mVisiblePatchCount = 0; - mHasZData = FALSE; - // "uninitialized" min/max z - mMinZ = 10000.f; - mMaxZ = -10000.f; + mHasZData = FALSE; + // "uninitialized" min/max z + mMinZ = 10000.f; + mMaxZ = -10000.f; - mWaterObjp = NULL; + mWaterObjp = NULL; - // In here temporarily. - mSurfacePatchUpdateCount = 0; + // In here temporarily. + mSurfacePatchUpdateCount = 0; - for (S32 i = 0; i < 8; i++) - { - mNeighbors[i] = NULL; - } + for (S32 i = 0; i < 8; i++) + { + mNeighbors[i] = NULL; + } } LLSurface::~LLSurface() { - delete [] mSurfaceZ; - mSurfaceZ = NULL; - - delete [] mNorm; - - mGridsPerEdge = 0; - mGridsPerPatchEdge = 0; - mPatchesPerEdge = 0; - mNumberOfPatches = 0; - destroyPatchData(); - - LLDrawPoolTerrain *poolp = (LLDrawPoolTerrain*) gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep); - if (!poolp) - { - LL_WARNS() << "No pool for terrain on destruction!" << LL_ENDL; - } - else if (poolp->mReferences.empty()) - { - gPipeline.removePool(poolp); - // Don't enable this until we blitz the draw pool for it as well. -- djs - if (mSTexturep) - { - mSTexturep = NULL; - } - if (mWaterTexturep) - { - mWaterTexturep = NULL; - } - } - else - { - LL_ERRS() << "Terrain pool not empty!" << LL_ENDL; - } + delete [] mSurfaceZ; + mSurfaceZ = NULL; + + delete [] mNorm; + + mGridsPerEdge = 0; + mGridsPerPatchEdge = 0; + mPatchesPerEdge = 0; + mNumberOfPatches = 0; + destroyPatchData(); + + LLDrawPoolTerrain *poolp = (LLDrawPoolTerrain*) gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep); + if (!poolp) + { + LL_WARNS() << "No pool for terrain on destruction!" << LL_ENDL; + } + else if (poolp->mReferences.empty()) + { + gPipeline.removePool(poolp); + // Don't enable this until we blitz the draw pool for it as well. -- djs + if (mSTexturep) + { + mSTexturep = NULL; + } + if (mWaterTexturep) + { + mWaterTexturep = NULL; + } + } + else + { + LL_ERRS() << "Terrain pool not empty!" << LL_ENDL; + } } void LLSurface::initClasses() @@ -150,538 +150,538 @@ void LLSurface::initClasses() void LLSurface::setRegion(LLViewerRegion *regionp) { - mRegionp = regionp; - mWaterObjp = NULL; // depends on regionp, needs recreating + mRegionp = regionp; + mWaterObjp = NULL; // depends on regionp, needs recreating } // Assumes that arguments are powers of 2, and that -// grids_per_edge / grids_per_patch_edge = power of 2 +// grids_per_edge / grids_per_patch_edge = power of 2 void LLSurface::create(const S32 grids_per_edge, - const S32 grids_per_patch_edge, - const LLVector3d &origin_global, - const F32 width) + const S32 grids_per_patch_edge, + const LLVector3d &origin_global, + const F32 width) { - // Initialize various constants for the surface - mGridsPerEdge = grids_per_edge + 1; // Add 1 for the east and north buffer - mOOGridsPerEdge = 1.f / mGridsPerEdge; - mGridsPerPatchEdge = grids_per_patch_edge; - mPatchesPerEdge = (mGridsPerEdge - 1) / mGridsPerPatchEdge; - mNumberOfPatches = mPatchesPerEdge * mPatchesPerEdge; - mMetersPerGrid = width / ((F32)(mGridsPerEdge - 1)); - mMetersPerEdge = mMetersPerGrid * (mGridsPerEdge - 1); - - mOriginGlobal.setVec(origin_global); - - mPVArray.create(mGridsPerEdge, mGridsPerPatchEdge, LLWorld::getInstance()->getRegionScale()); - - S32 number_of_grids = mGridsPerEdge * mGridsPerEdge; - - ///////////////////////////////////// - // - // Initialize data arrays for surface - /// - mSurfaceZ = new F32[number_of_grids]; - mNorm = new LLVector3[number_of_grids]; - - // Reset the surface to be a flat square grid - for(S32 i=0; i < number_of_grids; i++) - { - // Surface is flat and zero - // Normals all point up - mSurfaceZ[i] = 0.0f; - mNorm[i].setVec(0.f, 0.f, 1.f); - } + // Initialize various constants for the surface + mGridsPerEdge = grids_per_edge + 1; // Add 1 for the east and north buffer + mOOGridsPerEdge = 1.f / mGridsPerEdge; + mGridsPerPatchEdge = grids_per_patch_edge; + mPatchesPerEdge = (mGridsPerEdge - 1) / mGridsPerPatchEdge; + mNumberOfPatches = mPatchesPerEdge * mPatchesPerEdge; + mMetersPerGrid = width / ((F32)(mGridsPerEdge - 1)); + mMetersPerEdge = mMetersPerGrid * (mGridsPerEdge - 1); + + mOriginGlobal.setVec(origin_global); + + mPVArray.create(mGridsPerEdge, mGridsPerPatchEdge, LLWorld::getInstance()->getRegionScale()); + + S32 number_of_grids = mGridsPerEdge * mGridsPerEdge; + + ///////////////////////////////////// + // + // Initialize data arrays for surface + /// + mSurfaceZ = new F32[number_of_grids]; + mNorm = new LLVector3[number_of_grids]; + + // Reset the surface to be a flat square grid + for(S32 i=0; i < number_of_grids; i++) + { + // Surface is flat and zero + // Normals all point up + mSurfaceZ[i] = 0.0f; + mNorm[i].setVec(0.f, 0.f, 1.f); + } - mVisiblePatchCount = 0; + mVisiblePatchCount = 0; - /////////////////////// - // - // Initialize textures - // + /////////////////////// + // + // Initialize textures + // - initTextures(); + initTextures(); - // Has to be done after texture initialization - createPatchData(); + // Has to be done after texture initialization + createPatchData(); } LLViewerTexture* LLSurface::getSTexture() { - if (mSTexturep.notNull() && !mSTexturep->hasGLTexture()) - { - createSTexture(); - } - return mSTexturep; + if (mSTexturep.notNull() && !mSTexturep->hasGLTexture()) + { + createSTexture(); + } + return mSTexturep; } LLViewerTexture* LLSurface::getWaterTexture() { - if (mWaterTexturep.notNull() && !mWaterTexturep->hasGLTexture()) - { - createWaterTexture(); - } - return mWaterTexturep; + if (mWaterTexturep.notNull() && !mWaterTexturep->hasGLTexture()) + { + createWaterTexture(); + } + return mWaterTexturep; } void LLSurface::createSTexture() { - if (!mSTexturep) - { - // Fill with dummy gray data. - // GL NOT ACTIVE HERE - LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3); - U8 *default_texture = raw->getData(); - for (S32 i = 0; i < sTextureSize; i++) - { - for (S32 j = 0; j < sTextureSize; j++) - { - *(default_texture + (i*sTextureSize + j)*3) = 128; - *(default_texture + (i*sTextureSize + j)*3 + 1) = 128; - *(default_texture + (i*sTextureSize + j)*3 + 2) = 128; - } - } - - mSTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); - mSTexturep->dontDiscard(); - gGL.getTexUnit(0)->bind(mSTexturep); - mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - } + if (!mSTexturep) + { + // Fill with dummy gray data. + // GL NOT ACTIVE HERE + LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3); + U8 *default_texture = raw->getData(); + for (S32 i = 0; i < sTextureSize; i++) + { + for (S32 j = 0; j < sTextureSize; j++) + { + *(default_texture + (i*sTextureSize + j)*3) = 128; + *(default_texture + (i*sTextureSize + j)*3 + 1) = 128; + *(default_texture + (i*sTextureSize + j)*3 + 2) = 128; + } + } + + mSTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + mSTexturep->dontDiscard(); + gGL.getTexUnit(0)->bind(mSTexturep); + mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); + } } void LLSurface::createWaterTexture() { - if (!mWaterTexturep) - { - // Create the water texture - LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4); - U8 *default_texture = raw->getData(); - for (S32 i = 0; i < sTextureSize/2; i++) - { - for (S32 j = 0; j < sTextureSize/2; j++) - { - *(default_texture + (i*sTextureSize/2 + j)*4) = MAX_WATER_COLOR.mV[0]; - *(default_texture + (i*sTextureSize/2 + j)*4 + 1) = MAX_WATER_COLOR.mV[1]; - *(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2]; - *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3]; - } - } - - mWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); - mWaterTexturep->dontDiscard(); - gGL.getTexUnit(0)->bind(mWaterTexturep); - mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - } + if (!mWaterTexturep) + { + // Create the water texture + LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4); + U8 *default_texture = raw->getData(); + for (S32 i = 0; i < sTextureSize/2; i++) + { + for (S32 j = 0; j < sTextureSize/2; j++) + { + *(default_texture + (i*sTextureSize/2 + j)*4) = MAX_WATER_COLOR.mV[0]; + *(default_texture + (i*sTextureSize/2 + j)*4 + 1) = MAX_WATER_COLOR.mV[1]; + *(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2]; + *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3]; + } + } + + mWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + mWaterTexturep->dontDiscard(); + gGL.getTexUnit(0)->bind(mWaterTexturep); + mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); + } } void LLSurface::initTextures() { - /////////////////////// - // - // Main surface texture - // - createSTexture(); - - /////////////////////// - // - // Water texture - // - if (gSavedSettings.getBOOL("RenderWater") ) - { - createWaterTexture(); - mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); - gPipeline.createObject(mWaterObjp); - LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle()); - water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT); // region doesn't have a valid water height yet - mWaterObjp->setPositionGlobal(water_pos_global); - } + /////////////////////// + // + // Main surface texture + // + createSTexture(); + + /////////////////////// + // + // Water texture + // + if (gSavedSettings.getBOOL("RenderWater") ) + { + createWaterTexture(); + mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); + gPipeline.createObject(mWaterObjp); + LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle()); + water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT); // region doesn't have a valid water height yet + mWaterObjp->setPositionGlobal(water_pos_global); + } } -void LLSurface::setOriginGlobal(const LLVector3d &origin_global) +void LLSurface::setOriginGlobal(const LLVector3d &origin_global) { - LLVector3d new_origin_global; - mOriginGlobal = origin_global; - LLSurfacePatch *patchp; - S32 i, j; - // Need to update the southwest corners of the patches - for (j=0; j<mPatchesPerEdge; j++) - { - for (i=0; i<mPatchesPerEdge; i++) - { - patchp = getPatch(i, j); - - new_origin_global = patchp->getOriginGlobal(); - - new_origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge; - new_origin_global.mdV[1] = mOriginGlobal.mdV[1] + j * mMetersPerGrid * mGridsPerPatchEdge; - patchp->setOriginGlobal(new_origin_global); - } - } - - // Hack! - if (mWaterObjp.notNull() && mWaterObjp->mDrawable.notNull()) - { - const F64 x = origin_global.mdV[VX] + 128.0; - const F64 y = origin_global.mdV[VY] + 128.0; - const F64 z = mWaterObjp->getPositionGlobal().mdV[VZ]; - - LLVector3d water_origin_global(x, y, z); - - mWaterObjp->setPositionGlobal(water_origin_global); - } + LLVector3d new_origin_global; + mOriginGlobal = origin_global; + LLSurfacePatch *patchp; + S32 i, j; + // Need to update the southwest corners of the patches + for (j=0; j<mPatchesPerEdge; j++) + { + for (i=0; i<mPatchesPerEdge; i++) + { + patchp = getPatch(i, j); + + new_origin_global = patchp->getOriginGlobal(); + + new_origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge; + new_origin_global.mdV[1] = mOriginGlobal.mdV[1] + j * mMetersPerGrid * mGridsPerPatchEdge; + patchp->setOriginGlobal(new_origin_global); + } + } + + // Hack! + if (mWaterObjp.notNull() && mWaterObjp->mDrawable.notNull()) + { + const F64 x = origin_global.mdV[VX] + 128.0; + const F64 y = origin_global.mdV[VY] + 128.0; + const F64 z = mWaterObjp->getPositionGlobal().mdV[VZ]; + + LLVector3d water_origin_global(x, y, z); + + mWaterObjp->setPositionGlobal(water_origin_global); + } } void LLSurface::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ) { - S32 i; - for (i = 0; i < 8; i++) - { - if ( mNeighbors[i] != NULL ) - { - uniqueRegions.push_back( mNeighbors[i]->getRegion() ); - } - } + S32 i; + for (i = 0; i < 8; i++) + { + if ( mNeighbors[i] != NULL ) + { + uniqueRegions.push_back( mNeighbors[i]->getRegion() ); + } + } } void LLSurface::getNeighboringRegionsStatus( std::vector<S32>& regions ) { - S32 i; - for (i = 0; i < 8; i++) - { - if ( mNeighbors[i] != NULL ) - { - regions.push_back( i ); - } - } + S32 i; + for (i = 0; i < 8; i++) + { + if ( mNeighbors[i] != NULL ) + { + regions.push_back( i ); + } + } } void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction) { - S32 i; - LLSurfacePatch *patchp, *neighbor_patchp; - - mNeighbors[direction] = neighborp; - neighborp->mNeighbors[gDirOpposite[direction]] = this; - - // Connect patches - if (NORTHEAST == direction) - { - patchp = getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(0, 0); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - patchp->updateNorthEdge(); // Only update one of north or east. - patchp->dirtyZ(); - } - else if (NORTHWEST == direction) - { - patchp = getPatch(0, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, 0); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - } - else if (SOUTHWEST == direction) - { - patchp = getPatch(0, 0); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - neighbor_patchp->updateNorthEdge(); // Only update one of north or east. - neighbor_patchp->dirtyZ(); - } - else if (SOUTHEAST == direction) - { - patchp = getPatch(mPatchesPerEdge - 1, 0); - neighbor_patchp = neighborp->getPatch(0, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - } - else if (EAST == direction) - { - // Do east/west connections, first - for (i = 0; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(mPatchesPerEdge - 1, i); - neighbor_patchp = neighborp->getPatch(0, i); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - patchp->updateEastEdge(); - patchp->dirtyZ(); - } - - // Now do northeast/southwest connections - for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) - { - patchp = getPatch(mPatchesPerEdge - 1, i); - neighbor_patchp = neighborp->getPatch(0, i+1); - - patchp->connectNeighbor(neighbor_patchp, NORTHEAST); - neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); - } - // Now do southeast/northwest connections - for (i = 1; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(mPatchesPerEdge - 1, i); - neighbor_patchp = neighborp->getPatch(0, i-1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); - neighbor_patchp->connectNeighbor(patchp, NORTHWEST); - } - } - else if (NORTH == direction) - { - // Do north/south connections, first - for (i = 0; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(i, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(i, 0); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - patchp->updateNorthEdge(); - patchp->dirtyZ(); - } - - // Do northeast/southwest connections - for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) - { - patchp = getPatch(i, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(i+1, 0); - - patchp->connectNeighbor(neighbor_patchp, NORTHEAST); - neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); - } - // Do southeast/northwest connections - for (i = 1; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(i, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(i-1, 0); - - patchp->connectNeighbor(neighbor_patchp, NORTHWEST); - neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); - } - } - else if (WEST == direction) - { - // Do east/west connections, first - for (i = 0; i < mPatchesPerEdge; i++) - { - patchp = getPatch(0, i); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - neighbor_patchp->updateEastEdge(); - neighbor_patchp->dirtyZ(); - } - - // Now do northeast/southwest connections - for (i = 1; i < mPatchesPerEdge; i++) - { - patchp = getPatch(0, i); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i - 1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); - neighbor_patchp->connectNeighbor(patchp, NORTHEAST); - } - - // Now do northwest/southeast connections - for (i = 0; i < mPatchesPerEdge - 1; i++) - { - patchp = getPatch(0, i); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i + 1); - - patchp->connectNeighbor(neighbor_patchp, NORTHWEST); - neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); - } - } - else if (SOUTH == direction) - { - // Do north/south connections, first - for (i = 0; i < mPatchesPerEdge; i++) - { - patchp = getPatch(i, 0); - neighbor_patchp = neighborp->getPatch(i, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - neighbor_patchp->updateNorthEdge(); - neighbor_patchp->dirtyZ(); - } - - // Now do northeast/southwest connections - for (i = 1; i < mPatchesPerEdge; i++) - { - patchp = getPatch(i, 0); - neighbor_patchp = neighborp->getPatch(i - 1, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); - neighbor_patchp->connectNeighbor(patchp, NORTHEAST); - } - // Now do northeast/southwest connections - for (i = 0; i < mPatchesPerEdge - 1; i++) - { - patchp = getPatch(i, 0); - neighbor_patchp = neighborp->getPatch(i + 1, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); - neighbor_patchp->connectNeighbor(patchp, NORTHWEST); - } - } + S32 i; + LLSurfacePatch *patchp, *neighbor_patchp; + + mNeighbors[direction] = neighborp; + neighborp->mNeighbors[gDirOpposite[direction]] = this; + + // Connect patches + if (NORTHEAST == direction) + { + patchp = getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); + neighbor_patchp = neighborp->getPatch(0, 0); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + + patchp->updateNorthEdge(); // Only update one of north or east. + patchp->dirtyZ(); + } + else if (NORTHWEST == direction) + { + patchp = getPatch(0, mPatchesPerEdge - 1); + neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, 0); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + } + else if (SOUTHWEST == direction) + { + patchp = getPatch(0, 0); + neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + + neighbor_patchp->updateNorthEdge(); // Only update one of north or east. + neighbor_patchp->dirtyZ(); + } + else if (SOUTHEAST == direction) + { + patchp = getPatch(mPatchesPerEdge - 1, 0); + neighbor_patchp = neighborp->getPatch(0, mPatchesPerEdge - 1); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + } + else if (EAST == direction) + { + // Do east/west connections, first + for (i = 0; i < (S32)mPatchesPerEdge; i++) + { + patchp = getPatch(mPatchesPerEdge - 1, i); + neighbor_patchp = neighborp->getPatch(0, i); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + + patchp->updateEastEdge(); + patchp->dirtyZ(); + } + + // Now do northeast/southwest connections + for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) + { + patchp = getPatch(mPatchesPerEdge - 1, i); + neighbor_patchp = neighborp->getPatch(0, i+1); + + patchp->connectNeighbor(neighbor_patchp, NORTHEAST); + neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); + } + // Now do southeast/northwest connections + for (i = 1; i < (S32)mPatchesPerEdge; i++) + { + patchp = getPatch(mPatchesPerEdge - 1, i); + neighbor_patchp = neighborp->getPatch(0, i-1); + + patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); + neighbor_patchp->connectNeighbor(patchp, NORTHWEST); + } + } + else if (NORTH == direction) + { + // Do north/south connections, first + for (i = 0; i < (S32)mPatchesPerEdge; i++) + { + patchp = getPatch(i, mPatchesPerEdge - 1); + neighbor_patchp = neighborp->getPatch(i, 0); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + + patchp->updateNorthEdge(); + patchp->dirtyZ(); + } + + // Do northeast/southwest connections + for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) + { + patchp = getPatch(i, mPatchesPerEdge - 1); + neighbor_patchp = neighborp->getPatch(i+1, 0); + + patchp->connectNeighbor(neighbor_patchp, NORTHEAST); + neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); + } + // Do southeast/northwest connections + for (i = 1; i < (S32)mPatchesPerEdge; i++) + { + patchp = getPatch(i, mPatchesPerEdge - 1); + neighbor_patchp = neighborp->getPatch(i-1, 0); + + patchp->connectNeighbor(neighbor_patchp, NORTHWEST); + neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); + } + } + else if (WEST == direction) + { + // Do east/west connections, first + for (i = 0; i < mPatchesPerEdge; i++) + { + patchp = getPatch(0, i); + neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + + neighbor_patchp->updateEastEdge(); + neighbor_patchp->dirtyZ(); + } + + // Now do northeast/southwest connections + for (i = 1; i < mPatchesPerEdge; i++) + { + patchp = getPatch(0, i); + neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i - 1); + + patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); + neighbor_patchp->connectNeighbor(patchp, NORTHEAST); + } + + // Now do northwest/southeast connections + for (i = 0; i < mPatchesPerEdge - 1; i++) + { + patchp = getPatch(0, i); + neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i + 1); + + patchp->connectNeighbor(neighbor_patchp, NORTHWEST); + neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); + } + } + else if (SOUTH == direction) + { + // Do north/south connections, first + for (i = 0; i < mPatchesPerEdge; i++) + { + patchp = getPatch(i, 0); + neighbor_patchp = neighborp->getPatch(i, mPatchesPerEdge - 1); + + patchp->connectNeighbor(neighbor_patchp, direction); + neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + + neighbor_patchp->updateNorthEdge(); + neighbor_patchp->dirtyZ(); + } + + // Now do northeast/southwest connections + for (i = 1; i < mPatchesPerEdge; i++) + { + patchp = getPatch(i, 0); + neighbor_patchp = neighborp->getPatch(i - 1, mPatchesPerEdge - 1); + + patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); + neighbor_patchp->connectNeighbor(patchp, NORTHEAST); + } + // Now do northeast/southwest connections + for (i = 0; i < mPatchesPerEdge - 1; i++) + { + patchp = getPatch(i, 0); + neighbor_patchp = neighborp->getPatch(i + 1, mPatchesPerEdge - 1); + + patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); + neighbor_patchp->connectNeighbor(patchp, NORTHWEST); + } + } } void LLSurface::disconnectNeighbor(LLSurface *surfacep) { - S32 i; - for (i = 0; i < 8; i++) - { - if (surfacep == mNeighbors[i]) - { - mNeighbors[i] = NULL; - } - } - - // Iterate through surface patches, removing any connectivity to removed surface. - for (i = 0; i < mNumberOfPatches; i++) - { - (mPatchList + i)->disconnectNeighbor(surfacep); - } + S32 i; + for (i = 0; i < 8; i++) + { + if (surfacep == mNeighbors[i]) + { + mNeighbors[i] = NULL; + } + } + + // Iterate through surface patches, removing any connectivity to removed surface. + for (i = 0; i < mNumberOfPatches; i++) + { + (mPatchList + i)->disconnectNeighbor(surfacep); + } } void LLSurface::disconnectAllNeighbors() { - S32 i; - for (i = 0; i < 8; i++) - { - if (mNeighbors[i]) - { - mNeighbors[i]->disconnectNeighbor(this); - mNeighbors[i] = NULL; - } - } + S32 i; + for (i = 0; i < 8; i++) + { + if (mNeighbors[i]) + { + mNeighbors[i]->disconnectNeighbor(this); + mNeighbors[i] = NULL; + } + } } const LLVector3d &LLSurface::getOriginGlobal() const { - return mOriginGlobal; + return mOriginGlobal; } LLVector3 LLSurface::getOriginAgent() const { - return gAgent.getPosAgentFromGlobal(mOriginGlobal); + return gAgent.getPosAgentFromGlobal(mOriginGlobal); } F32 LLSurface::getMetersPerGrid() const { - return mMetersPerGrid; + return mMetersPerGrid; } S32 LLSurface::getGridsPerEdge() const { - return mGridsPerEdge; + return mGridsPerEdge; } S32 LLSurface::getPatchesPerEdge() const { - return mPatchesPerEdge; + return mPatchesPerEdge; } S32 LLSurface::getGridsPerPatchEdge() const { - return mGridsPerPatchEdge; + return mGridsPerPatchEdge; } void LLSurface::moveZ(const S32 x, const S32 y, const F32 delta) { - llassert(x >= 0); - llassert(y >= 0); - llassert(x < mGridsPerEdge); - llassert(y < mGridsPerEdge); - mSurfaceZ[x + y*mGridsPerEdge] += delta; + llassert(x >= 0); + llassert(y >= 0); + llassert(x < mGridsPerEdge); + llassert(y < mGridsPerEdge); + mSurfaceZ[x + y*mGridsPerEdge] += delta; } -void LLSurface::updatePatchVisibilities(LLAgent &agent) +void LLSurface::updatePatchVisibilities(LLAgent &agent) { - if (gShiftFrame) - { - return; - } - - LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgentCamera.getCameraPositionGlobal()); - - LLSurfacePatch *patchp; - - mVisiblePatchCount = 0; - for (S32 i=0; i<mNumberOfPatches; i++) - { - patchp = mPatchList + i; - - patchp->updateVisibility(); - if (patchp->getVisible()) - { - mVisiblePatchCount++; - patchp->updateCameraDistanceRegion(pos_region); - } - } + if (gShiftFrame) + { + return; + } + + LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgentCamera.getCameraPositionGlobal()); + + LLSurfacePatch *patchp; + + mVisiblePatchCount = 0; + for (S32 i=0; i<mNumberOfPatches; i++) + { + patchp = mPatchList + i; + + patchp->updateVisibility(); + if (patchp->getVisible()) + { + mVisiblePatchCount++; + patchp->updateCameraDistanceRegion(pos_region); + } + } } template<bool PBR> bool LLSurface::idleUpdate(F32 max_update_time) { - if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN)) - { - return false; - } - - // Perform idle time update of non-critical stuff. - // In this case, texture and normal updates. - LLTimer update_timer; - bool did_update = false; - - // If the Z height data has changed, we need to rebuild our - // property line vertex arrays. - if (mDirtyPatchList.size() > 0) - { - getRegion()->dirtyHeights(); - } - - // Always call updateNormals() / updateVerticalStats() - // every frame to avoid artifacts - for(std::set<LLSurfacePatch *>::iterator iter = mDirtyPatchList.begin(); - iter != mDirtyPatchList.end(); ) - { - std::set<LLSurfacePatch *>::iterator curiter = iter++; - LLSurfacePatch *patchp = *curiter; - patchp->updateNormals<PBR>(); - patchp->updateVerticalStats(); - if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time) - { - if (patchp->updateTexture()) - { - did_update = true; - patchp->clearDirty(); - mDirtyPatchList.erase(curiter); - } - } - } + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN)) + { + return false; + } + + // Perform idle time update of non-critical stuff. + // In this case, texture and normal updates. + LLTimer update_timer; + bool did_update = false; + + // If the Z height data has changed, we need to rebuild our + // property line vertex arrays. + if (mDirtyPatchList.size() > 0) + { + getRegion()->dirtyHeights(); + } + + // Always call updateNormals() / updateVerticalStats() + // every frame to avoid artifacts + for(std::set<LLSurfacePatch *>::iterator iter = mDirtyPatchList.begin(); + iter != mDirtyPatchList.end(); ) + { + std::set<LLSurfacePatch *>::iterator curiter = iter++; + LLSurfacePatch *patchp = *curiter; + patchp->updateNormals<PBR>(); + patchp->updateVerticalStats(); + if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time) + { + if (patchp->updateTexture()) + { + did_update = true; + patchp->clearDirty(); + mDirtyPatchList.erase(curiter); + } + } + } if (did_update) { @@ -689,76 +689,76 @@ bool LLSurface::idleUpdate(F32 max_update_time) mRegionp->updateReflectionProbes(); } - return did_update; + return did_update; } template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time); template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time); -void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch) +void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch) { - LLPatchHeader ph; - S32 j, i; - S32 patch[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - LLSurfacePatch *patchp; - - init_patch_decompressor(gopp->patch_size); - gopp->stride = mGridsPerEdge; - set_group_of_patch_header(gopp); - - while (1) - { - decode_patch_header(bitpack, &ph); - if (ph.quant_wbits == END_OF_PATCHES) - { - break; - } - - i = ph.patchids >> 5; - j = ph.patchids & 0x1F; - - if ((i >= mPatchesPerEdge) || (j >= mPatchesPerEdge)) - { - LL_WARNS() << "Received invalid terrain packet - patch header patch ID incorrect!" - << " patches per edge " << mPatchesPerEdge - << " i " << i - << " j " << j - << " dc_offset " << ph.dc_offset - << " range " << (S32)ph.range - << " quant_wbits " << (S32)ph.quant_wbits - << " patchids " << (S32)ph.patchids - << LL_ENDL; - return; - } - - patchp = &mPatchList[j*mPatchesPerEdge + i]; - - - decode_patch(bitpack, patch); - decompress_patch(patchp->getDataZ(), patch, &ph); - - // Update edges for neighbors. Need to guarantee that this gets done before we generate vertical stats. - patchp->updateNorthEdge(); - patchp->updateEastEdge(); - if (patchp->getNeighborPatch(WEST)) - { - patchp->getNeighborPatch(WEST)->updateEastEdge(); - } - if (patchp->getNeighborPatch(SOUTHWEST)) - { - patchp->getNeighborPatch(SOUTHWEST)->updateEastEdge(); - patchp->getNeighborPatch(SOUTHWEST)->updateNorthEdge(); - } - if (patchp->getNeighborPatch(SOUTH)) - { - patchp->getNeighborPatch(SOUTH)->updateNorthEdge(); - } - - // Dirty patch statistics, and flag that the patch has data. - patchp->dirtyZ(); - patchp->setHasReceivedData(); - } + LLPatchHeader ph; + S32 j, i; + S32 patch[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; + LLSurfacePatch *patchp; + + init_patch_decompressor(gopp->patch_size); + gopp->stride = mGridsPerEdge; + set_group_of_patch_header(gopp); + + while (1) + { + decode_patch_header(bitpack, &ph); + if (ph.quant_wbits == END_OF_PATCHES) + { + break; + } + + i = ph.patchids >> 5; + j = ph.patchids & 0x1F; + + if ((i >= mPatchesPerEdge) || (j >= mPatchesPerEdge)) + { + LL_WARNS() << "Received invalid terrain packet - patch header patch ID incorrect!" + << " patches per edge " << mPatchesPerEdge + << " i " << i + << " j " << j + << " dc_offset " << ph.dc_offset + << " range " << (S32)ph.range + << " quant_wbits " << (S32)ph.quant_wbits + << " patchids " << (S32)ph.patchids + << LL_ENDL; + return; + } + + patchp = &mPatchList[j*mPatchesPerEdge + i]; + + + decode_patch(bitpack, patch); + decompress_patch(patchp->getDataZ(), patch, &ph); + + // Update edges for neighbors. Need to guarantee that this gets done before we generate vertical stats. + patchp->updateNorthEdge(); + patchp->updateEastEdge(); + if (patchp->getNeighborPatch(WEST)) + { + patchp->getNeighborPatch(WEST)->updateEastEdge(); + } + if (patchp->getNeighborPatch(SOUTHWEST)) + { + patchp->getNeighborPatch(SOUTHWEST)->updateEastEdge(); + patchp->getNeighborPatch(SOUTHWEST)->updateNorthEdge(); + } + if (patchp->getNeighborPatch(SOUTH)) + { + patchp->getNeighborPatch(SOUTH)->updateNorthEdge(); + } + + // Dirty patch statistics, and flag that the patch has data. + patchp->dirtyZ(); + patchp->setHasReceivedData(); + } } @@ -766,157 +766,157 @@ void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL // "position" is region-local BOOL LLSurface::containsPosition(const LLVector3 &position) { - if (position.mV[VX] < 0.0f || position.mV[VX] > mMetersPerEdge || - position.mV[VY] < 0.0f || position.mV[VY] > mMetersPerEdge) - { - return FALSE; - } - return TRUE; + if (position.mV[VX] < 0.0f || position.mV[VX] > mMetersPerEdge || + position.mV[VY] < 0.0f || position.mV[VY] > mMetersPerEdge) + { + return FALSE; + } + return TRUE; } F32 LLSurface::resolveHeightRegion(const F32 x, const F32 y) const { - F32 height = 0.0f; - F32 oometerspergrid = 1.f/mMetersPerGrid; - - // Check to see if v is actually above surface - // We use (mGridsPerEdge-1) below rather than (mGridsPerEdge) - // becuase of the east and north buffers - - if (x >= 0.f && - x <= mMetersPerEdge && - y >= 0.f && - y <= mMetersPerEdge) - { - const S32 left = llfloor(x * oometerspergrid); - const S32 bottom = llfloor(y * oometerspergrid); - - // Don't walk off the edge of the array! - const S32 right = ( left+1 < (S32)mGridsPerEdge-1 ? left+1 : left ); - const S32 top = ( bottom+1 < (S32)mGridsPerEdge-1 ? bottom+1 : bottom ); - - // Figure out if v is in first or second triangle of the square - // and calculate the slopes accordingly - // | | - // -(i,j+1)---(i+1,j+1)-- - // | 1 / | ^ - // | / 2 | | - // | / | j - // --(i,j)----(i+1,j)-- - // | | - // - // i -> - // where N = mGridsPerEdge - - const F32 left_bottom = getZ( left, bottom ); - const F32 right_bottom = getZ( right, bottom ); - const F32 left_top = getZ( left, top ); - const F32 right_top = getZ( right, top ); - - // dx and dy are incremental steps from (mSurface + k) - F32 dx = x - left * mMetersPerGrid; - F32 dy = y - bottom * mMetersPerGrid; - - if (dy > dx) - { - // triangle 1 - dy *= left_top - left_bottom; - dx *= right_top - left_top; - } - else - { - // triangle 2 - dx *= right_bottom - left_bottom; - dy *= right_top - right_bottom; - } - height = left_bottom + (dx + dy) * oometerspergrid; - } - return height; + F32 height = 0.0f; + F32 oometerspergrid = 1.f/mMetersPerGrid; + + // Check to see if v is actually above surface + // We use (mGridsPerEdge-1) below rather than (mGridsPerEdge) + // becuase of the east and north buffers + + if (x >= 0.f && + x <= mMetersPerEdge && + y >= 0.f && + y <= mMetersPerEdge) + { + const S32 left = llfloor(x * oometerspergrid); + const S32 bottom = llfloor(y * oometerspergrid); + + // Don't walk off the edge of the array! + const S32 right = ( left+1 < (S32)mGridsPerEdge-1 ? left+1 : left ); + const S32 top = ( bottom+1 < (S32)mGridsPerEdge-1 ? bottom+1 : bottom ); + + // Figure out if v is in first or second triangle of the square + // and calculate the slopes accordingly + // | | + // -(i,j+1)---(i+1,j+1)-- + // | 1 / | ^ + // | / 2 | | + // | / | j + // --(i,j)----(i+1,j)-- + // | | + // + // i -> + // where N = mGridsPerEdge + + const F32 left_bottom = getZ( left, bottom ); + const F32 right_bottom = getZ( right, bottom ); + const F32 left_top = getZ( left, top ); + const F32 right_top = getZ( right, top ); + + // dx and dy are incremental steps from (mSurface + k) + F32 dx = x - left * mMetersPerGrid; + F32 dy = y - bottom * mMetersPerGrid; + + if (dy > dx) + { + // triangle 1 + dy *= left_top - left_bottom; + dx *= right_top - left_top; + } + else + { + // triangle 2 + dx *= right_bottom - left_bottom; + dy *= right_top - right_bottom; + } + height = left_bottom + (dx + dy) * oometerspergrid; + } + return height; } F32 LLSurface::resolveHeightGlobal(const LLVector3d& v) const { - if (!mRegionp) - { - return 0.f; - } - - LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(v); - - return resolveHeightRegion(pos_region); + if (!mRegionp) + { + return 0.f; + } + + LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(v); + + return resolveHeightRegion(pos_region); } LLVector3 LLSurface::resolveNormalGlobal(const LLVector3d& pos_global) const { - if (!mSurfaceZ) - { - // Hmm. Uninitialized surface! - return LLVector3::z_axis; - } - // - // Returns the vector normal to a surface at location specified by vector v - // - F32 oometerspergrid = 1.f/mMetersPerGrid; - LLVector3 normal; - F32 dzx, dzy; - - if (pos_global.mdV[VX] >= mOriginGlobal.mdV[VX] && - pos_global.mdV[VX] < mOriginGlobal.mdV[VX] + mMetersPerEdge && - pos_global.mdV[VY] >= mOriginGlobal.mdV[VY] && - pos_global.mdV[VY] < mOriginGlobal.mdV[VY] + mMetersPerEdge) - { - U32 i, j, k; - F32 dx, dy; - i = (U32) ((pos_global.mdV[VX] - mOriginGlobal.mdV[VX]) * oometerspergrid); - j = (U32) ((pos_global.mdV[VY] - mOriginGlobal.mdV[VY]) * oometerspergrid ); - k = i + j*mGridsPerEdge; - - // Figure out if v is in first or second triangle of the square - // and calculate the slopes accordingly - // | | - // -(k+N)---(k+1+N)-- - // | 1 / | ^ - // | / 2 | | - // | / | j - // --(k)----(k+1)-- - // | | - // - // i -> - // where N = mGridsPerEdge - - // dx and dy are incremental steps from (mSurface + k) - dx = (F32)(pos_global.mdV[VX] - i*mMetersPerGrid - mOriginGlobal.mdV[VX]); - dy = (F32)(pos_global.mdV[VY] - j*mMetersPerGrid - mOriginGlobal.mdV[VY]); - if (dy > dx) - { // triangle 1 - dzx = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + mGridsPerEdge); - dzy = *(mSurfaceZ + k) - *(mSurfaceZ + k + mGridsPerEdge); - normal.setVec(-dzx,dzy,1); - } - else - { // triangle 2 - dzx = *(mSurfaceZ + k) - *(mSurfaceZ + k + 1); - dzy = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + 1); - normal.setVec(dzx,-dzy,1); - } - } - normal.normVec(); - return normal; + if (!mSurfaceZ) + { + // Hmm. Uninitialized surface! + return LLVector3::z_axis; + } + // + // Returns the vector normal to a surface at location specified by vector v + // + F32 oometerspergrid = 1.f/mMetersPerGrid; + LLVector3 normal; + F32 dzx, dzy; + + if (pos_global.mdV[VX] >= mOriginGlobal.mdV[VX] && + pos_global.mdV[VX] < mOriginGlobal.mdV[VX] + mMetersPerEdge && + pos_global.mdV[VY] >= mOriginGlobal.mdV[VY] && + pos_global.mdV[VY] < mOriginGlobal.mdV[VY] + mMetersPerEdge) + { + U32 i, j, k; + F32 dx, dy; + i = (U32) ((pos_global.mdV[VX] - mOriginGlobal.mdV[VX]) * oometerspergrid); + j = (U32) ((pos_global.mdV[VY] - mOriginGlobal.mdV[VY]) * oometerspergrid ); + k = i + j*mGridsPerEdge; + + // Figure out if v is in first or second triangle of the square + // and calculate the slopes accordingly + // | | + // -(k+N)---(k+1+N)-- + // | 1 / | ^ + // | / 2 | | + // | / | j + // --(k)----(k+1)-- + // | | + // + // i -> + // where N = mGridsPerEdge + + // dx and dy are incremental steps from (mSurface + k) + dx = (F32)(pos_global.mdV[VX] - i*mMetersPerGrid - mOriginGlobal.mdV[VX]); + dy = (F32)(pos_global.mdV[VY] - j*mMetersPerGrid - mOriginGlobal.mdV[VY]); + if (dy > dx) + { // triangle 1 + dzx = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + mGridsPerEdge); + dzy = *(mSurfaceZ + k) - *(mSurfaceZ + k + mGridsPerEdge); + normal.setVec(-dzx,dzy,1); + } + else + { // triangle 2 + dzx = *(mSurfaceZ + k) - *(mSurfaceZ + k + 1); + dzy = *(mSurfaceZ + k + 1 + mGridsPerEdge) - *(mSurfaceZ + k + 1); + normal.setVec(dzx,-dzy,1); + } + } + normal.normVec(); + return normal; } LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const { -// x and y should be region-local coordinates. +// x and y should be region-local coordinates. // If x and y are outside of the surface, then the returned // index will be for the nearest boundary patch. // // 12 | 13| 14| 15 -// | | | +// | | | // +---+---+---+---+ // | 12| 13| 14| 15| // ----+---+---+---+---+----- @@ -926,393 +926,393 @@ LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const // ----+---+---+---+---+----- // | 0 | 1 | 2 | 3 | // +---+---+---+---+ -// | | | +// | | | // 0 | 1 | 2 | 3 // // When x and y are not region-local do the following first - S32 i, j; - if (x < 0.0f) - { - i = 0; - } - else if (x >= mMetersPerEdge) - { - i = mPatchesPerEdge - 1; - } - else - { - i = (U32) (x / (mMetersPerGrid * mGridsPerPatchEdge)); - } - - if (y < 0.0f) - { - j = 0; - } - else if (y >= mMetersPerEdge) - { - j = mPatchesPerEdge - 1; - } - else - { - j = (U32) (y / (mMetersPerGrid * mGridsPerPatchEdge)); - } - - // *NOTE: Super paranoia code follows. - S32 index = i + j * mPatchesPerEdge; - if((index < 0) || (index >= mNumberOfPatches)) - { - if(0 == mNumberOfPatches) - { - LL_WARNS() << "No patches for current region!" << LL_ENDL; - return NULL; - } - S32 old_index = index; - index = llclamp(old_index, 0, (mNumberOfPatches - 1)); - LL_WARNS() << "Clamping out of range patch index " << old_index - << " to " << index << LL_ENDL; - } - return &(mPatchList[index]); + S32 i, j; + if (x < 0.0f) + { + i = 0; + } + else if (x >= mMetersPerEdge) + { + i = mPatchesPerEdge - 1; + } + else + { + i = (U32) (x / (mMetersPerGrid * mGridsPerPatchEdge)); + } + + if (y < 0.0f) + { + j = 0; + } + else if (y >= mMetersPerEdge) + { + j = mPatchesPerEdge - 1; + } + else + { + j = (U32) (y / (mMetersPerGrid * mGridsPerPatchEdge)); + } + + // *NOTE: Super paranoia code follows. + S32 index = i + j * mPatchesPerEdge; + if((index < 0) || (index >= mNumberOfPatches)) + { + if(0 == mNumberOfPatches) + { + LL_WARNS() << "No patches for current region!" << LL_ENDL; + return NULL; + } + S32 old_index = index; + index = llclamp(old_index, 0, (mNumberOfPatches - 1)); + LL_WARNS() << "Clamping out of range patch index " << old_index + << " to " << index << LL_ENDL; + } + return &(mPatchList[index]); } LLSurfacePatch *LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const { - return resolvePatchRegion(pos_region.mV[VX], pos_region.mV[VY]); + return resolvePatchRegion(pos_region.mV[VX], pos_region.mV[VY]); } LLSurfacePatch *LLSurface::resolvePatchGlobal(const LLVector3d &pos_global) const { - llassert(mRegionp); - LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(pos_global); - return resolvePatchRegion(pos_region); + llassert(mRegionp); + LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(pos_global); + return resolvePatchRegion(pos_region); } -std::ostream& operator<<(std::ostream &s, const LLSurface &S) +std::ostream& operator<<(std::ostream &s, const LLSurface &S) { - s << "{ \n"; - s << " mGridsPerEdge = " << S.mGridsPerEdge - 1 << " + 1\n"; - s << " mGridsPerPatchEdge = " << S.mGridsPerPatchEdge << "\n"; - s << " mPatchesPerEdge = " << S.mPatchesPerEdge << "\n"; - s << " mOriginGlobal = " << S.mOriginGlobal << "\n"; - s << " mMetersPerGrid = " << S.mMetersPerGrid << "\n"; - s << " mVisiblePatchCount = " << S.mVisiblePatchCount << "\n"; - s << "}"; - return s; + s << "{ \n"; + s << " mGridsPerEdge = " << S.mGridsPerEdge - 1 << " + 1\n"; + s << " mGridsPerPatchEdge = " << S.mGridsPerPatchEdge << "\n"; + s << " mPatchesPerEdge = " << S.mPatchesPerEdge << "\n"; + s << " mOriginGlobal = " << S.mOriginGlobal << "\n"; + s << " mMetersPerGrid = " << S.mMetersPerGrid << "\n"; + s << " mVisiblePatchCount = " << S.mVisiblePatchCount << "\n"; + s << "}"; + return s; } // ---------------- LLSurface:: Protected ---------------- -void LLSurface::createPatchData() +void LLSurface::createPatchData() { - // Assumes mGridsPerEdge, mGridsPerPatchEdge, and mPatchesPerEdge have been properly set - // TODO -- check for create() called when surface is not empty - S32 i, j; - LLSurfacePatch *patchp; - - // Allocate memory - mPatchList = new LLSurfacePatch[mNumberOfPatches]; - - // One of each for each camera - mVisiblePatchCount = mNumberOfPatches; - - for (j=0; j<mPatchesPerEdge; j++) - { - for (i=0; i<mPatchesPerEdge; i++) - { - patchp = getPatch(i, j); - patchp->setSurface(this); - } - } - - for (j=0; j<mPatchesPerEdge; j++) - { - for (i=0; i<mPatchesPerEdge; i++) - { - patchp = getPatch(i, j); - patchp->mHasReceivedData = FALSE; - patchp->mSTexUpdate = TRUE; - - S32 data_offset = i * mGridsPerPatchEdge + j * mGridsPerPatchEdge * mGridsPerEdge; - - patchp->setDataZ(mSurfaceZ + data_offset); - patchp->setDataNorm(mNorm + data_offset); - - - // We make each patch point to its neighbors so we can do resolution checking - // when butting up different resolutions. Patches that don't have neighbors - // somewhere will point to NULL on that side. - if (i < mPatchesPerEdge-1) - { - patchp->setNeighborPatch(EAST,getPatch(i+1, j)); - } - else - { - patchp->setNeighborPatch(EAST, NULL); - } - - if (j < mPatchesPerEdge-1) - { - patchp->setNeighborPatch(NORTH, getPatch(i, j+1)); - } - else - { - patchp->setNeighborPatch(NORTH, NULL); - } - - if (i > 0) - { - patchp->setNeighborPatch(WEST, getPatch(i - 1, j)); - } - else - { - patchp->setNeighborPatch(WEST, NULL); - } - - if (j > 0) - { - patchp->setNeighborPatch(SOUTH, getPatch(i, j-1)); - } - else - { - patchp->setNeighborPatch(SOUTH, NULL); - } - - if (i < (mPatchesPerEdge-1) && j < (mPatchesPerEdge-1)) - { - patchp->setNeighborPatch(NORTHEAST, getPatch(i + 1, j + 1)); - } - else - { - patchp->setNeighborPatch(NORTHEAST, NULL); - } - - if (i > 0 && j < (mPatchesPerEdge-1)) - { - patchp->setNeighborPatch(NORTHWEST, getPatch(i - 1, j + 1)); - } - else - { - patchp->setNeighborPatch(NORTHWEST, NULL); - } - - if (i > 0 && j > 0) - { - patchp->setNeighborPatch(SOUTHWEST, getPatch(i - 1, j - 1)); - } - else - { - patchp->setNeighborPatch(SOUTHWEST, NULL); - } - - if (i < (mPatchesPerEdge-1) && j > 0) - { - patchp->setNeighborPatch(SOUTHEAST, getPatch(i + 1, j - 1)); - } - else - { - patchp->setNeighborPatch(SOUTHEAST, NULL); - } - - LLVector3d origin_global; - origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge; - origin_global.mdV[1] = mOriginGlobal.mdV[0] + j * mMetersPerGrid * mGridsPerPatchEdge; - origin_global.mdV[2] = 0.f; - patchp->setOriginGlobal(origin_global); - } - } + // Assumes mGridsPerEdge, mGridsPerPatchEdge, and mPatchesPerEdge have been properly set + // TODO -- check for create() called when surface is not empty + S32 i, j; + LLSurfacePatch *patchp; + + // Allocate memory + mPatchList = new LLSurfacePatch[mNumberOfPatches]; + + // One of each for each camera + mVisiblePatchCount = mNumberOfPatches; + + for (j=0; j<mPatchesPerEdge; j++) + { + for (i=0; i<mPatchesPerEdge; i++) + { + patchp = getPatch(i, j); + patchp->setSurface(this); + } + } + + for (j=0; j<mPatchesPerEdge; j++) + { + for (i=0; i<mPatchesPerEdge; i++) + { + patchp = getPatch(i, j); + patchp->mHasReceivedData = FALSE; + patchp->mSTexUpdate = TRUE; + + S32 data_offset = i * mGridsPerPatchEdge + j * mGridsPerPatchEdge * mGridsPerEdge; + + patchp->setDataZ(mSurfaceZ + data_offset); + patchp->setDataNorm(mNorm + data_offset); + + + // We make each patch point to its neighbors so we can do resolution checking + // when butting up different resolutions. Patches that don't have neighbors + // somewhere will point to NULL on that side. + if (i < mPatchesPerEdge-1) + { + patchp->setNeighborPatch(EAST,getPatch(i+1, j)); + } + else + { + patchp->setNeighborPatch(EAST, NULL); + } + + if (j < mPatchesPerEdge-1) + { + patchp->setNeighborPatch(NORTH, getPatch(i, j+1)); + } + else + { + patchp->setNeighborPatch(NORTH, NULL); + } + + if (i > 0) + { + patchp->setNeighborPatch(WEST, getPatch(i - 1, j)); + } + else + { + patchp->setNeighborPatch(WEST, NULL); + } + + if (j > 0) + { + patchp->setNeighborPatch(SOUTH, getPatch(i, j-1)); + } + else + { + patchp->setNeighborPatch(SOUTH, NULL); + } + + if (i < (mPatchesPerEdge-1) && j < (mPatchesPerEdge-1)) + { + patchp->setNeighborPatch(NORTHEAST, getPatch(i + 1, j + 1)); + } + else + { + patchp->setNeighborPatch(NORTHEAST, NULL); + } + + if (i > 0 && j < (mPatchesPerEdge-1)) + { + patchp->setNeighborPatch(NORTHWEST, getPatch(i - 1, j + 1)); + } + else + { + patchp->setNeighborPatch(NORTHWEST, NULL); + } + + if (i > 0 && j > 0) + { + patchp->setNeighborPatch(SOUTHWEST, getPatch(i - 1, j - 1)); + } + else + { + patchp->setNeighborPatch(SOUTHWEST, NULL); + } + + if (i < (mPatchesPerEdge-1) && j > 0) + { + patchp->setNeighborPatch(SOUTHEAST, getPatch(i + 1, j - 1)); + } + else + { + patchp->setNeighborPatch(SOUTHEAST, NULL); + } + + LLVector3d origin_global; + origin_global.mdV[0] = mOriginGlobal.mdV[0] + i * mMetersPerGrid * mGridsPerPatchEdge; + origin_global.mdV[1] = mOriginGlobal.mdV[0] + j * mMetersPerGrid * mGridsPerPatchEdge; + origin_global.mdV[2] = 0.f; + patchp->setOriginGlobal(origin_global); + } + } } void LLSurface::destroyPatchData() { - // Delete all of the cached patch data for these patches. + // Delete all of the cached patch data for these patches. - delete [] mPatchList; - mPatchList = NULL; - mVisiblePatchCount = 0; + delete [] mPatchList; + mPatchList = NULL; + mVisiblePatchCount = 0; } void LLSurface::setTextureSize(const S32 texture_size) { - sTextureSize = texture_size; + sTextureSize = texture_size; } U32 LLSurface::getRenderLevel(const U32 render_stride) const { - return mPVArray.mRenderLevelp[render_stride]; + return mPVArray.mRenderLevelp[render_stride]; } U32 LLSurface::getRenderStride(const U32 render_level) const { - return mPVArray.mRenderStridep[render_level]; + return mPVArray.mRenderStridep[render_level]; } LLSurfacePatch *LLSurface::getPatch(const S32 x, const S32 y) const { - if ((x < 0) || (x >= mPatchesPerEdge)) - { - LL_ERRS() << "Asking for patch out of bounds" << LL_ENDL; - return NULL; - } - if ((y < 0) || (y >= mPatchesPerEdge)) - { - LL_ERRS() << "Asking for patch out of bounds" << LL_ENDL; - return NULL; - } - - return mPatchList + x + y*mPatchesPerEdge; + if ((x < 0) || (x >= mPatchesPerEdge)) + { + LL_ERRS() << "Asking for patch out of bounds" << LL_ENDL; + return NULL; + } + if ((y < 0) || (y >= mPatchesPerEdge)) + { + LL_ERRS() << "Asking for patch out of bounds" << LL_ENDL; + return NULL; + } + + return mPatchList + x + y*mPatchesPerEdge; } void LLSurface::dirtyAllPatches() { - S32 i; - for (i = 0; i < mNumberOfPatches; i++) - { - mPatchList[i].dirtyZ(); - } + S32 i; + for (i = 0; i < mNumberOfPatches; i++) + { + mPatchList[i].dirtyZ(); + } } void LLSurface::dirtySurfacePatch(LLSurfacePatch *patchp) { - // Put surface patch on dirty surface patch list - mDirtyPatchList.insert(patchp); + // Put surface patch on dirty surface patch list + mDirtyPatchList.insert(patchp); } void LLSurface::setWaterHeight(F32 height) { - if (!mWaterObjp.isNull()) - { - LLVector3 water_pos_region = mWaterObjp->getPositionRegion(); - bool changed = water_pos_region.mV[VZ] != height; - water_pos_region.mV[VZ] = height; - mWaterObjp->setPositionRegion(water_pos_region); - if (changed) - { - LLWorld::getInstance()->updateWaterObjects(); - } - } - else - { - LL_WARNS() << "LLSurface::setWaterHeight with no water object!" << LL_ENDL; - } + if (!mWaterObjp.isNull()) + { + LLVector3 water_pos_region = mWaterObjp->getPositionRegion(); + bool changed = water_pos_region.mV[VZ] != height; + water_pos_region.mV[VZ] = height; + mWaterObjp->setPositionRegion(water_pos_region); + if (changed) + { + LLWorld::getInstance()->updateWaterObjects(); + } + } + else + { + LL_WARNS() << "LLSurface::setWaterHeight with no water object!" << LL_ENDL; + } } F32 LLSurface::getWaterHeight() const { - if (!mWaterObjp.isNull()) - { - // we have a water object, the usual case - return mWaterObjp->getPositionRegion().mV[VZ]; - } - else - { - return DEFAULT_WATER_HEIGHT; - } + if (!mWaterObjp.isNull()) + { + // we have a water object, the usual case + return mWaterObjp->getPositionRegion().mV[VZ]; + } + else + { + return DEFAULT_WATER_HEIGHT; + } } BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y, - const F32 width, const F32 height) + const F32 width, const F32 height) { - LL_PROFILE_ZONE_SCOPED - if (!getWaterTexture()) - { - return FALSE; - } - - S32 tex_width = mWaterTexturep->getWidth(); - S32 tex_height = mWaterTexturep->getHeight(); - S32 tex_comps = mWaterTexturep->getComponents(); - S32 tex_stride = tex_width * tex_comps; - LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps); - U8 *rawp = raw->getData(); - - F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width; - F32 scale_inv = 1.f / scale; - - S32 x_begin, y_begin, x_end, y_end; - - x_begin = ll_round(x * scale_inv); - y_begin = ll_round(y * scale_inv); - x_end = ll_round((x + width) * scale_inv); - y_end = ll_round((y + width) * scale_inv); - - if (x_end > tex_width) - { - x_end = tex_width; - } - if (y_end > tex_width) - { - y_end = tex_width; - } - - // OK, for now, just have the composition value equal the height at the point. - LLVector3 location; - LLColor4U coloru; - - const F32 WATER_HEIGHT = getWaterHeight(); - - S32 i, j, offset; - for (j = y_begin; j < y_end; j++) - { - for (i = x_begin; i < x_end; i++) - { - //F32 nv[2]; - //nv[0] = i/256.f; - //nv[1] = j/256.f; - // const S32 modulation = noise2(nv)*40; - offset = j*tex_stride + i*tex_comps; - location.mV[VX] = i*scale; - location.mV[VY] = j*scale; - - // Sample multiple points - const F32 height = resolveHeightRegion(location); - - if (height > WATER_HEIGHT) - { - // Above water... - coloru = MAX_WATER_COLOR; - coloru.mV[3] = ABOVE_WATERLINE_ALPHA; - *(rawp + offset++) = coloru.mV[0]; - *(rawp + offset++) = coloru.mV[1]; - *(rawp + offset++) = coloru.mV[2]; - *(rawp + offset++) = coloru.mV[3]; - } - else - { - // Want non-linear curve for transparency gradient - coloru = MAX_WATER_COLOR; - const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT)); - S32 alpha = 64 + ll_round((255-64)*frac); - - alpha = llmin(ll_round((F32)MAX_WATER_COLOR.mV[3]), alpha); - alpha = llmax(64, alpha); - - coloru.mV[3] = alpha; - *(rawp + offset++) = coloru.mV[0]; - *(rawp + offset++) = coloru.mV[1]; - *(rawp + offset++) = coloru.mV[2]; - *(rawp + offset++) = coloru.mV[3]; - } - } - } - - if (!mWaterTexturep->hasGLTexture()) - { - mWaterTexturep->createGLTexture(0, raw); - } - - mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin); - return TRUE; + LL_PROFILE_ZONE_SCOPED + if (!getWaterTexture()) + { + return FALSE; + } + + S32 tex_width = mWaterTexturep->getWidth(); + S32 tex_height = mWaterTexturep->getHeight(); + S32 tex_comps = mWaterTexturep->getComponents(); + S32 tex_stride = tex_width * tex_comps; + LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps); + U8 *rawp = raw->getData(); + + F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width; + F32 scale_inv = 1.f / scale; + + S32 x_begin, y_begin, x_end, y_end; + + x_begin = ll_round(x * scale_inv); + y_begin = ll_round(y * scale_inv); + x_end = ll_round((x + width) * scale_inv); + y_end = ll_round((y + width) * scale_inv); + + if (x_end > tex_width) + { + x_end = tex_width; + } + if (y_end > tex_width) + { + y_end = tex_width; + } + + // OK, for now, just have the composition value equal the height at the point. + LLVector3 location; + LLColor4U coloru; + + const F32 WATER_HEIGHT = getWaterHeight(); + + S32 i, j, offset; + for (j = y_begin; j < y_end; j++) + { + for (i = x_begin; i < x_end; i++) + { + //F32 nv[2]; + //nv[0] = i/256.f; + //nv[1] = j/256.f; + // const S32 modulation = noise2(nv)*40; + offset = j*tex_stride + i*tex_comps; + location.mV[VX] = i*scale; + location.mV[VY] = j*scale; + + // Sample multiple points + const F32 height = resolveHeightRegion(location); + + if (height > WATER_HEIGHT) + { + // Above water... + coloru = MAX_WATER_COLOR; + coloru.mV[3] = ABOVE_WATERLINE_ALPHA; + *(rawp + offset++) = coloru.mV[0]; + *(rawp + offset++) = coloru.mV[1]; + *(rawp + offset++) = coloru.mV[2]; + *(rawp + offset++) = coloru.mV[3]; + } + else + { + // Want non-linear curve for transparency gradient + coloru = MAX_WATER_COLOR; + const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT)); + S32 alpha = 64 + ll_round((255-64)*frac); + + alpha = llmin(ll_round((F32)MAX_WATER_COLOR.mV[3]), alpha); + alpha = llmax(64, alpha); + + coloru.mV[3] = alpha; + *(rawp + offset++) = coloru.mV[0]; + *(rawp + offset++) = coloru.mV[1]; + *(rawp + offset++) = coloru.mV[2]; + *(rawp + offset++) = coloru.mV[3]; + } + } + } + + if (!mWaterTexturep->hasGLTexture()) + { + mWaterTexturep->createGLTexture(0, raw); + } + + mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin); + return TRUE; } |