summaryrefslogtreecommitdiff
path: root/indra/llmath
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath')
-rwxr-xr-xindra/llmath/llcamera.cpp86
-rwxr-xr-xindra/llmath/llcamera.h37
-rwxr-xr-xindra/llmath/llvector4a.inl20
-rwxr-xr-xindra/llmath/llvolume.cpp219
4 files changed, 270 insertions, 92 deletions
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 22ba26f99b..33cf185196 100755
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -42,6 +42,11 @@ LLCamera::LLCamera() :
mPlaneCount(6),
mFrustumCornerDist(0.f)
{
+ for (U32 i = 0; i < PLANE_MASK_NUM; i++)
+ {
+ mPlaneMask[i] = PLANE_MASK_NONE;
+ }
+
calculateFrustumPlanes();
}
@@ -52,6 +57,11 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
mPlaneCount(6),
mFrustumCornerDist(0.f)
{
+ for (U32 i = 0; i < PLANE_MASK_NUM; i++)
+ {
+ mPlaneMask[i] = PLANE_MASK_NONE;
+ }
+
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;
@@ -87,14 +97,14 @@ F32 LLCamera::getMaxView() const
void LLCamera::setUserClipPlane(LLPlane& plane)
{
- mPlaneCount = 7;
- mAgentPlanes[6] = plane;
- mPlaneMask[6] = plane.calcPlaneMask();
+ mPlaneCount = AGENT_PLANE_USER_CLIP_NUM;
+ mAgentPlanes[AGENT_PLANE_USER_CLIP] = plane;
+ mPlaneMask[AGENT_PLANE_USER_CLIP] = plane.calcPlaneMask();
}
void LLCamera::disableUserClipPlane()
{
- mPlaneCount = 6;
+ mPlaneCount = AGENT_PLANE_NO_USER_CLIP_NUM;
}
void LLCamera::setView(F32 vertical_fov_rads)
@@ -161,31 +171,33 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
// ---------------- test methods ----------------
-S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
+static const LLVector4a sFrustumScaler[] =
{
- 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)
- };
+ 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) // 8 entries
+};
+S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
+{
U8 mask = 0;
bool result = false;
LLVector4a rscale, maxp, minp;
LLSimdScalar d;
- for (U32 i = 0; i < mPlaneCount; i++)
+ U32 max_planes = llmin(mPlaneCount, (U32) AGENT_PLANE_USER_CLIP_NUM); // mAgentPlanes[] size is 7
+ for (U32 i = 0; i < max_planes; i++)
{
mask = mPlaneMask[i];
- if (mask != 0xff)
+ if (mask < PLANE_MASK_NUM)
{
const LLPlane& p(mAgentPlanes[i]);
p.getAt<3>(d);
- rscale.setMul(radius, scaler[mask]);
+ rscale.setMul(radius, sFrustumScaler[mask]);
minp.setSub(center, rscale);
d = -d;
if (p.dot3(minp).getF32() > d)
@@ -207,29 +219,19 @@ S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
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;
bool result = false;
LLVector4a rscale, maxp, minp;
LLSimdScalar d;
- for (U32 i = 0; i < mPlaneCount; i++)
+ U32 max_planes = llmin(mPlaneCount, (U32) AGENT_PLANE_USER_CLIP_NUM); // mAgentPlanes[] size is 7
+ for (U32 i = 0; i < max_planes; i++)
{
mask = mPlaneMask[i];
- if ((i != 5) && (mask != 0xff))
+ if ((i != 5) && (mask < PLANE_MASK_NUM))
{
const LLPlane& p(mAgentPlanes[i]);
p.getAt<3>(d);
- rscale.setMul(radius, scaler[mask]);
+ rscale.setMul(radius, sFrustumScaler[mask]);
minp.setSub(center, rscale);
d = -d;
if (p.dot3(minp).getF32() > d)
@@ -369,7 +371,7 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius)
bool res = false;
for (int i = 0; i < 6; i++)
{
- if (mPlaneMask[i] != 0xff)
+ if (mPlaneMask[i] != PLANE_MASK_NONE)
{
float d = mAgentPlanes[i].dist(sphere_center);
@@ -541,14 +543,14 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx)
return;
}
- mPlaneMask[idx] = 0xff;
+ mPlaneMask[idx] = PLANE_MASK_NONE;
mAgentPlanes[idx].clear();
}
void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
{
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < AGENT_FRUSTRUM_NUM; i++)
{
mAgentFrustum[i] = frust[i];
}
@@ -560,22 +562,22 @@ 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] = planeFromPoints(frust[0], frust[1], frust[2]);
+ mAgentPlanes[AGENT_PLANE_NEAR] = planeFromPoints(frust[0], frust[1], frust[2]);
//far
- mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
+ mAgentPlanes[AGENT_PLANE_FAR] = planeFromPoints(frust[5], frust[4], frust[6]);
//left
- mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
+ mAgentPlanes[AGENT_PLANE_LEFT] = planeFromPoints(frust[4], frust[0], frust[7]);
//right
- mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
+ mAgentPlanes[AGENT_PLANE_RIGHT] = planeFromPoints(frust[1], frust[5], frust[6]);
//top
- mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
+ mAgentPlanes[AGENT_PLANE_TOP] = planeFromPoints(frust[3], frust[2], frust[6]);
//bottom
- mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
+ mAgentPlanes[AGENT_PLANE_BOTTOM] = planeFromPoints(frust[1], frust[0], frust[4]);
//cache plane octant facing mask for use in AABBInFrustum
for (U32 i = 0; i < mPlaneCount; i++)
@@ -635,7 +637,7 @@ void LLCamera::calculateWorldFrustumPlanes()
LLVector3 center = mOrigin - mXAxis*mNearPlane;
mWorldPlanePos = center;
LLVector3 pnorm;
- for (int p=0; p<4; p++)
+ for (int p = 0; p < PLANE_NUM; p++)
{
mLocalPlanes[p].getVector3(pnorm);
LLVector3 norm = rotateToAbsolute(pnorm);
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 0b591be622..1283cfb16b 100755
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -76,26 +76,39 @@ public:
PLANE_RIGHT = 1,
PLANE_BOTTOM = 2,
PLANE_TOP = 3,
- PLANE_NUM = 4
+ PLANE_NUM = 4,
+ PLANE_MASK_NONE = 0xff // Disable this plane
};
enum {
PLANE_LEFT_MASK = (1<<PLANE_LEFT),
PLANE_RIGHT_MASK = (1<<PLANE_RIGHT),
PLANE_BOTTOM_MASK = (1<<PLANE_BOTTOM),
PLANE_TOP_MASK = (1<<PLANE_TOP),
- PLANE_ALL_MASK = 0xf
+ PLANE_ALL_MASK = 0xf,
};
enum
- {
+ { // Indexes to mAgentPlanes[] and mPlaneMask[]
AGENT_PLANE_LEFT = 0,
- AGENT_PLANE_RIGHT,
- AGENT_PLANE_NEAR,
- AGENT_PLANE_BOTTOM,
- AGENT_PLANE_TOP,
- AGENT_PLANE_FAR,
+ AGENT_PLANE_RIGHT = 1,
+ AGENT_PLANE_NEAR = 2,
+ AGENT_PLANE_BOTTOM = 3,
+ AGENT_PLANE_TOP = 4,
+ AGENT_PLANE_FAR = 5,
+ AGENT_PLANE_USER_CLIP = 6
+ };
+ enum
+ { // Sizes for mAgentPlanes[]. 7th entry is special case for user clip
+ AGENT_PLANE_NO_USER_CLIP_NUM = 6,
+ AGENT_PLANE_USER_CLIP_NUM = 7,
+ PLANE_MASK_NUM = 8 // 7 actually used, 8 is for alignment
};
+ enum
+ {
+ AGENT_FRUSTRUM_NUM = 8
+ };
+
enum {
HORIZ_PLANE_LEFT = 0,
HORIZ_PLANE_RIGHT = 1,
@@ -108,15 +121,15 @@ public:
};
private:
- LL_ALIGN_16(LLPlane mAgentPlanes[7]); //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
- U8 mPlaneMask[8]; // 8 for alignment
+ LL_ALIGN_16(LLPlane mAgentPlanes[AGENT_PLANE_USER_CLIP_NUM]); //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+ U8 mPlaneMask[PLANE_MASK_NUM]; // 8 for alignment
F32 mView; // angle between top and bottom frustum planes in radians.
F32 mAspect; // width/height
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
F32 mNearPlane;
F32 mFarPlane;
- LL_ALIGN_16(LLPlane mLocalPlanes[4]);
+ LL_ALIGN_16(LLPlane mLocalPlanes[PLANE_NUM]);
F32 mFixedDistance; // Always return this distance, unless < 0
LLVector3 mFrustCenter; // center of frustum and radius squared for ultra-quick exclusion test
F32 mFrustRadiusSquared;
@@ -128,7 +141,7 @@ private:
LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera)
public:
- LLVector3 mAgentFrustum[8]; //8 corners of 6-plane frustum
+ LLVector3 mAgentFrustum[AGENT_FRUSTRUM_NUM]; //8 corners of 6-plane frustum
F32 mFrustumCornerDist; //distance to corner of frustum against far clip plane
LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; }
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
index 7c52ffef21..558fe09323 100755
--- a/indra/llmath/llvector4a.inl
+++ b/indra/llmath/llvector4a.inl
@@ -409,6 +409,26 @@ inline void LLVector4a::normalize3fast()
mQ = _mm_mul_ps( mQ, approxRsqrt );
}
+inline void LLVector4a::normalize3fast_checked(LLVector4a* d)
+{
+ if (!isFinite3())
+ {
+ *this = d ? *d : LLVector4a(0,1,0,1);
+ return;
+ }
+
+ LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
+
+ if (lenSqrd.getF32ptr()[0] <= FLT_EPSILON)
+ {
+ *this = d ? *d : LLVector4a(0,1,0,1);
+ return;
+ }
+
+ const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+ mQ = _mm_mul_ps( mQ, approxRsqrt );
+}
+
// Return true if this vector is normalized with respect to x,y,z up to tolerance
inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const
{
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 14cebfe5aa..a030d889af 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -136,6 +136,82 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
return true;
}
+// Finds tangent vec based on three vertices with texture coordinates.
+// Fills in dummy values if the triangle has degenerate texture coordinates.
+void calc_tangent_from_triangle(
+ LLVector4a& normal,
+ LLVector4a& tangent_out,
+ const LLVector4a& v1,
+ const LLVector2& w1,
+ const LLVector4a& v2,
+ const LLVector2& w2,
+ const LLVector4a& v3,
+ const LLVector2& w3)
+{
+ const F32* v1ptr = v1.getF32ptr();
+ const F32* v2ptr = v2.getF32ptr();
+ const F32* v3ptr = v3.getF32ptr();
+
+ float x1 = v2ptr[0] - v1ptr[0];
+ float x2 = v3ptr[0] - v1ptr[0];
+ float y1 = v2ptr[1] - v1ptr[1];
+ float y2 = v3ptr[1] - v1ptr[1];
+ float z1 = v2ptr[2] - v1ptr[2];
+ float z2 = v3ptr[2] - v1ptr[2];
+
+ float s1 = w2.mV[0] - w1.mV[0];
+ float s2 = w3.mV[0] - w1.mV[0];
+ float t1 = w2.mV[1] - w1.mV[1];
+ float t2 = w3.mV[1] - w1.mV[1];
+
+ F32 rd = s1*t2-s2*t1;
+
+ float r = ((rd*rd) > FLT_EPSILON) ? 1.0F / rd : 1024.f; //some made up large ratio for division by zero
+
+ llassert(llfinite(r));
+ llassert(!llisnan(r));
+
+ LLVector4a sdir(
+ (t2 * x1 - t1 * x2) * r,
+ (t2 * y1 - t1 * y2) * r,
+ (t2 * z1 - t1 * z2) * r);
+
+ LLVector4a tdir(
+ (s1 * x2 - s2 * x1) * r,
+ (s1 * y2 - s2 * y1) * r,
+ (s1 * z2 - s2 * z1) * r);
+
+ LLVector4a n = normal;
+ LLVector4a t = sdir;
+
+ LLVector4a ncrosst;
+ ncrosst.setCross3(n,t);
+
+ // Gram-Schmidt orthogonalize
+ n.mul(n.dot3(t).getF32());
+
+ LLVector4a tsubn;
+ tsubn.setSub(t,n);
+
+ if (tsubn.dot3(tsubn).getF32() > F_APPROXIMATELY_ZERO)
+ {
+ tsubn.normalize3fast_checked();
+
+ // Calculate handedness
+ F32 handedness = ncrosst.dot3(tdir).getF32() < 0.f ? -1.f : 1.f;
+
+ tsubn.getF32ptr()[3] = handedness;
+
+ tangent_out = tsubn;
+ }
+ else
+ {
+ // degenerate, make up a value
+ //
+ tangent_out.set(0,0,1,1);
+ }
+
+}
// intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
@@ -5908,10 +5984,10 @@ void LLVolumeFace::cacheOptimize()
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
}
- LLVector4a* binorm = NULL;
+ LLVector4a* tangent = NULL;
if (mTangents)
{
- binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+ tangent = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
}
//allocate mapping of old indices to new indices
@@ -5936,7 +6012,7 @@ void LLVolumeFace::cacheOptimize()
}
if (mTangents)
{
- binorm[cur_idx] = mTangents[idx];
+ tangent[cur_idx] = mTangents[idx];
}
cur_idx++;
@@ -5958,7 +6034,7 @@ void LLVolumeFace::cacheOptimize()
mNormals = norm;
mTexCoords = tc;
mWeights = wght;
- mTangents = binorm;
+ mTangents = tangent;
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
//llinfos << result << llendl;
@@ -6306,6 +6382,43 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
cuv = (min_uv + max_uv)*0.5f;
+
+ LLVector4a tangent;
+ calc_tangent_from_triangle(
+ *norm,
+ tangent,
+ *mCenter, cuv,
+ pos[0], tc[0],
+ pos[1], tc[1]);
+
+ if (tangent.getLength3() < 0.01)
+ {
+ tangent.set(1,0,0,1);
+ }
+ else
+ {
+ LLVector4a default_tangent;
+ default_tangent.set(1,0,0,1);
+ tangent.normalize3fast_checked(&default_tangent);
+ }
+
+ LLVector4a normal;
+ LLVector4a d0, d1;
+
+ d0.setSub(*mCenter, pos[0]);
+ d1.setSub(*mCenter, pos[1]);
+
+ if (mTypeMask & TOP_MASK)
+ {
+ normal.setCross3(d0, d1);
+ }
+ else
+ {
+ normal.setCross3(d1, d0);
+ }
+
+ normal.normalize3fast_checked();
+
VertexData vd;
vd.setPosition(*mCenter);
vd.mTexCoord = cuv;
@@ -6318,6 +6431,14 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
num_vertices++;
}
+ allocateTangents(num_vertices);
+
+ for (S32 i = 0; i < num_vertices; i++)
+ {
+ mTangents[i].load4a(tangent.getF32ptr());
+ norm[i].load4a(normal.getF32ptr());
+ }
+
if (partial_build)
{
return TRUE;
@@ -6553,36 +6674,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
}
- LLVector4a d0,d1;
-
- d0.setSub(mPositions[mIndices[1]], mPositions[mIndices[0]]);
- d1.setSub(mPositions[mIndices[2]], mPositions[mIndices[0]]);
-
- LLVector4a normal;
- normal.setCross3(d0,d1);
-
- if (normal.dot3(normal).getF32() > F_APPROXIMATELY_ZERO)
- {
- normal.normalize3fast();
- }
- else
- { //degenerate, make up a value
- normal.set(0,0,1);
- }
-
- llassert(llfinite(normal.getF32ptr()[0]));
- llassert(llfinite(normal.getF32ptr()[1]));
- llassert(llfinite(normal.getF32ptr()[2]));
-
- llassert(!llisnan(normal.getF32ptr()[0]));
- llassert(!llisnan(normal.getF32ptr()[1]));
- llassert(!llisnan(normal.getF32ptr()[2]));
-
- for (S32 i = 0; i < num_vertices; i++)
- {
- norm[i].load4a(normal.getF32ptr());
- }
-
return TRUE;
}
@@ -6611,11 +6702,13 @@ void LLVolumeFace::createTangents()
CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices/3, mIndices, mTangents);
//normalize tangents
+ LLVector4a default_norm;
+ default_norm.set(0,1,0,1);
for (U32 i = 0; i < mNumVertices; i++)
{
- //binorm[i].normalize3fast();
+ //tangent[i].normalize3fast();
//bump map/planar projection code requires normals to be normalized
- mNormals[i].normalize3fast();
+ mNormals[i].normalize3fast_checked();
}
}
}
@@ -6800,7 +6893,7 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
//transform appended face normal and store
norm_mat.rotate(src_norm[i], dst_norm[i]);
- dst_norm[i].normalize3fast();
+ dst_norm[i].normalize3fast_checked();
//copy appended face texture coordinate
dst_tc[i] = src_tc[i];
@@ -7209,11 +7302,61 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
return TRUE;
}
+// Finds binormal based on three vertices with texture coordinates.
+// Fills in dummy values if the triangle has degenerate texture coordinates.
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+ const LLVector4a& pos0,
+ const LLVector2& tex0,
+ const LLVector4a& pos1,
+ const LLVector2& tex1,
+ const LLVector4a& pos2,
+ const LLVector2& tex2)
+{
+ 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] );
+
+ 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] );
+
+ 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] );
+
+ 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[VX] && r1[VX] && r2[VX] )
+ {
+ binormal.set(
+ -r0[VZ] / r0[VX],
+ -r1[VZ] / r1[VX],
+ -r2[VZ] / r2[VX]);
+ // binormal.normVec();
+ }
+ else
+ {
+ binormal.set( 0, 1 , 0 );
+ }
+}
+
//adapted from Lengyel, Eric. �Computing Tangent Space Basis Vectors for an Arbitrary Mesh�. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent)
{
- //LLVector4a *tan1 = new LLVector4a[vertexCount * 2];
LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a));
LLVector4a* tan2 = tan1 + vertexCount;