summaryrefslogtreecommitdiff
path: root/indra/newview/llspatialpartition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llspatialpartition.cpp')
-rw-r--r--indra/newview/llspatialpartition.cpp1695
1 files changed, 1329 insertions, 366 deletions
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index fb984a7c62..fa329eb0ae 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -32,15 +32,19 @@
#include "llviewerobjectlist.h"
#include "llvovolume.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llviewercamera.h"
#include "llface.h"
#include "llviewercontrol.h"
#include "llviewerregion.h"
#include "llcamera.h"
#include "pipeline.h"
+#include "llmeshrepository.h"
#include "llrender.h"
#include "lloctree.h"
+#include "llphysicsshapebuilderutil.h"
#include "llvoavatar.h"
+#include "llvolumemgr.h"
#include "lltextureatlas.h"
static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
@@ -60,6 +64,12 @@ const F32 SG_OCCLUSION_FUDGE = 0.25f;
static U32 sZombieGroups = 0;
U32 LLSpatialGroup::sNodeCount = 0;
+
+#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
+
+std::set<GLuint> LLSpatialGroup::sPendingQueries;
+
+
BOOL LLSpatialGroup::sNoDelete = FALSE;
static F32 sLastMaxTexPriority = 1.f;
@@ -77,6 +87,9 @@ protected:
virtual void releaseName(GLuint name)
{
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ LLSpatialGroup::sPendingQueries.erase(name);
+#endif
glDeleteQueriesARB(1, &name);
}
};
@@ -95,23 +108,6 @@ void sg_assert(BOOL expr)
#endif
}
-#if LL_DEBUG
-void validate_drawable(LLDrawable* drawablep)
-{
- F64 rad = drawablep->getBinRadius();
- const LLVector3* ext = drawablep->getSpatialExtents();
-
- if (rad < 0 || rad > 4096 ||
- (ext[1]-ext[0]).magVec() > 4096)
- {
- llwarns << "Invalid drawable found in octree." << llendl;
- }
-}
-#else
-#define validate_drawable(x)
-#endif
-
-
S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
{
return AABBSphereIntersectR2(min, max, origin, rad*rad);
@@ -151,6 +147,55 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe
}
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
+{
+ return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
+{
+ F32 d = 0.f;
+ F32 t;
+
+ LLVector4a origina;
+ origina.load3(origin.mV);
+
+ LLVector4a v;
+ v.setSub(min, origina);
+
+ if (v.dot3(v) < r)
+ {
+ v.setSub(max, origina);
+ if (v.dot3(v) < r)
+ {
+ return 2;
+ }
+ }
+
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (origin.mV[i] < min[i])
+ {
+ t = min[i] - origin.mV[i];
+ d += t*t;
+ }
+ else if (origin.mV[i] > max[i])
+ {
+ t = origin.mV[i] - max[i];
+ d += t*t;
+ }
+
+ if (d > r)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
typedef enum
{
b000 = 0x00,
@@ -168,76 +213,113 @@ typedef enum
//gives you a triangle fan index array
static U8 sOcclusionIndices[] =
{
- // 000
+ //000
b111, b110, b010, b011, b001, b101, b100, b110,
- //001
- b110, b000, b010, b011, b111, b101, b100, b000,
+ //001
+ b011, b010, b000, b001, b101, b111, b110, b010,
//010
b101, b100, b110, b111, b011, b001, b000, b100,
//011
- b100, b010, b110, b111, b101, b001, b000, b010,
- //100
- b011, b010, b000, b001, b101, b111, b110, b010,
+ b001, b000, b100, b101, b111, b011, b010, b000,
+ //100
+ b110, b000, b010, b011, b111, b101, b100, b000,
//101
b010, b100, b000, b001, b011, b111, b110, b100,
//110
- b001, b000, b100, b101, b111, b011, b010, b000,
+ b100, b010, b110, b111, b101, b001, b000, b010,
//111
b000, b110, b100, b101, b001, b011, b010, b110,
};
-U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center)
+U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
{
- LLVector3 d = center - camera->getOrigin();
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
- U8 cypher = 0;
- if (d.mV[0] > 0)
- {
- cypher |= b100;
- }
- if (d.mV[1] > 0)
- {
- cypher |= b010;
- }
- if (d.mV[2] > 0)
- {
- cypher |= b001;
- }
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
+ return cypher*8;
+}
+U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
+{
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
+
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
return sOcclusionIndices+cypher*8;
}
-
+
+
+static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
+
void LLSpatialGroup::buildOcclusion()
{
- if (!mOcclusionVerts)
+ if (mOcclusionVerts.isNull())
{
- mOcclusionVerts = new F32[8*3];
+
+ mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX,
+ LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
+ mOcclusionVerts->allocateBuffer(8, 64, true);
+
+ LLStrider<U16> idx;
+ mOcclusionVerts->getIndexStrider(idx);
+ for (U32 i = 0; i < 64; i++)
+ {
+ *idx++ = sOcclusionIndices[i];
+ }
}
- LLVector3 r = mBounds[1] + LLVector3(SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE);
+ LLVector4a fudge;
+ fudge.splat(SG_OCCLUSION_FUDGE);
+
+ LLVector4a r;
+ r.setAdd(mBounds[1], fudge);
- for (U32 k = 0; k < 3; k++)
+ LLStrider<LLVector3> pos;
+
{
- r.mV[k] = llmin(mBounds[1].mV[k]+0.25f, r.mV[k]);
+ LLFastTimer t(FTM_BUILD_OCCLUSION);
+ mOcclusionVerts->getVertexStrider(pos);
}
- F32* v = mOcclusionVerts;
- F32* c = mBounds[0].mV;
- F32* s = r.mV;
+ {
+ LLVector4a* v = (LLVector4a*) pos.get();
+
+ const LLVector4a& c = mBounds[0];
+ const LLVector4a& s = r;
+
+ static const LLVector4a octant[] =
+ {
+ LLVector4a(-1.f, -1.f, -1.f),
+ LLVector4a(-1.f, -1.f, 1.f),
+ LLVector4a(-1.f, 1.f, -1.f),
+ LLVector4a(-1.f, 1.f, 1.f),
+
+ LLVector4a(1.f, -1.f, -1.f),
+ LLVector4a(1.f, -1.f, 1.f),
+ LLVector4a(1.f, 1.f, -1.f),
+ LLVector4a(1.f, 1.f, 1.f),
+ };
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ LLVector4a p;
+ p.setMul(s, octant[i]);
+ p.add(c);
+ v[i] = p;
+ }
+ }
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- v[0] = c[0]-s[0]; v[1] = c[1]-s[1]; v[2] = c[2]-s[2]; // 0 - 0000
- v[3] = c[0]-s[0]; v[4] = c[1]-s[1]; v[5] = c[2]+s[2]; // 1 - 0001
- v[6] = c[0]-s[0]; v[7] = c[1]+s[1]; v[8] = c[2]-s[2]; // 2 - 0010
- v[9] = c[0]-s[0]; v[10] = c[1]+s[1]; v[11] = c[2]+s[2]; // 3 - 0011
-
- v[12] = c[0]+s[0]; v[13] = c[1]-s[1]; v[14] = c[2]-s[2]; // 4 - 0100
- v[15] = c[0]+s[0]; v[16] = c[1]-s[1]; v[17] = c[2]+s[2]; // 5 - 0101
- v[18] = c[0]+s[0]; v[19] = c[1]+s[1]; v[20] = c[2]-s[2]; // 6 - 0110
- v[21] = c[0]+s[0]; v[22] = c[1]+s[1]; v[23] = c[2]+s[2]; // 7 - 0111
+ {
+ mOcclusionVerts->setBuffer(0);
+ }
clearState(LLSpatialGroup::OCCLUSION_DIRTY);
}
@@ -281,6 +363,11 @@ LLSpatialGroup::~LLSpatialGroup()
llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
}*/
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
if (isState(DEAD))
{
sZombieGroups--;
@@ -288,12 +375,17 @@ LLSpatialGroup::~LLSpatialGroup()
sNodeCount--;
- if (gGLManager.mHasOcclusionQuery && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ if (gGLManager.mHasOcclusionQuery)
{
- sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
+ {
+ if (mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ }
+ }
}
- delete [] mOcclusionVerts;
mOcclusionVerts = NULL;
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -435,7 +527,7 @@ BOOL LLSpatialGroup::isRecentlyVisible() const
BOOL LLSpatialGroup::isVisible() const
{
- return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE;
+ return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
}
void LLSpatialGroup::setVisible()
@@ -450,8 +542,10 @@ void LLSpatialGroup::validate()
sg_assert(!isState(DIRTY));
sg_assert(!isDead());
- LLVector3 myMin = mBounds[0] - mBounds[1];
- LLVector3 myMax = mBounds[0] + mBounds[1];
+ LLVector4a myMin;
+ myMin.setSub(mBounds[0], mBounds[1]);
+ LLVector4a myMax;
+ myMax.setAdd(mBounds[0], mBounds[1]);
validateDrawMap();
@@ -483,16 +577,18 @@ void LLSpatialGroup::validate()
group->validate();
//ensure all children are enclosed in this node
- LLVector3 center = group->mBounds[0];
- LLVector3 size = group->mBounds[1];
+ LLVector4a center = group->mBounds[0];
+ LLVector4a size = group->mBounds[1];
- LLVector3 min = center - size;
- LLVector3 max = center + size;
+ LLVector4a min;
+ min.setSub(center, size);
+ LLVector4a max;
+ max.setAdd(center, size);
for (U32 j = 0; j < 3; j++)
{
- sg_assert(min.mV[j] >= myMin.mV[j]-0.02f);
- sg_assert(max.mV[j] <= myMax.mV[j]+0.02f);
+ sg_assert(min[j] >= myMin[j]-0.02f);
+ sg_assert(max[j] <= myMax[j]+0.02f);
}
}
@@ -502,52 +598,8 @@ void LLSpatialGroup::validate()
void LLSpatialGroup::checkStates()
{
#if LL_OCTREE_PARANOIA_CHECK
- LLOctreeStateCheck checker;
- checker.traverse(mOctreeNode);
-#endif
-}
-
-void validate_draw_info(LLDrawInfo& params)
-{
-#if LL_OCTREE_PARANOIA_CHECK
- if (params.mVertexBuffer.isNull())
- {
- llerrs << "Draw batch has no vertex buffer." << llendl;
- }
-
- //bad range
- if (params.mStart >= params.mEnd)
- {
- llerrs << "Draw batch has invalid range." << llendl;
- }
-
- if (params.mEnd >= (U32) params.mVertexBuffer->getNumVerts())
- {
- llerrs << "Draw batch has buffer overrun error." << llendl;
- }
-
- if (params.mOffset + params.mCount > (U32) params.mVertexBuffer->getNumIndices())
- {
- llerrs << "Draw batch has index buffer ovverrun error." << llendl;
- }
-
- //bad indices
- U16* indicesp = (U16*) params.mVertexBuffer->getIndicesPointer();
- if (indicesp)
- {
- for (U32 i = params.mOffset; i < params.mOffset+params.mCount; i++)
- {
- if (indicesp[i] < (U16)params.mStart)
- {
- llerrs << "Draw batch has vertex buffer index out of range error (index too low)." << llendl;
- }
-
- if (indicesp[i] > (U16)params.mEnd)
- {
- llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl;
- }
- }
- }
+ //LLOctreeStateCheck checker;
+ //checker.traverse(mOctreeNode);
#endif
}
@@ -560,8 +612,8 @@ void LLSpatialGroup::validateDrawMap()
for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
{
LLDrawInfo& params = **j;
-
- validate_draw_info(params);
+
+ params.validate();
}
}
#endif
@@ -572,19 +624,17 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
drawablep->updateSpatialExtents();
- validate_drawable(drawablep);
OctreeNode* parent = mOctreeNode->getOctParent();
if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&
(mOctreeNode->contains(drawablep) ||
- (drawablep->getBinRadius() > mOctreeNode->getSize().mdV[0] &&
+ (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
{
unbound();
setState(OBJECT_DIRTY);
//setState(GEOM_DIRTY);
- validate_drawable(drawablep);
return TRUE;
}
@@ -602,7 +652,6 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc
else
{
drawablep->setSpatialGroup(this);
- validate_drawable(drawablep);
setState(OBJECT_DIRTY | GEOM_DIRTY);
setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
gPipeline.markRebuild(this, TRUE);
@@ -703,7 +752,7 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
}
-BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut)
+BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
{
const OctreeNode* node = mOctreeNode;
@@ -716,8 +765,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
return FALSE;
}
- LLVector3& newMin = mObjectExtents[0];
- LLVector3& newMax = mObjectExtents[1];
+ LLVector4a& newMin = mObjectExtents[0];
+ LLVector4a& newMax = mObjectExtents[1];
if (isState(OBJECT_DIRTY))
{ //calculate new bounding box
@@ -726,10 +775,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
//initialize bounding box to first element
OctreeNode::const_element_iter i = node->getData().begin();
LLDrawable* drawablep = *i;
- const LLVector3* minMax = drawablep->getSpatialExtents();
+ const LLVector4a* minMax = drawablep->getSpatialExtents();
- newMin.setVec(minMax[0]);
- newMax.setVec(minMax[1]);
+ newMin = minMax[0];
+ newMax = minMax[1];
for (++i; i != node->getData().end(); ++i)
{
@@ -753,8 +802,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
}*/
}
- mObjectBounds[0] = (newMin + newMax) * 0.5f;
- mObjectBounds[1] = (newMax - newMin) * 0.5f;
+ mObjectBounds[0].setAdd(newMin, newMax);
+ mObjectBounds[0].mul(0.5f);
+ mObjectBounds[1].setSub(newMax, newMin);
+ mObjectBounds[1].mul(0.5f);
}
if (empty)
@@ -764,17 +815,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
}
else
{
- for (U32 i = 0; i < 3; i++)
- {
- if (newMin.mV[i] < minOut.mV[i])
- {
- minOut.mV[i] = newMin.mV[i];
- }
- if (newMax.mV[i] > maxOut.mV[i])
- {
- maxOut.mV[i] = newMax.mV[i];
- }
- }
+ minOut.setMin(minOut, newMin);
+ maxOut.setMax(maxOut, newMax);
}
return TRUE;
@@ -865,18 +907,19 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
return TRUE;
}
-void LLSpatialGroup::shift(const LLVector3 &offset)
+void LLSpatialGroup::shift(const LLVector4a &offset)
{
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- LLVector3d offsetd(offset);
- mOctreeNode->setCenter(mOctreeNode->getCenter()+offsetd);
+ LLVector4a t = mOctreeNode->getCenter();
+ t.add(offset);
+ mOctreeNode->setCenter(t);
mOctreeNode->updateMinMax();
- mBounds[0] += offset;
- mExtents[0] += offset;
- mExtents[1] += offset;
- mObjectBounds[0] += offset;
- mObjectExtents[0] += offset;
- mObjectExtents[1] += offset;
+ mBounds[0].add(offset);
+ mExtents[0].add(offset);
+ mExtents[1].add(offset);
+ mObjectBounds[0].add(offset);
+ mObjectExtents[0].add(offset);
+ mObjectExtents[1].add(offset);
//if (!mSpatialPartition->mRenderByGroup)
{
@@ -884,15 +927,9 @@ void LLSpatialGroup::shift(const LLVector3 &offset)
gPipeline.markRebuild(this, TRUE);
}
- if (mOcclusionVerts)
+ if (mOcclusionVerts.notNull())
{
- for (U32 i = 0; i < 8; i++)
- {
- F32* v = mOcclusionVerts+i*3;
- v[0] += offset.mV[0];
- v[1] += offset.mV[1];
- v[2] += offset.mV[2];
- }
+ setState(OCCLUSION_DIRTY);
}
}
@@ -1079,12 +1116,23 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
{
mOcclusionState[i] |= state;
+
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
}
}
}
else
{
mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
}
}
@@ -1152,13 +1200,11 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
mOctreeNode(node),
mSpatialPartition(part),
mVertexBuffer(NULL),
- mBufferUsage(GL_STATIC_DRAW_ARB),
+ mBufferUsage(part->mBufferUsage),
mDistance(0.f),
mDepth(0.f),
mLastUpdateDistance(-1.f),
mLastUpdateTime(gFrameTimeSeconds),
- mViewAngle(0.f),
- mLastUpdateViewAngle(-1.f),
mAtlasList(4),
mCurUpdatingTime(0),
mCurUpdatingSlotp(NULL),
@@ -1167,13 +1213,18 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
sNodeCount++;
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ mViewAngle.splat(0.f);
+ mLastUpdateViewAngle.splat(-1.f);
+ mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =
+ mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
+
sg_assert(mOctreeNode->getListenerCount() == 0);
mOctreeNode->addListener(this);
setState(SG_INITIAL_STATE_MASK);
gPipeline.markRebuild(this, TRUE);
- mBounds[0] = LLVector3(node->getCenter());
- mBounds[1] = LLVector3(node->getSize());
+ mBounds[0] = node->getCenter();
+ mBounds[1] = node->getSize();
part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
mLODHash = part->mLODSeed;
@@ -1210,8 +1261,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
#endif
if (!getData().empty())
{
- mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() :
- (F32) mOctreeNode->getSize().magVec();
+ mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
+ (F32) mOctreeNode->getSize().getLength3().getF32();
mDistance = mSpatialPartition->calcDistance(this, camera);
mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
}
@@ -1219,24 +1270,31 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
{
- LLVector3 eye = group->mObjectBounds[0] - camera.getOrigin();
+ LLVector4a eye;
+ LLVector4a origin;
+ origin.load3(camera.getOrigin().mV);
+
+ eye.setSub(group->mObjectBounds[0], origin);
F32 dist = 0.f;
if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
{
- LLVector3 v = eye;
- dist = eye.normVec();
+ LLVector4a v = eye;
+
+ dist = eye.getLength3().getF32();
+ eye.normalize3fast();
if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
{
if (!group->mSpatialPartition->isBridge())
{
- LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0),
- eye * LLVector3(0,1,0),
- eye * LLVector3(0,0,1));
+ LLVector4a view_angle = eye;
- if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f)
+ LLVector4a diff;
+ diff.setSub(view_angle, group->mLastUpdateViewAngle);
+
+ if (diff.getLength3().getF32() > 0.64f)
{
group->mViewAngle = view_angle;
group->mLastUpdateViewAngle = view_angle;
@@ -1253,17 +1311,20 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
LLVector3 at = camera.getAtAxis();
- //front of bounding box
- for (U32 i = 0; i < 3; i++)
- {
- v.mV[i] -= group->mObjectBounds[1].mV[i]*0.25f * at.mV[i];
- }
+ LLVector4a ata;
+ ata.load3(at.mV);
- group->mDepth = v * at;
+ LLVector4a t = ata;
+ //front of bounding box
+ t.mul(0.25f);
+ t.mul(group->mObjectBounds[1]);
+ v.sub(t);
+
+ group->mDepth = v.dot3(ata).getF32();
}
else
{
- dist = eye.magVec();
+ dist = eye.getLength3().getF32();
}
if (dist < 16.f)
@@ -1289,7 +1350,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const
}
else
{
- return (gFrameTimeSeconds - mLastUpdateTime+4.f)/mDistance;
+ F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
+ return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
}
}
@@ -1300,8 +1362,8 @@ BOOL LLSpatialGroup::needsUpdate()
BOOL LLSpatialGroup::changeLOD()
{
- if (isState(ALPHA_DIRTY))
- { ///an alpha sort is going to happen, update distance and LOD
+ if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
+ { ///a rebuild is going to happen, update distance and LoD
return TRUE;
}
@@ -1314,7 +1376,7 @@ BOOL LLSpatialGroup::changeLOD()
return TRUE;
}
- if (mDistance > mRadius)
+ if (mDistance > mRadius*2.f)
{
return FALSE;
}
@@ -1416,7 +1478,6 @@ void LLSpatialGroup::destroyGL()
}
}
- delete [] mOcclusionVerts;
mOcclusionVerts = NULL;
for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
@@ -1425,8 +1486,7 @@ void LLSpatialGroup::destroyGL()
for (S32 j = 0; j < drawable->getNumFaces(); j++)
{
LLFace* facep = drawable->getFace(j);
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
}
@@ -1459,8 +1519,8 @@ BOOL LLSpatialGroup::rebound()
}
else
{
- LLVector3& newMin = mExtents[0];
- LLVector3& newMax = mExtents[1];
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
group->clearState(SKIP_FRUSTUM_CHECK);
group->rebound();
@@ -1474,26 +1534,19 @@ BOOL LLSpatialGroup::rebound()
group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
group->clearState(SKIP_FRUSTUM_CHECK);
group->rebound();
- const LLVector3& max = group->mExtents[1];
- const LLVector3& min = group->mExtents[0];
+ const LLVector4a& max = group->mExtents[1];
+ const LLVector4a& min = group->mExtents[0];
- for (U32 j = 0; j < 3; j++)
- {
- if (max.mV[j] > newMax.mV[j])
- {
- newMax.mV[j] = max.mV[j];
- }
- if (min.mV[j] < newMin.mV[j])
- {
- newMin.mV[j] = min.mV[j];
- }
- }
+ newMax.setMax(newMax, max);
+ newMin.setMin(newMin, min);
}
boundObjects(FALSE, newMin, newMax);
- mBounds[0] = (newMin + newMax)*0.5f;
- mBounds[1] = (newMax - newMin)*0.5f;
+ mBounds[0].setAdd(newMin, newMax);
+ mBounds[0].mul(0.5f);
+ mBounds[1].setSub(newMax, newMin);
+ mBounds[1].mul(0.5f);
}
setState(OCCLUSION_DIRTY);
@@ -1516,31 +1569,53 @@ void LLSpatialGroup::checkOcclusion()
}
else if (isOcclusionState(QUERY_PENDING))
{ //otherwise, if a query is pending, read it back
- GLuint res = 1;
- if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
- }
- if (isOcclusionState(DISCARD_QUERY))
+ GLuint available = 0;
+ if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
{
- res = 2;
- }
-
- if (res > 0)
- {
- assert_states_valid(this);
- clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
}
else
{
- assert_states_valid(this);
- setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
+ available = 1;
}
- clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ if (available)
+ { //result is available, read it back, otherwise wait until next frame
+ GLuint res = 1;
+ if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
+ }
+ else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ { //delete the query to avoid holding onto hundreds of pending queries
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+
+ if (isOcclusionState(DISCARD_QUERY))
+ {
+ res = 2;
+ }
+
+ if (res > 0)
+ {
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ assert_states_valid(this);
+ setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
}
else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
{ //check occlusion has been issued for occluded node that has not had a query issued
@@ -1551,12 +1626,18 @@ void LLSpatialGroup::checkOcclusion()
}
}
+static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
+static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
+
void LLSpatialGroup::doOcclusion(LLCamera* camera)
{
if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
{
+ // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
if (earlyFail(camera, this))
{
+ LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
assert_states_valid(this);
clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
@@ -1564,38 +1645,82 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
}
else
{
+ if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
{
- LLFastTimer t(FTM_RENDER_OCCLUSION);
+ { //no query pending, or previous query to be discarded
+ LLFastTimer t(FTM_RENDER_OCCLUSION);
- if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
- }
+ if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
+ }
- if (!mOcclusionVerts || isState(LLSpatialGroup::OCCLUSION_DIRTY))
- {
- buildOcclusion();
- }
+ if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY))
+ {
+ 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);
+
+ LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);
+
+#if !LL_DARWIN
+ U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB;
+#else
+ U32 mode = GL_SAMPLES_PASSED_ARB;
+#endif
+
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
- glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
- if (camera->getOrigin().isExactlyZero())
- { //origin is invalid, draw entire box
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, sOcclusionIndices);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, sOcclusionIndices+b111*8);
+ {
+ LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+
+ mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+ if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
+ {
+ LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
+ if (camera->getOrigin().isExactlyZero())
+ { //origin is invalid, draw entire box
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+ else
+ {
+ if (camera->getOrigin().isExactlyZero())
+ { //origin is invalid, draw entire box
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+
+ glEndQueryARB(mode);
+ }
}
- else
+
{
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
+ LLFastTimer t(FTM_SET_OCCLUSION_STATE);
+ setOcclusionState(LLSpatialGroup::QUERY_PENDING);
+ clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
}
- glEndQueryARB(GL_SAMPLES_PASSED_ARB);
}
-
- setOcclusionState(LLSpatialGroup::QUERY_PENDING);
- clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
}
}
}
@@ -1617,10 +1742,11 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
mSlopRatio = 0.25f;
mInfiniteFarClip = FALSE;
- LLGLNamePool::registerPool(&sQueryPool);
+ LLVector4a center, size;
+ center.splat(0.f);
+ size.splat(1.f);
- mOctree = new LLSpatialGroup::OctreeRoot(LLVector3d(0,0,0),
- LLVector3d(1,1,1),
+ mOctree = new LLSpatialGroup::OctreeRoot(center,size,
NULL);
new LLSpatialGroup(mOctree, this);
}
@@ -1640,7 +1766,6 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
drawablep->updateSpatialExtents();
- validate_drawable(drawablep);
//keep drawable from being garbage collected
LLPointer<LLDrawable> ptr = drawablep;
@@ -1724,16 +1849,16 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL
class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
{
public:
- LLSpatialShift(LLVector3 offset) : mOffset(offset) { }
+ const LLVector4a& mOffset;
+
+ LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
virtual void visit(const LLSpatialGroup::OctreeNode* branch)
{
((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);
}
-
- LLVector3 mOffset;
};
-void LLSpatialPartition::shift(const LLVector3 &offset)
+void LLSpatialPartition::shift(const LLVector4a &offset)
{ //shift octree node bounding boxes by offset
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
LLSpatialShift shifter(offset);
@@ -1895,7 +2020,7 @@ public:
class LLOctreeCullVisExtents: public LLOctreeCullShadow
{
public:
- LLOctreeCullVisExtents(LLCamera* camera, LLVector3& min, LLVector3& max)
+ LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
virtual bool earlyFail(LLSpatialGroup* group)
@@ -1962,8 +2087,8 @@ public:
}
BOOL mEmpty;
- LLVector3& mMin;
- LLVector3& mMax;
+ LLVector4a& mMin;
+ LLVector4a& mMax;
};
class LLOctreeCullDetectVisible: public LLOctreeCullShadow
@@ -2032,6 +2157,8 @@ public:
void drawBox(const LLVector3& c, const LLVector3& r)
{
+ LLVertexBuffer::unbind();
+
gGL.begin(LLRender::TRIANGLE_STRIP);
//left front
gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
@@ -2067,6 +2194,11 @@ void drawBox(const LLVector3& c, const LLVector3& r)
gGL.end();
}
+void drawBox(const LLVector4a& c, const LLVector4a& r)
+{
+ drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r));
+}
+
void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
{
LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
@@ -2113,6 +2245,11 @@ void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
gGL.end();
}
+void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
+{
+ drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
+}
+
class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -2156,14 +2293,21 @@ BOOL LLSpatialPartition::isOcclusionEnabled()
BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
{
+ LLVector4a visMina, visMaxa;
+ visMina.load3(visMin.mV);
+ visMaxa.load3(visMax.mV);
+
{
LLFastTimer ftm(FTM_CULL_REBOUND);
LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
group->rebound();
}
- LLOctreeCullVisExtents vis(&camera, visMin, visMax);
+ LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
vis.traverse(mOctree);
+
+ visMin.set(visMina.getF32ptr());
+ visMax.set(visMaxa.getF32ptr());
return vis.mEmpty;
}
@@ -2226,25 +2370,36 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
}
const F32 vel = SG_OCCLUSION_FUDGE*2.f;
- LLVector3 c = group->mBounds[0];
- LLVector3 r = group->mBounds[1] + LLVector3(vel,vel,vel);
-
+ LLVector4a fudge;
+ fudge.splat(vel);
+
+ const LLVector4a& c = group->mBounds[0];
+ LLVector4a r;
+ r.setAdd(group->mBounds[1], fudge);
+
/*if (r.magVecSquared() > 1024.0*1024.0)
{
return TRUE;
}*/
- LLVector3 e = camera->getOrigin();
+ LLVector4a e;
+ e.load3(camera->getOrigin().mV);
- LLVector3 min = c - r;
- LLVector3 max = c + r;
+ LLVector4a min;
+ min.setSub(c,r);
+ LLVector4a max;
+ max.setAdd(c,r);
- for (U32 j = 0; j < 3; j++)
+ S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
+ if (lt)
{
- if (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j])
- {
- return FALSE;
- }
+ return FALSE;
+ }
+
+ S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
+ if (gt)
+ {
+ return FALSE;
}
return TRUE;
@@ -2275,7 +2430,9 @@ void pushVerts(LLSpatialGroup* group, U32 mask)
void pushVerts(LLFace* face, U32 mask)
{
- LLVertexBuffer* buffer = face->mVertexBuffer;
+ llassert(face->verify());
+
+ LLVertexBuffer* buffer = face->getVertexBuffer();
if (buffer)
{
@@ -2286,7 +2443,25 @@ void pushVerts(LLFace* face, U32 mask)
U16 offset = face->getIndicesStart();
buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
}
+}
+void pushVerts(LLDrawable* drawable, U32 mask)
+{
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ pushVerts(drawable->getFace(i), mask);
+ }
+}
+
+void pushVerts(LLVolume* volume)
+{
+ LLVertexBuffer::unbind();
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ glVertexPointer(3, GL_FLOAT, 16, face.mPositions);
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
}
void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
@@ -2364,7 +2539,6 @@ void renderOctree(LLSpatialGroup* group)
{
//render solid object bounding box, color
//coded by buffer usage and activity
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
LLVector4 col;
if (group->mBuilt > 0.f)
@@ -2405,7 +2579,7 @@ void renderOctree(LLSpatialGroup* group)
for (S32 j = 0; j < drawable->getNumFaces(); j++)
{
LLFace* face = drawable->getFace(j);
- if (face->mVertexBuffer.notNull())
+ if (face->getVertexBuffer())
{
if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
{
@@ -2420,10 +2594,10 @@ void renderOctree(LLSpatialGroup* group)
continue;
}
- face->mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
// (face->mExtents[1]-face->mExtents[0])*0.5f);
- face->mVertexBuffer->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
+ face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
}
}
@@ -2450,7 +2624,16 @@ void renderOctree(LLSpatialGroup* group)
}
gGL.color4fv(col.mV);
- drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+ LLVector4a fudge;
+ fudge.splat(0.001f);
+ LLVector4a size = group->mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(fudge);
+
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ drawBox(group->mObjectBounds[0], fudge);
+ }
gGL.setSceneBlendType(LLRender::BT_ALPHA);
@@ -2481,8 +2664,12 @@ void renderOctree(LLSpatialGroup* group)
for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
{
LLDrawInfo* draw_info = *j;
- LLVector3 center = (draw_info->mExtents[1] + draw_info->mExtents[0])*0.5f;
- LLVector3 size = (draw_info->mExtents[1] - draw_info->mExtents[0])*0.5f;
+ LLVector4a center;
+ center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]);
+ size.mul(0.5f);
drawBoxOutline(center, size);
}
}
@@ -2529,17 +2716,17 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
gGL.color4f(0.f, 0.75f, 0.f, 0.5f);
pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
}
- else if (camera && group->mOcclusionVerts)
+ else if (camera && group->mOcclusionVerts.notNull())
{
LLVertexBuffer::unbind();
- glVertexPointer(3, GL_FLOAT, 0, group->mOcclusionVerts);
-
+ group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
glColor4f(1.0f, 0.f, 0.f, 0.5f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
+ group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor4f(1.0f, 1.f, 1.f, 1.0f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
+ group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
@@ -2560,6 +2747,49 @@ void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
gGL.end();
}
+void renderUpdateType(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
+ {
+ return;
+ }
+ LLGLEnable blend(GL_BLEND);
+ switch (vobj->getLastUpdateType())
+ {
+ case OUT_FULL:
+ glColor4f(0,1,0,0.5f);
+ break;
+ case OUT_TERSE_IMPROVED:
+ glColor4f(0,1,1,0.5f);
+ break;
+ case OUT_FULL_COMPRESSED:
+ if (vobj->getLastUpdateCached())
+ {
+ glColor4f(1,0,0,0.5f);
+ }
+ else
+ {
+ glColor4f(1,1,0,0.5f);
+ }
+ break;
+ case OUT_FULL_CACHED:
+ glColor4f(0,0,1,0.5f);
+ break;
+ default:
+ llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
+ break;
+ };
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+}
+
void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
@@ -2591,9 +2821,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;
@@ -2611,8 +2842,8 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
}
}
- const LLVector3* ext;
- LLVector3 pos, size;
+ const LLVector4a* ext;
+ LLVector4a pos, size;
//render face bounding boxes
for (S32 i = 0; i < drawable->getNumFaces(); i++)
@@ -2621,20 +2852,21 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
ext = facep->mExtents;
- if (ext[0].isExactlyZero() && ext[1].isExactlyZero())
- {
- continue;
- }
- pos = (ext[0] + ext[1]) * 0.5f;
- size = (ext[1] - ext[0]) * 0.5f;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
drawBoxOutline(pos,size);
}
//render drawable bounding box
ext = drawable->getSpatialExtents();
- pos = (ext[0] + ext[1]) * 0.5f;
- size = (ext[1] - ext[0]) * 0.5f;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
LLViewerObject* vobj = drawable->getVObj();
if (vobj && vobj->onActiveList())
@@ -2651,7 +2883,506 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
{
drawBoxOutline(pos,size);
}
+}
+
+void renderNormals(LLDrawable* drawablep)
+{
+ LLVertexBuffer::unbind();
+
+ LLVOVolume* vol = drawablep->getVOVolume();
+ if (vol)
+ {
+ LLVolume* volume = vol->getVolume();
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) vol->getRelativeXform().mMatrix);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ gGL.begin(LLRender::LINES);
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ LLVector4a n,p;
+
+ n.setMul(face.mNormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.color4f(1,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+
+ if (face.mBinormals)
+ {
+ n.setMul(face.mBinormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.color4f(0,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+ }
+ }
+
+ gGL.end();
+ }
+
+ gGL.popMatrix();
+ }
+}
+
+S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale)
+{
+ const S32 DEFAULT_DETAIL = 1;
+ const F32 LARGE_THRESHOLD = 5.f;
+ const F32 MEGA_THRESHOLD = 25.f;
+
+ S32 detail = DEFAULT_DETAIL;
+ F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f;
+
+ if (avg_scale > LARGE_THRESHOLD)
+ {
+ detail += 1;
+ if (avg_scale > MEGA_THRESHOLD)
+ {
+ detail += 1;
+ }
+ }
+
+ return detail;
+}
+
+void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
+{
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ const LLVector3 center(0,0,0);
+ const LLVector3 size(0.25f,0.25f,0.25f);
+
+ if (decomp)
+ {
+ if (!decomp->mBaseHullMesh.empty())
+ {
+ glColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+ }
+ else
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ gGL.color3f(0,1,1);
+ drawBoxOutline(center, size);
+ }
+
+ }
+ else
+ {
+ gGL.color3f(1,0,1);
+ drawBoxOutline(center, size);
+ }
+}
+
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
+{
+ glColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glPolygonOffset(3.f, 3.f);
+ glLineWidth(3.f);
+ glColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
+{
+ if (volume->isSelected())
+ {
+ LLVector3 construct_me(5,5,5);
+ construct_me.normalize();
+ }
+
+ U8 physics_type = volume->getPhysicsShapeType();
+
+ if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible())
+ {
+ return;
+ }
+
+ //not allowed to return at this point without rendering *something*
+
+ F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold");
+ F32 cost = volume->getObjectCost();
+
+ LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor");
+ LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor");
+ LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor");
+
+ F32 normalizedCost = 1.f - exp( -(cost / threshold) );
+
+ LLColor4 color;
+ if ( normalizedCost <= 0.5f )
+ {
+ color = lerp( low, mid, 2.f * normalizedCost );
+ }
+ else
+ {
+ color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) );
+ }
+
+ LLColor4 line_color = color*0.5f;
+
+ U32 data_mask = LLVertexBuffer::MAP_VERTEX;
+
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+
+ LLPhysicsVolumeParams physics_params(volume_params,
+ physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+
+ LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec;
+ LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec);
+
+ U32 type = physics_spec.getType();
+
+ LLVector3 center(0,0,0);
+ LLVector3 size(0.25f,0.25f,0.25f);
+
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) volume->getRelativeXform().mMatrix);
+
+ if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
+ {
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ if (decomp)
+ { //render a physics based mesh
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (!decomp->mHull.empty())
+ { //decomposition exists, use that
+
+ if (decomp->mMesh.empty())
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ }
+
+ for (U32 i = 0; i < decomp->mMesh.size(); ++i)
+ {
+ render_hull(decomp->mMesh[i], color, line_color);
+ }
+ }
+ else if (!decomp->mPhysicsShapeMesh.empty())
+ {
+ //decomp has physics mesh, render that mesh
+ glColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else
+ { //no mesh or decomposition, render base hull
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+
+ if (decomp->mPhysicsShapeMesh.empty())
+ {
+ //attempt to fetch physics shape mesh if available
+ gMeshRepo.fetchPhysicsShape(mesh_id);
+ }
+ }
+ }
+ else
+ {
+ gGL.color3f(1,1,0);
+ drawBoxOutline(center, size);
+ }
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX ||
+ type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ if (volume->isMesh())
+ {
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+ }
+#if LL_WINDOWS
+ else
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (!phys_volume->mHullPoints)
+ { //build convex hull
+ std::vector<LLVector3> pos;
+ std::vector<U16> index;
+
+ S32 index_offset = 0;
+
+ for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = phys_volume->getVolumeFace(i);
+ if (index_offset + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ pos.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (S32 j = 0; j < face.mNumIndices; ++j)
+ {
+ index.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+
+ if (!pos.empty() && !index.empty())
+ {
+ LLCDMeshData mesh;
+ mesh.mIndexBase = &index[0];
+ mesh.mVertexBase = pos[0].mV;
+ mesh.mNumVertices = pos.size();
+ mesh.mVertexStrideBytes = 12;
+ mesh.mIndexStrideBytes = 6;
+ mesh.mIndexType = LLCDMeshData::INT_16;
+
+ mesh.mNumTriangles = index.size()/3;
+
+ LLCDMeshData res;
+
+ LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res );
+
+ //copy res into phys_volume
+ phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices);
+ phys_volume->mNumHullPoints = res.mNumVertices;
+
+ S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF;
+ phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size);
+ phys_volume->mNumHullIndices = res.mNumTriangles*3;
+
+ const F32* v = res.mVertexBase;
+
+ for (S32 i = 0; i < res.mNumVertices; ++i)
+ {
+ F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes);
+ phys_volume->mHullPoints[i].load3(p);
+ }
+
+ if (res.mIndexType == LLCDMeshData::INT_16)
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = idx[0];
+ phys_volume->mHullIndices[i*3+1] = idx[1];
+ phys_volume->mHullIndices[i*3+2] = idx[2];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = (U16) idx[0];
+ phys_volume->mHullIndices[i*3+1] = (U16) idx[1];
+ phys_volume->mHullIndices[i*3+2] = (U16) idx[2];
+ }
+ }
+ }
+ }
+
+ if (phys_volume->mHullPoints)
+ {
+ //render hull
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glColor4fv(line_color.mV);
+ LLVertexBuffer::unbind();
+
+ glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+ }
+ else
+ {
+ gGL.color3f(1,0,1);
+ drawBoxOutline(center, size);
+ }
+
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+#endif //LL_WINDOWS
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX)
+ {
+ LLVector3 center = physics_spec.getCenter();
+ LLVector3 scale = physics_spec.getScale();
+ LLVector3 vscale = volume->getScale()*2.f;
+ scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]);
+
+ gGL.color4fv(color.mV);
+ drawBox(center, scale);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE)
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ glColor4fv(color.mV);
+ pushVerts(sphere);
+ LLPrimitive::sVolumeManager->unrefVolume(sphere);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER)
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ glColor4fv(color.mV);
+ pushVerts(cylinder);
+ LLPrimitive::sVolumeManager->unrefVolume(cylinder);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glColor4fv(line_color.mV);
+ pushVerts(phys_volume);
+
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ pushVerts(phys_volume);
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (phys_volume->mHullPoints && phys_volume->mHullIndices)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ LLVertexBuffer::unbind();
+ glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
+ glColor4fv(line_color.mV);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+ }
+ else
+ {
+ gGL.color3f(1,0,1);
+ drawBoxOutline(center, size);
+ gMeshRepo.buildHull(volume_params, detail);
+ }
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT)
+ {
+ //TODO: implement sculpted prim physics display
+ }
+ else
+ {
+ llerrs << "Unhandled type" << llendl;
+ }
+
+ gGL.popMatrix();
+
+ /*{ //analytical shape, just push visual rep.
+ glColor3fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ pushVerts(drawable, data_mask);
+ glColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ pushVerts(drawable, data_mask);
+ }*/
+}
+
+void renderPhysicsShapes(LLSpatialGroup* group)
+{
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ LLVOVolume* volume = drawable->getVOVolume();
+ if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
+ {
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.pushMatrix();
+ LLVector3 trans = drawable->getRegion()->getOriginAgent();
+ glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ renderPhysicsShape(drawable, volume);
+ gGL.popMatrix();
+ }
+ else
+ {
+ renderPhysicsShape(drawable, volume);
+ }
+ }
+ else
+ {
+ LLViewerObject* object = drawable->getVObj();
+ if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
+ {
+ //push face vertices for terrain
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (buff)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ glColor3f(0.2f, 0.5f, 0.3f);
+ buff->draw(LLRender::TRIANGLES, buff->getRequestedIndices(), 0);
+
+ glColor3f(0.2f, 1.f, 0.3f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ buff->draw(LLRender::TRIANGLES, buff->getRequestedIndices(), 0);
+ }
+ }
+ }
+ }
+ }
}
void renderTexturePriority(LLDrawable* drawable)
@@ -2690,8 +3421,13 @@ void renderTexturePriority(LLDrawable* drawable)
// gGL.color4f(1,0,1,1);
//}
- LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f;
- LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f);
+ LLVector4a center;
+ center.setAdd(facep->mExtents[1],facep->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(facep->mExtents[1],facep->mExtents[0]);
+ size.mul(0.5f);
+ size.add(LLVector4a(0.01f));
drawBox(center, size);
/*S32 boost = imagep->getBoostLevel();
@@ -2715,7 +3451,6 @@ void renderPoints(LLDrawable* drawablep)
{
gGL.begin(LLRender::POINTS);
gGL.color3f(1,1,1);
- LLVector3 center(drawablep->getPositionGroup());
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
{
gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
@@ -2747,8 +3482,12 @@ void renderShadowFrusta(LLDrawInfo* params)
LLGLEnable blend(GL_BLEND);
gGL.setSceneBlendType(LLRender::BT_ADD);
- LLVector3 center = (params->mExtents[1]+params->mExtents[0])*0.5f;
- LLVector3 size = (params->mExtents[1]-params->mExtents[0])*0.5f;
+ LLVector4a center;
+ center.setAdd(params->mExtents[1], params->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(params->mExtents[1],params->mExtents[0]);
+ size.mul(0.5f);
if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
{
@@ -2792,10 +3531,14 @@ void renderLights(LLDrawable* drawablep)
pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
}
- const LLVector3* ext = drawablep->getSpatialExtents();
+ const LLVector4a* ext = drawablep->getSpatialExtents();
- LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
- LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
{
LLGLDepthTest depth(GL_FALSE, GL_TRUE);
@@ -2805,65 +3548,206 @@ void renderLights(LLDrawable* drawablep)
gGL.color4f(1,1,0,1);
F32 rad = drawablep->getVOVolume()->getLightRadius();
- drawBoxOutline(pos, LLVector3(rad,rad,rad));
+ drawBoxOutline(pos, LLVector4a(rad));
}
}
-
-void renderRaycast(LLDrawable* drawablep)
+class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
{
- if (drawablep->getVObj() != gDebugRaycastObject)
+public:
+
+
+ LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+ : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
{
- return;
+
}
-
+
+ void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ {
+ LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector3 center, size;
+
+ if (branch->getData().empty())
+ {
+ gGL.color3f(1.f,0.2f,0.f);
+ center.set(branch->getCenter().getF32ptr());
+ size.set(branch->getSize().getF32ptr());
+ }
+ else
+ {
+ gGL.color3f(0.75f, 1.f, 0.f);
+ center.set(vl->mBounds[0].getF32ptr());
+ size.set(vl->mBounds[1].getF32ptr());
+ }
+
+ drawBoxOutline(center, size);
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER);
+
+ if (i == 1)
+ {
+ gGL.color4f(0,1,1,0.5f);
+ }
+ else
+ {
+ gGL.color4f(0,0.5f,0.5f, 0.25f);
+ drawBoxOutline(center, size);
+ }
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(3.f);
+ }
+
+ gGL.begin(LLRender::TRIANGLES);
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
+ iter != branch->getData().end();
+ ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ gGL.vertex3fv(tri->mV[0]->getF32ptr());
+ gGL.vertex3fv(tri->mV[1]->getF32ptr());
+ gGL.vertex3fv(tri->mV[2]->getF32ptr());
+ }
+ gGL.end();
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(1.f);
+ }
+ }
+ }
+};
+
+void renderRaycast(LLDrawable* drawablep)
+{
if (drawablep->getNumFaces())
{
LLGLEnable blend(GL_BLEND);
gGL.color4f(0,1,1,0.5f);
- if (drawablep->getVOVolume() && gDebugRaycastFaceHit != -1)
+ if (drawablep->getVOVolume())
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ LLVOVolume* vobj = drawablep->getVOVolume();
+ LLVolume* volume = vobj->getVolume();
+
+ bool transform = true;
+ if (drawablep->isState(LLDrawable::RIGGED))
+ {
+ volume = vobj->getRiggedVolume();
+ transform = false;
+ }
+
+ if (volume)
+ {
+ LLVector3 trans = drawablep->getRegion()->getOriginAgent();
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ if (!face.mOctree)
+ {
+ ((LLVolumeFace*) &face)->createOctree();
+ }
+
+ gGL.pushMatrix();
+ glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
+
+ LLVector3 start, end;
+ if (transform)
+ {
+ start = vobj->agentPositionToVolume(gDebugRaycastStart);
+ end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+ }
+ else
+ {
+ start = gDebugRaycastStart;
+ end = gDebugRaycastEnd;
+ }
+
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+ LLVector4a dir;
+ dir.setSub(enda, starta);
+
+ F32 t = 1.f;
+
+ LLRenderOctreeRaycast render(starta, dir, &t);
+ gGL.flush();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ {
+ //render face positions
+ LLVertexBuffer::unbind();
+ glColor4f(0,1,1,0.5f);
+ glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
+
+ render.traverse(face.mOctree);
+ gGL.popMatrix();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ }
}
else if (drawablep->isAvatar())
{
- LLGLDepthTest depth(GL_FALSE);
- LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
- av->renderCollisionVolumes();
- }
-
- // draw intersection point
- glPushMatrix();
- glLoadMatrixd(gGLModelView);
- LLVector3 translate = gDebugRaycastIntersection;
- glTranslatef(translate.mV[0], translate.mV[1], translate.mV[2]);
- LLCoordFrame orient;
- orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
- LLMatrix4 rotation;
- orient.getRotMatrixToParent(rotation);
- glMultMatrixf((float*)rotation.mMatrix);
-
- gGL.color4f(1,0,0,0.5f);
- drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
- gGL.color4f(0,1,0,0.5f);
- drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
- gGL.color4f(0,0,1,0.5f);
- drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
- glPopMatrix();
-
- // draw bounding box of prim
- const LLVector3* ext = drawablep->getSpatialExtents();
-
- LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
- LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
+ av->renderCollisionVolumes();
+ }
+ }
- LLGLDepthTest depth(GL_FALSE, GL_TRUE);
- gGL.color4f(0,0.5f,0.5f,1);
- drawBoxOutline(pos, size);
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ // draw intersection point
+ glPushMatrix();
+ glLoadMatrixd(gGLModelView);
+ LLVector3 translate = gDebugRaycastIntersection;
+ glTranslatef(translate.mV[0], translate.mV[1], translate.mV[2]);
+ LLCoordFrame orient;
+ orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
+ LLMatrix4 rotation;
+ orient.getRotMatrixToParent(rotation);
+ glMultMatrixf((float*)rotation.mMatrix);
+
+ gGL.color4f(1,0,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
+ gGL.color4f(0,1,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
+ gGL.color4f(0,0,1,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
+ glPopMatrix();
+
+ // draw bounding box of prim
+ const LLVector4a* ext = drawablep->getSpatialExtents();
+
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+ LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+ gGL.color4f(0,0.5f,0.5f,1);
+ drawBoxOutline(pos, size);
+ }
}
}
@@ -2885,7 +3769,6 @@ void renderAgentTarget(LLVOAvatar* avatar)
}
}
-
class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -2945,8 +3828,8 @@ public:
return;
}
- LLVector3 nodeCenter = group->mBounds[0];
- LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter());
+ LLVector4a nodeCenter = group->mBounds[0];
+ LLVector4a octCenter = group->mOctreeNode->getCenter();
group->rebuildGeom();
group->rebuildMesh();
@@ -2969,14 +3852,25 @@ public:
{
renderBoundingBox(drawable);
}
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
+ {
+ renderNormals(drawable);
+ }
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
{
if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
{
gGL.color4f(0.6f, 0.6f, 0.1f, 1.f);
- const LLVector3* ext = drawable->getSpatialExtents();
- drawBoxOutline((ext[0]+ext[1])*0.5f, (ext[1]-ext[0])*0.5f);
+ const LLVector4a* ext = drawable->getSpatialExtents();
+ LLVector4a center;
+ center.setAdd(ext[0], ext[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+ drawBoxOutline(center, size);
}
}
@@ -2999,6 +3893,10 @@ public:
{
renderRaycast(drawable);
}
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+ {
+ renderUpdateType(drawable);
+ }
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
@@ -3037,6 +3935,41 @@ public:
}
};
+
+class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+ stop_glerror();
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ stop_glerror();
+ }
+
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ renderPhysicsShapes(group);
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+
+ }
+};
+
class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
{
public:
@@ -3155,20 +4088,41 @@ public:
};
+void LLSpatialPartition::renderPhysicsShapes()
+{
+ LLSpatialBridge* bridge = asBridge();
+ LLCamera* camera = LLViewerCamera::getInstance();
+
+ if (bridge)
+ {
+ camera = NULL;
+ }
+
+ gGL.flush();
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glLineWidth(3.f);
+ LLOctreeRenderPhysicsShapes render_physics(camera);
+ render_physics.traverse(mOctree);
+ gGL.flush();
+ glLineWidth(1.f);
+}
+
void LLSpatialPartition::renderDebug()
{
if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
LLPipeline::RENDER_DEBUG_OCCLUSION |
LLPipeline::RENDER_DEBUG_LIGHTS |
LLPipeline::RENDER_DEBUG_BATCH_SIZE |
+ LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
LLPipeline::RENDER_DEBUG_BBOXES |
+ LLPipeline::RENDER_DEBUG_NORMALS |
LLPipeline::RENDER_DEBUG_POINTS |
LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
LLPipeline::RENDER_DEBUG_RAYCAST |
LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
LLPipeline::RENDER_DEBUG_AGENT_TARGET |
- LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
+ //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
{
return;
@@ -3207,7 +4161,11 @@ void LLSpatialPartition::renderDebug()
void LLSpatialGroup::drawObjectBox(LLColor4 col)
{
gGL.color4fv(col.mV);
- drawBox(mObjectBounds[0], mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+ LLVector4a size;
+ size = mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(LLVector4a(0.001f));
+ drawBox(mObjectBounds[0], size);
}
@@ -3267,8 +4225,8 @@ public:
LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
- LLVector3 size;
- LLVector3 center;
+ LLVector4a size;
+ LLVector4a center;
size = group->mBounds[1];
center = group->mBounds[0];
@@ -3285,7 +4243,11 @@ public:
local_end = mEnd * local_matrix;
}
- if (LLLineSegmentBoxIntersect(local_start, local_end, center, size))
+ LLVector4a start, end;
+ start.load3(local_start.mV);
+ end.load3(local_end.mV);
+
+ if (LLLineSegmentBoxIntersect(start, end, center, size))
{
check(child);
}
@@ -3375,18 +4337,9 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
mDistance(0.f),
mDrawMode(LLRender::TRIANGLES)
{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+
mDebugColor = (rand() << 16) + rand();
- if (mStart >= mVertexBuffer->getRequestedVerts() ||
- mEnd >= mVertexBuffer->getRequestedVerts())
- {
- llerrs << "Invalid draw info vertex range." << llendl;
- }
-
- if (mOffset >= (U32) mVertexBuffer->getRequestedIndices() ||
- mOffset + mCount > (U32) mVertexBuffer->getRequestedIndices())
- {
- llerrs << "Invalid draw info index range." << llendl;
- }
}
LLDrawInfo::~LLDrawInfo()
@@ -3400,6 +4353,16 @@ LLDrawInfo::~LLDrawInfo()
{
mFace->setDrawInfo(NULL);
}
+
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+}
+
+void LLDrawInfo::validate()
+{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
}
LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)