Port of SNOW-643 : Water flicker at high altitude. This doesn't fix the low altitude flicker though (STORM-306)

meow-7.2.2
Merov Linden 2010-09-30 22:57:05 -07:00
parent df67c34b42
commit c7b6ebaf76
28 changed files with 448 additions and 159 deletions

View File

@ -610,41 +610,46 @@ void LLGLManager::shutdownGL()
void LLGLManager::initExtensions()
{
#if LL_MESA_HEADLESS
# if GL_ARB_multitexture
# ifdef GL_ARB_multitexture
mHasMultitexture = TRUE;
# else
mHasMultitexture = FALSE;
# endif
# if GL_ARB_texture_env_combine
# ifdef GL_ARB_texture_env_combine
mHasARBEnvCombine = TRUE;
# else
mHasARBEnvCombine = FALSE;
# endif
# if GL_ARB_texture_compression
# ifdef GL_ARB_texture_compression
mHasCompressedTextures = TRUE;
# else
mHasCompressedTextures = FALSE;
# endif
# if GL_ARB_vertex_buffer_object
# ifdef GL_ARB_vertex_buffer_object
mHasVertexBufferObject = TRUE;
# else
mHasVertexBufferObject = FALSE;
# endif
# if GL_EXT_framebuffer_object
# ifdef GL_EXT_framebuffer_object
mHasFramebufferObject = TRUE;
# else
mHasFramebufferObject = FALSE;
# endif
# if GL_EXT_framebuffer_multisample
# ifdef GL_EXT_framebuffer_multisample
mHasFramebufferMultisample = TRUE;
# else
mHasFramebufferMultisample = FALSE;
# endif
# if GL_ARB_draw_buffers
# ifdef GL_ARB_draw_buffers
mHasDrawBuffers = TRUE;
#else
mHasDrawBuffers = FALSE;
# endif
# if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
mHasDepthClamp = TRUE;
#else
mHasDepthClamp = FALSE;
#endif
# if GL_EXT_blend_func_separate
mHasBlendFuncSeparate = TRUE;
#else
@ -671,6 +676,7 @@ void LLGLManager::initExtensions()
mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)
&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
@ -694,6 +700,7 @@ void LLGLManager::initExtensions()
if (getenv("LL_GL_NOEXT"))
{
//mHasMultitexture = FALSE; // NEEDED!
mHasDepthClamp = FALSE;
mHasARBEnvCombine = FALSE;
mHasCompressedTextures = FALSE;
mHasVertexBufferObject = FALSE;
@ -755,6 +762,7 @@ void LLGLManager::initExtensions()
if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;
if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE;
if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S
if (strchr(blacklist,'v')) mHasDepthClamp = FALSE;
}
#endif // LL_LINUX || LL_SOLARIS
@ -2037,7 +2045,7 @@ void LLGLDepthTest::checkState()
}
}
LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P)
{
for (U32 i = 0; i < 4; i++)
{
@ -2050,7 +2058,7 @@ LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
glMatrixMode(GL_MODELVIEW);
}
LLGLClampToFarClip::~LLGLClampToFarClip()
LLGLSquashToFarClip::~LLGLSquashToFarClip()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();

View File

@ -92,6 +92,7 @@ public:
BOOL mHasOcclusionQuery;
BOOL mHasPointParameters;
BOOL mHasDrawBuffers;
BOOL mHasDepthClamp;
BOOL mHasTextureRectangle;
// Other extensions.
@ -315,11 +316,11 @@ private:
leaves this class.
Does not stack.
*/
class LLGLClampToFarClip
class LLGLSquashToFarClip
{
public:
LLGLClampToFarClip(glh::matrix4f projection);
~LLGLClampToFarClip();
LLGLSquashToFarClip(glh::matrix4f projection);
~LLGLSquashToFarClip();
};
/*

View File

@ -829,5 +829,15 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
#endif // LL_MESA / LL_WINDOWS / LL_DARWIN
// Even when GL_ARB_depth_clamp is available in the driver, the (correct)
// headers, and therefore GL_DEPTH_CLAMP might not be defined.
// In that case GL_DEPTH_CLAMP_NV should be defined, but why not just
// use the known numeric.
//
// To avoid #ifdef's in the code. Just define this here.
#ifndef GL_DEPTH_CLAMP
// Probably (still) called GL_DEPTH_CLAMP_NV.
#define GL_DEPTH_CLAMP 0x864F
#endif
#endif // LL_LLGLHEADERS_H

View File

@ -358,6 +358,7 @@ void LLDrawable::makeActive()
{
U32 pcode = mVObjp->getPCode();
if (pcode == LLViewerObject::LL_VO_WATER ||
pcode == LLViewerObject::LL_VO_VOID_WATER ||
pcode == LLViewerObject::LL_VO_SURFACE_PATCH ||
pcode == LLViewerObject::LL_VO_PART_GROUP ||
pcode == LLViewerObject::LL_VO_HUD_PART_GROUP ||

View File

@ -89,6 +89,7 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
case POOL_SKY:
poolp = new LLDrawPoolSky();
break;
case POOL_VOIDWATER:
case POOL_WATER:
poolp = new LLDrawPoolWater();
break;

View File

@ -57,6 +57,7 @@ public:
POOL_BUMP,
POOL_INVISIBLE, // see below *
POOL_AVATAR,
POOL_VOIDWATER,
POOL_WATER,
POOL_GLOW,
POOL_ALPHA,

View File

@ -68,7 +68,7 @@ void LLDrawPoolGround::render(S32 pass)
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
LLGLClampToFarClip far_clip(glh_get_current_projection());
LLGLSquashToFarClip far_clip(glh_get_current_projection());
F32 water_height = gAgent.getRegion()->getWaterHeight();
glPushMatrix();

View File

@ -97,7 +97,7 @@ void LLDrawPoolSky::render(S32 pass)
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
LLGLClampToFarClip far_clip(glh_get_current_projection());
LLGLSquashToFarClip far_clip(glh_get_current_projection());
LLGLEnable fog_enable( (mVertexShaderLevel < 1 && LLViewerCamera::getInstance()->cameraUnderWater()) ? GL_FOG : 0);

View File

@ -532,6 +532,7 @@ void LLDrawPoolWater::shade()
glColor4fv(water_color.mV);
{
LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
LLGLDisable cullface(GL_CULL_FACE);
for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
@ -548,30 +549,19 @@ void LLDrawPoolWater::shade()
sNeedsReflectionUpdate = TRUE;
if (water->getUseTexture())
if (water->getUseTexture() || !water->getIsEdgePatch())
{
sNeedsDistortionUpdate = TRUE;
face->renderIndexed();
}
else if (gGLManager.mHasDepthClamp || deferred_render)
{
face->renderIndexed();
}
else
{ //smash background faces to far clip plane
if (water->getIsEdgePatch())
{
if (deferred_render)
{
face->renderIndexed();
}
else
{
LLGLClampToFarClip far_clip(glh_get_current_projection());
face->renderIndexed();
}
}
else
{
sNeedsDistortionUpdate = TRUE;
face->renderIndexed();
}
{
LLGLSquashToFarClip far_clip(glh_get_current_projection());
face->renderIndexed();
}
}
}

View File

@ -260,7 +260,7 @@ void LLDrawPoolWLSky::render(S32 pass)
LLGLDepthTest depth(GL_TRUE, GL_FALSE);
LLGLDisable clip(GL_CLIP_PLANE0);
LLGLClampToFarClip far_clip(glh_get_current_projection());
LLGLSquashToFarClip far_clip(glh_get_current_projection());
renderSkyHaze(camHeightLocal);

View File

@ -210,13 +210,6 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg)
llassert(msg);
if (!msg) return;
LLHost host = msg->getSender();
if (host != gAgent.getRegionHost())
{
// update is for a different region than the one we're in
return;
}
//const S32 SIM_NAME_BUF = 256;
U32 region_flags;
U8 sim_access;
@ -234,6 +227,8 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg)
S32 redirect_grid_y;
LLUUID cache_id;
LLHost host = msg->getSender();
msg->getStringFast(_PREHASH_RegionInfo, _PREHASH_SimName, sim_name);
msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_EstateID, estate_id);
msg->getU32Fast(_PREHASH_RegionInfo, _PREHASH_ParentEstateID, parent_estate_id);
@ -243,6 +238,15 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg)
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_ObjectBonusFactor, object_bonus_factor);
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_BillableFactor, billable_factor);
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_WaterHeight, water_height);
if (host != gAgent.getRegionHost())
{
// Update is for a different region than the one we're in.
// Just check for a waterheight change.
LLWorld::getInstance()->waterHeightRegionInfo(sim_name, water_height);
return;
}
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainRaiseLimit, terrain_raise_limit);
msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainLowerLimit, terrain_lower_limit);
msg->getS32Fast(_PREHASH_RegionInfo, _PREHASH_PricePerMeter, price_per_meter);

View File

@ -1555,7 +1555,9 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
{
if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
{
if (earlyFail(camera, this))
// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
if ((mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER && !gGLManager.mHasDepthClamp) ||
earlyFail(camera, this))
{
setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
assert_states_valid(this);
@ -1576,7 +1578,18 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
{
buildOcclusion();
}
// Depth clamp all water to avoid it being culled as a result of being
// behind the far clip plane, and in the case of edge water to avoid
// it being culled while still visible.
bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||
mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
if (use_depth_clamp)
{
glEnable(GL_DEPTH_CLAMP);
}
glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
if (camera->getOrigin().isExactlyZero())
@ -1592,6 +1605,11 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
}
glEndQueryARB(GL_SAMPLES_PASSED_ARB);
if (use_depth_clamp)
{
glDisable(GL_DEPTH_CLAMP);
}
}
setOcclusionState(LLSpatialGroup::QUERY_PENDING);
@ -2591,9 +2609,10 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
gGL.color4f(0.5f,0.5f,0.5f,1.0f);
break;
case LLViewerObject::LL_VO_PART_GROUP:
case LLViewerObject::LL_VO_HUD_PART_GROUP:
case LLViewerObject::LL_VO_HUD_PART_GROUP:
gGL.color4f(0,0,1,1);
break;
case LLViewerObject::LL_VO_VOID_WATER:
case LLViewerObject::LL_VO_WATER:
gGL.color4f(0,0.5f,1,1);
break;

View File

@ -551,6 +551,13 @@ public:
virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }
};
//spatial partition for hole and edge water (implemented in LLVOWater.cpp)
class LLVoidWaterPartition : public LLWaterPartition
{
public:
LLVoidWaterPartition();
};
//spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp)
class LLTerrainPartition : public LLSpatialPartition
{

View File

@ -1162,8 +1162,13 @@ 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
{

View File

@ -573,7 +573,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
S32 water_clip = 0;
if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER))
(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||
gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
{
if (LLViewerCamera::getInstance()->cameraUnderWater())
{

View File

@ -167,8 +167,10 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
res = new LLVOSurfacePatch(id, pcode, regionp); break;
case LL_VO_SKY:
res = new LLVOSky(id, pcode, regionp); break;
case LL_VO_VOID_WATER:
res = new LLVOVoidWater(id, pcode, regionp); break;
case LL_VO_WATER:
res = new LLVOWater(id, pcode, regionp); break;
res = new LLVOWater(id, pcode, regionp); break;
case LL_VO_GROUND:
res = new LLVOGround(id, pcode, regionp); break;
case LL_VO_PART_GROUP:

View File

@ -131,7 +131,7 @@ public:
typedef const child_list_t const_child_list_t;
LLViewerObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp, BOOL is_global = FALSE);
LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global = FALSE);
MEM_TYPE_NEW(LLMemType::MTYPE_OBJECT);
virtual void markDead(); // Mark this object as dead, and clean up its references
@ -518,14 +518,14 @@ public:
{
LL_VO_CLOUDS = LL_PCODE_APP | 0x20,
LL_VO_SURFACE_PATCH = LL_PCODE_APP | 0x30,
//LL_VO_STARS = LL_PCODE_APP | 0x40,
LL_VO_WL_SKY = LL_PCODE_APP | 0x40,
LL_VO_SQUARE_TORUS = LL_PCODE_APP | 0x50,
LL_VO_SKY = LL_PCODE_APP | 0x60,
LL_VO_WATER = LL_PCODE_APP | 0x70,
LL_VO_GROUND = LL_PCODE_APP | 0x80,
LL_VO_PART_GROUP = LL_PCODE_APP | 0x90,
LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xa0,
LL_VO_WL_SKY = LL_PCODE_APP | 0xb0, // should this be moved to 0x40?
LL_VO_VOID_WATER = LL_PCODE_APP | 0x70,
LL_VO_WATER = LL_PCODE_APP | 0x80,
LL_VO_GROUND = LL_PCODE_APP | 0x90,
LL_VO_PART_GROUP = LL_PCODE_APP | 0xa0,
LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xb0,
LL_VO_HUD_PART_GROUP = LL_PCODE_APP | 0xc0,
} EVOType;
@ -717,8 +717,8 @@ public:
class LLAlphaObject : public LLViewerObject
{
public:
LLAlphaObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp)
: LLViewerObject(id,type,regionp)
LLAlphaObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
: LLViewerObject(id,pcode,regionp)
{ mDepth = 0.f; }
virtual F32 getPartSize(S32 idx);
@ -735,8 +735,8 @@ public:
class LLStaticViewerObject : public LLViewerObject
{
public:
LLStaticViewerObject(const LLUUID& id, const LLPCode type, LLViewerRegion* regionp, BOOL is_global = FALSE)
: LLViewerObject(id,type,regionp, is_global)
LLStaticViewerObject(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp, BOOL is_global = FALSE)
: LLViewerObject(id,pcode,regionp, is_global)
{ }
virtual void updateDrawable(BOOL force_damped);

View File

@ -261,6 +261,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
//MUST MATCH declaration of eObjectPartitions
mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD
mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN
mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER
mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER
mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE
mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE

View File

@ -73,6 +73,7 @@ public:
{
PARTITION_HUD=0,
PARTITION_TERRAIN,
PARTITION_VOIDWATER,
PARTITION_WATER,
PARTITION_TREE,
PARTITION_PARTICLE,

View File

@ -335,8 +335,8 @@ void LLViewerShaderMgr::setShaders()
}
else
{
LLPipeline::sRenderGlow =
LLPipeline::sWaterReflections = FALSE;
LLPipeline::sRenderGlow = FALSE;
LLPipeline::sWaterReflections = FALSE;
}
//hack to reset buffers that change behavior with shaders

View File

@ -1406,6 +1406,11 @@ LLViewerWindow::LLViewerWindow(
gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
}
if (!gGLManager.mHasDepthClamp)
{
LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL;
}
// If we crashed while initializng GL stuff last time, disable certain features
if (gSavedSettings.getBOOL("RenderInitError"))
{

View File

@ -80,7 +80,7 @@ public:
//============================================================================
LLVOSurfacePatch::LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
: LLStaticViewerObject(id, LL_VO_SURFACE_PATCH, regionp),
: LLStaticViewerObject(id, pcode, regionp),
mDirtiedPatch(FALSE),
mPool(NULL),
mBaseComp(0),

View File

@ -61,7 +61,8 @@ const F32 WAVE_STEP_INV = (1. / WAVE_STEP);
LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
: LLStaticViewerObject(id, LL_VO_WATER, regionp)
: LLStaticViewerObject(id, pcode, regionp),
mRenderType(LLPipeline::RENDER_TYPE_WATER)
{
// Terrain must draw during selection passes so it can block objects behind it.
mbCanSelect = FALSE;
@ -114,7 +115,7 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline)
{
pipeline->allocDrawable(this);
mDrawable->setLit(FALSE);
mDrawable->setRenderType(LLPipeline::RENDER_TYPE_WATER);
mDrawable->setRenderType(mRenderType);
LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
@ -268,6 +269,11 @@ U32 LLVOWater::getPartitionType() const
return LLViewerRegion::PARTITION_WATER;
}
U32 LLVOVoidWater::getPartitionType() const
{
return LLViewerRegion::PARTITION_VOIDWATER;
}
LLWaterPartition::LLWaterPartition()
: LLSpatialPartition(0, FALSE, 0)
{
@ -275,3 +281,9 @@ LLWaterPartition::LLWaterPartition()
mDrawableType = LLPipeline::RENDER_TYPE_WATER;
mPartitionType = LLViewerRegion::PARTITION_WATER;
}
LLVoidWaterPartition::LLVoidWaterPartition()
{
mDrawableType = LLPipeline::RENDER_TYPE_VOIDWATER;
mPartitionType = LLViewerRegion::PARTITION_VOIDWATER;
}

View File

@ -29,6 +29,7 @@
#include "llviewerobject.h"
#include "llviewertexture.h"
#include "pipeline.h"
#include "v2math.h"
const U32 N_RES = 16; //32 // number of subdivisions of wave tile
@ -77,6 +78,19 @@ public:
protected:
BOOL mUseTexture;
BOOL mIsEdgePatch;
S32 mRenderType;
};
class LLVOVoidWater : public LLVOWater
{
public:
LLVOVoidWater(LLUUID const& id, LLPCode pcode, LLViewerRegion* regionp) : LLVOWater(id, pcode, regionp)
{
mRenderType = LLPipeline::RENDER_TYPE_VOIDWATER;
}
/*virtual*/ U32 getPartitionType() const;
};
#endif // LL_VOSURFACEPATCH_H

View File

@ -55,6 +55,11 @@
#include "pipeline.h"
#include "llappviewer.h" // for do_disconnect()
#include <deque>
#include <queue>
#include <map>
#include <cstring>
//
// Globals
//
@ -834,10 +839,69 @@ F32 LLWorld::getLandFarClip() const
void LLWorld::setLandFarClip(const F32 far_clip)
{
static S32 const rwidth = (S32)REGION_WIDTH_U32;
S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
S32 const n2 = (llceil(far_clip) - 1) / rwidth;
bool need_water_objects_update = n1 != n2;
mLandFarClip = far_clip;
if (need_water_objects_update)
{
updateWaterObjects();
}
}
// Some region that we're connected to, but not the one we're in, gave us
// a (possibly) new water height. Update it in our local copy.
void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height)
{
for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
{
if ((*iter)->getName() == sim_name)
{
(*iter)->setWaterHeight(water_height);
break;
}
}
}
// There are three types of water objects:
// Region water objects: the water in a region.
// Hole water objects: water in the void but within current draw distance.
// Edge water objects: the water outside the draw distance, up till the horizon.
//
// For example:
//
// -----------------------horizon-------------------------
// | | | |
// | Edge Water | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | rwidth | |
// | | <-----> | |
// -------------------------------------------------------
// | |Hole |other| | |
// | |Water|reg. | | |
// | |-----------------| |
// | |other|cur. |<--> | |
// | |reg. | reg.| \__|_ draw distance |
// | |-----------------| |
// | | | |<--->| |
// | | | | \__|_ range |
// -------------------------------------------------------
// | |<----width------>|<--horizon ext.->|
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// -------------------------------------------------------
//
void LLWorld::updateWaterObjects()
{
if (!gAgent.getRegion())
@ -850,128 +914,265 @@ void LLWorld::updateWaterObjects()
return;
}
// First, determine the min and max "box" of water objects
S32 min_x = 0;
S32 min_y = 0;
S32 max_x = 0;
S32 max_y = 0;
// Region width in meters.
S32 const rwidth = (S32)REGION_WIDTH_U32;
// The distance we might see into the void
// when standing on the edge of a region, in meters.
S32 const draw_distance = llceil(mLandFarClip);
// We can only have "holes" in the water (where there no region) if we
// can have existing regions around it. Taking into account that this
// code is only executed when we enter a region, and not when we walk
// around in it, we (only) need to take into account regions that fall
// within the draw_distance.
//
// Set 'range' to draw_distance, rounded up to the nearest multiple of rwidth.
S32 const nsims = (draw_distance + rwidth - 1) / rwidth;
S32 const range = nsims * rwidth;
// Get South-West corner of current region.
LLViewerRegion const* regionp = gAgent.getRegion();
U32 region_x, region_y;
S32 rwidth = 256;
// We only want to fill in water for stuff that's near us, say, within 256 or 512m
S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256;
LLViewerRegion* regionp = gAgent.getRegion();
from_region_handle(regionp->getHandle(), &region_x, &region_y);
min_x = (S32)region_x - range;
min_y = (S32)region_y - range;
max_x = (S32)region_x + range;
max_y = (S32)region_y + range;
// The min. and max. coordinates of the South-West corners of the Hole water objects.
S32 const min_x = (S32)region_x - range;
S32 const min_y = (S32)region_y - range;
S32 const max_x = (S32)region_x + range;
S32 const max_y = (S32)region_y + range;
F32 height = 0.f;
for (region_list_t::iterator iter = mRegionList.begin();
iter != mRegionList.end(); ++iter)
// Attempt to determine a sensible water height for all the
// Hole Water objects.
//
// It make little sense to try to guess what the best water
// height should be when that isn't completely obvious: if it's
// impossible to satisfy every region's water height without
// getting a jump in the water height.
//
// In order to keep the reasoning simple, we assume something
// logical as a group of connected regions, where the coastline
// is at the outer edge. Anything more complex that would "break"
// under such an assumption would probably break anyway (would
// depend on terrain editing and existing mega prims, say, if
// anything would make sense at all).
//
// So, what we do is find all connected regions within the
// draw distance that border void, and then pick the lowest
// water height of those (coast) regions.
S32 const n = 2 * nsims + 1;
S32 const origin = nsims + nsims * n;
std::vector<F32> water_heights(n * n);
std::vector<U8> checked(n * n, 0); // index = nx + ny * n + origin;
U8 const region_bit = 1;
U8 const hole_bit = 2;
U8 const bordering_hole_bit = 4;
U8 const bordering_edge_bit = 8;
// Use the legacy waterheight for the Edge water in the case
// that we don't find any Hole water at all.
F32 water_height = DEFAULT_WATER_HEIGHT;
int max_count = 0;
LL_DEBUGS("WaterHeight") << "Current region: " << regionp->getName() << "; water height: " << regionp->getWaterHeight() << " m." << LL_ENDL;
std::map<S32, int> water_height_counts;
typedef std::queue<std::pair<S32, S32>, std::deque<std::pair<S32, S32> > > nxny_pairs_type;
nxny_pairs_type nxny_pairs;
nxny_pairs.push(nxny_pairs_type::value_type(0, 0));
water_heights[origin] = regionp->getWaterHeight();
checked[origin] = region_bit;
// For debugging purposes.
int number_of_connected_regions = 1;
int uninitialized_regions = 0;
int bordering_hole = 0;
int bordering_edge = 0;
while(!nxny_pairs.empty())
{
S32 const nx = nxny_pairs.front().first;
S32 const ny = nxny_pairs.front().second;
LL_DEBUGS("WaterHeight") << "nx,ny = " << nx << "," << ny << LL_ENDL;
S32 const index = nx + ny * n + origin;
nxny_pairs.pop();
for (S32 dir = 0; dir < 4; ++dir)
{
S32 const cnx = nx + gDirAxes[dir][0];
S32 const cny = ny + gDirAxes[dir][1];
LL_DEBUGS("WaterHeight") << "dir = " << dir << "; cnx,cny = " << cnx << "," << cny << LL_ENDL;
S32 const cindex = cnx + cny * n + origin;
bool is_hole = false;
bool is_edge = false;
LLViewerRegion* new_region_found = NULL;
if (cnx < -nsims || cnx > nsims ||
cny < -nsims || cny > nsims)
{
LL_DEBUGS("WaterHeight") << " Edge Water!" << LL_ENDL;
// Bumped into Edge water object.
is_edge = true;
}
else if (checked[cindex])
{
LL_DEBUGS("WaterHeight") << " Already checked before!" << LL_ENDL;
// Already checked.
is_hole = (checked[cindex] & hole_bit);
}
else
{
S32 x = (S32)region_x + cnx * rwidth;
S32 y = (S32)region_y + cny * rwidth;
U64 region_handle = to_region_handle(x, y);
new_region_found = getRegionFromHandle(region_handle);
is_hole = !new_region_found;
checked[cindex] = is_hole ? hole_bit : region_bit;
}
if (is_hole)
{
// This was a region that borders at least one 'hole'.
// Count the found coastline.
F32 new_water_height = water_heights[index];
LL_DEBUGS("WaterHeight") << " This is void; counting coastline with water height of " << new_water_height << LL_ENDL;
S32 new_water_height_cm = llround(new_water_height * 100);
int count = (water_height_counts[new_water_height_cm] += 1);
// Just use the lowest water height: this is mainly about the horizon water,
// and whatever we do, we don't want it to be possible to look under the water
// when looking in the distance: it is better to make a step downwards in water
// height when going away from the avie than a step upwards. However, since
// everyone is used to DEFAULT_WATER_HEIGHT, don't allow a single region
// to drag the water level below DEFAULT_WATER_HEIGHT on it's own.
if (bordering_hole == 0 || // First time we get here.
(new_water_height >= DEFAULT_WATER_HEIGHT &&
new_water_height < water_height) ||
(new_water_height < DEFAULT_WATER_HEIGHT &&
count > max_count)
)
{
water_height = new_water_height;
}
if (count > max_count)
{
max_count = count;
}
if (!(checked[index] & bordering_hole_bit))
{
checked[index] |= bordering_hole_bit;
++bordering_hole;
}
}
else if (is_edge && !(checked[index] & bordering_edge_bit))
{
checked[index] |= bordering_edge_bit;
++bordering_edge;
}
if (!new_region_found)
{
// Dead end, there is no region here.
continue;
}
// Found a new connected region.
++number_of_connected_regions;
if (new_region_found->getName().empty())
{
// Uninitialized LLViewerRegion, don't use it's water height.
LL_DEBUGS("WaterHeight") << " Uninitialized region." << LL_ENDL;
++uninitialized_regions;
continue;
}
nxny_pairs.push(nxny_pairs_type::value_type(cnx, cny));
water_heights[cindex] = new_region_found->getWaterHeight();
LL_DEBUGS("WaterHeight") << " Found a new region (name: " << new_region_found->getName() << "; water height: " << water_heights[cindex] << " m)!" << LL_ENDL;
}
}
llinfos << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions <<
" uninitialized); number of regions bordering Hole water: " << bordering_hole <<
"; number of regions bordering Edge water: " << bordering_edge << llendl;
llinfos << "Coastline count (height, count): ";
bool first = true;
for (std::map<S32, int>::iterator iter = water_height_counts.begin(); iter != water_height_counts.end(); ++iter)
{
if (!first) llcont << ", ";
llcont << "(" << (iter->first / 100.f) << ", " << iter->second << ")";
first = false;
}
llcont << llendl;
llinfos << "Water height used for Hole and Edge water objects: " << water_height << llendl;
// Update all Region water objects.
for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
{
LLViewerRegion* regionp = *iter;
LLVOWater* waterp = regionp->getLand().getWaterObj();
height += regionp->getWaterHeight();
if (waterp)
{
gObjectList.updateActive(waterp);
}
}
// Clean up all existing Hole water objects.
for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin();
iter != mHoleWaterObjects.end(); ++ iter)
iter != mHoleWaterObjects.end(); ++iter)
{
LLVOWater* waterp = *iter;
gObjectList.killObject(waterp);
}
mHoleWaterObjects.clear();
// Now, get a list of the holes
S32 x, y;
for (x = min_x; x <= max_x; x += rwidth)
// Let the Edge and Hole water boxes be 1024 meter high so that they
// are never too small to be drawn (A LL_VO_*_WATER box has water
// rendered on it's bottom surface only), and put their bottom at
// the current regions water height.
F32 const box_height = 1024;
F32 const water_center_z = water_height + box_height / 2;
// Create new Hole water objects within 'range' where there is no region.
for (S32 x = min_x; x <= max_x; x += rwidth)
{
for (y = min_y; y <= max_y; y += rwidth)
for (S32 y = min_y; y <= max_y; y += rwidth)
{
U64 region_handle = to_region_handle(x, y);
if (!getRegionFromHandle(region_handle))
{
LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
LLVOWater* waterp = (LLVOWater*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion());
waterp->setUseTexture(FALSE);
waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
y + rwidth/2,
256.f+DEFAULT_WATER_HEIGHT));
waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
waterp->setPositionGlobal(LLVector3d(x + rwidth / 2, y + rwidth / 2, water_center_z));
waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, box_height));
gPipeline.createObject(waterp);
mHoleWaterObjects.push_back(waterp);
}
}
}
// Update edge water objects
S32 wx, wy;
S32 center_x, center_y;
wx = (max_x - min_x) + rwidth;
wy = (max_y - min_y) + rwidth;
center_x = min_x + (wx >> 1);
center_y = min_y + (wy >> 1);
S32 add_boundary[4] = {
512 - (max_x - region_x),
512 - (max_y - region_y),
512 - (region_x - min_x),
512 - (region_y - min_y) };
// Center of the region.
S32 const center_x = region_x + rwidth / 2;
S32 const center_y = region_y + rwidth / 2;
// Width of the area with Hole water objects.
S32 const width = rwidth + 2 * range;
S32 const horizon_extend = 2048 + 512 - range; // Legacy value.
// The overlap is needed to get rid of sky pixels being visible between the
// Edge and Hole water object at greater distances (due to floating point
// round off errors).
S32 const edge_hole_overlap = 1; // Twice the actual overlap.
S32 dir;
for (dir = 0; dir < 8; dir++)
for (S32 dir = 0; dir < 8; ++dir)
{
S32 dim[2] = { 0 };
switch (gDirAxes[dir][0])
{
case -1: dim[0] = add_boundary[2]; break;
case 0: dim[0] = wx; break;
default: dim[0] = add_boundary[0]; break;
}
switch (gDirAxes[dir][1])
{
case -1: dim[1] = add_boundary[3]; break;
case 0: dim[1] = wy; break;
default: dim[1] = add_boundary[1]; break;
}
// Size of the Edge water objects.
S32 const dim_x = (gDirAxes[dir][0] == 0) ? width : (horizon_extend + edge_hole_overlap);
S32 const dim_y = (gDirAxes[dir][1] == 0) ? width : (horizon_extend + edge_hole_overlap);
// And their position.
S32 const water_center_x = center_x + (width + horizon_extend) / 2 * gDirAxes[dir][0];
S32 const water_center_y = center_y + (width + horizon_extend) / 2 * gDirAxes[dir][1];
// Resize and reshape the water objects
const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]);
const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]);
LLVOWater* waterp = mEdgeWaterObjects[dir];
if (!waterp || waterp->isDead())
{
// The edge water objects can be dead because they're attached to the region that the
// agent was in when they were originally created.
mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER,
gAgent.getRegion());
mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion());
waterp = mEdgeWaterObjects[dir];
waterp->setUseTexture(FALSE);
waterp->setIsEdgePatch(TRUE);
waterp->setIsEdgePatch(TRUE); // Mark that this is edge water and not hole water.
gPipeline.createObject(waterp);
}
waterp->setRegion(gAgent.getRegion());
LLVector3d water_pos(water_center_x, water_center_y,
DEFAULT_WATER_HEIGHT+256.f);
LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
//stretch out to horizon
water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]);
water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]);
water_pos.mdV[0] += 1024.f * gDirAxes[dir][0];
water_pos.mdV[1] += 1024.f * gDirAxes[dir][1];
LLVector3d water_pos(water_center_x, water_center_y, water_center_z);
LLVector3 water_scale((F32) dim_x, (F32) dim_y, box_height);
waterp->setPositionGlobal(water_pos);
waterp->setScale(water_scale);

View File

@ -137,6 +137,7 @@ public:
LLViewerTexture *getDefaultWaterTexture();
void updateWaterObjects();
void waterHeightRegionInfo(std::string const& sim_name, F32 water_height);
void shiftRegions(const LLVector3& offset);
void setSpaceTimeUSec(const U64 space_time_usec);

View File

@ -628,14 +628,14 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
//static
void LLPipeline::updateRenderDeferred()
{
BOOL deferred = (gSavedSettings.getBOOL("RenderDeferred") &&
LLRenderTarget::sUseFBO &&
LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
gSavedSettings.getBOOL("VertexShaderEnable") &&
gSavedSettings.getBOOL("RenderAvatarVP") &&
(gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) &&
!gUseWireframe;
BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") &&
LLRenderTarget::sUseFBO &&
LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
gSavedSettings.getBOOL("VertexShaderEnable") &&
gSavedSettings.getBOOL("RenderAvatarVP") &&
gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) &&
!gUseWireframe;
sRenderDeferred = deferred;
}
@ -1632,20 +1632,14 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
camera.disableUserClipPlane();
if (gSky.mVOSkyp.notNull() && gSky.mVOSkyp->mDrawable.notNull())
if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
gSky.mVOSkyp.notNull() &&
gSky.mVOSkyp->mDrawable.notNull())
{
// Hack for sky - always visible.
if (hasRenderType(LLPipeline::RENDER_TYPE_SKY))
{
gSky.mVOSkyp->mDrawable->setVisible(camera);
sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
gSky.updateCull();
stop_glerror();
}
}
else
{
llinfos << "No sky drawable!" << llendl;
gSky.mVOSkyp->mDrawable->setVisible(camera);
sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
gSky.updateCull();
stop_glerror();
}
if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
@ -2214,6 +2208,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
LLPipeline::RENDER_TYPE_TERRAIN,
LLPipeline::RENDER_TYPE_TREE,
LLPipeline::RENDER_TYPE_SKY,
LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_WATER,
LLPipeline::END_RENDER_TYPES))
{
@ -5005,6 +5000,10 @@ void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
void LLPipeline::toggleRenderType(U32 type)
{
gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
if (type == LLPipeline::RENDER_TYPE_WATER)
{
gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
}
}
//static
@ -7331,6 +7330,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
gPipeline.pushRenderTypeMask();
clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_GROUND,
LLPipeline::RENDER_TYPE_SKY,
LLPipeline::RENDER_TYPE_CLOUDS,
@ -7383,6 +7383,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
{
camera.setFar(camera_in.getFar());
clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_GROUND,
END_RENDER_TYPES);
stop_glerror();
@ -7899,6 +7900,7 @@ void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<L
LLPipeline::RENDER_TYPE_TREE,
LLPipeline::RENDER_TYPE_TERRAIN,
LLPipeline::RENDER_TYPE_WATER,
LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
LLPipeline::RENDER_TYPE_AVATAR,
LLPipeline::RENDER_TYPE_PASS_SIMPLE,
@ -8082,6 +8084,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
LLPipeline::RENDER_TYPE_TREE,
LLPipeline::RENDER_TYPE_TERRAIN,
LLPipeline::RENDER_TYPE_WATER,
LLPipeline::RENDER_TYPE_VOIDWATER,
LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
LLPipeline::RENDER_TYPE_PASS_SIMPLE,
LLPipeline::RENDER_TYPE_PASS_BUMP,

View File

@ -358,6 +358,7 @@ public:
RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR,
RENDER_TYPE_TREE = LLDrawPool::POOL_TREE,
RENDER_TYPE_INVISIBLE = LLDrawPool::POOL_INVISIBLE,
RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER,
RENDER_TYPE_WATER = LLDrawPool::POOL_WATER,
RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA,
RENDER_TYPE_GLOW = LLDrawPool::POOL_GLOW,