summaryrefslogtreecommitdiff
path: root/indra/llmath
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath')
-rw-r--r--indra/llmath/CMakeLists.txt4
-rw-r--r--indra/llmath/llcamera.cpp216
-rw-r--r--indra/llmath/llcamera.h29
-rw-r--r--indra/llmath/lloctree.h255
-rw-r--r--indra/llmath/lltreenode.h3
-rw-r--r--indra/llmath/llvolume.cpp2331
-rw-r--r--indra/llmath/llvolume.h183
-rw-r--r--indra/llmath/llvolumemgr.cpp15
-rw-r--r--indra/llmath/llvolumemgr.h1
-rw-r--r--indra/llmath/m4math.cpp88
-rw-r--r--indra/llmath/m4math.h7
-rw-r--r--indra/llmath/v2math.cpp15
-rw-r--r--indra/llmath/v2math.h3
-rw-r--r--indra/llmath/v3math.cpp22
-rw-r--r--indra/llmath/v3math.h17
-rw-r--r--indra/llmath/v4color.h18
16 files changed, 2368 insertions, 839 deletions
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index e93fe90650..dda07133d5 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -22,6 +22,7 @@ set(llmath_SOURCE_FILES
llsphere.cpp
llvolume.cpp
llvolumemgr.cpp
+ llvolumeoctree.cpp
llsdutil_math.cpp
m3math.cpp
m4math.cpp
@@ -62,8 +63,11 @@ set(llmath_HEADER_FILES
llv4matrix3.h
llv4matrix4.h
llv4vector3.h
+ llvector4a.h
+ llmatrix4a.h
llvolume.h
llvolumemgr.h
+ llvolumeoctree.h
llsdutil_math.h
m3math.h
m4math.h
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 487ed6451f..6b56e4870e 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -48,10 +48,10 @@ LLCamera::LLCamera() :
mPlaneCount(6),
mFrustumCornerDist(0.f)
{
+ alignPlanes();
calculateFrustumPlanes();
}
-
LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) :
LLCoordFrame(),
mViewHeightInPixels(view_height_in_pixels),
@@ -59,6 +59,7 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
mPlaneCount(6),
mFrustumCornerDist(0.f)
{
+ alignPlanes();
mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO);
mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE);
if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE;
@@ -67,6 +68,23 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
setView(vertical_fov_rads);
}
+LLCamera::~LLCamera()
+{
+
+}
+
+const LLCamera& LLCamera::operator=(const LLCamera& rhs)
+{
+ memcpy(this, &rhs, sizeof(LLCamera));
+ alignPlanes();
+ LLVector4a::memcpyNonAliased16((F32*) mAgentPlanes, (F32*) rhs.mAgentPlanes, 4*7);
+ return *this;
+}
+
+void LLCamera::alignPlanes()
+{
+ mAgentPlanes = (LLPlane*) LL_NEXT_ALIGNED_ADDRESS<U8>(mAgentPlaneBuffer);
+}
// ---------------- LLCamera::getFoo() member functions ----------------
@@ -91,8 +109,8 @@ F32 LLCamera::getMaxView() const
void LLCamera::setUserClipPlane(LLPlane plane)
{
mPlaneCount = 7;
- mAgentPlanes[6].p = plane;
- mAgentPlanes[6].mask = calcPlaneMask(plane);
+ mAgentPlanes[6] = plane;
+ mPlaneMask[6] = calcPlaneMask(plane);
}
void LLCamera::disableUserClipPlane()
@@ -164,129 +182,66 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
// ---------------- test methods ----------------
-S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
-{
- static const LLVector3 scaler[] = {
- LLVector3(-1,-1,-1),
- LLVector3( 1,-1,-1),
- LLVector3(-1, 1,-1),
- LLVector3( 1, 1,-1),
- LLVector3(-1,-1, 1),
- LLVector3( 1,-1, 1),
- LLVector3(-1, 1, 1),
- LLVector3( 1, 1, 1)
+S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
+{
+ static const LLVector4a scaler[] = {
+ LLVector4a(-1,-1,-1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a(-1, 1,-1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1,-1, 1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a( 1, 1, 1)
};
U8 mask = 0;
S32 result = 2;
- /*if (mFrustumCornerDist > 0.f && radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
- { //box is larger than frustum, check frustum quads against box planes
-
- static const LLVector3 dir[] =
- {
- LLVector3(1, 0, 0),
- LLVector3(-1, 0, 0),
- LLVector3(0, 1, 0),
- LLVector3(0, -1, 0),
- LLVector3(0, 0, 1),
- LLVector3(0, 0, -1)
- };
-
- U32 quads[] =
+ for (U32 i = 0; i < mPlaneCount; i++)
+ {
+ mask = mPlaneMask[i];
+ if (mask == 0xff)
{
- 0, 1, 2, 3,
- 0, 1, 5, 4,
- 2, 3, 7, 6,
- 3, 0, 7, 4,
- 1, 2, 6, 4,
- 4, 5, 6, 7
- };
-
- result = 0;
-
- BOOL total_inside = TRUE;
- for (U32 i = 0; i < 6; i++)
- {
- LLVector3 p = center + radius.scaledVec(dir[i]);
- F32 d = -p*dir[i];
-
- for (U32 j = 0; j < 6; j++)
- { //for each quad
- F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
- if (dist > 0)
- { //at least one frustum point is outside the AABB
- total_inside = FALSE;
- for (U32 k = 1; k < 4; k++)
- { //for each other point on quad
- if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f)
- { //quad is straddling some plane of AABB
- return 1;
- }
- }
- }
- else
- {
- for (U32 k = 1; k < 4; k++)
- {
- if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
- {
- return 1;
- }
- }
- }
- }
+ continue;
}
- if (total_inside)
+ const LLPlane& p = mAgentPlanes[i];
+ const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p);
+ float d = p.mV[3];
+ LLVector4a rscale;
+ rscale.setMul(radius, scaler[mask]);
+
+ LLVector4a minp, maxp;
+ minp.setSub(center, rscale);
+ maxp.setAdd(center, rscale);
+
+ if (n.dot3(minp) > -d)
{
- result = 1;
+ return 0;
}
- }
- else*/
- {
- for (U32 i = 0; i < mPlaneCount; i++)
+
+ if (n.dot3(maxp) > -d)
{
- mask = mAgentPlanes[i].mask;
- if (mask == 0xff)
- {
- continue;
- }
- LLPlane p = mAgentPlanes[i].p;
- LLVector3 n = LLVector3(p);
- float d = p.mV[3];
- LLVector3 rscale = radius.scaledVec(scaler[mask]);
-
- LLVector3 minp = center - rscale;
- LLVector3 maxp = center + rscale;
-
- if (n * minp > -d)
- {
- return 0;
- }
-
- if (n * maxp > -d)
- {
- result = 1;
- }
+ result = 1;
}
}
-
return result;
}
-S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius)
-{
- static const LLVector3 scaler[] = {
- LLVector3(-1,-1,-1),
- LLVector3( 1,-1,-1),
- LLVector3(-1, 1,-1),
- LLVector3( 1, 1,-1),
- LLVector3(-1,-1, 1),
- LLVector3( 1,-1, 1),
- LLVector3(-1, 1, 1),
- LLVector3( 1, 1, 1)
+
+S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
+{
+ static const LLVector4a scaler[] = {
+ LLVector4a(-1,-1,-1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a(-1, 1,-1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1,-1, 1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a( 1, 1, 1)
};
U8 mask = 0;
@@ -299,25 +254,28 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& r
continue;
}
- mask = mAgentPlanes[i].mask;
+ mask = mPlaneMask[i];
if (mask == 0xff)
{
continue;
}
- LLPlane p = mAgentPlanes[i].p;
- LLVector3 n = LLVector3(p);
+
+ const LLPlane& p = mAgentPlanes[i];
+ const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p);
float d = p.mV[3];
- LLVector3 rscale = radius.scaledVec(scaler[mask]);
+ LLVector4a rscale;
+ rscale.setMul(radius, scaler[mask]);
- LLVector3 minp = center - rscale;
- LLVector3 maxp = center + rscale;
+ LLVector4a minp, maxp;
+ minp.setSub(center, rscale);
+ maxp.setAdd(center, rscale);
- if (n * minp > -d)
+ if (n.dot3(minp) > -d)
{
return 0;
}
- if (n * maxp > -d)
+ if (n.dot3(maxp) > -d)
{
result = 1;
}
@@ -447,12 +405,12 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius)
int res = 2;
for (int i = 0; i < 6; i++)
{
- if (mAgentPlanes[i].mask == 0xff)
+ if (mPlaneMask[i] == 0xff)
{
continue;
}
- float d = mAgentPlanes[i].p.dist(sphere_center);
+ float d = mAgentPlanes[i].dist(sphere_center);
if (d > radius)
{
@@ -644,12 +602,14 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx)
return;
}
- mAgentPlanes[idx].mask = 0xff;
- mAgentPlanes[idx].p.clearVec();
+ mPlaneMask[idx] = 0xff;
+ mAgentPlanes[idx].clearVec();
}
void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
{
+ alignPlanes();
+
for (int i = 0; i < 8; i++)
{
mAgentFrustum[i] = frust[i];
@@ -662,27 +622,27 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
//order of planes is important, keep most likely to fail in the front of the list
//near - frust[0], frust[1], frust[2]
- mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]);
+ mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]);
//far
- mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]);
+ mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
//left
- mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]);
+ mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
//right
- mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]);
+ mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
//top
- mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]);
+ mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
//bottom
- mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]);
+ mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
//cache plane octant facing mask for use in AABBInFrustum
for (U32 i = 0; i < mPlaneCount; i++)
{
- mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p);
+ mPlaneMask[i] = calcPlaneMask(mAgentPlanes[i]);
}
}
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 0c81067919..c40e819dcf 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -37,6 +37,7 @@
#include "llmath.h"
#include "llcoordframe.h"
#include "llplane.h"
+#include "llvector4a.h"
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
@@ -79,6 +80,14 @@ class LLCamera
: public LLCoordFrame
{
public:
+
+ LLCamera(const LLCamera& rhs)
+ {
+ *this = rhs;
+ }
+
+ const LLCamera& operator=(const LLCamera& rhs);
+
enum {
PLANE_LEFT = 0,
PLANE_RIGHT = 1,
@@ -129,13 +138,9 @@ private:
LLPlane mWorldPlanes[PLANE_NUM];
LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
- struct frustum_plane
- {
- frustum_plane() : mask(0) {}
- LLPlane p;
- U8 mask;
- };
- frustum_plane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+ LLPlane* mAgentPlanes; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+ U8 mAgentPlaneBuffer[sizeof(LLPlane)*8];
+ U8 mPlaneMask[7];
U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
@@ -143,12 +148,14 @@ private:
public:
LLVector3 mAgentFrustum[8]; //8 corners of 6-plane frustum
F32 mFrustumCornerDist; //distance to corner of frustum against far clip plane
- LLPlane getAgentPlane(U32 idx) { return mAgentPlanes[idx].p; }
+ LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; }
public:
LLCamera();
LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
- virtual ~LLCamera(){} // no-op virtual destructor
+ virtual ~LLCamera();
+
+ void alignPlanes();
void setUserClipPlane(LLPlane plane);
void disableUserClipPlane();
@@ -199,8 +206,8 @@ public:
S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
- S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
- S32 AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius);
+ S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
+ S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
//does a quick 'n dirty sphere-sphere check
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 2f34fb1bb0..59828ae565 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -35,6 +35,7 @@
#include "lltreenode.h"
#include "v3math.h"
+#include "llvector4a.h"
#include <vector>
#include <set>
@@ -73,6 +74,13 @@ public:
};
template <class T>
+class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
+{
+public:
+ virtual void traverse(const LLOctreeNode<T>* node);
+};
+
+template <class T>
class LLOctreeNode : public LLTreeNode<T>
{
public:
@@ -87,23 +95,22 @@ public:
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
- static const U8 OCTANT_POSITIVE_X = 0x01;
- static const U8 OCTANT_POSITIVE_Y = 0x02;
- static const U8 OCTANT_POSITIVE_Z = 0x04;
-
- LLOctreeNode( LLVector3d center,
- LLVector3d size,
+ LLOctreeNode( const LLVector4a& center,
+ const LLVector4a& size,
BaseType* parent,
- U8 octant = 255)
+ S32 octant = -1)
: mParent((oct_node*)parent),
- mCenter(center),
- mSize(size),
mOctant(octant)
{
+ mD = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*4);
+
+ mD[CENTER] = center;
+ mD[SIZE] = size;
+
updateMinMax();
- if ((mOctant == 255) && mParent)
+ if ((mOctant == -1) && mParent)
{
- mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
+ mOctant = ((oct_node*) mParent)->getOctant(mD[CENTER]);
}
clearChildren();
@@ -117,43 +124,30 @@ 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 LLVector3d& getCenter() const { return mCenter; }
- inline const LLVector3d& getSize() const { return mSize; }
- inline void setCenter(LLVector3d center) { mCenter = center; }
- inline void setSize(LLVector3d size) { mSize = size; }
- inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
- inline U8 getOctant() const { return mOctant; }
- inline void setOctant(U8 octant) { mOctant = octant; }
+ 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 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 const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
- U8 getOctant(const F64 pos[]) const //get the octant pos is in
+ S32 getOctant(const LLVector4a& pos) const //get the octant pos is in
{
- U8 ret = 0;
-
- if (pos[0] > mCenter.mdV[0])
- {
- ret |= OCTANT_POSITIVE_X;
- }
- if (pos[1] > mCenter.mdV[1])
- {
- ret |= OCTANT_POSITIVE_Y;
- }
- if (pos[2] > mCenter.mdV[2])
- {
- ret |= OCTANT_POSITIVE_Z;
- }
-
- return ret;
+ return pos.greaterThan4(mD[CENTER]).getComparisonMask() & 0x7;
}
- inline bool isInside(const LLVector3d& pos, const F64& rad) const
+ inline bool isInside(const LLVector4a& pos, const F32& rad) const
{
- return rad <= mSize.mdV[0]*2.0 && isInside(pos);
+ return rad <= mD[SIZE][0]*2.f && isInside(pos);
}
inline bool isInside(T* data) const
@@ -161,29 +155,27 @@ public:
return isInside(data->getPositionGroup(), data->getBinRadius());
}
- bool isInside(const LLVector3d& pos) const
+ bool isInside(const LLVector4a& pos) const
{
- const F64& x = pos.mdV[0];
- const F64& y = pos.mdV[1];
- const F64& z = pos.mdV[2];
-
- if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
- y > mMax.mdV[1] || y <= mMin.mdV[1] ||
- z > mMax.mdV[2] || z <= mMin.mdV[2])
+ S32 gt = pos.greaterThan4(mD[MAX]).getComparisonMask() & 0x7;
+ if (gt)
{
return false;
}
-
+
+ S32 lt = pos.lessEqual4(mD[MIN]).getComparisonMask() & 0x7;
+ if (lt)
+ {
+ return false;
+ }
+
return true;
}
void updateMinMax()
{
- for (U32 i = 0; i < 3; i++)
- {
- mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
- mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
- }
+ mD[MAX].setAdd(mD[CENTER], mD[SIZE]);
+ mD[MIN].setSub(mD[CENTER], mD[SIZE]);
}
inline oct_listener* getOctListener(U32 index)
@@ -196,34 +188,34 @@ public:
return contains(xform->getBinRadius());
}
- bool contains(F64 radius)
+ bool contains(F32 radius)
{
if (mParent == NULL)
{ //root node contains nothing
return false;
}
- F64 size = mSize.mdV[0];
- F64 p_size = size * 2.0;
+ F32 size = mD[SIZE][0];
+ F32 p_size = size * 2.f;
- return (radius <= 0.001 && size <= 0.001) ||
+ return (radius <= 0.001f && size <= 0.001f) ||
(radius <= p_size && radius > size);
}
- static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
+ static void pushCenter(LLVector4a &center, const LLVector4a &size, const T* data)
{
- const LLVector3d& pos = data->getPositionGroup();
- for (U32 i = 0; i < 3; i++)
- {
- if (pos.mdV[i] > center.mdV[i])
- {
- center.mdV[i] += size.mdV[i];
- }
- else
- {
- center.mdV[i] -= size.mdV[i];
- }
- }
+ const LLVector4a& pos = data->getPositionGroup();
+
+ LLVector4a gt = pos.greaterThan4(center);
+
+ LLVector4a up;
+ up.mQ = _mm_and_ps(size.mQ, gt.mQ);
+
+ LLVector4a down;
+ down.mQ = _mm_andnot_ps(gt.mQ, size.mQ);
+
+ center.add(up);
+ center.sub(down);
}
void accept(oct_traveler* visitor) { visitor->visit(this); }
@@ -242,21 +234,21 @@ public:
void accept(tree_traveler* visitor) const { visitor->visit(this); }
void accept(oct_traveler* visitor) const { visitor->visit(this); }
- oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
+ oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
{
LLOctreeNode<T>* node = this;
if (node->isInside(pos, rad))
{
//do a quick search by octant
- U8 octant = node->getOctant(pos.mdV);
+ S32 octant = node->getOctant(pos);
BOOL keep_going = TRUE;
//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().mdV[0] >= rad)
+ while (keep_going && node->getSize()[0] >= rad)
{
keep_going = FALSE;
for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
@@ -264,7 +256,7 @@ public:
if (node->getChild(i)->getOctant() == octant)
{
node = node->getChild(i);
- octant = node->getOctant(pos.mdV);
+ octant = node->getOctant(pos);
keep_going = TRUE;
}
}
@@ -282,7 +274,7 @@ public:
{
if (data == NULL)
{
- //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
+ OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
return false;
}
LLOctreeNode<T>* parent = getOctParent();
@@ -292,7 +284,7 @@ public:
{
if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
(contains(data->getBinRadius()) ||
- (data->getBinRadius() > getSize().mdV[0] &&
+ (data->getBinRadius() > getSize()[0] &&
parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
{ //it belongs here
#if LL_OCTREE_PARANOIA_CHECK
@@ -323,16 +315,22 @@ public:
}
//it's here, but no kids are in the right place, make a new kid
- LLVector3d center(getCenter());
- LLVector3d size(getSize()*0.5);
+ LLVector4a center = getCenter();
+ LLVector4a size = getSize();
+ size.mul(0.5f);
//push center in direction of data
LLOctreeNode<T>::pushCenter(center, size, data);
// handle case where floating point number gets too small
- if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
- llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
- llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
+ LLVector4a val;
+ val.setSub(center, getCenter());
+ val.setAbs(val);
+ LLVector4a app_zero;
+ app_zero.mQ = F_APPROXIMATELY_ZERO_4A;
+ S32 lt = val.lessThan4(app_zero).getComparisonMask() & 0x7;
+
+ if( lt == 0x7 )
{
mData.insert(data);
BaseType::insert(data);
@@ -350,7 +348,7 @@ public:
//make sure no existing node matches this position
for (U32 i = 0; i < getChildCount(); i++)
{
- if (mChild[i]->getCenter() == center)
+ if (mChild[i]->getCenter().equal3(center))
{
OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
return false;
@@ -368,7 +366,7 @@ public:
else
{
//it's not in here, give it to the root
- //OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
+ OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
oct_node* node = this;
@@ -475,13 +473,19 @@ public:
void addChild(oct_node* child, BOOL silent = FALSE)
{
#if LL_OCTREE_PARANOIA_CHECK
+
+ if (child->getSize().equal3(getSize()))
+ {
+ OCT_ERRS << "Child size is same as parent size!" << llendl;
+ }
+
for (U32 i = 0; i < getChildCount(); i++)
{
- if(mChild[i]->getSize() != child->getSize())
+ if(!mChild[i]->getSize().equal3(child->getSize()))
{
OCT_ERRS <<"Invalid octree child size." << llendl;
}
- if (mChild[i]->getCenter() == child->getCenter())
+ if (mChild[i]->getCenter().equal3(child->getCenter()))
{
OCT_ERRS <<"Duplicate octree child position." << llendl;
}
@@ -506,7 +510,7 @@ public:
}
}
- void removeChild(U8 index, BOOL destroy = FALSE)
+ void removeChild(S32 index, BOOL destroy = FALSE)
{
for (U32 i = 0; i < this->getListenerCount(); i++)
{
@@ -547,18 +551,26 @@ public:
}
}
- //OCT_ERRS << "Octree failed to delete requested child." << llendl;
+ OCT_ERRS << "Octree failed to delete requested child." << llendl;
}
protected:
+ typedef enum
+ {
+ CENTER = 0,
+ SIZE = 1,
+ MAX = 2,
+ MIN = 3
+ } eDName;
+
+ LLVector4a* mD;
+
+ oct_node* mParent;
+ S32 mOctant;
+
child_list mChild;
element_list mData;
- oct_node* mParent;
- LLVector3d mCenter;
- LLVector3d mSize;
- LLVector3d mMax;
- LLVector3d mMin;
- U8 mOctant;
+
};
//just like a regular node, except it might expand on insert and compress on balance
@@ -569,9 +581,9 @@ public:
typedef LLOctreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
- LLOctreeRoot( LLVector3d center,
- LLVector3d size,
- BaseType* parent)
+ LLOctreeRoot(const LLVector4a& center,
+ const LLVector4a& size,
+ BaseType* parent)
: BaseType(center, size, parent)
{
}
@@ -612,28 +624,33 @@ public:
{
if (data == NULL)
{
- //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
+ OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
return false;
}
if (data->getBinRadius() > 4096.0)
{
- //OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
+ OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
return false;
}
- const F64 MAX_MAG = 1024.0*1024.0;
+ LLVector4a MAX_MAG;
+ MAX_MAG.splat(1024.f*1024.f);
+
+ const LLVector4a& v = data->getPositionGroup();
+
+ LLVector4a val;
+ val.setSub(v, BaseType::mD[BaseType::CENTER]);
+ val.setAbs(val);
+ S32 lt = val.lessThan4(MAX_MAG).getComparisonMask() & 0x7;
- const LLVector3d& v = data->getPositionGroup();
- if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
- fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
- fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
+ if (lt != 0x7)
{
- //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+ OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
return false;
}
- if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
+ if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
{
//we got it, just act like a branch
oct_node* node = getNodeAt(data);
@@ -649,31 +666,34 @@ public:
else if (this->getChildCount() == 0)
{
//first object being added, just wrap it up
- while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+ while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
{
- LLVector3d center, size;
+ LLVector4a center, size;
center = this->getCenter();
size = this->getSize();
LLOctreeNode<T>::pushCenter(center, size, data);
this->setCenter(center);
- this->setSize(size*2);
+ size.mul(2.f);
+ this->setSize(size);
this->updateMinMax();
}
LLOctreeNode<T>::insert(data);
}
else
{
- while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+ while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
{
//the data is outside the root node, we need to grow
- LLVector3d center(this->getCenter());
- LLVector3d size(this->getSize());
+ LLVector4a center(this->getCenter());
+ LLVector4a size(this->getSize());
//expand this node
- LLVector3d newcenter(center);
+ LLVector4a newcenter(center);
LLOctreeNode<T>::pushCenter(newcenter, size, data);
this->setCenter(newcenter);
- this->setSize(size*2);
+ LLVector4a size2 = size;
+ size2.mul(2.f);
+ this->setSize(size2);
this->updateMinMax();
//copy our children to a new branch
@@ -710,4 +730,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
traverse(node->getChild(i));
}
}
+
+template <class T>
+void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
+{
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+ node->accept(this);
+}
+
#endif
diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h
index ee9836241a..e6d2521b2a 100644
--- a/indra/llmath/lltreenode.h
+++ b/indra/llmath/lltreenode.h
@@ -34,6 +34,9 @@
#include "stdtypes.h"
#include "xform.h"
+#include "llpointer.h"
+#include "llrefcount.h"
+
#include <vector>
template <class T> class LLTreeNode;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 3c3356f41d..25db58491e 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1,4 +1,5 @@
/**
+
* @file llvolume.cpp
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
@@ -30,6 +31,7 @@
*/
#include "linden_common.h"
+#include "llmemory.h"
#include "llmath.h"
#include <set>
@@ -43,9 +45,14 @@
#include "v4math.h"
#include "m4math.h"
#include "m3math.h"
+#include "llmatrix4a.h"
+#include "lloctree.h"
#include "lldarray.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llstl.h"
+#include "llsdserialize.h"
+#include "llvector4a.h"
#define DEBUG_SILHOUETTE_BINORMALS 0
#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -105,127 +112,264 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
{
- float fAWdU[3];
- LLVector3 dir;
- LLVector3 diff;
+ return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV);
+}
+
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size)
+{
+ F32 fAWdU[3];
+ F32 dir[3];
+ F32 diff[3];
for (U32 i = 0; i < 3; i++)
{
- dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
- diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
- fAWdU[i] = fabsf(dir.mV[i]);
- if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
+ dir[i] = 0.5f * (end[i] - start[i]);
+ diff[i] = (0.5f * (end[i] + start[i])) - center[i];
+ fAWdU[i] = fabsf(dir[i]);
+ if(fabsf(diff[i])>size[i] + fAWdU[i]) return false;
}
float f;
- f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false;
- f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false;
- f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false;
+ f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false;
+ f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false;
+ f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false;
return true;
}
+
// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
// returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
// and returns the intersection point along dir in intersection_t.
// Moller-Trumbore algorithm
-BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
- F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t)
{
- F32 u, v, t;
/* find vectors for two edges sharing vert0 */
- LLVector3 edge1 = vert1 - vert0;
+ LLVector4a edge1;
+ edge1.setSub(vert1, vert0);
- LLVector3 edge2 = vert2 - vert0;;
+ LLVector4a edge2;
+ edge2.setSub(vert2, vert0);
/* begin calculating determinant - also used to calculate U parameter */
- LLVector3 pvec = dir % edge2;
-
- /* if determinant is near zero, ray lies in plane of triangle */
- F32 det = edge1 * pvec;
+ LLVector4a pvec;
+ pvec.setCross3(dir, edge2);
- if (!two_sided)
+ /* if determinant is near zero, ray lies in plane of triangle */
+ LLVector4a det;
+ det.setAllDot3(edge1, pvec);
+
+ if (det.greaterEqual4(LLVector4a::getApproximatelyZero()).getComparisonMask() & 0x7)
{
- if (det < F_APPROXIMATELY_ZERO)
- {
- return FALSE;
- }
-
/* calculate distance from vert0 to ray origin */
- LLVector3 tvec = orig - vert0;
+ LLVector4a tvec;
+ tvec.setSub(orig, vert0);
/* calculate U parameter and test bounds */
- u = tvec * pvec;
+ LLVector4a u;
+ u.setAllDot3(tvec,pvec);
- if (u < 0.f || u > det)
+ if ((u.greaterEqual4(LLVector4a::getZero()).getComparisonMask() & 0x7) &&
+ (u.lessEqual4(det).getComparisonMask() & 0x7))
{
- return FALSE;
+ /* prepare to test V parameter */
+ LLVector4a qvec;
+ qvec.setCross3(tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ LLVector4a v;
+ v.setAllDot3(dir, qvec);
+
+
+ //if (!(v < 0.f || u + v > det))
+
+ LLVector4a sum_uv;
+ sum_uv.setAdd(u, v);
+
+ S32 v_gequal = v.greaterEqual4(LLVector4a::getZero()).getComparisonMask() & 0x7;
+ S32 sum_lequal = sum_uv.lessEqual4(det).getComparisonMask() & 0x7;
+
+ if (v_gequal && sum_lequal)
+ {
+ /* calculate t, scale parameters, ray intersects triangle */
+ LLVector4a t;
+ t.setAllDot3(edge2,qvec);
+
+ t.div(det);
+ u.div(det);
+ v.div(det);
+
+ intersection_a = u[0];
+ intersection_b = v[0];
+ intersection_t = t[0];
+ return TRUE;
+ }
}
-
- /* prepare to test V parameter */
- LLVector3 qvec = tvec % edge1;
+ }
- /* calculate V parameter and test bounds */
- v = dir * qvec;
- if (v < 0.f || u + v > det)
- {
- return FALSE;
- }
+ return FALSE;
+}
+
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t)
+{
+ F32 u, v, t;
+
+ /* find vectors for two edges sharing vert0 */
+ LLVector4a edge1;
+ edge1.setSub(vert1, vert0);
+
+
+ LLVector4a edge2;
+ edge2.setSub(vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ LLVector4a pvec;
+ pvec.setCross3(dir, edge2);
- /* calculate t, scale parameters, ray intersects triangle */
- t = edge2 * qvec;
- F32 inv_det = 1.0 / det;
- t *= inv_det;
- u *= inv_det;
- v *= inv_det;
+ /* if determinant is near zero, ray lies in plane of triangle */
+ F32 det = edge1.dot3(pvec);
+
+
+ if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
+ {
+ return FALSE;
}
+
+ F32 inv_det = 1.f / det;
+
+ /* calculate distance from vert0 to ray origin */
+ LLVector4a tvec;
+ tvec.setSub(orig, vert0);
- else // two sided
- {
- if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
- {
- return FALSE;
- }
- F32 inv_det = 1.0 / det;
+ /* calculate U parameter and test bounds */
+ u = (tvec.dot3(pvec)) * inv_det;
+ if (u < 0.f || u > 1.f)
+ {
+ return FALSE;
+ }
- /* calculate distance from vert0 to ray origin */
- LLVector3 tvec = orig - vert0;
+ /* prepare to test V parameter */
+ tvec.sub(edge1);
- /* calculate U parameter and test bounds */
- u = (tvec * pvec) * inv_det;
- if (u < 0.f || u > 1.f)
+ /* calculate V parameter and test bounds */
+ v = (dir.dot3(tvec)) * inv_det;
+
+ if (v < 0.f || u + v > 1.f)
+ {
+ return FALSE;
+ }
+
+ /* calculate t, ray intersects triangle */
+ t = (edge2.dot3(tvec)) * inv_det;
+
+ intersection_a = u;
+ intersection_b = v;
+ intersection_t = t;
+
+
+ return TRUE;
+}
+
+//helper for non-aligned vectors
+BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
+{
+ LLVector4a vert0a, vert1a, vert2a, origa, dira;
+ vert0a.load3(vert0.mV);
+ vert1a.load3(vert1.mV);
+ vert2a.load3(vert2.mV);
+ origa.load3(orig.mV);
+ dira.load3(dir.mV);
+
+ if (two_sided)
+ {
+ return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira,
+ intersection_a, intersection_b, intersection_t);
+ }
+ else
+ {
+ return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira,
+ intersection_a, intersection_b, intersection_t);
+ }
+}
+
+class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
+{
+public:
+ const LLVolumeFace* mFace;
+
+ LLVolumeOctreeRebound(const LLVolumeFace* face)
+ {
+ mFace = face;
+ }
+
+ virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ {
+ LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector4a& min = node->mExtents[0];
+ LLVector4a& max = node->mExtents[1];
+
+ if (branch->getElementCount() != 0)
{
- return FALSE;
+ const LLVolumeTriangle* tri = *(branch->getData().begin());
+
+ min = *(tri->mV[0]);
+ max = *(tri->mV[0]);
+
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
+ branch->getData().begin(); iter != branch->getData().end(); ++iter)
+ {
+ //stretch by triangles in node
+ tri = *iter;
+
+ min.setMin(*tri->mV[0]);
+ min.setMin(*tri->mV[1]);
+ min.setMin(*tri->mV[2]);
+
+ max.setMax(*tri->mV[0]);
+ max.setMax(*tri->mV[1]);
+ max.setMax(*tri->mV[2]);
}
- /* prepare to test V parameter */
- LLVector3 qvec = tvec - edge1;
-
- /* calculate V parameter and test bounds */
- v = (dir * qvec) * inv_det;
-
- if (v < 0.f || u + v > 1.f)
+ for (S32 i = 0; i < branch->getChildCount(); ++i)
+ { //stretch by child extents
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+ min.setMin(child->mExtents[0]);
+ max.setMax(child->mExtents[1]);
+ }
+ }
+ else if (branch->getChildCount() != 0)
{
- return FALSE;
+ LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
+
+ 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(child->mExtents[0]);
+ max.setMax(child->mExtents[1]);
+ }
+ }
+ else
+ {
+ llerrs << "WTF? Empty leaf" << llendl;
}
+
+ node->mBounds[0].setAdd(min, max);
+ node->mBounds[0].mul(0.5f);
- /* calculate t, ray intersects triangle */
- t = (edge2 * qvec) * inv_det;
+ node->mBounds[1].setSub(max,min);
+ node->mBounds[1].mul(0.5f);
}
-
- if (intersection_a != NULL)
- *intersection_a = u;
- if (intersection_b != NULL)
- *intersection_b = v;
- if (intersection_t != NULL)
- *intersection_t = t;
-
-
- return TRUE;
-}
+};
//-------------------------------------------------------------------
@@ -1675,7 +1819,9 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mFaceMask = 0x0;
mDetail = detail;
mSculptLevel = -2;
-
+ mIsTetrahedron = FALSE;
+ mLODScaleBias.setVec(1,1,1);
+
// set defaults
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
{
@@ -1690,7 +1836,8 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
mGenerateSingleFace = generate_single_face;
generate();
- if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE)
+
+ if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
{
createVolumeFaces();
}
@@ -1841,6 +1988,585 @@ BOOL LLVolume::generate()
return FALSE;
}
+void LLVolumeFace::VertexData::init()
+{
+ if (!mData)
+ {
+ mData = (LLVector4a*) ll_aligned_malloc_16(32);
+ }
+}
+
+LLVolumeFace::VertexData::VertexData()
+{
+ mData = NULL;
+ init();
+}
+
+LLVolumeFace::VertexData::VertexData(const VertexData& rhs)
+{
+ mData = NULL;
+ *this = rhs;
+}
+
+const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs)
+{
+ if (this != &rhs)
+ {
+ init();
+ LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 8);
+ mTexCoord = rhs.mTexCoord;
+ }
+ return *this;
+}
+
+LLVolumeFace::VertexData::~VertexData()
+{
+ ll_aligned_free_16(mData);
+}
+
+LLVector4a& LLVolumeFace::VertexData::getPosition()
+{
+ return mData[POSITION];
+}
+
+LLVector4a& LLVolumeFace::VertexData::getNormal()
+{
+ return mData[NORMAL];
+}
+
+const LLVector4a& LLVolumeFace::VertexData::getPosition() const
+{
+ return mData[POSITION];
+}
+
+const LLVector4a& LLVolumeFace::VertexData::getNormal() const
+{
+ return mData[NORMAL];
+}
+
+
+void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos)
+{
+ mData[POSITION] = pos;
+}
+
+void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm)
+{
+ mData[NORMAL] = norm;
+}
+
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
+{
+ if (mData[POSITION].notEqual3(rhs.getPosition()))
+ {
+ return mData[POSITION].less3(rhs.getPosition());
+ }
+
+ if (mData[NORMAL].notEqual3(rhs.getNormal()))
+ {
+ return mData[NORMAL].less3(rhs.getNormal());
+ }
+
+ if (mTexCoord != rhs.mTexCoord)
+ {
+ return mTexCoord < rhs.mTexCoord;
+ }
+
+ return false;
+}
+
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
+{
+ return mData[POSITION].equal3(rhs.getPosition()) &&
+ mData[NORMAL].equal3(rhs.getNormal()) &&
+ mTexCoord == rhs.mTexCoord;
+}
+
+bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
+{
+ bool retval = false;
+ if (rhs.mData[POSITION].equal3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+ {
+ if (angle_cutoff > 1.f)
+ {
+ retval = (mData[NORMAL].equal3(rhs.mData[NORMAL]));
+ }
+ else
+ {
+ F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]);
+ retval = cur_angle > angle_cutoff;
+ }
+ }
+
+ return retval;
+}
+
+BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
+{
+ std::ifstream is;
+
+ is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
+
+ BOOL success = createVolumeFacesFromStream(is);
+
+ is.close();
+
+ return success;
+}
+
+BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
+{
+ mSculptLevel = -1; // default is an error occured
+
+ LLSD header;
+ {
+ if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024))
+ {
+ llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl;
+ return FALSE;
+ }
+ }
+
+ std::string nm[] =
+ {
+ "lowest_lod",
+ "low_lod",
+ "medium_lod",
+ "high_lod"
+ };
+
+ S32 lod = llclamp((S32) mDetail, 0, 3);
+
+ while (lod < 4 &&
+ (header[nm[lod]]["offset"].asInteger() == -1 ||
+ header[nm[lod]]["size"].asInteger() == 0 ))
+ {
+ ++lod;
+ }
+
+ if (lod >= 4)
+ {
+ lod = llclamp((S32) mDetail, 0, 3);
+
+ while (lod >= 0 &&
+ (header[nm[lod]]["offset"].asInteger() == -1 ||
+ header[nm[lod]]["size"].asInteger() == 0) )
+ {
+ --lod;
+ }
+
+ if (lod < 0)
+ {
+ llwarns << "Mesh header missing LOD offsets. Not a valid mesh asset!" << llendl;
+ return FALSE;
+ }
+ }
+
+ is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+ return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
+}
+
+bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
+{
+ //input stream is now pointing at a zlib compressed block of LLSD
+ //decompress block
+ LLSD mdl;
+ if (!unzip_llsd(mdl, is, size))
+ {
+ llwarns << "not a valid mesh asset!" << llendl;
+ return false;
+ }
+
+ {
+ U32 face_count = mdl.size();
+
+ if (face_count == 0)
+ {
+ llerrs << "WTF?" << llendl;
+ }
+
+ mVolumeFaces.resize(face_count);
+
+ for (U32 i = 0; i < face_count; ++i)
+ {
+ LLSD::Binary pos = mdl[i]["Position"];
+ LLSD::Binary norm = mdl[i]["Normal"];
+ LLSD::Binary tc = mdl[i]["TexCoord0"];
+ LLSD::Binary idx = mdl[i]["TriangleList"];
+
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ //copy out indices
+ face.resizeIndices(idx.size()/2);
+
+ if (idx.empty() || face.mNumIndices < 3)
+ { //why is there an empty index list?
+ llerrs <<"WTF?" << llendl;
+ continue;
+ }
+
+ U16* indices = (U16*) &(idx[0]);
+ for (U32 j = 0; j < idx.size()/2; ++j)
+ {
+ face.mIndices[j] = indices[j];
+ }
+
+ //copy out vertices
+ U32 num_verts = pos.size()/(3*2);
+ face.resizeVertices(num_verts);
+
+ if (mdl[i].has("Weights"))
+ {
+ face.allocateWeights(num_verts);
+
+ LLSD::Binary weights = mdl[i]["Weights"];
+
+ U32 idx = 0;
+
+ U32 cur_vertex = 0;
+ while (idx < weights.size() && cur_vertex < num_verts)
+ {
+ const U8 END_INFLUENCES = 0xFF;
+ U8 joint = weights[idx++];
+
+ U32 cur_influence = 0;
+ LLVector4 wght(0,0,0,0);
+
+ while (joint != END_INFLUENCES)
+ {
+ U16 influence = weights[idx++];
+ influence |= ((U16) weights[idx++] << 8);
+
+ F32 w = llmin((F32) influence / 65535.f, 0.99999f);
+ wght.mV[cur_influence++] = (F32) joint + w;
+
+ if (cur_influence >= 4)
+ {
+ joint = END_INFLUENCES;
+ }
+ else
+ {
+ joint = weights[idx++];
+ }
+ }
+
+ face.mWeights[cur_vertex].loadua(wght.mV);
+
+ cur_vertex++;
+ }
+
+ if (cur_vertex != num_verts || idx != weights.size())
+ {
+ llwarns << "Vertex weight count does not match vertex count!" << llendl;
+ }
+
+ }
+
+ LLVector3 minp;
+ LLVector3 maxp;
+ LLVector2 min_tc;
+ LLVector2 max_tc;
+
+ minp.setValue(mdl[i]["PositionDomain"]["Min"]);
+ maxp.setValue(mdl[i]["PositionDomain"]["Max"]);
+ LLVector4a min_pos, max_pos;
+ min_pos.load3(minp.mV);
+ max_pos.load3(maxp.mV);
+
+ min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+ max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+ LLVector4a pos_range;
+ pos_range.setSub(max_pos, min_pos);
+ LLVector2 tc_range = max_tc - min_tc;
+
+ LLVector4a& min = face.mExtents[0];
+ LLVector4a& max = face.mExtents[1];
+
+ min.clear();
+ max.clear();
+
+ LLVector4a* pos_out = face.mPositions;
+ LLVector4a* norm_out = face.mNormals;
+ LLVector2* tc_out = face.mTexCoords;
+
+ for (U32 j = 0; j < num_verts; ++j)
+ {
+ U16* v = (U16*) &(pos[j*3*2]);
+
+ pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]);
+ pos_out->div(65535.f);
+ pos_out->mul(pos_range);
+ pos_out->add(min_pos);
+
+ if (j == 0)
+ {
+ min = *pos_out;
+ max = min;
+ }
+ else
+ {
+ min.setMin(*pos_out);
+ max.setMax(*pos_out);
+ }
+
+ pos_out++;
+
+ U16* n = (U16*) &(norm[j*3*2]);
+
+ norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
+ norm_out->div(65535.f);
+ norm_out->mul(2.f);
+ norm_out->sub(1.f);
+ norm_out++;
+
+ U16* t = (U16*) &(tc[j*2*2]);
+
+ tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0];
+ tc_out->mV[1] = (F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1];
+
+ tc_out++;
+ }
+
+
+ // modifier flags?
+ bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR);
+ bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT);
+
+
+ // translate to actions:
+ bool do_reflect_x = false;
+ bool do_reverse_triangles = false;
+ bool do_invert_normals = false;
+
+ if (do_mirror)
+ {
+ do_reflect_x = true;
+ do_reverse_triangles = !do_reverse_triangles;
+ }
+
+ if (do_invert)
+ {
+ do_invert_normals = true;
+ do_reverse_triangles = !do_reverse_triangles;
+ }
+
+ // now do the work
+
+ if (do_reflect_x)
+ {
+ LLVector4a* p = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (S32 i = 0; i < face.mNumVertices; i++)
+ {
+ p[i].mul(-1.0f);
+ n[i].mul(-1.0f);
+ }
+ }
+
+ if (do_invert_normals)
+ {
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (S32 i = 0; i < face.mNumVertices; i++)
+ {
+ n[i].mul(-1.0f);
+ }
+ }
+
+ if (do_reverse_triangles)
+ {
+ for (U32 j = 0; j < face.mNumIndices; j += 3)
+ {
+ // swap the 2nd and 3rd index
+ S32 swap = face.mIndices[j+1];
+ face.mIndices[j+1] = face.mIndices[j+2];
+ face.mIndices[j+2] = swap;
+ }
+ }
+
+ }
+ }
+
+ mSculptLevel = 0; // success!
+ return true;
+}
+
+void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
+{
+ LLVector4a v0;
+ v0.setSub(cv[1].getPosition(), cv[0].getNormal());
+ LLVector4a v1;
+ v1.setSub(cv[2].getNormal(), cv[0].getPosition());
+
+ cv[0].getNormal().setCross3(v0,v1);
+ cv[0].getNormal().normalize3fast();
+ cv[1].setNormal(cv[0].getNormal());
+ cv[2].setNormal(cv[1].getNormal());
+}
+
+BOOL LLVolume::isTetrahedron()
+{
+ return mIsTetrahedron;
+}
+
+void LLVolume::makeTetrahedron()
+{
+ mVolumeFaces.clear();
+
+ LLVolumeFace face;
+
+ F32 x = 0.25f;
+ LLVector4a p[] =
+ { //unit tetrahedron corners
+ LLVector4a(x,x,x),
+ LLVector4a(-x,-x,x),
+ LLVector4a(-x,x,-x),
+ LLVector4a(x,-x,-x)
+ };
+
+ face.mExtents[0].splat(-x);
+ face.mExtents[1].splat(x);
+
+ LLVolumeFace::VertexData cv[3];
+
+ //set texture coordinates
+ cv[0].mTexCoord = LLVector2(0,0);
+ cv[1].mTexCoord = LLVector2(1,0);
+ cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
+
+
+ //side 1
+ cv[0].setPosition(p[1]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[2]);
+
+ tetrahedron_set_normal(cv);
+
+ face.resizeVertices(12);
+ face.resizeIndices(12);
+
+ LLVector4a* v = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+ LLVector2* tc = (LLVector2*) face.mTexCoords;
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+
+ //side 2
+ cv[0].setPosition(p[3]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[1]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //side 3
+ cv[0].setPosition(p[3]);
+ cv[1].setPosition(p[1]);
+ cv[2].setPosition(p[2]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //side 4
+ cv[0].setPosition(p[2]);
+ cv[1].setPosition(p[0]);
+ cv[2].setPosition(p[3]);
+
+ tetrahedron_set_normal(cv);
+
+ v[0] = cv[0].getPosition();
+ v[1] = cv[1].getPosition();
+ v[2] = cv[2].getPosition();
+ v += 3;
+
+ n[0] = cv[0].getNormal();
+ n[1] = cv[1].getNormal();
+ n[2] = cv[2].getNormal();
+ n += 3;
+
+ tc[0] = cv[0].mTexCoord;
+ tc[1] = cv[1].mTexCoord;
+ tc[2] = cv[2].mTexCoord;
+ tc += 3;
+
+ //set index buffer
+ for (U16 i = 0; i < 12; i++)
+ {
+ face.mIndices[i] = i;
+ }
+
+ mVolumeFaces.push_back(face);
+ mSculptLevel = 0;
+ mIsTetrahedron = TRUE;
+}
+
+void LLVolume::copyVolumeFaces(LLVolume* volume)
+{
+ mVolumeFaces = volume->mVolumeFaces;
+ mSculptLevel = 0;
+ mIsTetrahedron = FALSE;
+}
+
+
+S32 LLVolume::getNumFaces() const
+{
+#if LL_MESH_ENABLED
+ U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+ if (sculpt_type == LL_SCULPT_TYPE_MESH)
+ {
+ return LL_SCULPT_MESH_MAX_FACES;
+ }
+#endif
+
+ return (S32)mProfilep->mFaces.size();
+}
+
void LLVolume::createVolumeFaces()
{
@@ -2320,7 +3046,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
return mSculptID < params.mSculptID;
}
-
return mSculptType < params.mSculptType;
@@ -3378,34 +4103,66 @@ S32 LLVolume::getNumTriangleIndices() const
return count;
}
+
+S32 LLVolume::getNumTriangles() const
+{
+ U32 triangle_count = 0;
+
+ for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+ {
+ triangle_count += getVolumeFace(i).mNumIndices/3;
+ }
+
+ return triangle_count;
+}
+
+
//-----------------------------------------------------------------------------
// generateSilhouetteVertices()
//-----------------------------------------------------------------------------
void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
std::vector<LLVector3> &normals,
std::vector<S32> &segments,
- const LLVector3& obj_cam_vec,
- const LLMatrix4& mat,
- const LLMatrix3& norm_mat,
+ const LLVector3& obj_cam_vec_in,
+ const LLMatrix4& mat_in,
+ const LLMatrix3& norm_mat_in,
S32 face_mask)
{
LLMemType m1(LLMemType::MTYPE_VOLUME);
-
+
+ LLMatrix4a mat;
+ mat.loadu(mat_in);
+
+ LLMatrix4a norm_mat;
+ norm_mat.loadu(norm_mat_in);
+
+ LLVector4a obj_cam_vec;
+ obj_cam_vec.load3(obj_cam_vec_in.mV);
+
vertices.clear();
normals.clear();
segments.clear();
+#if LL_MESH_ENABLED
+ if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ {
+ return;
+ }
+#endif
+
S32 cur_index = 0;
//for each face
for (face_list_t::iterator iter = mVolumeFaces.begin();
iter != mVolumeFaces.end(); ++iter)
{
- const LLVolumeFace& face = *iter;
+ LLVolumeFace& face = *iter;
- if (!(face_mask & (0x1 << cur_index++)))
+ if (!(face_mask & (0x1 << cur_index++)) ||
+ face.mNumIndices == 0 || face.mEdge.empty())
{
continue;
}
+
if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
}
@@ -3418,7 +4175,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
#if DEBUG_SILHOUETTE_EDGE_MAP
//for each triangle
- U32 count = face.mIndices.size();
+ U32 count = face.mNumIndices;
for (U32 j = 0; j < count/3; j++) {
//get vertices
S32 v1 = face.mIndices[j*3+0];
@@ -3426,9 +4183,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 v3 = face.mIndices[j*3+2];
//get current face center
- LLVector3 cCenter = (face.mVertices[v1].mPosition +
- face.mVertices[v2].mPosition +
- face.mVertices[v3].mPosition) / 3.0f;
+ LLVector3 cCenter = (face.mVertices[v1].getPosition() +
+ face.mVertices[v2].getPosition() +
+ face.mVertices[v3].getPosition()) / 3.0f;
//for each edge
for (S32 k = 0; k < 3; k++) {
@@ -3446,9 +4203,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
v3 = face.mIndices[nIndex*3+2];
//get neighbor face center
- LLVector3 nCenter = (face.mVertices[v1].mPosition +
- face.mVertices[v2].mPosition +
- face.mVertices[v3].mPosition) / 3.0f;
+ LLVector3 nCenter = (face.mVertices[v1].getPosition() +
+ face.mVertices[v2].getPosition() +
+ face.mVertices[v3].getPosition()) / 3.0f;
//draw line
vertices.push_back(cCenter);
@@ -3471,15 +4228,15 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
#elif DEBUG_SILHOUETTE_NORMALS
//for each vertex
- for (U32 j = 0; j < face.mVertices.size(); j++) {
- vertices.push_back(face.mVertices[j].mPosition);
- vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f);
+ for (U32 j = 0; j < face.mNumVertices; j++) {
+ vertices.push_back(face.mVertices[j].getPosition());
+ vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f);
normals.push_back(LLVector3(0,0,1));
normals.push_back(LLVector3(0,0,1));
segments.push_back(vertices.size());
#if DEBUG_SILHOUETTE_BINORMALS
- vertices.push_back(face.mVertices[j].mPosition);
- vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f);
+ vertices.push_back(face.mVertices[j].getPosition());
+ vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f);
normals.push_back(LLVector3(0,0,1));
normals.push_back(LLVector3(0,0,1));
segments.push_back(vertices.size());
@@ -3497,26 +4254,36 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each triangle
std::vector<U8> fFacing;
- vector_append(fFacing, face.mIndices.size()/3);
- for (U32 j = 0; j < face.mIndices.size()/3; j++)
+ vector_append(fFacing, face.mNumIndices/3);
+
+ LLVector4a* v = (LLVector4a*) face.mPositions;
+ LLVector4a* n = (LLVector4a*) face.mNormals;
+
+ for (U32 j = 0; j < face.mNumIndices/3; j++)
{
//approximate normal
S32 v1 = face.mIndices[j*3+0];
S32 v2 = face.mIndices[j*3+1];
S32 v3 = face.mIndices[j*3+2];
- LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) %
- (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
-
- if (norm.magVecSquared() < 0.00000001f)
+ LLVector4a c1,c2;
+ c1.setSub(v[v1], v[v2]);
+ c2.setSub(v[v2], v[v3]);
+
+ LLVector4a norm;
+
+ norm.setCross3(c1, c2);
+
+ if (norm.dot3(norm) < 0.00000001f)
{
fFacing[j] = AWAY | TOWARDS;
}
else
{
//get view vector
- LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
- bool away = view * norm > 0.0f;
+ LLVector4a view;
+ view.setSub(obj_cam_vec, v[v1]);
+ bool away = view.dot3(norm) > 0.0f;
if (away)
{
fFacing[j] = AWAY;
@@ -3529,7 +4296,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
}
//for each triangle
- for (U32 j = 0; j < face.mIndices.size()/3; j++)
+ for (U32 j = 0; j < face.mNumIndices/3; j++)
{
if (fFacing[j] == (AWAY | TOWARDS))
{ //this is a degenerate triangle
@@ -3562,15 +4329,21 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 v1 = face.mIndices[j*3+k];
S32 v2 = face.mIndices[j*3+((k+1)%3)];
- vertices.push_back(face.mVertices[v1].mPosition*mat);
- LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat;
- norm1.normVec();
- normals.push_back(norm1);
+ LLVector4a t;
+ mat.affineTransform(v[v1], t);
+ vertices.push_back(LLVector3(t[0], t[1], t[2]));
- vertices.push_back(face.mVertices[v2].mPosition*mat);
- LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat;
- norm2.normVec();
- normals.push_back(norm2);
+ norm_mat.rotate(n[v1], t);
+
+ t.normalize3fast();
+ normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+ mat.affineTransform(v[v2], t);
+ vertices.push_back(LLVector3(t[0], t[1], t[2]));
+
+ norm_mat.rotate(n[v2], t);
+ t.normalize3fast();
+ normals.push_back(LLVector3(t[0], t[1], t[2]));
segments.push_back(vertices.size());
}
@@ -3585,6 +4358,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
{
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+
+ return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
+
+}
+
+
+S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ S32 face,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
S32 hit_face = -1;
S32 start_face;
@@ -3601,16 +4387,23 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
end_face = face;
}
- LLVector3 dir = end - start;
+ LLVector4a dir;
+ dir.setSub(end, start);
F32 closest_t = 2.f; // must be larger than 1
+ end_face = llmin(end_face, getNumVolumeFaces()-1);
+
for (S32 i = start_face; i <= end_face; i++)
{
- const LLVolumeFace &face = getVolumeFace((U32)i);
+ LLVolumeFace &face = mVolumeFaces[i];
+
+ LLVector4a box_center;
+ box_center.setAdd(face.mExtents[0], face.mExtents[1]);
+ box_center.mul(0.5f);
- LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f;
- LLVector3 box_size = face.mExtents[1] - face.mExtents[0];
+ LLVector4a box_size;
+ box_size.setSub(face.mExtents[1], face.mExtents[0]);
if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
{
@@ -3618,56 +4411,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
{
genBinormals(i);
}
-
- for (U32 tri = 0; tri < face.mIndices.size()/3; tri++)
- {
- S32 index1 = face.mIndices[tri*3+0];
- S32 index2 = face.mIndices[tri*3+1];
- S32 index3 = face.mIndices[tri*3+2];
- F32 a, b, t;
+ if (!face.mOctree)
+ {
+ face.createOctree();
+ }
- if (LLTriangleRayIntersect(face.mVertices[index1].mPosition,
- face.mVertices[index2].mPosition,
- face.mVertices[index3].mPosition,
- start, dir, &a, &b, &t, FALSE))
- {
- if ((t >= 0.f) && // if hit is after start
- (t <= 1.f) && // and before end
- (t < closest_t)) // and this hit is closer
- {
- closest_t = t;
- hit_face = i;
+ //LLVector4a* p = (LLVector4a*) face.mPositions;
- if (intersection != NULL)
- {
- *intersection = start + dir * closest_t;
- }
-
- if (tex_coord != NULL)
+ LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
+ intersect.traverse(face.mOctree);
+ if (intersect.mHitFace)
{
- *tex_coord = ((1.f - a - b) * face.mVertices[index1].mTexCoord +
- a * face.mVertices[index2].mTexCoord +
- b * face.mVertices[index3].mTexCoord);
-
- }
-
- if (normal != NULL)
- {
- *normal = ((1.f - a - b) * face.mVertices[index1].mNormal +
- a * face.mVertices[index2].mNormal +
- b * face.mVertices[index3].mNormal);
- }
-
- if (bi_normal != NULL)
- {
- *bi_normal = ((1.f - a - b) * face.mVertices[index1].mBinormal +
- a * face.mVertices[index2].mBinormal +
- b * face.mVertices[index3].mBinormal);
- }
-
- }
- }
+ hit_face = i;
}
}
}
@@ -4115,11 +4871,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
return TRUE;
}
+LLSD LLVolumeParams::sculptAsLLSD() const
+{
+ LLSD sd = LLSD();
+ sd["id"] = getSculptID();
+ sd["type"] = getSculptType();
+
+ return sd;
+}
+
+bool LLVolumeParams::sculptFromLLSD(LLSD& sd)
+{
+ setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger());
+ return true;
+}
+
LLSD LLVolumeParams::asLLSD() const
{
LLSD sd = LLSD();
sd["path"] = mPathParams;
sd["profile"] = mProfileParams;
+ sd["sculpt"] = sculptAsLLSD();
+
return sd;
}
@@ -4127,6 +4900,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
{
mPathParams.fromLLSD(sd["path"]);
mProfileParams.fromLLSD(sd["profile"]);
+ sculptFromLLSD(sd["sculpt"]);
+
return true;
}
@@ -4169,6 +4944,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity
// for collison purposes
BOOL LLVolumeParams::isConvex() const
{
+ if (!getSculptID().isNull())
+ {
+ // can't determine, be safe and say no:
+ return FALSE;
+ }
+
F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
F32 hollow = mProfileParams.getHollow();
@@ -4409,9 +5190,156 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
return s;
}
+LLVolumeFace::LLVolumeFace() :
+ mID(0),
+ mTypeMask(0),
+ mBeginS(0),
+ mBeginT(0),
+ mNumS(0),
+ mNumT(0),
+ mNumVertices(0),
+ mNumIndices(0),
+ mPositions(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL),
+ mIndices(NULL),
+ mWeights(NULL),
+ mOctree(NULL)
+{
+ mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+ mCenter = mExtents+2;
+}
+
+LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
+: mID(0),
+ mTypeMask(0),
+ mBeginS(0),
+ mBeginT(0),
+ mNumS(0),
+ mNumT(0),
+ mNumVertices(0),
+ mNumIndices(0),
+ mPositions(NULL),
+ mNormals(NULL),
+ mBinormals(NULL),
+ mTexCoords(NULL),
+ mIndices(NULL),
+ mWeights(NULL),
+ mOctree(NULL)
+{
+ mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+ mCenter = mExtents+2;
+ *this = src;
+}
+
+LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
+{
+ if (&src == this)
+ { //self assignment, do nothing
+ return *this;
+ }
+
+ mID = src.mID;
+ mTypeMask = src.mTypeMask;
+ mBeginS = src.mBeginS;
+ mBeginT = src.mBeginT;
+ mNumS = src.mNumS;
+ mNumT = src.mNumT;
+
+ mExtents[0] = src.mExtents[0];
+ mExtents[1] = src.mExtents[1];
+ *mCenter = *src.mCenter;
+
+ mNumVertices = 0;
+ mNumIndices = 0;
+
+ freeData();
+
+ LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 12);
+
+ resizeVertices(src.mNumVertices);
+ resizeIndices(src.mNumIndices);
+
+ if (mNumVertices)
+ {
+ S32 vert_size = mNumVertices*4;
+ S32 tc_size = (mNumVertices*8+0xF) & ~0xF;
+ tc_size /= 4;
+
+ LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
+ LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
+ LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+
+
+ if (src.mBinormals)
+ {
+ allocateBinormals(src.mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size);
+ }
+ else
+ {
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+ }
+
+ if (src.mWeights)
+ {
+ allocateWeights(src.mNumVertices);
+ LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
+ }
+ else
+ {
+ ll_aligned_free_16(mWeights);
+ mWeights = NULL;
+ }
+ }
+
+ if (mNumIndices)
+ {
+ S32 idx_size = (mNumIndices*2+0xF) & ~0xF;
+ idx_size /= 4;
+
+ LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size);
+ }
+
+ //delete
+ return *this;
+}
+
+LLVolumeFace::~LLVolumeFace()
+{
+ ll_aligned_free_16(mExtents);
+ mExtents = NULL;
+
+ freeData();
+}
+
+void LLVolumeFace::freeData()
+{
+ ll_aligned_free_16(mPositions);
+ mPositions = NULL;
+ ll_aligned_free_16(mNormals);
+ mNormals = NULL;
+ ll_aligned_free_16(mTexCoords);
+ mTexCoords = NULL;
+ ll_aligned_free_16(mIndices);
+ mIndices = NULL;
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+ ll_aligned_free_16(mWeights);
+ mWeights = NULL;
+
+ delete mOctree;
+ mOctree = NULL;
+}
BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
{
+ //tree for this face is no longer valid
+ delete mOctree;
+ mOctree = NULL;
+
if (mTypeMask & CAP_MASK)
{
return createCap(volume, partial_build);
@@ -4427,6 +5355,155 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
}
}
+void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
+{
+ cv.setPosition(mPositions[index]);
+ cv.setNormal(mNormals[index]);
+ cv.mTexCoord = mTexCoords[index];
+}
+
+bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
+{
+ return getPosition().equal3(rhs.getPosition()) &&
+ mTexCoord == rhs.mTexCoord &&
+ getNormal().equal3(rhs.getNormal());
+}
+
+bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const
+{
+ if (a.mV[0] != b.mV[0])
+ {
+ return a.mV[0] < b.mV[0];
+ }
+
+ if (a.mV[1] != b.mV[1])
+ {
+ return a.mV[1] < b.mV[1];
+ }
+
+ return a.mV[2] < b.mV[2];
+}
+
+void LLVolumeFace::optimize(F32 angle_cutoff)
+{
+ LLVolumeFace new_face;
+
+ VertexMapData::PointMap point_map;
+
+ //remove redundant vertices
+ for (U32 i = 0; i < mNumIndices; ++i)
+ {
+ U16 index = mIndices[i];
+
+ LLVolumeFace::VertexData cv;
+ getVertexData(index, cv);
+
+ BOOL found = FALSE;
+ VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32()));
+ if (point_iter != point_map.end())
+ { //duplicate point might exist
+ for (U32 j = 0; j < point_iter->second.size(); ++j)
+ {
+ LLVolumeFace::VertexData& tv = (point_iter->second)[j];
+ if (tv.compareNormal(cv, angle_cutoff))
+ {
+ found = TRUE;
+ new_face.pushIndex((point_iter->second)[j].mIndex);
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ new_face.pushVertex(cv);
+ U16 index = (U16) new_face.mNumVertices-1;
+ new_face.pushIndex(index);
+
+ VertexMapData d;
+ d.setPosition(cv.getPosition());
+ d.mTexCoord = cv.mTexCoord;
+ d.setNormal(cv.getNormal());
+ d.mIndex = index;
+ if (point_iter != point_map.end())
+ {
+ point_iter->second.push_back(d);
+ }
+ else
+ {
+ point_map[LLVector3(d.getPosition().getF32())].push_back(d);
+ }
+ }
+ }
+
+ swapData(new_face);
+}
+
+
+void LLVolumeFace::createOctree()
+{
+ LLVector4a center;
+ LLVector4a size;
+ center.splat(0.f);
+ size.splat(1.f);
+
+ mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
+ new LLVolumeOctreeListener(mOctree);
+
+ for (U32 i = 0; i < mNumIndices; i+= 3)
+ {
+ 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]];
+
+ tri->mV[0] = &v0;
+ tri->mV[1] = &v1;
+ tri->mV[2] = &v2;
+
+ tri->mIndex[0] = mIndices[i];
+ tri->mIndex[1] = mIndices[i+1];
+ tri->mIndex[2] = mIndices[i+2];
+
+ LLVector4a min = v0;
+ min.setMin(v1);
+ min.setMin(v2);
+
+ LLVector4a max = v0;
+ max.setMax(v1);
+ max.setMax(v2);
+
+ LLVector4a center;
+ center.setAdd(min, max);
+ center.mul(0.5f);
+
+ *tri->mPositionGroup = center;
+
+ LLVector4a size;
+ size.setSub(max,min);
+
+ tri->mRadius = size.length3() * 0.5f;
+
+ mOctree->insert(tri);
+ }
+
+ LLVolumeOctreeRebound rebound(this);
+ rebound.traverse(mOctree);
+}
+
+
+void LLVolumeFace::swapData(LLVolumeFace& rhs)
+{
+ llswap(rhs.mPositions, mPositions);
+ llswap(rhs.mNormals, mNormals);
+ llswap(rhs.mBinormals, mBinormals);
+ llswap(rhs.mTexCoords, mTexCoords);
+ llswap(rhs.mIndices,mIndices);
+ llswap(rhs.mNumVertices, mNumVertices);
+ llswap(rhs.mNumIndices, mNumIndices);
+}
+
void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
LLVolumeFace::VertexData& v1,
LLVolumeFace::VertexData& v2,
@@ -4434,10 +5511,21 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0,
F32 coef01,
F32 coef02)
{
- vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02);
+
+ LLVector4a lhs;
+ lhs.setSub(v1.getPosition(), v0.getPosition());
+ lhs.mul(coef01);
+ LLVector4a rhs;
+ rhs.setSub(v2.getPosition(), v0.getPosition());
+ rhs.mul(coef02);
+
+ rhs.add(lhs);
+ rhs.add(v0.getPosition());
+
+ vout.setPosition(rhs);
+
vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
- vout.mNormal = v0.mNormal;
- vout.mBinormal = v0.mBinormal;
+ vout.setNormal(v0.getNormal());
}
BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
@@ -4457,84 +5545,112 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
num_vertices = (grid_size+1)*(grid_size+1);
num_indices = quad_count * 4;
- LLVector3& min = mExtents[0];
- LLVector3& max = mExtents[1];
+ LLVector4a& min = mExtents[0];
+ LLVector4a& max = mExtents[1];
S32 offset = 0;
if (mTypeMask & TOP_MASK)
+ {
offset = (max_t-1) * max_s;
+ }
else
+ {
offset = mBeginS;
+ }
- VertexData corners[4];
- VertexData baseVert;
- for(int t = 0; t < 4; t++){
- corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
- corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
- corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
- }
- baseVert.mNormal =
- ((corners[1].mPosition-corners[0].mPosition) %
- (corners[2].mPosition-corners[1].mPosition));
- baseVert.mNormal.normVec();
- if(!(mTypeMask & TOP_MASK)){
- baseVert.mNormal *= -1.0f;
- }else{
- //Swap the UVs on the U(X) axis for top face
- LLVector2 swap;
- swap = corners[0].mTexCoord;
- corners[0].mTexCoord=corners[3].mTexCoord;
- corners[3].mTexCoord=swap;
- swap = corners[1].mTexCoord;
- corners[1].mTexCoord=corners[2].mTexCoord;
- corners[2].mTexCoord=swap;
- }
- baseVert.mBinormal = calc_binormal_from_triangle(
- corners[0].mPosition, corners[0].mTexCoord,
- corners[1].mPosition, corners[1].mTexCoord,
- corners[2].mPosition, corners[2].mTexCoord);
- for(int t = 0; t < 4; t++){
- corners[t].mBinormal = baseVert.mBinormal;
- corners[t].mNormal = baseVert.mNormal;
- }
- mHasBinormals = TRUE;
-
- if (partial_build)
{
- mVertices.clear();
- }
+ VertexData corners[4];
+ VertexData baseVert;
+ for(S32 t = 0; t < 4; t++)
+ {
+ corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV);
+ corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
+ corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
+ }
- S32 vtop = mVertices.size();
- for(int gx = 0;gx<grid_size+1;gx++){
- for(int gy = 0;gy<grid_size+1;gy++){
- VertexData newVert;
- LerpPlanarVertex(
- corners[0],
- corners[1],
- corners[3],
- newVert,
- (F32)gx/(F32)grid_size,
- (F32)gy/(F32)grid_size);
- mVertices.push_back(newVert);
+ {
+ LLVector4a lhs;
+ lhs.setSub(corners[1].getPosition(), corners[0].getPosition());
+ LLVector4a rhs;
+ rhs.setSub(corners[2].getPosition(), corners[1].getPosition());
+ baseVert.getNormal().setCross3(lhs, rhs);
+ baseVert.getNormal().normalize3fast();
+ }
- if (gx == 0 && gy == 0)
- {
- min = max = newVert.mPosition;
- }
- else
+ if(!(mTypeMask & TOP_MASK))
+ {
+ baseVert.getNormal().mul(-1.0f);
+ }
+ else
+ {
+ //Swap the UVs on the U(X) axis for top face
+ LLVector2 swap;
+ swap = corners[0].mTexCoord;
+ corners[0].mTexCoord=corners[3].mTexCoord;
+ corners[3].mTexCoord=swap;
+ swap = corners[1].mTexCoord;
+ corners[1].mTexCoord=corners[2].mTexCoord;
+ corners[2].mTexCoord=swap;
+ }
+
+ LLVector4a binormal;
+
+ calc_binormal_from_triangle( binormal,
+ corners[0].getPosition(), corners[0].mTexCoord,
+ corners[1].getPosition(), corners[1].mTexCoord,
+ corners[2].getPosition(), corners[2].mTexCoord);
+
+ binormal.normalize3fast();
+
+ S32 size = (grid_size+1)*(grid_size+1);
+ resizeVertices(size);
+ allocateBinormals(size);
+
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+
+ for(int gx = 0;gx<grid_size+1;gx++)
+ {
+ for(int gy = 0;gy<grid_size+1;gy++)
{
- update_min_max(min,max,newVert.mPosition);
+ VertexData newVert;
+ LerpPlanarVertex(
+ corners[0],
+ corners[1],
+ corners[3],
+ newVert,
+ (F32)gx/(F32)grid_size,
+ (F32)gy/(F32)grid_size);
+
+ *pos++ = newVert.getPosition();
+ *norm++ = baseVert.getNormal();
+ *tc++ = newVert.mTexCoord;
+ *binorm++ = binormal;
+
+ if (gx == 0 && gy == 0)
+ {
+ min = max = newVert.getPosition();
+ }
+ else
+ {
+ min.setMin(newVert.getPosition());
+ max.setMax(newVert.getPosition());
+ }
}
}
- }
- mCenter = (min + max) * 0.5f;
+ mCenter->setAdd(min, max);
+ mCenter->mul(0.5f);
+ }
if (!partial_build)
{
-#if GEN_TRI_STRIP
- mTriStrip.clear();
-#endif
+ resizeIndices(grid_size*grid_size*6);
+
+ U16* out = mIndices;
+
S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
for(S32 gx = 0;gx<grid_size;gx++)
{
@@ -4545,59 +5661,23 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
{
for(S32 i=5;i>=0;i--)
{
- mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
- }
-
+ *out++ = ((gy*(grid_size+1))+gx+idxs[i]);
+ }
#if GEN_TRI_STRIP
- if (gy == 0)
- {
- mTriStrip.push_back((gx+1)*(grid_size+1));
- mTriStrip.push_back((gx+1)*(grid_size+1));
- mTriStrip.push_back(gx*(grid_size+1));
- }
-
- mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
- mTriStrip.push_back(gy+1+gx*(grid_size+1));
-
-
- if (gy == grid_size-1)
- {
- mTriStrip.push_back(gy+1+gx*(grid_size+1));
- }
#endif
}
else
{
for(S32 i=0;i<6;i++)
{
- mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
+ *out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
-
#if GEN_TRI_STRIP
- if (gy == 0)
- {
- mTriStrip.push_back(gx*(grid_size+1));
- mTriStrip.push_back(gx*(grid_size+1));
- mTriStrip.push_back((gx+1)*(grid_size+1));
- }
-
- mTriStrip.push_back(gy+1+gx*(grid_size+1));
- mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
-
- if (gy == grid_size-1)
- {
- mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
- }
#endif
}
}
- }
-
#if GEN_TRI_STRIP
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
}
#endif
}
@@ -4629,17 +5709,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
num_vertices = profile.size();
num_indices = (profile.size() - 2)*3;
- mVertices.resize(num_vertices);
+ if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
+ {
+ resizeVertices(num_vertices+1);
+ allocateBinormals(num_vertices+1);
- if (!partial_build)
+ if (!partial_build)
+ {
+ resizeIndices(num_indices+3);
+ }
+ }
+ else
{
- mIndices.resize(num_indices);
+ resizeVertices(num_vertices);
+ allocateBinormals(num_vertices);
+
+ if (!partial_build)
+ {
+ resizeIndices(num_indices);
+ }
}
S32 max_s = volume->getProfile().getTotal();
S32 max_t = volume->getPath().mPath.size();
- mCenter.clearVec();
+ mCenter->clear();
S32 offset = 0;
if (mTypeMask & TOP_MASK)
@@ -4657,82 +5751,90 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LLVector2 cuv;
LLVector2 min_uv, max_uv;
- LLVector3& min = mExtents[0];
- LLVector3& max = mExtents[1];
+ LLVector4a& min = mExtents[0];
+ LLVector4a& max = mExtents[1];
+
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
// Copy the vertices into the array
for (S32 i = 0; i < num_vertices; i++)
{
if (mTypeMask & TOP_MASK)
{
- mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
- mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f;
+ tc[i].mV[0] = profile[i].mV[0]+0.5f;
+ tc[i].mV[1] = profile[i].mV[1]+0.5f;
}
else
{
// Mirror for underside.
- mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
- mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1];
+ tc[i].mV[0] = profile[i].mV[0]+0.5f;
+ tc[i].mV[1] = 0.5f - profile[i].mV[1];
}
- mVertices[i].mPosition = mesh[i + offset].mPos;
+ pos[i].load3(mesh[i + offset].mPos.mV);
if (i == 0)
{
- min = max = mVertices[i].mPosition;
- min_uv = max_uv = mVertices[i].mTexCoord;
+ min = max = pos[i];
+ min_uv = max_uv = tc[i];
}
else
{
- update_min_max(min,max, mVertices[i].mPosition);
- update_min_max(min_uv, max_uv, mVertices[i].mTexCoord);
+ update_min_max(min,max,pos[i]);
+ update_min_max(min_uv, max_uv, tc[i]);
}
}
- mCenter = (min+max)*0.5f;
+ mCenter->setAdd(min, max);
+ mCenter->mul(0.5f);
+
cuv = (min_uv + max_uv)*0.5f;
- LLVector3 binormal = calc_binormal_from_triangle(
- mCenter, cuv,
- mVertices[0].mPosition, mVertices[0].mTexCoord,
- mVertices[1].mPosition, mVertices[1].mTexCoord);
- binormal.normVec();
+ LLVector4a binormal;
+ calc_binormal_from_triangle(binormal,
+ *mCenter, cuv,
+ pos[0], tc[0],
+ pos[1], tc[1]);
+ binormal.normalize3fast();
- LLVector3 d0;
- LLVector3 d1;
- LLVector3 normal;
+ LLVector4a normal;
+ LLVector4a d0, d1;
+
- d0 = mCenter-mVertices[0].mPosition;
- d1 = mCenter-mVertices[1].mPosition;
+ d0.setSub(*mCenter, pos[0]);
+ d1.setSub(*mCenter, pos[1]);
- normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
- normal.normVec();
+ if (mTypeMask & TOP_MASK)
+ {
+ normal.setCross3(d0, d1);
+ }
+ else
+ {
+ normal.setCross3(d1, d0);
+ }
+
+ normal.normalize3fast();
VertexData vd;
- vd.mPosition = mCenter;
- vd.mNormal = normal;
- vd.mBinormal = binormal;
+ vd.setPosition(*mCenter);
vd.mTexCoord = cuv;
if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
{
- mVertices.push_back(vd);
+ pos[num_vertices] = *mCenter;
+ tc[num_vertices] = cuv;
num_vertices++;
- if (!partial_build)
- {
- vector_append(mIndices, 3);
- }
}
-
for (S32 i = 0; i < num_vertices; i++)
{
- mVertices[i].mBinormal = binormal;
- mVertices[i].mNormal = normal;
+ binorm[i].load4a((F32*) &binormal.mQ);
+ norm[i].load4a((F32*) &normal.mQ);
}
- mHasBinormals = TRUE;
-
if (partial_build)
{
return TRUE;
@@ -4840,8 +5942,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
pt2--;
}
}
-
- makeTriStrip();
}
else
{
@@ -4946,8 +6046,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
pt2--;
}
}
-
- makeTriStrip();
}
}
else
@@ -4969,131 +6067,320 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
mIndices[3*i+v2] = i + 1;
}
-#if GEN_TRI_STRIP
- //make tri strip
- if (mTypeMask & OPEN_MASK)
- {
- makeTriStrip();
- }
- else
- {
- S32 j = num_vertices-2;
- if (mTypeMask & TOP_MASK)
+
+ }
+
+ return TRUE;
+}
+
+void LLVolumeFace::createBinormals()
+{
+ LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+ if (!mBinormals)
+ {
+ allocateBinormals(mNumVertices);
+
+ //generate binormals
+ LLVector4a* pos = mPositions;
+ LLVector2* tc = (LLVector2*) mTexCoords;
+ LLVector4a* binorm = (LLVector4a*) mBinormals;
+
+ for (U32 i = 0; i < mNumIndices/3; i++)
+ { //for each triangle
+ const U16& i0 = mIndices[i*3+0];
+ const U16& i1 = mIndices[i*3+1];
+ const U16& i2 = mIndices[i*3+2];
+
+ //calculate binormal
+ LLVector4a binormal;
+ calc_binormal_from_triangle(binormal,
+ pos[i0], tc[i0],
+ pos[i1], tc[i1],
+ pos[i2], tc[i2]);
+
+
+ //add triangle normal to vertices
+ binorm[i0].add(binormal);
+ binorm[i1].add(binormal);
+ binorm[i2].add(binormal);
+
+ //even out quad contributions
+ if (i % 2 == 0)
{
- mTriStrip.push_back(0);
- for (S32 i = 0; i <= j; ++i)
- {
- mTriStrip.push_back(i);
- if (i != j)
- {
- mTriStrip.push_back(j);
- }
- --j;
- }
+ binorm[i2].add(binormal);
}
- else
+ else
{
- mTriStrip.push_back(j);
- for (S32 i = 0; i <= j; ++i)
- {
- if (i != j)
- {
- mTriStrip.push_back(j);
- }
- mTriStrip.push_back(i);
- --j;
- }
+ binorm[i1].add(binormal);
}
-
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
+ }
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
- }
+ //normalize binormals
+ for (U32 i = 0; i < mNumVertices; i++)
+ {
+ binorm[i].normalize3fast();
+ //bump map/planar projection code requires normals to be normalized
+ mNormals[i].normalize3fast();
}
-#endif
}
-
- return TRUE;
}
-void LLVolumeFace::makeTriStrip()
+void LLVolumeFace::resizeVertices(S32 num_verts)
{
-#if GEN_TRI_STRIP
- for (U32 i = 0; i < mIndices.size(); i+=3)
+ ll_aligned_free_16(mPositions);
+ ll_aligned_free_16(mNormals);
+ ll_aligned_free_16(mBinormals);
+ ll_aligned_free_16(mTexCoords);
+
+ mBinormals = NULL;
+
+ if (num_verts)
+ {
+ mPositions = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+ mNormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+
+ //pad texture coordinate block end to allow for QWORD reads
+ S32 size = ((num_verts*8) + 0xF) & ~0xF;
+ mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
+ }
+ else
{
- U16 i0 = mIndices[i];
- U16 i1 = mIndices[i+1];
- U16 i2 = mIndices[i+2];
+ mPositions = NULL;
+ mNormals = NULL;
+ mTexCoords = NULL;
+ }
+
+ mNumVertices = num_verts;
+}
+
+void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
+{
+ pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord);
+}
+
+void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc)
+{
+ S32 new_verts = mNumVertices+1;
+ S32 new_size = new_verts*16;
+ S32 old_size = mNumVertices*16;
+
+ //positions
+ LLVector4a* dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+ if (mPositions)
+ {
+ LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mPositions, old_size/4);
+ ll_aligned_free_16(mPositions);
+ }
+ mPositions = dst;
- if ((i/3)%2 == 1)
+ //normals
+ dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+ if (mNormals)
+ {
+ LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mNormals, old_size/4);
+ ll_aligned_free_16(mNormals);
+ }
+ mNormals = dst;
+
+ //tex coords
+ 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);
+ if (mTexCoords)
{
- mTriStrip.push_back(i0);
- mTriStrip.push_back(i0);
- mTriStrip.push_back(i1);
- mTriStrip.push_back(i2);
- mTriStrip.push_back(i2);
+ LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mTexCoords, old_size/4);
+ ll_aligned_free_16(mTexCoords);
}
- else
+ }
+ mTexCoords = (LLVector2*) dst;
+
+ //just clear binormals
+ ll_aligned_free_16(mBinormals);
+ mBinormals = NULL;
+
+ mPositions[mNumVertices] = pos;
+ mNormals[mNumVertices] = norm;
+ mTexCoords[mNumVertices] = tc;
+
+ mNumVertices++;
+}
+
+void LLVolumeFace::allocateBinormals(S32 num_verts)
+{
+ ll_aligned_free_16(mBinormals);
+ mBinormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+}
+
+void LLVolumeFace::allocateWeights(S32 num_verts)
+{
+ ll_aligned_free_16(mWeights);
+ mWeights = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+}
+
+void LLVolumeFace::resizeIndices(S32 num_indices)
+{
+ ll_aligned_free_16(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);
+ }
+ else
+ {
+ mIndices = NULL;
+ }
+
+ mNumIndices = num_indices;
+}
+
+void LLVolumeFace::pushIndex(const U16& idx)
+{
+ S32 new_count = mNumIndices + 1;
+ S32 new_size = ((new_count*2)+0xF) & ~0xF;
+
+ S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
+ if (new_size != old_size)
+ {
+ U16* dst = (U16*) ll_aligned_malloc_16(new_size);
+ if (mIndices)
{
- mTriStrip.push_back(i2);
- mTriStrip.push_back(i2);
- mTriStrip.push_back(i1);
- mTriStrip.push_back(i0);
- mTriStrip.push_back(i0);
+ LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mIndices, old_size/4);
+ ll_aligned_free_16(mIndices);
}
+ mIndices = dst;
}
+
+ mIndices[mNumIndices++] = idx;
+}
+
+void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx)
+{
+ resizeVertices(v.size());
+ resizeIndices(idx.size());
- if (mTriStrip.size()%2 == 1)
+ for (U32 i = 0; i < v.size(); ++i)
{
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
+ mPositions[i] = v[i].getPosition();
+ mNormals[i] = v[i].getNormal();
+ mTexCoords[i] = v[i].mTexCoord;
+ }
+
+ for (U32 i = 0; i < idx.size(); ++i)
+ {
+ mIndices[i] = idx[i];
}
-#endif
}
-void LLVolumeFace::createBinormals()
+void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in)
{
- LLMemType m1(LLMemType::MTYPE_VOLUME);
+ U16 offset = mNumVertices;
+
+ S32 new_count = face.mNumVertices + mNumVertices;
+
+ if (new_count > 65536)
+ {
+ llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl;
+ }
- if (!mHasBinormals)
+ if (face.mNumVertices == 0)
{
- //generate binormals
- for (U32 i = 0; i < mIndices.size()/3; i++)
- { //for each triangle
- const VertexData& v0 = mVertices[mIndices[i*3+0]];
- const VertexData& v1 = mVertices[mIndices[i*3+1]];
- const VertexData& v2 = mVertices[mIndices[i*3+2]];
-
- //calculate binormal
- LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
- v1.mPosition, v1.mTexCoord,
- v2.mPosition, v2.mTexCoord);
+ llerrs << "Cannot append empty face." << llendl;
+ }
- for (U32 j = 0; j < 3; j++)
- { //add triangle normal to vertices
- mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
- }
+ //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);
+
- //even out quad contributions
- if (i % 2 == 0)
- {
- mVertices[mIndices[i*3+2]].mBinormal += binorm;
- }
- else
- {
- mVertices[mIndices[i*3+1]].mBinormal += binorm;
- }
- }
+ if (mNumVertices > 0)
+ { //copy old buffers
+ LLVector4a::memcpyNonAliased16((F32*) new_pos, (F32*) mPositions, mNumVertices*4);
+ LLVector4a::memcpyNonAliased16((F32*) new_norm, (F32*) mNormals, mNumVertices*4);
+ LLVector4a::memcpyNonAliased16((F32*) new_tc, (F32*) mTexCoords, mNumVertices*2);
+ }
- //normalize binormals
- for (U32 i = 0; i < mVertices.size(); i++)
+ //free old buffer space
+ ll_aligned_free_16(mPositions);
+ ll_aligned_free_16(mNormals);
+ ll_aligned_free_16(mTexCoords);
+
+ //point to new buffers
+ mPositions = new_pos;
+ mNormals = new_norm;
+ mTexCoords = new_tc;
+
+ mNumVertices = new_count;
+
+ //get destination address of appended face
+ LLVector4a* dst_pos = mPositions+offset;
+ LLVector2* dst_tc = mTexCoords+offset;
+ LLVector4a* dst_norm = mNormals+offset;
+
+ //get source addresses of appended face
+ const LLVector4a* src_pos = face.mPositions;
+ const LLVector2* src_tc = face.mTexCoords;
+ const LLVector4a* src_norm = face.mNormals;
+
+ //load aligned matrices
+ LLMatrix4a mat, norm_mat;
+ mat.loadu(mat_in);
+ norm_mat.loadu(norm_mat_in);
+
+ for (U32 i = 0; i < face.mNumVertices; ++i)
+ {
+ //transform appended face position and store
+ mat.affineTransform(src_pos[i], dst_pos[i]);
+
+ //transform appended face normal and store
+ norm_mat.rotate(src_norm[i], dst_norm[i]);
+ dst_norm[i].normalize3fast();
+
+ //copy appended face texture coordinate
+ dst_tc[i] = src_tc[i];
+
+ if (offset == 0 && i == 0)
+ { //initialize bounding box
+ mExtents[0] = mExtents[1] = dst_pos[i];
+ }
+ else
{
- mVertices[i].mBinormal.normVec();
- mVertices[i].mNormal.normVec();
+ //stretch bounding box
+ update_min_max(mExtents[0], mExtents[1], dst_pos[i]);
}
+ }
- mHasBinormals = TRUE;
+
+ new_count = mNumIndices + face.mNumIndices;
+
+ //allocate new index buffer
+ U16* new_indices = (U16*) ll_aligned_malloc_16((new_count*2+0xF) & ~0xF);
+ if (mNumIndices > 0)
+ { //copy old index buffer
+ S32 old_size = (mNumIndices*2+0xF) & ~0xF;
+ LLVector4a::memcpyNonAliased16((F32*) new_indices, (F32*) mIndices, old_size/4);
+ }
+
+ //free old index buffer
+ ll_aligned_free_16(mIndices);
+
+ //point to new index buffer
+ mIndices = new_indices;
+
+ //get destination address into new index buffer
+ U16* dst_idx = mIndices+mNumIndices;
+ mNumIndices = new_count;
+
+ for (U32 i = 0; i < face.mNumIndices; ++i)
+ { //copy indices, offsetting by old vertex count
+ dst_idx[i] = face.mIndices[i]+offset;
}
}
@@ -5123,18 +6410,24 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
num_vertices = mNumS*mNumT;
num_indices = (mNumS-1)*(mNumT-1)*6;
- mVertices.resize(num_vertices);
-
if (!partial_build)
{
- mIndices.resize(num_indices);
+ resizeVertices(num_vertices);
+ resizeIndices(num_indices);
+
+#if LL_MESH_ENABLED
+ if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
+ {
+ mEdge.resize(num_indices);
+ }
+#else
mEdge.resize(num_indices);
- }
- else
- {
- mHasBinormals = FALSE;
+#endif
}
+ LLVector4a* pos = (LLVector4a*) mPositions;
+ LLVector4a* norm = (LLVector4a*) mNormals;
+ LLVector2* tc = (LLVector2*) mTexCoords;
S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
@@ -5185,21 +6478,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
i = mBeginS + s + max_s*t;
}
- mVertices[cur_vertex].mPosition = mesh[i].mPos;
- mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
- mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
- mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
+ norm[cur_vertex].clear();
cur_vertex++;
if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
{
- mVertices[cur_vertex].mPosition = mesh[i].mPos;
- mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
- mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
- mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
+ norm[cur_vertex].clear();
+
cur_vertex++;
}
}
@@ -5217,29 +6509,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
i = mBeginS + s + max_s*t;
ss = profile[mBeginS + s].mV[2] - begin_stex;
- mVertices[cur_vertex].mPosition = mesh[i].mPos;
- mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
-
- mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
- mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
+ pos[cur_vertex].load3(mesh[i].mPos.mV);
+ tc[cur_vertex] = LLVector2(ss,tt);
+ norm[cur_vertex].clear();
+
cur_vertex++;
}
}
//get bounding box for this side
- LLVector3& face_min = mExtents[0];
- LLVector3& face_max = mExtents[1];
- mCenter.clearVec();
+ LLVector4a& face_min = mExtents[0];
+ LLVector4a& face_max = mExtents[1];
+ mCenter->clear();
+
+ face_min = face_max = pos[0];
- face_min = face_max = mVertices[0].mPosition;
- for (U32 i = 1; i < mVertices.size(); ++i)
+ for (U32 i = 1; i < mNumVertices; ++i)
{
- update_min_max(face_min, face_max, mVertices[i].mPosition);
+ update_min_max(face_min, face_max, pos[i]);
}
- mCenter = (face_min + face_max) * 0.5f;
+ mCenter->setAdd(face_min, face_max);
+ mCenter->mul(0.5f);
S32 cur_index = 0;
S32 cur_edge = 0;
@@ -5248,17 +6540,12 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
if (!partial_build)
{
#if GEN_TRI_STRIP
- mTriStrip.clear();
#endif
-
// Now we generate the indices.
for (t = 0; t < (mNumT-1); t++)
{
#if GEN_TRI_STRIP
- //prepend terminating index to strip
- mTriStrip.push_back(mNumS*t);
#endif
-
for (s = 0; s < (mNumS-1); s++)
{
mIndices[cur_index++] = s + mNumS*t; //bottom left
@@ -5269,15 +6556,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
#if GEN_TRI_STRIP
- if (s == 0)
- {
- mTriStrip.push_back(s+mNumS*t);
- mTriStrip.push_back(s+mNumS*(t+1));
- }
- mTriStrip.push_back(s+1+mNumS*t);
- mTriStrip.push_back(s+1+mNumS*(t+1));
#endif
-
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; //bottom left/top right neighbor face
if (t < mNumT-2) { //top right/top left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
@@ -5319,51 +6598,58 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face
}
#if GEN_TRI_STRIP
- //append terminating vertex to strip
- mTriStrip.push_back(mNumS-1+mNumS*(t+1));
#endif
- }
-
#if GEN_TRI_STRIP
- if (mTriStrip.size()%2 == 1)
- {
- mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
}
#endif
}
//generate normals
- for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle
+ for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle
{
const U16* idx = &(mIndices[i*3]);
-
- VertexData* v[] =
- { &mVertices[idx[0]], &mVertices[idx[1]], &mVertices[idx[2]] };
-
- //calculate triangle normal
- LLVector3 norm = (v[0]->mPosition-v[1]->mPosition) % (v[0]->mPosition-v[2]->mPosition);
+
- v[0]->mNormal += norm;
- v[1]->mNormal += norm;
- v[2]->mNormal += norm;
+ LLVector4a* v[] =
+ { pos+idx[0], pos+idx[1], pos+idx[2] };
+
+ LLVector4a* n[] =
+ { norm+idx[0], norm+idx[1], norm+idx[2] };
+
+ //calculate triangle normal
+ LLVector4a a, b, c;
+
+ a.setSub(*v[0], *v[1]);
+ b.setSub(*v[0], *v[2]);
+ c.setCross3(a,b);
+ n[0]->add(c);
+ n[1]->add(c);
+ n[2]->add(c);
+
//even out quad contributions
- v[i%2+1]->mNormal += norm;
+ n[i%2+1]->add(c);
}
// adjust normals based on wrapping and stitching
- BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
- BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f);
+ LLVector4a top;
+ top.setSub(pos[0], pos[mNumS*(mNumT-2)]);
+ BOOL s_bottom_converges = (top.dot3(top) < 0.000001f);
+
+ top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]);
+ BOOL s_top_converges = (top.dot3(top) < 0.000001f);
+
if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes
{
if (volume->getPath().isOpen() == FALSE)
{ //wrap normals on T
for (S32 i = 0; i < mNumS; i++)
{
- LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
- mVertices[i].mNormal = norm;
- mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+ norm[i] = n;
+ norm[mNumS*(mNumT-1)+i] = n;
}
}
@@ -5371,9 +6657,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{ //wrap normals on S
for (S32 i = 0; i < mNumT; i++)
{
- LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
- mVertices[mNumS * i].mNormal = norm;
- mVertices[mNumS * i+mNumS-1].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+ norm[mNumS * i] = n;
+ norm[mNumS * i+mNumS-1] = n;
}
}
@@ -5384,7 +6671,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{ //all lower S have same normal
for (S32 i = 0; i < mNumT; i++)
{
- mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
+ norm[mNumS*i].set(1,0,0);
}
}
@@ -5392,7 +6679,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{ //all upper S have same normal
for (S32 i = 0; i < mNumT; i++)
{
- mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
+ norm[mNumS*i+mNumS-1].set(-1,0,0);
}
}
}
@@ -5420,30 +6707,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{
// average normals for north pole
- LLVector3 average(0.0, 0.0, 0.0);
+ LLVector4a average;
+ average.clear();
+
for (S32 i = 0; i < mNumS; i++)
{
- average += mVertices[i].mNormal;
+ average.add(norm[i]);
}
// set average
for (S32 i = 0; i < mNumS; i++)
{
- mVertices[i].mNormal = average;
+ norm[i] = average;
}
// average normals for south pole
- average = LLVector3(0.0, 0.0, 0.0);
+ average.clear();
+
for (S32 i = 0; i < mNumS; i++)
{
- average += mVertices[i + mNumS * (mNumT - 1)].mNormal;
+ average.add(norm[i + mNumS * (mNumT - 1)]);
}
// set average
for (S32 i = 0; i < mNumS; i++)
{
- mVertices[i + mNumS * (mNumT - 1)].mNormal = average;
+ norm[i + mNumS * (mNumT - 1)] = average;
}
}
@@ -5453,23 +6743,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
{
for (S32 i = 0; i < mNumT; i++)
{
- LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
- mVertices[mNumS * i].mNormal = norm;
- mVertices[mNumS * i+mNumS-1].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+ norm[mNumS * i] = n;
+ norm[mNumS * i+mNumS-1] = n;
}
}
-
-
if (wrap_t)
{
for (S32 i = 0; i < mNumS; i++)
{
- LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
- mVertices[i].mNormal = norm;
- mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+ LLVector4a n;
+ n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+ norm[i] = n;
+ norm[mNumS*(mNumT-1)+i] = n;
}
-
}
}
@@ -5479,41 +6768,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
// Finds binormal based on three vertices with texture coordinates.
// Fills in dummy values if the triangle has degenerate texture coordinates.
-LLVector3 calc_binormal_from_triangle(
- const LLVector3& pos0,
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+ const LLVector4a& pos0,
const LLVector2& tex0,
- const LLVector3& pos1,
+ const LLVector4a& pos1,
const LLVector2& tex1,
- const LLVector3& pos2,
+ const LLVector4a& pos2,
const LLVector2& tex2)
{
- LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] );
- LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] );
- LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] );
+ LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] );
- LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] );
- LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] );
- LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] );
+ LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] );
- LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] );
- LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] );
- LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] );
+ LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] );
+ LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] );
+ LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] );
- LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2);
- LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2);
- LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2);
+ LLVector4a lhs, rhs;
+
+ LLVector4a r0;
+ lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2);
+ r0.setCross3(lhs, rhs);
+
+ LLVector4a r1;
+ lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2);
+ r1.setCross3(lhs, rhs);
+
+ LLVector4a r2;
+ lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2);
+ r2.setCross3(lhs, rhs);
- if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] )
+ if( r0[VX] && r1[VX] && r2[VX] )
{
- LLVector3 binormal(
- -r0.mV[VZ] / r0.mV[VX],
- -r1.mV[VZ] / r1.mV[VX],
- -r2.mV[VZ] / r2.mV[VX]);
+ binormal.set(
+ -r0[VZ] / r0[VX],
+ -r1[VZ] / r1[VX],
+ -r2[VZ] / r2[VX]);
// binormal.normVec();
- return binormal;
}
else
{
- return LLVector3( 0, 1 , 0 );
+ binormal.set( 0, 1 , 0 );
}
}
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index d9f80f0e30..af28337f57 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -40,8 +40,15 @@ class LLPathParams;
class LLVolumeParams;
class LLProfile;
class LLPath;
+
+#define LL_MESH_ENABLED 1
+
+template <class T> class LLOctreeNode;
+
+class LLVector4a;
class LLVolumeFace;
class LLVolume;
+class LLVolumeTriangle;
#include "lldarray.h"
#include "lluuid.h"
@@ -49,6 +56,8 @@ class LLVolume;
//#include "vmath.h"
#include "v2math.h"
#include "v3math.h"
+#include "v3dmath.h"
+#include "v4math.h"
#include "llquaternion.h"
#include "llstrider.h"
#include "v4coloru.h"
@@ -183,12 +192,20 @@ const U8 LL_SCULPT_TYPE_SPHERE = 1;
const U8 LL_SCULPT_TYPE_TORUS = 2;
const U8 LL_SCULPT_TYPE_PLANE = 3;
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
-
-const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER;
+#if LL_MESH_ENABLED
+const U8 LL_SCULPT_TYPE_MESH = 5;
+
+const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
+ LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
+#else
+const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
+ LL_SCULPT_TYPE_CYLINDER;
+#endif
const U8 LL_SCULPT_FLAG_INVERT = 64;
const U8 LL_SCULPT_FLAG_MIRROR = 128;
+const S32 LL_SCULPT_MESH_MAX_FACES = 8;
class LLProfileParams
{
@@ -575,6 +592,9 @@ public:
BOOL importLegacyStream(std::istream& input_stream);
BOOL exportLegacyStream(std::ostream& output_stream) const;
+ LLSD sculptAsLLSD() const;
+ bool sculptFromLLSD(LLSD& sd);
+
LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd);
@@ -634,7 +654,6 @@ public:
const F32& getSkew() const { return mPathParams.getSkew(); }
const LLUUID& getSculptID() const { return mSculptID; }
const U8& getSculptType() const { return mSculptType; }
-
BOOL isConvex() const;
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
@@ -785,30 +804,86 @@ public:
class LLVolumeFace
{
public:
- LLVolumeFace() :
- mID(0),
- mTypeMask(0),
- mHasBinormals(FALSE),
- mBeginS(0),
- mBeginT(0),
- mNumS(0),
- mNumT(0)
+ class VertexData
{
- }
+ enum
+ {
+ POSITION = 0,
+ NORMAL = 1
+ };
+
+ private:
+ void init();
+ public:
+ VertexData();
+ VertexData(const VertexData& rhs);
+ const VertexData& operator=(const VertexData& rhs);
+
+ ~VertexData();
+ LLVector4a& getPosition();
+ LLVector4a& getNormal();
+ const LLVector4a& getPosition() const;
+ const LLVector4a& getNormal() const;
+ void setPosition(const LLVector4a& pos);
+ void setNormal(const LLVector4a& norm);
+
+
+ LLVector2 mTexCoord;
+
+ bool operator<(const VertexData& rhs) const;
+ bool operator==(const VertexData& rhs) const;
+ bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
+
+ private:
+ LLVector4a* mData;
+ };
+
+ LLVolumeFace();
+ LLVolumeFace(const LLVolumeFace& src);
+ LLVolumeFace& operator=(const LLVolumeFace& rhs);
+
+ ~LLVolumeFace();
+private:
+ void freeData();
+public:
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
void createBinormals();
- void makeTriStrip();
- class VertexData
+ void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
+
+ void resizeVertices(S32 num_verts);
+ void allocateBinormals(S32 num_verts);
+ void allocateWeights(S32 num_verts);
+ void resizeIndices(S32 num_indices);
+ void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
+
+ void pushVertex(const VertexData& cv);
+ void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc);
+ void pushIndex(const U16& idx);
+
+ void swapData(LLVolumeFace& rhs);
+
+ void getVertexData(U16 indx, LLVolumeFace::VertexData& cv);
+
+ class VertexMapData : public LLVolumeFace::VertexData
{
public:
- LLVector3 mPosition;
- LLVector3 mNormal;
- LLVector3 mBinormal;
- LLVector2 mTexCoord;
+ U16 mIndex;
+
+ bool operator==(const LLVolumeFace::VertexData& rhs) const;
+
+ struct ComparePosition
+ {
+ bool operator()(const LLVector3& a, const LLVector3& b) const;
+ };
+
+ typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
};
+ void optimize(F32 angle_cutoff = 2.f);
+ void createOctree();
+
enum
{
SINGLE_MASK = 0x0001,
@@ -827,22 +902,34 @@ public:
public:
S32 mID;
U32 mTypeMask;
- LLVector3 mCenter;
- BOOL mHasBinormals;
-
+
// Only used for INNER/OUTER faces
S32 mBeginS;
S32 mBeginT;
S32 mNumS;
S32 mNumT;
- LLVector3 mExtents[2]; //minimum and maximum point of face
+ LLVector4a* mExtents; //minimum and maximum point of face
+ LLVector4a* mCenter;
+
+ S32 mNumVertices;
+ S32 mNumIndices;
+
+ LLVector4a* mPositions;
+ LLVector4a* mNormals;
+ LLVector4a* mBinormals;
+ LLVector2* mTexCoords;
+ U16* mIndices;
- std::vector<VertexData> mVertices;
- std::vector<U16> mIndices;
- std::vector<U16> mTriStrip;
std::vector<S32> mEdge;
+ //list of skin weights for rigged volumes
+ // format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
+ // mWeights.size() should be empty or match mVertices.size()
+ LLVector4a* mWeights;
+
+ LLOctreeNode<LLVolumeTriangle>* mOctree;
+
private:
BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
@@ -853,8 +940,7 @@ class LLVolume : public LLRefCount
{
friend class LLVolumeLODGroup;
-private:
- LLVolume(const LLVolume&); // Don't implement
+protected:
~LLVolume(); // use unref
public:
@@ -876,7 +962,7 @@ public:
U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); }
U8 getPathType() const { return mParams.getPathParams().getCurveType(); }
- S32 getNumFaces() const { return (S32)mProfilep->mFaces.size(); }
+ S32 getNumFaces() const;
S32 getNumVolumeFaces() const { return mVolumeFaces.size(); }
F32 getDetail() const { return mDetail; }
const LLVolumeParams& getParams() const { return mParams; }
@@ -898,12 +984,15 @@ public:
BOOL isUnique() const { return mUnique; }
S32 getSculptLevel() const { return mSculptLevel; }
-
+ void setSculptLevel(S32 level) { mSculptLevel = level; }
+
S32 *getTriangleIndices(U32 &num_indices) const;
// returns number of triangle indeces required for path/profile mesh
S32 getNumTriangleIndices() const;
+ S32 getNumTriangles() const;
+
void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
std::vector<LLVector3> &normals,
std::vector<S32> &segments,
@@ -922,6 +1011,13 @@ public:
LLVector3* normal = NULL, // return the surface normal at the intersection point
LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point
);
+
+ S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ S32 face = 1,
+ LLVector3* intersection = NULL,
+ LLVector2* tex_coord = NULL,
+ LLVector3* normal = NULL,
+ LLVector3* bi_normal = NULL);
// The following cleans up vertices and triangles,
// getting rid of degenerate triangles and duplicate vertices,
@@ -948,6 +1044,8 @@ 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);
+
private:
void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
F32 sculptGetSurfaceArea();
@@ -958,11 +1056,19 @@ private:
protected:
BOOL generate();
void createVolumeFaces();
+public:
+ virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
+ virtual BOOL createVolumeFacesFromStream(std::istream& is);
+ virtual bool unpackVolumeFaces(std::istream& is, S32 size);
+
+ virtual void makeTetrahedron();
+ virtual BOOL isTetrahedron();
protected:
BOOL mUnique;
F32 mDetail;
S32 mSculptLevel;
+ BOOL mIsTetrahedron;
LLVolumeParams mParams;
LLPath *mPathp;
@@ -976,17 +1082,26 @@ protected:
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
-LLVector3 calc_binormal_from_triangle(
- const LLVector3& pos0,
+void calc_binormal_from_triangle(
+ LLVector4a& binormal,
+ const LLVector4a& pos0,
const LLVector2& tex0,
- const LLVector3& pos1,
+ const LLVector4a& pos1,
const LLVector2& tex1,
- const LLVector3& pos2,
+ const LLVector4a& pos2,
const LLVector2& tex2);
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
+BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
+
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
- F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
+ F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
+
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t);
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+ F32& intersection_a, F32& intersection_b, F32& intersection_t);
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 53641fceab..419e0015ba 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -320,7 +320,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
{
llassert_always(mLODRefs[i] > 0);
mLODRefs[i]--;
-#if 1 // SJB: Possible opt: keep other lods around
+#if 0 // SJB: Possible opt: keep other lods around
if (!mLODRefs[i])
{
mVolumeLODs[i] = NULL;
@@ -375,6 +375,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
return mDetailScales[detail];
}
+S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
+{
+ for (S32 i = 1; i < 4; i++)
+ {
+ if (mDetailScales[i] > detail)
+ {
+ return i-1;
+ }
+ }
+
+ return 3;
+}
+
F32 LLVolumeLODGroup::dump()
{
F32 usage = 0.f;
diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h
index a78ea76a1a..f5dc4cd748 100644
--- a/indra/llmath/llvolumemgr.h
+++ b/indra/llmath/llvolumemgr.h
@@ -59,6 +59,7 @@ public:
static S32 getDetailFromTan(const F32 tan_angle);
static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher);
static F32 getVolumeScaleFromDetail(const S32 detail);
+ static S32 getVolumeDetailFromScale(F32 scale);
LLVolume* refLOD(const S32 detail);
BOOL derefLOD(LLVolume *volumep);
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index d8e7b4aaf9..ce5428f0e1 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -221,8 +221,33 @@ const LLMatrix4& LLMatrix4::transpose()
F32 LLMatrix4::determinant() const
{
- llerrs << "Not implemented!" << llendl;
- return 0.f;
+ F32 value =
+ mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][0] -
+ mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][0] -
+ mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][0] +
+ mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][0] +
+ mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][0] -
+ mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][0] -
+ mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][1] +
+ mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][1] +
+ mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][1] -
+ mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][1] -
+ mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][1] +
+ mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][1] +
+ mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][2] -
+ mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][2] -
+ mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][2] +
+ mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][2] +
+ mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][2] -
+ mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][2] -
+ mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][3] +
+ mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][3] +
+ mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][3] -
+ mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][3] -
+ mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][3] +
+ mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][3];
+
+ return value;
}
// Only works for pure orthonormal, homogeneous transform matrices.
@@ -428,6 +453,17 @@ const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector
return (*this);
}
+const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale)
+{
+ setIdentity();
+
+ mMatrix[VX][VX] = scale.mV[VX];
+ mMatrix[VY][VY] = scale.mV[VY];
+ mMatrix[VZ][VZ] = scale.mV[VZ];
+
+ return (*this);
+}
+
const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos)
{
F32 sx, sy, sz;
@@ -648,37 +684,6 @@ const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 &
// LLMatrix4 Operators
-
-/* Not implemented to help enforce code consistency with the syntax of
- row-major notation. This is a Good Thing.
-LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b)
-{
- // Operate "to the right" on column-vector b
- LLVector4 vec;
- vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] +
- a.mMatrix[VY][VX] * b.mV[VY] +
- a.mMatrix[VZ][VX] * b.mV[VZ] +
- a.mMatrix[VW][VX] * b.mV[VW];
-
- vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] +
- a.mMatrix[VY][VY] * b.mV[VY] +
- a.mMatrix[VZ][VY] * b.mV[VZ] +
- a.mMatrix[VW][VY] * b.mV[VW];
-
- vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] +
- a.mMatrix[VY][VZ] * b.mV[VY] +
- a.mMatrix[VZ][VZ] * b.mV[VZ] +
- a.mMatrix[VW][VZ] * b.mV[VW];
-
- vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] +
- a.mMatrix[VY][VW] * b.mV[VY] +
- a.mMatrix[VZ][VW] * b.mV[VZ] +
- a.mMatrix[VW][VW] * b.mV[VW];
- return vec;
-}
-*/
-
-
LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b)
{
// Operate "to the left" on row-vector a
@@ -774,6 +779,23 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b)
return FALSE;
}
+bool operator<(const LLMatrix4& a, const LLMatrix4 &b)
+{
+ U32 i, j;
+ for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
+ {
+ for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
+ {
+ if (a.mMatrix[i][j] != b.mMatrix[i][j])
+ {
+ return a.mMatrix[i][j] < b.mMatrix[i][j];
+ }
+ }
+ }
+
+ return false;
+}
+
const LLMatrix4& operator*=(LLMatrix4 &a, F32 k)
{
U32 i, j;
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index e74b7afe9b..40599a0886 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -159,6 +159,7 @@ public:
const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation
const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position
+ const LLMatrix4& initScale(const LLVector3 &scale);
// Set all
const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos);
@@ -225,10 +226,7 @@ public:
// Operators
//
-// Not implemented to enforce code that agrees with symbolic syntax
-// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b
-
-// friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b
+ // friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b
friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b
friend const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b
friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b); // Rotates a but does not translate
@@ -236,6 +234,7 @@ public:
friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b
friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b
+ friend bool operator<(const LLMatrix4 &a, const LLMatrix4& b); // Return a < b
friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b
friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b
diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp
index 555e1f92bb..220336e0c2 100644
--- a/indra/llmath/v2math.cpp
+++ b/indra/llmath/v2math.cpp
@@ -115,3 +115,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u)
a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u );
}
+
+LLSD LLVector2::getValue() const
+{
+ LLSD ret;
+ ret[0] = mV[0];
+ ret[1] = mV[1];
+ return ret;
+}
+
+void LLVector2::setValue(LLSD& sd)
+{
+ mV[0] = (F32) sd[0].asReal();
+ mV[1] = (F32) sd[1].asReal();
+}
+
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index 65f3714313..ae26c85ce4 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -66,6 +66,9 @@ class LLVector2
void set(const LLVector2 &vec); // Sets LLVector2 to vec
void set(const F32 *vec); // Sets LLVector2 to vec
+ LLSD getValue() const;
+ void setValue(LLSD& sd);
+
void setVec(F32 x, F32 y); // deprecated
void setVec(const LLVector2 &vec); // deprecated
void setVec(const F32 *vec); // deprecated
diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp
index 63683ed496..82aad6550b 100644
--- a/indra/llmath/v3math.cpp
+++ b/indra/llmath/v3math.cpp
@@ -197,6 +197,28 @@ const LLVector3& LLVector3::rotVec(const LLQuaternion &q)
return *this;
}
+const LLVector3& LLVector3::transVec(const LLMatrix4& mat)
+{
+ setVec(
+ mV[VX] * mat.mMatrix[VX][VX] +
+ mV[VY] * mat.mMatrix[VX][VY] +
+ mV[VZ] * mat.mMatrix[VX][VZ] +
+ mat.mMatrix[VX][VW],
+
+ mV[VX] * mat.mMatrix[VY][VX] +
+ mV[VY] * mat.mMatrix[VY][VY] +
+ mV[VZ] * mat.mMatrix[VY][VZ] +
+ mat.mMatrix[VY][VW],
+
+ mV[VX] * mat.mMatrix[VZ][VX] +
+ mV[VY] * mat.mMatrix[VZ][VY] +
+ mV[VZ] * mat.mMatrix[VZ][VZ] +
+ mat.mMatrix[VZ][VW]);
+
+ return *this;
+}
+
+
const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec)
{
if ( !vec.isExactlyZero() && angle )
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index 73738cffd2..75c860a91e 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -40,6 +40,7 @@
class LLVector2;
class LLVector4;
class LLMatrix3;
+class LLMatrix4;
class LLVector3d;
class LLQuaternion;
@@ -115,6 +116,7 @@ class LLVector3
const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
+ const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
@@ -529,6 +531,21 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos)
}
}
+inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos)
+{
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (min.mV[i] > pos[i])
+ {
+ min.mV[i] = pos[i];
+ }
+ if (max.mV[i] < pos[i])
+ {
+ max.mV[i] = pos[i];
+ }
+ }
+}
+
inline F32 angle_between(const LLVector3& a, const LLVector3& b)
{
LLVector3 an = a;
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index d6fbdec61e..6b63b976b0 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -114,6 +114,7 @@ class LLColor4
const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4
+ bool operator<(const LLColor4& rhs) const;
friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a
friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b
friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b
@@ -595,6 +596,23 @@ inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u)
a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
}
+inline bool LLColor4::operator<(const LLColor4& rhs) const
+{
+ if (mV[0] != rhs.mV[0])
+ {
+ return mV[0] < rhs.mV[0];
+ }
+ if (mV[1] != rhs.mV[1])
+ {
+ return mV[1] < rhs.mV[1];
+ }
+ if (mV[2] != rhs.mV[2])
+ {
+ return mV[2] < rhs.mV[2];
+ }
+
+ return mV[3] < rhs.mV[3];
+}
void LLColor4::clamp()
{