diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llsurface.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llsurface.cpp')
-rw-r--r-- | indra/newview/llsurface.cpp | 2628 |
1 files changed, 1314 insertions, 1314 deletions
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index b6fcddb508..ce880c09ee 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -1,1314 +1,1314 @@ -/** - * @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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llsurface.h" - -#include "llrender.h" - -#include "llviewertexturelist.h" -#include "llpatchvertexarray.h" -#include "patch_dct.h" -#include "patch_code.h" -#include "llbitpack.h" -#include "llviewerobjectlist.h" -#include "llregionhandle.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llappviewer.h" -#include "llworld.h" -#include "llviewercontrol.h" -#include "llviewertexture.h" -#include "llsurfacepatch.h" -#include "llvosurfacepatch.h" -#include "llvowater.h" -#include "pipeline.h" -#include "llviewerregion.h" -#include "llvlcomposition.h" -#include "noise.h" -#include "llviewercamera.h" -#include "llglheaders.h" -#include "lldrawpoolterrain.h" -#include "lldrawable.h" - -extern LLPipeline gPipeline; -extern bool gShiftFrame; - -LLColor4U MAX_WATER_COLOR(0, 48, 96, 240); - - -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) -{ - // Surface data - mSurfaceZ = NULL; - mNorm = NULL; - - // Patch data - mPatchList = NULL; - - // One of each for each camera - mVisiblePatchCount = 0; - - mHasZData = false; - // "uninitialized" min/max z - mMinZ = 10000.f; - mMaxZ = -10000.f; - - mWaterObjp = NULL; - - // In here temporarily. - mSurfacePatchUpdateCount = 0; - - 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; - } -} - -void LLSurface::initClasses() -{ -} - -void LLSurface::setRegion(LLViewerRegion *regionp) -{ - 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 -void LLSurface::create(const S32 grids_per_edge, - 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); - } - - - mVisiblePatchCount = 0; - - - /////////////////////// - // - // Initialize textures - // - - initTextures(); - - // Has to be done after texture initialization - createPatchData(); -} - -LLViewerTexture* LLSurface::getSTexture() -{ - if (mSTexturep.notNull() && !mSTexturep->hasGLTexture()) - { - createSTexture(); - } - return mSTexturep; -} - -LLViewerTexture* LLSurface::getWaterTexture() -{ - 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); - } -} - -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); - } -} - -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); - } -} - - -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); - } -} - -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() ); - } - } -} - - -void LLSurface::getNeighboringRegionsStatus( std::vector<S32>& regions ) -{ - 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); - } - } -} - -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); - } -} - - -void LLSurface::disconnectAllNeighbors() -{ - 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; -} - -LLVector3 LLSurface::getOriginAgent() const -{ - return gAgent.getPosAgentFromGlobal(mOriginGlobal); -} - -F32 LLSurface::getMetersPerGrid() const -{ - return mMetersPerGrid; -} - -S32 LLSurface::getGridsPerEdge() const -{ - return mGridsPerEdge; -} - -S32 LLSurface::getPatchesPerEdge() const -{ - return mPatchesPerEdge; -} - -S32 LLSurface::getGridsPerPatchEdge() const -{ - 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; -} - - -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); - } - } -} - -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(); - 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) - { - // some patches changed, update region reflection probes - mRegionp->updateReflectionProbes(); - } - - return did_update; -} - -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(); - } -} - - -// Retrurns true if "position" is within the bounds of surface. -// "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; -} - - -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 LLSurface::resolveHeightGlobal(const LLVector3d& v) const -{ - 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; - - -} - -LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const -{ -// 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| -// ----+---+---+---+---+----- -// 8 | 8 | 9 | 10| 11| 11 -// ----+---+---+---+---+----- -// 4 | 4 | 5 | 6 | 7 | 7 -// ----+---+---+---+---+----- -// | 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]); -} - - -LLSurfacePatch *LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const -{ - 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); -} - - -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; -} - - -// ---------------- LLSurface:: Protected ---------------- - -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); - } - } -} - - -void LLSurface::destroyPatchData() -{ - // Delete all of the cached patch data for these patches. - - delete [] mPatchList; - mPatchList = NULL; - mVisiblePatchCount = 0; -} - - -void LLSurface::setTextureSize(const S32 texture_size) -{ - sTextureSize = texture_size; -} - - -U32 LLSurface::getRenderLevel(const U32 render_stride) const -{ - return mPVArray.mRenderLevelp[render_stride]; -} - - -U32 LLSurface::getRenderStride(const U32 render_level) const -{ - 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; -} - - -void LLSurface::dirtyAllPatches() -{ - 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); -} - - -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; - } -} - -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; - } -} - - -bool LLSurface::generateWaterTexture(const F32 x, const F32 y, - 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; -} +/**
+ * @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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llsurface.h"
+
+#include "llrender.h"
+
+#include "llviewertexturelist.h"
+#include "llpatchvertexarray.h"
+#include "patch_dct.h"
+#include "patch_code.h"
+#include "llbitpack.h"
+#include "llviewerobjectlist.h"
+#include "llregionhandle.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llappviewer.h"
+#include "llworld.h"
+#include "llviewercontrol.h"
+#include "llviewertexture.h"
+#include "llsurfacepatch.h"
+#include "llvosurfacepatch.h"
+#include "llvowater.h"
+#include "pipeline.h"
+#include "llviewerregion.h"
+#include "llvlcomposition.h"
+#include "noise.h"
+#include "llviewercamera.h"
+#include "llglheaders.h"
+#include "lldrawpoolterrain.h"
+#include "lldrawable.h"
+
+extern LLPipeline gPipeline;
+extern bool gShiftFrame;
+
+LLColor4U MAX_WATER_COLOR(0, 48, 96, 240);
+
+
+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)
+{
+ // Surface data
+ mSurfaceZ = NULL;
+ mNorm = NULL;
+
+ // Patch data
+ mPatchList = NULL;
+
+ // One of each for each camera
+ mVisiblePatchCount = 0;
+
+ mHasZData = false;
+ // "uninitialized" min/max z
+ mMinZ = 10000.f;
+ mMaxZ = -10000.f;
+
+ mWaterObjp = NULL;
+
+ // In here temporarily.
+ mSurfacePatchUpdateCount = 0;
+
+ 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;
+ }
+}
+
+void LLSurface::initClasses()
+{
+}
+
+void LLSurface::setRegion(LLViewerRegion *regionp)
+{
+ 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
+void LLSurface::create(const S32 grids_per_edge,
+ 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);
+ }
+
+
+ mVisiblePatchCount = 0;
+
+
+ ///////////////////////
+ //
+ // Initialize textures
+ //
+
+ initTextures();
+
+ // Has to be done after texture initialization
+ createPatchData();
+}
+
+LLViewerTexture* LLSurface::getSTexture()
+{
+ if (mSTexturep.notNull() && !mSTexturep->hasGLTexture())
+ {
+ createSTexture();
+ }
+ return mSTexturep;
+}
+
+LLViewerTexture* LLSurface::getWaterTexture()
+{
+ 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);
+ }
+}
+
+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);
+ }
+}
+
+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);
+ }
+}
+
+
+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);
+ }
+}
+
+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() );
+ }
+ }
+}
+
+
+void LLSurface::getNeighboringRegionsStatus( std::vector<S32>& regions )
+{
+ 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);
+ }
+ }
+}
+
+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);
+ }
+}
+
+
+void LLSurface::disconnectAllNeighbors()
+{
+ 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;
+}
+
+LLVector3 LLSurface::getOriginAgent() const
+{
+ return gAgent.getPosAgentFromGlobal(mOriginGlobal);
+}
+
+F32 LLSurface::getMetersPerGrid() const
+{
+ return mMetersPerGrid;
+}
+
+S32 LLSurface::getGridsPerEdge() const
+{
+ return mGridsPerEdge;
+}
+
+S32 LLSurface::getPatchesPerEdge() const
+{
+ return mPatchesPerEdge;
+}
+
+S32 LLSurface::getGridsPerPatchEdge() const
+{
+ 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;
+}
+
+
+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);
+ }
+ }
+}
+
+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();
+ 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)
+ {
+ // some patches changed, update region reflection probes
+ mRegionp->updateReflectionProbes();
+ }
+
+ return did_update;
+}
+
+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();
+ }
+}
+
+
+// Retrurns true if "position" is within the bounds of surface.
+// "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;
+}
+
+
+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 LLSurface::resolveHeightGlobal(const LLVector3d& v) const
+{
+ 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;
+
+
+}
+
+LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const
+{
+// 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|
+// ----+---+---+---+---+-----
+// 8 | 8 | 9 | 10| 11| 11
+// ----+---+---+---+---+-----
+// 4 | 4 | 5 | 6 | 7 | 7
+// ----+---+---+---+---+-----
+// | 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]);
+}
+
+
+LLSurfacePatch *LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const
+{
+ 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);
+}
+
+
+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;
+}
+
+
+// ---------------- LLSurface:: Protected ----------------
+
+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);
+ }
+ }
+}
+
+
+void LLSurface::destroyPatchData()
+{
+ // Delete all of the cached patch data for these patches.
+
+ delete [] mPatchList;
+ mPatchList = NULL;
+ mVisiblePatchCount = 0;
+}
+
+
+void LLSurface::setTextureSize(const S32 texture_size)
+{
+ sTextureSize = texture_size;
+}
+
+
+U32 LLSurface::getRenderLevel(const U32 render_stride) const
+{
+ return mPVArray.mRenderLevelp[render_stride];
+}
+
+
+U32 LLSurface::getRenderStride(const U32 render_level) const
+{
+ 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;
+}
+
+
+void LLSurface::dirtyAllPatches()
+{
+ 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);
+}
+
+
+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;
+ }
+}
+
+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;
+ }
+}
+
+
+bool LLSurface::generateWaterTexture(const F32 x, const F32 y,
+ 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;
+}
|