summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/00-Common.cmake2
-rw-r--r--indra/cmake/GooglePerfTools.cmake5
-rw-r--r--indra/llmath/lloctree.h127
-rw-r--r--indra/llmath/llvolume.cpp180
-rw-r--r--indra/llmath/llvolume.h4
-rw-r--r--indra/llmath/llvolumeoctree.cpp61
-rw-r--r--indra/llmath/llvolumeoctree.h6
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/lldrawable.cpp8
-rw-r--r--indra/newview/lldrawable.h56
-rw-r--r--indra/newview/lldrawpoolavatar.cpp10
-rw-r--r--indra/newview/llface.cpp34
-rw-r--r--indra/newview/llfloatertools.cpp8
-rw-r--r--indra/newview/llselectmgr.cpp50
-rw-r--r--indra/newview/llspatialpartition.cpp109
-rw-r--r--indra/newview/llviewerobject.cpp14
-rw-r--r--indra/newview/llvovolume.cpp314
-rw-r--r--indra/newview/llvovolume.h32
18 files changed, 805 insertions, 221 deletions
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index beb4f181b5..8b0864a539 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -38,7 +38,7 @@ if (WINDOWS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP"
CACHE STRING "C++ compiler debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
- "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Gm /INCREMENTAL"
+ "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Gm"
CACHE STRING "C++ compiler release-with-debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP"
diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake
index 946fc6b375..ee231dcde6 100644
--- a/indra/cmake/GooglePerfTools.cmake
+++ b/indra/cmake/GooglePerfTools.cmake
@@ -6,7 +6,7 @@ if (STANDALONE)
else (STANDALONE)
use_prebuilt_binary(google)
if (WINDOWS)
- use_prebuilt_binary(google-perftools)
+ use_prebuilt_binary(tcmalloc)
set(TCMALLOC_LIBRARIES
debug libtcmalloc_minimal-debug
optimized libtcmalloc_minimal)
@@ -29,8 +29,7 @@ if (GOOGLE_PERFTOOLS_FOUND)
endif (GOOGLE_PERFTOOLS_FOUND)
if (WINDOWS)
- # *TODO -reenable this once we get server usage sorted out
- #set(USE_GOOGLE_PERFTOOLS ON)
+ set(USE_GOOGLE_PERFTOOLS ON)
endif (WINDOWS)
if (USE_GOOGLE_PERFTOOLS)
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 73910ef98d..63adfa85b2 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -95,22 +95,30 @@ public:
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
+ /*void* operator new(size_t size)
+ {
+ return ll_aligned_malloc_16(size);
+ }
+
+ void operator delete(void* ptr)
+ {
+ ll_aligned_free_16(ptr);
+ }*/
+
LLOctreeNode( const LLVector4a& center,
const LLVector4a& size,
BaseType* parent,
- S32 octant = -1)
+ U8 octant = 255)
: mParent((oct_node*)parent),
mOctant(octant)
{
- mD = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*4);
-
- mD[CENTER] = center;
- mD[SIZE] = size;
+ mCenter = center;
+ mSize = size;
updateMinMax();
- if ((mOctant == -1) && mParent)
+ if ((mOctant == 255) && mParent)
{
- mOctant = ((oct_node*) mParent)->getOctant(mD[CENTER]);
+ mOctant = ((oct_node*) mParent)->getOctant(mCenter);
}
clearChildren();
@@ -124,30 +132,27 @@ public:
{
delete getChild(i);
}
-
- ll_aligned_free_16(mD);
}
inline const BaseType* getParent() const { return mParent; }
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
- inline const LLVector4a& getCenter() const { return mD[CENTER]; }
- inline const LLVector4a& getSize() const { return mD[SIZE]; }
- inline void setCenter(const LLVector4a& center) { mD[CENTER] = center; }
- inline void setSize(const LLVector4a& size) { mD[SIZE] = size; }
+ inline const LLVector4a& getCenter() const { return mCenter; }
+ inline const LLVector4a& getSize() const { return mSize; }
+ inline void setCenter(const LLVector4a& center) { mCenter = center; }
+ inline void setSize(const LLVector4a& size) { mSize = size; }
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
- inline S32 getOctant() const { return mOctant; }
- inline void setOctant(S32 octant) { mOctant = octant; }
+ inline U8 getOctant() const { return mOctant; }
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
- S32 getOctant(const LLVector4a& pos) const //get the octant pos is in
+ U8 getOctant(const LLVector4a& pos) const //get the octant pos is in
{
- return pos.greaterThan(mD[CENTER]).getGatheredBits() & 0x7;
+ return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
}
inline bool isInside(const LLVector4a& pos, const F32& rad) const
{
- return rad <= mD[SIZE][0]*2.f && isInside(pos);
+ return rad <= mSize[0]*2.f && isInside(pos);
}
inline bool isInside(T* data) const
@@ -157,13 +162,13 @@ public:
bool isInside(const LLVector4a& pos) const
{
- S32 gt = pos.greaterThan(mD[MAX]).getGatheredBits() & 0x7;
+ S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
if (gt)
{
return false;
}
- S32 lt = pos.lessEqual(mD[MIN]).getGatheredBits() & 0x7;
+ S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
if (lt)
{
return false;
@@ -174,8 +179,8 @@ public:
void updateMinMax()
{
- mD[MAX].setAdd(mD[CENTER], mD[SIZE]);
- mD[MIN].setSub(mD[CENTER], mD[SIZE]);
+ mMax.setAdd(mCenter, mSize);
+ mMin.setSub(mCenter, mSize);
}
inline oct_listener* getOctListener(U32 index)
@@ -195,7 +200,7 @@ public:
return false;
}
- F32 size = mD[SIZE][0];
+ F32 size = mSize[0];
F32 p_size = size * 2.f;
return (radius <= 0.001f && size <= 0.001f) ||
@@ -234,6 +239,29 @@ public:
void accept(tree_traveler* visitor) const { visitor->visit(this); }
void accept(oct_traveler* visitor) const { visitor->visit(this); }
+ void validateChildMap()
+ {
+ for (U32 i = 0; i < 8; i++)
+ {
+ U8 idx = mChildMap[i];
+ if (idx != 255)
+ {
+ LLOctreeNode<T>* child = mChild[idx];
+
+ if (child->getOctant() != i)
+ {
+ llerrs << "Invalid child map, bad octant data." << llendl;
+ }
+
+ if (getOctant(child->getCenter()) != child->getOctant())
+ {
+ llerrs << "Invalid child octant compared to position data." << llendl;
+ }
+ }
+ }
+ }
+
+
oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
{
LLOctreeNode<T>* node = this;
@@ -241,25 +269,19 @@ public:
if (node->isInside(pos, rad))
{
//do a quick search by octant
- S32 octant = node->getOctant(pos);
- BOOL keep_going = TRUE;
-
+ U8 octant = node->getOctant(pos);
+
//traverse the tree until we find a node that has no node
//at the appropriate octant or is smaller than the object.
//by definition, that node is the smallest node that contains
// the data
- while (keep_going && node->getSize()[0] >= rad)
+ U8 next_node = node->mChildMap[octant];
+
+ while (next_node != 255 && node->getSize()[0] >= rad)
{
- keep_going = FALSE;
- for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
- {
- if (node->getChild(i)->getOctant() == octant)
- {
- node = node->getChild(i);
- octant = node->getOctant(pos);
- keep_going = TRUE;
- }
- }
+ node = node->getChild(next_node);
+ octant = node->getOctant(pos);
+ next_node = node->mChildMap[octant];
}
}
else if (!node->contains(rad) && node->getParent())
@@ -439,6 +461,9 @@ public:
void clearChildren()
{
mChild.clear();
+
+ U32* foo = (U32*) mChildMap;
+ foo[0] = foo[1] = 0xFFFFFFFF;
}
void validate()
@@ -496,6 +521,8 @@ public:
}
#endif
+ mChildMap[child->getOctant()] = (U8) mChild.size();
+
mChild.push_back(child);
child->setParent(this);
@@ -517,6 +544,8 @@ public:
listener->handleChildRemoval(this, getChild(index));
}
+
+
if (destroy)
{
mChild[index]->destroy();
@@ -524,6 +553,15 @@ public:
}
mChild.erase(mChild.begin() + index);
+ //rebuild child map
+ U32* foo = (U32*) mChildMap;
+ foo[0] = foo[1] = 0xFFFFFFFF;
+
+ for (U32 i = 0; i < mChild.size(); ++i)
+ {
+ mChildMap[mChild[i]->getOctant()] = i;
+ }
+
checkAlive();
}
@@ -562,15 +600,20 @@ protected:
MIN = 3
} eDName;
- LLVector4a* mD;
+ LLVector4a mCenter;
+ LLVector4a mSize;
+ LLVector4a mMax;
+ LLVector4a mMin;
oct_node* mParent;
- S32 mOctant;
+ U8 mOctant;
child_list mChild;
+ U8 mChildMap[8];
+
element_list mData;
-};
+};
//just like a regular node, except it might expand on insert and compress on balance
template <class T>
@@ -613,6 +656,8 @@ public:
//destroy child
child->clearChildren();
delete child;
+
+ return false;
}
return true;
@@ -639,7 +684,7 @@ public:
const LLVector4a& v = data->getPositionGroup();
LLVector4a val;
- val.setSub(v, BaseType::mD[BaseType::CENTER]);
+ val.setSub(v, BaseType::mCenter);
val.setAbs(val);
S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index ab9f8c4c24..24528a8ce9 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -94,6 +94,8 @@ const F32 SKEW_MAX = 0.95f;
const F32 SCULPT_MIN_AREA = 0.002f;
const S32 SCULPT_MIN_AREA_DETAIL = 1;
+extern BOOL gDebugGL;
+
BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
{
LLVector3 test = (pt2-pt1)%(pt3-pt2);
@@ -308,22 +310,26 @@ public:
}
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
- {
+ { //this is a depth first traversal, so it's safe to assum all children have complete
+ //bounding data
+
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
LLVector4a& min = node->mExtents[0];
LLVector4a& max = node->mExtents[1];
- if (branch->getElementCount() != 0)
- {
+ if (!branch->getData().empty())
+ { //node has data, find AABB that binds data set
const LLVolumeTriangle* tri = *(branch->getData().begin());
-
+
+ //initialize min/max to first available vertex
min = *(tri->mV[0]);
max = *(tri->mV[0]);
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
branch->getData().begin(); iter != branch->getData().end(); ++iter)
- {
+ { //for each triangle in node
+
//stretch by triangles in node
tri = *iter;
@@ -335,33 +341,27 @@ public:
max.setMax(max, *tri->mV[1]);
max.setMax(max, *tri->mV[2]);
}
-
- for (S32 i = 0; i < branch->getChildCount(); ++i)
- { //stretch by child extents
- LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
- min.setMin(min, child->mExtents[0]);
- max.setMax(min, child->mExtents[1]);
- }
}
- else if (branch->getChildCount() != 0)
- {
+ else if (!branch->getChildren().empty())
+ { //no data, but child nodes exist
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
+ //initialize min/max to extents of first child
min = child->mExtents[0];
max = child->mExtents[1];
-
- for (S32 i = 1; i < branch->getChildCount(); ++i)
- { //stretch by child extents
- child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
- min.setMin(min, child->mExtents[0]);
- max.setMax(max, child->mExtents[1]);
- }
}
else
{
llerrs << "WTF? Empty leaf" << llendl;
}
-
+
+ for (S32 i = 0; i < branch->getChildCount(); ++i)
+ { //stretch by child extents
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+ min.setMin(min, child->mExtents[0]);
+ max.setMax(max, child->mExtents[1]);
+ }
+
node->mBounds[0].setAdd(min, max);
node->mBounds[0].mul(0.5f);
@@ -370,7 +370,6 @@ public:
}
};
-
//-------------------------------------------------------------------
// statics
//-------------------------------------------------------------------
@@ -1991,7 +1990,7 @@ void LLVolumeFace::VertexData::init()
{
if (!mData)
{
- mData = (LLVector4a*) ll_aligned_malloc_16(32);
+ mData = new LLVector4a[2];
}
}
@@ -2020,7 +2019,7 @@ const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolu
LLVolumeFace::VertexData::~VertexData()
{
- ll_aligned_free_16(mData);
+ delete [] mData;
}
LLVector4a& LLVolumeFace::VertexData::getPosition()
@@ -2258,12 +2257,12 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
U32 cur_influence = 0;
LLVector4 wght(0,0,0,0);
- while (joint != END_INFLUENCES)
+ while (joint != END_INFLUENCES && idx < weights.size())
{
U16 influence = weights[idx++];
influence |= ((U16) weights[idx++] << 8);
- F32 w = llmin((F32) influence / 65535.f, 0.99999f);
+ F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
wght.mV[cur_influence++] = (F32) joint + w;
if (cur_influence >= 4)
@@ -2570,14 +2569,13 @@ void LLVolume::makeTetrahedron()
mIsTetrahedron = TRUE;
}
-void LLVolume::copyVolumeFaces(LLVolume* volume)
+void LLVolume::copyVolumeFaces(const LLVolume* volume)
{
mVolumeFaces = volume->mVolumeFaces;
mSculptLevel = 0;
mIsTetrahedron = FALSE;
}
-
S32 LLVolume::getNumFaces() const
{
#if LL_MESH_ENABLED
@@ -5232,7 +5230,7 @@ LLVolumeFace::LLVolumeFace() :
mWeights(NULL),
mOctree(NULL)
{
- mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+ mExtents = new LLVector4a[3];
mCenter = mExtents+2;
}
@@ -5253,7 +5251,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mWeights(NULL),
mOctree(NULL)
{
- mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+ mExtents = new LLVector4a[3];
mCenter = mExtents+2;
*this = src;
}
@@ -5288,7 +5286,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
if (mNumVertices)
{
- S32 vert_size = mNumVertices*4*sizeof(F32);
+ S32 vert_size = mNumVertices*sizeof(LLVector4a);
S32 tc_size = (mNumVertices*8+0xF) & ~0xF;
LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
@@ -5303,7 +5301,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
}
else
{
- ll_aligned_free_16(mBinormals);
+ delete [] mBinormals;
mBinormals = NULL;
}
@@ -5314,7 +5312,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
}
else
{
- ll_aligned_free_16(mWeights);
+ delete [] mWeights;
mWeights = NULL;
}
}
@@ -5332,7 +5330,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
LLVolumeFace::~LLVolumeFace()
{
- ll_aligned_free_16(mExtents);
+ delete [] mExtents;
mExtents = NULL;
freeData();
@@ -5340,17 +5338,17 @@ LLVolumeFace::~LLVolumeFace()
void LLVolumeFace::freeData()
{
- ll_aligned_free_16(mPositions);
+ delete [] mPositions;
mPositions = NULL;
- ll_aligned_free_16(mNormals);
+ delete [] mNormals;
mNormals = NULL;
- ll_aligned_free_16(mTexCoords);
+ delete [] mTexCoords;
mTexCoords = NULL;
- ll_aligned_free_16(mIndices);
+ delete [] mIndices;
mIndices = NULL;
- ll_aligned_free_16(mBinormals);
+ delete [] mBinormals;
mBinormals = NULL;
- ll_aligned_free_16(mWeights);
+ delete [] mWeights;
mWeights = NULL;
delete mOctree;
@@ -5463,56 +5461,73 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
}
-void LLVolumeFace::createOctree()
+void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
{
- LLVector4a center;
- LLVector4a size;
- center.splat(0.f);
- size.splat(1.f);
+ if (mOctree)
+ {
+ return;
+ }
mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
new LLVolumeOctreeListener(mOctree);
for (U32 i = 0; i < mNumIndices; i+= 3)
- {
+ { //for each triangle
LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
const LLVector4a& v0 = mPositions[mIndices[i]];
const LLVector4a& v1 = mPositions[mIndices[i+1]];
const LLVector4a& v2 = mPositions[mIndices[i+2]];
+ //store pointers to vertex data
tri->mV[0] = &v0;
tri->mV[1] = &v1;
tri->mV[2] = &v2;
+ //store indices
tri->mIndex[0] = mIndices[i];
tri->mIndex[1] = mIndices[i+1];
tri->mIndex[2] = mIndices[i+2];
+ //get minimum point
LLVector4a min = v0;
min.setMin(min, v1);
min.setMin(min, v2);
+ //get maximum point
LLVector4a max = v0;
max.setMax(max, v1);
max.setMax(max, v2);
+ //compute center
LLVector4a center;
center.setAdd(min, max);
center.mul(0.5f);
*tri->mPositionGroup = center;
+ //compute "radius"
LLVector4a size;
size.setSub(max,min);
- tri->mRadius = size.getLength3().getF32() * 0.5f;
+ tri->mRadius = size.getLength3().getF32() * scaler;
+ //insert
mOctree->insert(tri);
}
+ //remove unneeded octree layers
+ while (!mOctree->balance()) { }
+
+ //calculate AABB for each node
LLVolumeOctreeRebound rebound(this);
rebound.traverse(mOctree);
+
+ if (gDebugGL)
+ {
+ LLVolumeOctreeValidate validate;
+ validate.traverse(mOctree);
+ }
}
@@ -6146,21 +6161,21 @@ void LLVolumeFace::createBinormals()
void LLVolumeFace::resizeVertices(S32 num_verts)
{
- ll_aligned_free_16(mPositions);
- ll_aligned_free_16(mNormals);
- ll_aligned_free_16(mBinormals);
- ll_aligned_free_16(mTexCoords);
+ delete [] mPositions;
+ delete [] mNormals;
+ delete [] mBinormals;
+ delete [] mTexCoords;
mBinormals = NULL;
if (num_verts)
{
- mPositions = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
- mNormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+ mPositions = new LLVector4a[num_verts];
+ mNormals = new LLVector4a[num_verts];
//pad texture coordinate block end to allow for QWORD reads
S32 size = ((num_verts*8) + 0xF) & ~0xF;
- mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
+ mTexCoords = new LLVector2[size/8];
}
else
{
@@ -6184,20 +6199,20 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
S32 old_size = mNumVertices*16;
//positions
- LLVector4a* dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+ LLVector4a* dst = new LLVector4a[new_verts];
if (mPositions)
{
LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mPositions, old_size);
- ll_aligned_free_16(mPositions);
+ delete [] mPositions;
}
mPositions = dst;
//normals
- dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+ dst = new LLVector4a[new_verts];
if (mNormals)
{
LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mNormals, old_size);
- ll_aligned_free_16(mNormals);
+ delete [] mNormals;
}
mNormals = dst;
@@ -6205,19 +6220,18 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
new_size = ((new_verts*8)+0xF) & ~0xF;
old_size = ((mNumVertices*8)+0xF) & ~0xF;
- dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
{
- LLVector2* dst = (LLVector2*) ll_aligned_malloc_16(new_size);
+ LLVector2* dst = new LLVector2[new_size/8];
if (mTexCoords)
{
LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mTexCoords, old_size);
- ll_aligned_free_16(mTexCoords);
+ delete [] mTexCoords;
}
+ mTexCoords = dst;
}
- mTexCoords = (LLVector2*) dst;
//just clear binormals
- ll_aligned_free_16(mBinormals);
+ delete [] mBinormals;
mBinormals = NULL;
mPositions[mNumVertices] = pos;
@@ -6229,26 +6243,26 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
void LLVolumeFace::allocateBinormals(S32 num_verts)
{
- ll_aligned_free_16(mBinormals);
- mBinormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+ delete [] mBinormals;
+ mBinormals = new LLVector4a[num_verts];
}
void LLVolumeFace::allocateWeights(S32 num_verts)
{
- ll_aligned_free_16(mWeights);
- mWeights = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+ delete [] mWeights;
+ mWeights = new LLVector4a[num_verts];
}
void LLVolumeFace::resizeIndices(S32 num_indices)
{
- ll_aligned_free_16(mIndices);
-
+ delete [] mIndices;
+
if (num_indices)
{
//pad index block end to allow for QWORD reads
S32 size = ((num_indices*2) + 0xF) & ~0xF;
- mIndices = (U16*) ll_aligned_malloc_16(size);
+ mIndices = new U16[size/2];
}
else
{
@@ -6266,11 +6280,11 @@ void LLVolumeFace::pushIndex(const U16& idx)
S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
if (new_size != old_size)
{
- U16* dst = (U16*) ll_aligned_malloc_16(new_size);
+ U16* dst = new U16[new_size/2];
if (mIndices)
{
LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mIndices, old_size);
- ll_aligned_free_16(mIndices);
+ delete [] mIndices;
}
mIndices = dst;
}
@@ -6313,9 +6327,9 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
}
//allocate new buffer space
- LLVector4a* new_pos = (LLVector4a*) ll_aligned_malloc_16(new_count*16);
- LLVector4a* new_norm = (LLVector4a*) ll_aligned_malloc_16(new_count*16);
- LLVector2* new_tc = (LLVector2*) ll_aligned_malloc_16((new_count*8+0xF) & ~0xF);
+ LLVector4a* new_pos = new LLVector4a[new_count];
+ LLVector4a* new_norm = new LLVector4a[new_count];
+ LLVector2* new_tc = new LLVector2[((new_count*8+0xF) & ~0xF)/8];
if (mNumVertices > 0)
@@ -6326,10 +6340,10 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
}
//free old buffer space
- ll_aligned_free_16(mPositions);
- ll_aligned_free_16(mNormals);
- ll_aligned_free_16(mTexCoords);
-
+ delete [] mPositions;
+ delete [] mNormals;
+ delete [] mTexCoords;
+
//point to new buffers
mPositions = new_pos;
mNormals = new_norm;
@@ -6379,7 +6393,7 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
new_count = mNumIndices + face.mNumIndices;
//allocate new index buffer
- U16* new_indices = (U16*) ll_aligned_malloc_16((new_count*2+0xF) & ~0xF);
+ U16* new_indices = new U16[((new_count*2+0xF) & ~0xF)/2];
if (mNumIndices > 0)
{ //copy old index buffer
S32 old_size = (mNumIndices*2+0xF) & ~0xF;
@@ -6387,8 +6401,8 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
}
//free old index buffer
- ll_aligned_free_16(mIndices);
-
+ delete [] mIndices;
+
//point to new index buffer
mIndices = new_indices;
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index af28337f57..32364bd4b8 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -882,7 +882,7 @@ public:
};
void optimize(F32 angle_cutoff = 2.f);
- void createOctree();
+ void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
enum
{
@@ -1044,7 +1044,7 @@ public:
LLVector3 mLODScaleBias; // vector for biasing LOD based on scale
void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
- void copyVolumeFaces(LLVolume* volume);
+ void copyVolumeFaces(const LLVolume* volume);
private:
void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
index 194b1faf81..cb6211f63c 100644
--- a/indra/llmath/llvolumeoctree.cpp
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -126,8 +126,8 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
const F32* center = vl->mBounds[0].getF32();
const F32* size = vl->mBounds[1].getF32();*/
- //if (LLLineSegmentBoxIntersect(mStart.getF32(), mEnd.getF32(), vl->mBounds[0].getF32(), vl->mBounds[1].getF32()))
- if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
+ //if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
+ if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr()))
{
node->accept(this);
for (S32 i = 0; i < node->getChildCount(); ++i)
@@ -206,3 +206,60 @@ const F32& LLVolumeTriangle::getBinRadius() const
}
+//TEST CODE
+
+void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+{
+ LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ //make sure bounds matches extents
+ LLVector4a& min = node->mExtents[0];
+ LLVector4a& max = node->mExtents[1];
+
+ LLVector4a& center = node->mBounds[0];
+ LLVector4a& size = node->mBounds[1];
+
+ LLVector4a test_min, test_max;
+ test_min.setSub(center, size);
+ test_max.setAdd(center, size);
+
+ if (!test_min.equals3(min, 0.001f) ||
+ !test_max.equals3(max, 0.001f))
+ {
+ llerrs << "Bad bounding box data found." << llendl;
+ }
+
+ test_min.sub(LLVector4a(0.001f));
+ test_max.add(LLVector4a(0.001f));
+
+ for (U32 i = 0; i < branch->getChildCount(); ++i)
+ {
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+
+ //make sure all children fit inside this node
+ if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) ||
+ child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ))
+ {
+ llerrs << "Child protrudes from bounding box." << llendl;
+ }
+ }
+
+ //children fit, check data
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
+ iter != branch->getData().end(); ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ //validate triangle
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) ||
+ tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ))
+ {
+ llerrs << "Triangle protrudes from node." << llendl;
+ }
+ }
+ }
+}
+
+
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 0031626498..0a02a2c597 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -88,8 +88,6 @@ public:
F32* mClosestT;
bool mHitFace;
- LLOctreeTriangleRayIntersect() { };
-
LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
const LLVolumeFace* face, F32* closest_t,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal);
@@ -134,5 +132,9 @@ public:
virtual const F32& getBinRadius() const;
};
+class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
+{
+ virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
+};
#endif
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 73f752b218..0f2d461511 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1422,9 +1422,7 @@ if (WINDOWS)
set_target_properties(${VIEWER_BINARY_NAME}
PROPERTIES
- # *TODO -reenable this once we get server usage sorted out
- #LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:\"__tcmalloc\""
- LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS"
+ LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc"
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO"
LINK_FLAGS_RELEASE ${release_flags}
)
@@ -1640,6 +1638,7 @@ if (WINDOWS)
endif (WINDOWS)
target_link_libraries(${VIEWER_BINARY_NAME}
+ ${GOOGLE_PERFTOOLS_LIBRARIES}
${LLAUDIO_LIBRARIES}
${LLCHARACTER_LIBRARIES}
${LLIMAGE_LIBRARIES}
@@ -1676,7 +1675,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${LLLOGIN_LIBRARIES}
- ${GOOGLE_PERFTOOLS_LIBRARIES}
${LLCONVEXDECOMP_LIBRARY}
)
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 68f52e04bc..efbb62011c 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -189,6 +189,11 @@ LLVOVolume* LLDrawable::getVOVolume() const
}
}
+const LLMatrix4& LLDrawable::getRenderMatrix() const
+{
+ return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix();
+}
+
BOOL LLDrawable::isLight() const
{
LLViewerObject* objectp = mVObjp;
@@ -713,8 +718,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
LLVOVolume* volume = getVOVolume();
if (volume)
{
- volume->updateRelativeXform();
- pos = volume->getRelativeXform().getTranslation();
+ pos.set(getPositionGroup().getF32ptr());
if (isStatic())
{
pos += volume->getRegion()->getOriginAgent();
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index fc90bc57c4..a17e2172aa 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -101,7 +101,7 @@ public:
LLVOVolume* getVOVolume() const; // cast mVObjp tp LLVOVolume if OK
const LLMatrix4& getWorldMatrix() const { return mXform.getWorldMatrix(); }
- const LLMatrix4& getRenderMatrix() const { return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix(); }
+ const LLMatrix4& getRenderMatrix() const;
void setPosition(LLVector3 v) const { }
const LLVector3& getPosition() const { return mXform.getPosition(); }
const LLVector3& getWorldPosition() const { return mXform.getPositionW(); }
@@ -250,35 +250,37 @@ public:
typedef enum e_drawable_flags
{
- IN_REBUILD_Q1 = 0x00000002,
- IN_REBUILD_Q2 = 0x00000004,
- IN_LIGHT_Q = 0x00000008,
- EARLY_MOVE = 0x00000010,
- MOVE_UNDAMPED = 0x00000020,
- ON_MOVE_LIST = 0x00000040,
- USE_BACKLIGHT = 0x00000080,
- UV = 0x00000100,
- UNLIT = 0x00000200,
- LIGHT = 0x00000400,
- LIGHTING_BUILT = 0x00000800,
- REBUILD_VOLUME = 0x00001000, //volume changed LOD or parameters, or vertex buffer changed
- REBUILD_TCOORD = 0x00002000, //texture coordinates changed
- REBUILD_COLOR = 0x00004000, //color changed
- REBUILD_POSITION= 0x00010000, //vertex positions/normals changed
+ IN_REBUILD_Q1 = 0x00000001,
+ IN_REBUILD_Q2 = 0x00000002,
+ IN_LIGHT_Q = 0x00000004,
+ EARLY_MOVE = 0x00000008,
+ MOVE_UNDAMPED = 0x00000010,
+ ON_MOVE_LIST = 0x00000020,
+ USE_BACKLIGHT = 0x00000040,
+ UV = 0x00000080,
+ UNLIT = 0x00000100,
+ LIGHT = 0x00000200,
+ LIGHTING_BUILT = 0x00000400,
+ REBUILD_VOLUME = 0x00000800, //volume changed LOD or parameters, or vertex buffer changed
+ REBUILD_TCOORD = 0x00001000, //texture coordinates changed
+ REBUILD_COLOR = 0x00002000, //color changed
+ REBUILD_POSITION= 0x00004000, //vertex positions/normals changed
REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
REBUILD_ALL = REBUILD_GEOMETRY|REBUILD_VOLUME,
- ON_SHIFT_LIST = 0x00100000,
- BLOCKER = 0x00400000,
- ACTIVE = 0x00800000,
- DEAD = 0x01000000,
- INVISIBLE = 0x02000000, // stay invisible until flag is cleared
- NEARBY_LIGHT = 0x04000000, // In gPipeline.mNearbyLightSet
- BUILT = 0x08000000,
- FORCE_INVISIBLE = 0x10000000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
- CLEAR_INVISIBLE = 0x20000000, // clear FORCE_INVISIBLE next draw frame
- REBUILD_SHADOW = 0x40000000,
- HAS_ALPHA = 0x80000000,
+ REBUILD_RIGGED = 0x00008000,
+ ON_SHIFT_LIST = 0x00010000,
+ BLOCKER = 0x00020000,
+ ACTIVE = 0x00040000,
+ DEAD = 0x00080000,
+ INVISIBLE = 0x00100000, // stay invisible until flag is cleared
+ NEARBY_LIGHT = 0x00200000, // In gPipeline.mNearbyLightSet
+ BUILT = 0x00400000,
+ FORCE_INVISIBLE = 0x00800000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
+ CLEAR_INVISIBLE = 0x01000000, // clear FORCE_INVISIBLE next draw frame
+ REBUILD_SHADOW = 0x02000000,
+ HAS_ALPHA = 0x04000000,
+ RIGGED = 0x08000000,
} EDrawableFlags;
LLXformMatrix mXform;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index ccc060f3fa..5cf6082f12 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1325,6 +1325,12 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
#if LL_MESH_ENABLED
void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
{
+ LLVector4a* weight = vol_face.mWeights;
+ if (!weight)
+ {
+ return;
+ }
+
LLVertexBuffer* buffer = face->mVertexBuffer;
U32 data_mask = 0;
@@ -1403,8 +1409,6 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
}
}
- LLVector4a* weight = vol_face.mWeights;
-
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
@@ -1422,7 +1426,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
{
F32 w = weight[j][k];
- idx[k] = (S32) floorf(w);
+ idx[k] = llclamp((S32) floorf(w), 0, 63);
wght[k] = w - floorf(w);
scale += wght[k];
}
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 7c24eb77cd..3fa60e9f1e 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -556,8 +556,36 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
}
glColor4fv(color.mV);
- mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+
+ if (mDrawablep->isState(LLDrawable::RIGGED))
+ {
+ LLVOVolume* volume = mDrawablep->getVOVolume();
+ if (volume)
+ {
+ LLRiggedVolume* rigged = volume->getRiggedVolume();
+ if (rigged)
+ {
+ LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.f, -1.f);
+ glMultMatrixf((F32*) volume->getRelativeXform().mMatrix);
+ const LLVolumeFace& vol_face = rigged->getVolumeFace(getTEOffset());
+ LLVertexBuffer::unbind();
+ glVertexPointer(3, GL_FLOAT, 16, vol_face.mPositions);
+ if (vol_face.mTexCoords)
+ {
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords);
+ }
+ glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ }
+ }
+ else
+ {
+ mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+ mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+ }
gGL.popMatrix();
}
@@ -720,7 +748,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
//get bounding box
- if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+ if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
{
//VECTORIZE THIS
LLMatrix4a mat_vert;
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index fa5d9b0892..653f838779 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1016,10 +1016,12 @@ S32 LLFloaterTools::calcRenderCost()
LLSelectNode *select_node = *selection_iter;
if (select_node)
{
- LLVOVolume *viewer_volume = (LLVOVolume*)select_node->getObject();
- if (viewer_volume)
+ LLViewerObject *vobj = select_node->getObject();
+ if (vobj->getVolume())
{
- cost += viewer_volume->getRenderCost(textures);
+ LLVOVolume* volume = (LLVOVolume*) vobj;
+
+ cost += volume->getRenderCost(textures);
for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
{
// add the cost of each individual texture in the linkset
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index ff2929695d..21f7e780e2 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -5395,6 +5395,42 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power)
return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
}
+
+//helper function for pushing relevant vertices from drawable to GL
+void pushWireframe(LLDrawable* drawable)
+{
+ if (drawable->isState(LLDrawable::RIGGED))
+ { //render straight from rigged volume if this is a rigged attachment
+ LLVOVolume* vobj = drawable->getVOVolume();
+ if (vobj)
+ {
+ vobj->updateRiggedVolume();
+ LLRiggedVolume* rigged_volume = vobj->getRiggedVolume();
+ if (rigged_volume)
+ {
+ LLVertexBuffer::unbind();
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
+ for (S32 i = 0; i < rigged_volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = rigged_volume->getVolumeFace(i);
+ glVertexPointer(3, GL_FLOAT, 16, face.mPositions);
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
+ gGL.popMatrix();
+ }
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+}
+
void LLSelectNode::renderOneWireframe(const LLColor4& color)
{
LLViewerObject* objectp = getObject();
@@ -5442,11 +5478,7 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color)
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
{
glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- LLFace* face = drawable->getFace(i);
- pushVerts(face, LLVertexBuffer::MAP_VERTEX);
- }
+ pushWireframe(drawable);
}
}
@@ -5455,13 +5487,9 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color)
glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(3.f, 2.f);
+ glPolygonOffset(3.f, 3.f);
glLineWidth(3.f);
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- LLFace* face = drawable->getFace(i);
- pushVerts(face, LLVertexBuffer::MAP_VERTEX);
- }
+ pushWireframe(drawable);
glLineWidth(1.f);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
gGL.popMatrix();
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 425fa42339..0f9f35dc57 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -3035,11 +3035,11 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
{
public:
- LLRenderOctreeRaycast(const LLVector3& start, const LLVector3& end)
+
+ LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+ : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
{
- mStart.load3(start.mV);
- mEnd.load3(end.mV);
- mDir.setSub(mEnd, mStart);
+
}
void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
@@ -3047,9 +3047,22 @@ public:
LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
LLVector3 center, size;
- center.set(vl->mBounds[0].getF32ptr());
- size.set(vl->mBounds[1].getF32ptr());
+
+ 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);
@@ -3061,9 +3074,14 @@ public:
else
{
gGL.color4f(0,0.5f,0.5f, 0.25f);
+ drawBoxOutline(center, size);
+ }
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(3.f);
}
-
- drawBoxOutline(center, size);
gGL.begin(LLRender::TRIANGLES);
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
@@ -3077,6 +3095,12 @@ public:
gGL.vertex3fv(tri->mV[2]->getF32ptr());
}
gGL.end();
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(1.f);
+ }
}
}
};
@@ -3096,26 +3120,63 @@ void renderRaycast(LLDrawable* drawablep)
LLVOVolume* vobj = drawablep->getVOVolume();
LLVolume* volume = vobj->getVolume();
- for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+
+ bool transform = true;
+ if (drawablep->isState(LLDrawable::RIGGED))
{
- const LLVolumeFace& face = volume->getVolumeFace(i);
- if (!face.mOctree)
+ volume = vobj->getRiggedVolume();
+ transform = false;
+ }
+
+ if (volume)
+ {
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
- ((LLVolumeFace*) &face)->createOctree();
- }
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ if (!face.mOctree)
+ {
+ ((LLVolumeFace*) &face)->createOctree();
+ }
- gGL.pushMatrix();
- glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
- LLVector3 start, end;
- start = vobj->agentPositionToVolume(gDebugRaycastStart);
- end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+ gGL.pushMatrix();
+ glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
- LLRenderOctreeRaycast render(start, end);
- gGL.flush();
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- render.traverse(face.mOctree);
- gGL.popMatrix();
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ 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())
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index fd2212f25d..4c1a1958e8 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3279,6 +3279,15 @@ const LLVector3 LLViewerObject::getPositionEdit() const
const LLVector3 LLViewerObject::getRenderPosition() const
{
+ if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+ {
+ LLVOAvatar* avatar = getAvatar();
+ if (avatar)
+ {
+ return avatar->getPositionAgent();
+ }
+ }
+
if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
{
return getPositionAgent();
@@ -3297,6 +3306,11 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const
const LLQuaternion LLViewerObject::getRenderRotation() const
{
LLQuaternion ret;
+ if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+ {
+ return ret;
+ }
+
if (mDrawable.isNull() || mDrawable->isStatic())
{
ret = getRotationEdit();
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 5448e7dcd9..f09ce5b363 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -41,9 +41,11 @@
#include "llviewercontrol.h"
#include "lldir.h"
#include "llflexibleobject.h"
+#include "llfloatertools.h"
#include "llmaterialtable.h"
#include "llprimitive.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llvolumemgr.h"
#include "llvolumemessage.h"
#include "material_codes.h"
@@ -70,6 +72,7 @@
#include "llselectmgr.h"
#include "pipeline.h"
#include "llsdutil.h"
+#include "llmatrix4a.h"
#include "llmediaentry.h"
#include "llmediadataclient.h"
#include "llmeshrepository.h"
@@ -1355,7 +1358,14 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
LLVector4a min,max;
- BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
+ BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+
+ bool rigged = false;
+ LLVolume* volume = mRiggedVolume;
+ if (!volume)
+ {
+ volume = getVolume();
+ }
for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
{
@@ -1364,7 +1374,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
{
continue;
}
- res &= face->genVolumeBBoxes(*getVolume(), i,
+ res &= face->genVolumeBBoxes(*volume, i,
mRelativeXform, mRelativeXformInvTrans,
(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
@@ -1415,7 +1425,21 @@ void LLVOVolume::updateRelativeXform()
LLDrawable* drawable = mDrawable;
- if (drawable->isActive())
+ if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
+ { //rigged volume (which is in agent space) is used for generating bounding boxes etc
+ //inverse of render matrix should go to partition space
+ mRelativeXform = getRenderMatrix();
+
+ F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
+ F32* src = (F32*) mRelativeXform.mMatrix;
+ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
+ dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
+ dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
+
+ mRelativeXform.invert();
+ mRelativeXformInvTrans.transpose();
+ }
+ else if (drawable->isActive())
{
// setup relative transforms
LLQuaternion delta_rot;
@@ -1497,11 +1521,22 @@ void LLVOVolume::updateRelativeXform()
static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
+static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLFastTimer t(FTM_UPDATE_PRIMITIVES);
+ if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
+ {
+ {
+ LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
+ updateRiggedVolume();
+ }
+ genBBoxes(FALSE);
+ mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
+ }
+
if (mVolumeImpl != NULL)
{
BOOL res;
@@ -1597,7 +1632,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLPipeline::sCompiles++;
}
-
+
mVolumeChanged = FALSE;
mLODChanged = FALSE;
mSculptChanged = FALSE;
@@ -2724,6 +2759,11 @@ BOOL LLVOVolume::isVolumeGlobal() const
{
return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
}
+ else if (mRiggedVolume.notNull())
+ {
+ return TRUE;
+ }
+
return FALSE;
}
@@ -3390,12 +3430,37 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
BOOL ret = FALSE;
LLVolume* volume = getVolume();
+
+ bool transform = true;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_RIGGED, TRUE);
+ volume = mRiggedVolume;
+ transform = false;
+ }
+ else
+ { //cannot pick rigged attachments on other avatars or when not in build mode
+ return FALSE;
+ }
+ }
+
if (volume)
{
LLVector3 v_start, v_end, v_dir;
- v_start = agentPositionToVolume(start);
- v_end = agentPositionToVolume(end);
+ if (transform)
+ {
+ v_start = agentPositionToVolume(start);
+ v_end = agentPositionToVolume(end);
+ }
+ else
+ {
+ v_start = start;
+ v_end = end;
+ }
LLVector3 p;
LLVector3 n;
@@ -3455,18 +3520,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
if (intersection != NULL)
{
- *intersection = volumePositionToAgent(p); // must map back to agent space
+ if (transform)
+ {
+ *intersection = volumePositionToAgent(p); // must map back to agent space
+ }
+ else
+ {
+ *intersection = p;
+ }
}
if (normal != NULL)
{
- *normal = volumeDirectionToAgent(n);
+ if (transform)
+ {
+ *normal = volumeDirectionToAgent(n);
+ }
+ else
+ {
+ *normal = n;
+ }
+
(*normal).normVec();
}
if (bi_normal != NULL)
{
- *bi_normal = volumeDirectionToAgent(bn);
+ if (transform)
+ {
+ *bi_normal = volumeDirectionToAgent(bn);
+ }
+ else
+ {
+ *bi_normal = bn;
+ }
(*bi_normal).normVec();
}
@@ -3484,6 +3571,201 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
return ret;
}
+bool LLVOVolume::treatAsRigged()
+{
+ return LLFloater::isVisible(gFloaterTools) &&
+ isAttachment() &&
+ getAvatar() &&
+ getAvatar()->isSelf() &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
+}
+
+LLRiggedVolume* LLVOVolume::getRiggedVolume()
+{
+ return mRiggedVolume;
+}
+
+void LLVOVolume::clearRiggedVolume()
+{
+ if (mRiggedVolume.notNull())
+ {
+ mRiggedVolume = NULL;
+ updateRelativeXform();
+ }
+}
+
+void LLVOVolume::updateRiggedVolume()
+{
+ //Update mRiggedVolume to match current animation frame of avatar.
+ //Also update position/size in octree.
+
+ if (!treatAsRigged())
+ {
+ clearRiggedVolume();
+
+ return;
+ }
+
+ LLVolume* volume = getVolume();
+
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID());
+
+ if (!skin)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ LLVOAvatar* avatar = getAvatar();
+
+ if (!avatar)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ if (!mRiggedVolume)
+ {
+ LLVolumeParams p;
+ mRiggedVolume = new LLRiggedVolume(p);
+ updateRelativeXform();
+ }
+
+ mRiggedVolume->update(skin, avatar, volume);
+
+}
+
+static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
+static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
+
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+{
+ bool copy = false;
+ if (volume->getNumVolumeFaces() != getNumVolumeFaces())
+ {
+ copy = true;
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
+ {
+ const LLVolumeFace& src_face = volume->getVolumeFace(i);
+ const LLVolumeFace& dst_face = getVolumeFace(i);
+
+ if (src_face.mNumIndices != dst_face.mNumIndices ||
+ src_face.mNumVertices != dst_face.mNumVertices)
+ {
+ copy = true;
+ }
+ }
+
+ if (copy)
+ {
+ copyVolumeFaces(volume);
+ }
+
+ //build matrix palette
+ LLMatrix4a mp[64];
+ LLMatrix4* mat = (LLMatrix4*) mp;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = skin->mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& vol_face = volume->getVolumeFace(i);
+
+ LLVolumeFace& dst_face = mVolumeFaces[i];
+
+ LLVector4a* weight = vol_face.mWeights;
+
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+ LLVector4a* pos = dst_face.mPositions;
+
+ {
+ LLFastTimer t(FTM_SKIN_RIGGED);
+
+ for (U32 j = 0; j < dst_face.mNumVertices; ++j)
+ {
+ LLMatrix4a final_mat;
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j][k];
+
+ idx[k] = (S32) floorf(w);
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mp[idx[k]], w);
+
+ final_mat.add(src);
+ }
+
+
+ LLVector4a& v = vol_face.mPositions[j];
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
+ pos[j] = dst;
+ }
+
+ //update bounding box
+ LLVector4a& min = dst_face.mExtents[0];
+ LLVector4a& max = dst_face.mExtents[1];
+
+ min = pos[0];
+ max = pos[1];
+
+ for (U32 j = 1; j < dst_face.mNumVertices; ++j)
+ {
+ min.setMin(min, pos[j]);
+ max.setMax(max, pos[j]);
+ }
+
+ dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
+ dst_face.mCenter->mul(0.5f);
+
+ }
+
+ {
+ LLFastTimer t(FTM_RIGGED_OCTREE);
+ delete dst_face.mOctree;
+ dst_face.mOctree = NULL;
+
+ LLVector4a size;
+ size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
+ size.splat(size.getLength3().getF32()*0.5f);
+
+ dst_face.createOctree(1.f);
+ }
+ }
+}
+
U32 LLVOVolume::getPartitionType() const
{
if (isHUDAttachment())
@@ -3732,6 +4014,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+ bool is_rigged = false;
+
//for each face
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
{
@@ -3747,8 +4031,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
facep->mVertexBuffer = NULL;
facep->mLastVertexBuffer = NULL;
}
-
+
facep->setState(LLFace::RIGGED);
+ is_rigged = true;
//get drawpool of avatar with rigged face
LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
@@ -3958,6 +4243,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
facep->mLastVertexBuffer = NULL;
}
}
+
+ if (is_rigged)
+ {
+ drawablep->setState(LLDrawable::RIGGED);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::RIGGED);
+ }
}
group->mBufferUsage = useage;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index eeb98726c9..f058710a27 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -46,6 +46,8 @@ class LLDrawPool;
class LLSelectNode;
class LLObjectMediaDataClient;
class LLObjectMediaNavigateClient;
+class LLVOAvatar;
+class LLMeshSkinInfo;
typedef std::vector<viewer_media_t> media_list_t;
@@ -54,6 +56,18 @@ enum LLVolumeInterfaceType
INTERFACE_FLEXIBLE = 1,
};
+
+class LLRiggedVolume : public LLVolume
+{
+public:
+ LLRiggedVolume(const LLVolumeParams& params)
+ : LLVolume(params, 0.f)
+ {
+ }
+
+ void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
+};
+
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
class LLVolumeInterface
{
@@ -289,6 +303,21 @@ public:
void removeMDCImpl() { --mMDCImplCount; }
S32 getMDCImplCount() { return mMDCImplCount; }
+
+ //rigged volume update (for raycasting)
+ void updateRiggedVolume();
+ LLRiggedVolume* getRiggedVolume();
+
+ //returns true if volume should be treated as a rigged volume
+ // - Build tools are open
+ // - object is an attachment
+ // - object is attached to self
+ // - object is rendered as rigged
+ bool treatAsRigged();
+
+ //clear out rigged volume and revert back to non-rigged state for picking/LOD/distance updates
+ void clearRiggedVolume();
+
protected:
S32 computeLODDetail(F32 distance, F32 radius);
BOOL calcLOD();
@@ -322,6 +351,9 @@ private:
S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1
S32 mIndexInTex;
S32 mMDCImplCount;
+
+ LLPointer<LLRiggedVolume> mRiggedVolume;
+
// statics
public:
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop