From 5666681f85bc179f5abe3bbcbd87d294031549be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Fri, 9 Feb 2024 23:16:24 +0100 Subject: llmath: BOOL (int) to real bool --- indra/llmath/llbbox.cpp | 10 +++++----- indra/llmath/llbbox.h | 6 +++--- indra/llmath/llsphere.cpp | 12 ++++++------ indra/llmath/llsphere.h | 8 ++++---- indra/llmath/llvolume.cpp | 4 ++-- indra/llmath/llvolume.h | 10 +++++----- indra/llmath/llvolumemgr.cpp | 12 ++++++------ indra/llmath/llvolumemgr.h | 4 ++-- 8 files changed, 33 insertions(+), 33 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index 3e2c05a6e6..395992e68f 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -38,7 +38,7 @@ void LLBBox::addPointLocal(const LLVector3& p) { mMinLocal = p; mMaxLocal = p; - mEmpty = FALSE; + mEmpty = false; } else { @@ -140,7 +140,7 @@ LLVector3 LLBBox::agentToLocalBasis(const LLVector3& v) const return v * m; } -BOOL LLBBox::containsPointLocal(const LLVector3& p) const +bool LLBBox::containsPointLocal(const LLVector3& p) const { if ( (p.mV[VX] < mMinLocal.mV[VX]) ||(p.mV[VX] > mMaxLocal.mV[VX]) @@ -149,12 +149,12 @@ BOOL LLBBox::containsPointLocal(const LLVector3& p) const ||(p.mV[VZ] < mMinLocal.mV[VZ]) ||(p.mV[VZ] > mMaxLocal.mV[VZ])) { - return FALSE; + return false; } - return TRUE; + return true; } -BOOL LLBBox::containsPointAgent(const LLVector3& p) const +bool LLBBox::containsPointAgent(const LLVector3& p) const { LLVector3 point_local = agentToLocal(p); return containsPointLocal(point_local); diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index 28e69b75e1..f15d4c2061 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -64,8 +64,8 @@ public: LLVector3 getExtentLocal() const { return mMaxLocal - mMinLocal; } - BOOL containsPointLocal(const LLVector3& p) const; - BOOL containsPointAgent(const LLVector3& p) const; + bool containsPointLocal(const LLVector3& p) const; + bool containsPointAgent(const LLVector3& p) const; void addPointAgent(LLVector3 p); void addBBoxAgent(const LLBBox& b); @@ -92,7 +92,7 @@ private: LLVector3 mMaxLocal; LLVector3 mPosAgent; // Position relative to Agent's Region LLQuaternion mRotation; - BOOL mEmpty; // Nothing has been added to this bbox yet + bool mEmpty; // Nothing has been added to this bbox yet }; //LLBBox operator*(const LLBBox &a, const LLMatrix4 &b); diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index a8d6200488..7292e3c0de 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -69,18 +69,18 @@ F32 LLSphere::getRadius() const return mRadius; } -// returns 'TRUE' if this sphere completely contains other_sphere -BOOL LLSphere::contains(const LLSphere& other_sphere) const +// returns 'true' if this sphere completely contains other_sphere +bool LLSphere::contains(const LLSphere& other_sphere) const { F32 separation = (mCenter - other_sphere.mCenter).length(); - return (mRadius >= separation + other_sphere.mRadius) ? TRUE : FALSE; + return (mRadius >= separation + other_sphere.mRadius) ? true : false; } -// returns 'TRUE' if this sphere completely contains other_sphere -BOOL LLSphere::overlaps(const LLSphere& other_sphere) const +// returns 'true' if this sphere completely contains other_sphere +bool LLSphere::overlaps(const LLSphere& other_sphere) const { F32 separation = (mCenter - other_sphere.mCenter).length(); - return (separation <= mRadius + other_sphere.mRadius) ? TRUE : FALSE; + return (separation <= mRadius + other_sphere.mRadius) ? true : false; } // returns overlap diff --git a/indra/llmath/llsphere.h b/indra/llmath/llsphere.h index 7c60a11406..ba8e437ecf 100644 --- a/indra/llmath/llsphere.h +++ b/indra/llmath/llsphere.h @@ -47,11 +47,11 @@ public: const LLVector3& getCenter() const; F32 getRadius() const; - // returns TRUE if this sphere completely contains other_sphere - BOOL contains(const LLSphere& other_sphere) const; + // returns true if this sphere completely contains other_sphere + bool contains(const LLSphere& other_sphere) const; - // returns TRUE if this sphere overlaps other_sphere - BOOL overlaps(const LLSphere& other_sphere) const; + // returns true if this sphere overlaps other_sphere + bool overlaps(const LLSphere& other_sphere) const; // returns overlap distance // negative overlap is closest approach diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 6d36daa92a..838eb9c653 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -4789,10 +4789,10 @@ LLVolumeFace::LLVolumeFace() : mJustWeights(NULL), mJointIndices(NULL), #endif - mWeightsScrubbed(FALSE), + mWeightsScrubbed(false), mOctree(NULL), mOctreeTriangles(NULL), - mOptimized(FALSE) + mOptimized(false) { mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); mExtents[0].splat(-0.5f); diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index afed98ff36..9048118243 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -687,9 +687,9 @@ class LLProfile public: LLProfile() - : mOpen(FALSE), - mConcave(FALSE), - mDirty(TRUE), + : mOpen(false), + mConcave(false), + mDirty(true), mTotalOut(0), mTotal(2) { @@ -779,9 +779,9 @@ public: public: LLPath() - : mOpen(FALSE), + : mOpen(false), mTotal(0), - mDirty(TRUE), + mDirty(true), mStep(1) { } diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 9399504529..d1e145cff1 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -59,9 +59,9 @@ LLVolumeMgr::~LLVolumeMgr() mDataMutex = NULL; } -BOOL LLVolumeMgr::cleanup() +bool LLVolumeMgr::cleanup() { - BOOL no_refs = TRUE; + bool no_refs = true; if (mDataMutex) { mDataMutex->lock(); @@ -73,7 +73,7 @@ BOOL LLVolumeMgr::cleanup() LLVolumeLODGroup *volgroupp = iter->second; if (volgroupp->cleanupRefs() == false) { - no_refs = FALSE; + no_refs = false; } delete volgroupp; } @@ -301,7 +301,7 @@ LLVolume* LLVolumeLODGroup::refLOD(const S32 lod) return mVolumeLODs[lod]; } -BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) +bool LLVolumeLODGroup::derefLOD(LLVolume *volumep) { llassert_always(mRefs > 0); mRefs--; @@ -317,11 +317,11 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) mVolumeLODs[i] = NULL; } #endif - return TRUE; + return true; } } LL_ERRS() << "Deref of non-matching LOD in volume LOD group" << LL_ENDL; - return FALSE; + return false; } S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle) diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index c75906f675..b0baf7054d 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -56,7 +56,7 @@ public: static S32 getVolumeDetailFromScale(F32 scale); LLVolume* refLOD(const S32 detail); - BOOL derefLOD(LLVolume *volumep); + bool derefLOD(LLVolume *volumep); S32 getNumRefs() const { return mRefs; } const LLVolumeParams* getVolumeParams() const { return &mVolumeParams; }; @@ -80,7 +80,7 @@ class LLVolumeMgr public: LLVolumeMgr(); virtual ~LLVolumeMgr(); - BOOL cleanup(); // Cleanup all volumes being managed, returns TRUE if no dangling references + bool cleanup(); // Cleanup all volumes being managed, returns true if no dangling references virtual LLVolumeLODGroup* getGroup( const LLVolumeParams& volume_params ) const; -- cgit v1.2.3 From 04a02e83e9dcc29d4649e8003d523621b5119d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Fri, 9 Feb 2024 23:22:06 +0100 Subject: misc: BOOL (int) to real bool --- indra/llmath/raytrace.cpp | 74 +++++++++++++++++++++++------------------------ indra/llmath/raytrace.h | 26 ++++++++--------- 2 files changed, 50 insertions(+), 50 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index f38fe49bcb..fde12876c7 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -34,8 +34,8 @@ #include "raytrace.h" -BOOL line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, +bool line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, LLVector3 &intersection) { F32 N = line_direction * plane_normal; @@ -43,19 +43,19 @@ BOOL line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, { // line is perpendicular to plane normal // so it is either entirely on plane, or not on plane at all - return FALSE; + return false; } // Ax + By, + Cz + D = 0 // D = - (plane_point * plane_normal) // N = line_direction * plane_normal // intersection = line_point - ((D + plane_normal * line_point) / N) * line_direction intersection = line_point - ((plane_normal * line_point - plane_point * plane_normal) / N) * line_direction; - return TRUE; + return true; } -BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, +bool ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, LLVector3 &intersection) { F32 N = ray_direction * plane_normal; @@ -63,7 +63,7 @@ BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, { // ray is perpendicular to plane normal // so it is either entirely on plane, or not on plane at all - return FALSE; + return false; } // Ax + By, + Cz + D = 0 // D = - (plane_point * plane_normal) @@ -73,14 +73,14 @@ BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (alpha < 0.0f) { // ray points away from plane - return FALSE; + return false; } intersection = ray_point + alpha * ray_direction; - return TRUE; + return true; } -BOOL ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, LLVector3 &intersection) { @@ -88,15 +88,15 @@ BOOL ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, { if (circle_radius >= (intersection - circle_center).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, +bool ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal) { LLVector3 side_01 = point_1 - point_0; @@ -112,15 +112,15 @@ BOOL ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f && intersection_normal * (side_20 % (intersection - point_2)) >= 0.0f) { - return TRUE; + return true; } } - return FALSE; + return false; } // assumes a parallelogram -BOOL ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -140,14 +140,14 @@ BOOL ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, intersection_normal * (side_23 % (intersection - point_2)) >= 0.0f && intersection_normal * (side_30 % (intersection - point_3)) >= 0.0f) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &sphere_center, F32 sphere_radius, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -160,7 +160,7 @@ BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, F32 radius_squared = sphere_radius * sphere_radius; if (shortest_distance > radius_squared) { - return FALSE; + return false; } F32 half_chord = (F32) sqrt(radius_squared - shortest_distance); @@ -170,7 +170,7 @@ BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (dot < 0.0f) { // ray shoots away from sphere and is not inside it - return FALSE; + return false; } shortest_distance = ray_direction * ((closest_approach - half_chord * ray_direction) - ray_point); @@ -195,11 +195,11 @@ BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, intersection_normal.setVec(0.0f, 0.0f, 0.0f); } - return TRUE; + return true; } -BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -270,15 +270,15 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (dot < 0.0f) { // ray points away from cylinder bottom - return FALSE; + return false; } // ray hit top from outside intersection = ray_point - (shortest_distance + cyl_length) * cyl_axis; intersection_normal = -cyl_axis; } - return TRUE; + return true; } - return FALSE; + return false; } // check for intersection with infinite cylinder @@ -299,7 +299,7 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (out < 0.0f) { // cylinder is behind the ray, so we return FALSE - return FALSE; + return false; } in = dist_to_closest_point - half_chord_length; // dist to entering point @@ -341,14 +341,14 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (shortest_distance > out) { // ray missed the finite cylinder - return FALSE; + return false; } if (shortest_distance > in) { // ray intersects cylinder at top plane intersection = temp_vector; intersection_normal = -cyl_axis; - return TRUE; + return true; } } else @@ -357,7 +357,7 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (shortest_distance < in) { // missed the finite cylinder - return FALSE; + return false; } } @@ -370,14 +370,14 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (shortest_distance > out) { // ray missed the finite cylinder - return FALSE; + return false; } if (shortest_distance > in) { // ray intersects cylinder at bottom plane intersection = temp_vector; intersection_normal = cyl_axis; - return TRUE; + return true; } } else @@ -386,7 +386,7 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (shortest_distance < in) { // ray missed the finite cylinder - return FALSE; + return false; } } @@ -399,14 +399,14 @@ BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (shortest_distance < 0.0f || shortest_distance > cyl_length) { // ray missed finite cylinder - return FALSE; + return false; } } - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index 2d32af0c86..92bca45566 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -61,26 +61,26 @@ class LLQuaternion; // frame. -// returns TRUE iff line is not parallel to plane. -BOOL line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, +// returns true if line is not parallel to plane. +bool line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, LLVector3 &intersection); -// returns TRUE iff line is not parallel to plane. -BOOL ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, +// returns true if line is not parallel to plane. +bool ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, LLVector3 &intersection); -BOOL ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, LLVector3 &intersection); // point_0 through point_2 define the plane_normal via the right-hand rule: // circle from point_0 to point_2 with fingers ==> thumb points in direction of normal -BOOL ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, +bool ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal); @@ -88,19 +88,19 @@ BOOL ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, // right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right // ==> thumb points in direction of normal // assumes a parallelogram, so point_3 is determined by the other points -BOOL ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, +bool ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &sphere_center, F32 sphere_radius, LLVector3 &intersection, LLVector3 &intersection_normal); // finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom", // and by the cylinder radius "cyl_radius" -BOOL ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); -- cgit v1.2.3 From 70f8dc7a4f4be217fea5439e474fc75e567c23c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Sat, 10 Feb 2024 22:37:52 +0100 Subject: miscellaneous: BOOL (int) to real bool --- indra/llmath/llquaternion.cpp | 6 +++--- indra/llmath/raytrace.cpp | 2 +- indra/llmath/v3math.h | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 57a976b57a..1e7c39df65 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -963,7 +963,7 @@ BOOL LLQuaternion::parseQuat(const std::string& buf, LLQuaternion* value) { if( buf.empty() || value == NULL) { - return FALSE; + return false; } LLQuaternion quat; @@ -971,10 +971,10 @@ BOOL LLQuaternion::parseQuat(const std::string& buf, LLQuaternion* value) if( 4 == count ) { value->set( quat ); - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index fde12876c7..314255374a 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -1226,7 +1226,7 @@ BOOL linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } return FALSE; diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 068f489020..31abf433a0 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -119,7 +119,7 @@ class LLVector3 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 - BOOL isNull() const; // Returns TRUE if vector has a _very_small_ length + bool isNull() const; // Returns TRUE if vector has a _very_small_ length BOOL isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; } F32 operator[](int idx) const { return mV[idx]; } @@ -539,13 +539,13 @@ inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u) } -inline BOOL LLVector3::isNull() const +inline bool LLVector3::isNull() const { if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ] ) { - return TRUE; + return true; } - return FALSE; + return false; } inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos) @@ -598,9 +598,9 @@ inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) F32 dot = an * bn; if ( (1.0f - fabs(dot)) < epsilon) { - return TRUE; + return true; } - return FALSE; + return false; } inline std::ostream& operator<<(std::ostream& s, const LLVector3 &a) -- cgit v1.2.3 From 9480a98cffaafa5826b8daad20020cf399bbbefc Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 16 Feb 2024 00:07:58 +0100 Subject: Replace most of BOOL with bool in llmath --- indra/llmath/llcoordframe.h | 2 +- indra/llmath/llinterp.h | 53 +++++++++---------- indra/llmath/llmath.h | 62 +++++++++++----------- indra/llmath/lloctree.h | 10 ++-- indra/llmath/llquaternion.cpp | 2 +- indra/llmath/llquaternion.h | 14 ++--- indra/llmath/llrect.h | 8 +-- indra/llmath/llvolume.cpp | 57 ++++++-------------- indra/llmath/llvolume.h | 17 ++---- indra/llmath/llvolumeoctree.cpp | 2 +- indra/llmath/raytrace.cpp | 113 +++++++++++++++++++--------------------- indra/llmath/raytrace.h | 25 ++++----- indra/llmath/v2math.cpp | 14 ++--- indra/llmath/v2math.h | 16 +++--- indra/llmath/v3dmath.cpp | 36 ++++++------- indra/llmath/v3dmath.h | 27 +++++----- indra/llmath/v3math.cpp | 60 ++++++++++----------- indra/llmath/v3math.h | 24 ++++----- indra/llmath/v4color.cpp | 20 +++---- indra/llmath/v4color.h | 6 +-- indra/llmath/v4coloru.cpp | 12 ++--- indra/llmath/v4coloru.h | 3 +- indra/llmath/v4math.cpp | 40 ++++---------- indra/llmath/v4math.h | 14 +++-- 24 files changed, 286 insertions(+), 351 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llcoordframe.h b/indra/llmath/llcoordframe.h index 909adf260c..1d3f4f7e3e 100644 --- a/indra/llmath/llcoordframe.h +++ b/indra/llmath/llcoordframe.h @@ -61,7 +61,7 @@ public: //LLCoordFrame(const F32 *origin, const F32 *rotation); // Assumes "origin" is 1x3 and "rotation" is 1x9 array //LLCoordFrame(const F32 *origin_and_rotation); // Assumes "origin_and_rotation" is 1x12 array - BOOL isFinite() { return mOrigin.isFinite() && mXAxis.isFinite() && mYAxis.isFinite() && mZAxis.isFinite(); } + bool isFinite() { return mOrigin.isFinite() && mXAxis.isFinite() && mYAxis.isFinite() && mZAxis.isFinite(); } void reset(); void resetAxes(); diff --git a/indra/llmath/llinterp.h b/indra/llmath/llinterp.h index 5187646179..a107d301d8 100644 --- a/indra/llmath/llinterp.h +++ b/indra/llmath/llinterp.h @@ -41,7 +41,6 @@ class LLInterpVal { public: virtual ~LLInterpVal() {} - virtual void interp(LLInterpVal &target, const F32 frac); // Linear interpolation for each type }; template @@ -52,7 +51,7 @@ public: virtual ~LLInterp() {} virtual void start(); - void update(const F32 time); + virtual void update(const F32 time) = 0; const Type &getCurVal() const; void setStartVal(const Type &start_val); @@ -67,15 +66,15 @@ public: void setEndTime(const F32 time); F32 getEndTime() const; - BOOL isActive() const; - BOOL isDone() const; + bool isActive() const; + bool isDone() const; protected: F32 mStartTime; F32 mEndTime; F32 mDuration; - BOOL mActive; - BOOL mDone; + bool mActive; + bool mDone; Type mStartVal; Type mEndVal; @@ -88,8 +87,8 @@ template class LLInterpLinear : public LLInterp { public: - /*virtual*/ void start(); - void update(const F32 time); + void start() override; + void update(const F32 time) override; F32 getCurFrac() const; protected: F32 mCurFrac; @@ -108,10 +107,10 @@ class LLInterpAttractor : public LLInterp { public: LLInterpAttractor(); - /*virtual*/ void start(); + void start() override; void setStartVel(const Type &vel); void setForce(const F32 force); - void update(const F32 time); + void update(const F32 time) override; protected: F32 mForce; Type mStartVel; @@ -123,7 +122,7 @@ class LLInterpFunc : public LLInterp { public: LLInterpFunc(); - void update(const F32 time); + void update(const F32 time) override; void setFunc(Type (*)(const F32, void *data), void *data); protected: @@ -151,8 +150,8 @@ LLInterp::LLInterp() mEndTime = 1.f; mDuration = 1.f; mCurTime = 0.f; - mDone = FALSE; - mActive = FALSE; + mDone = false; + mActive = false; } template @@ -166,8 +165,8 @@ void LLInterp::start() { mCurVal = mStartVal; mCurTime = mStartTime; - mDone = FALSE; - mActive = FALSE; + mDone = false; + mActive = false; } template @@ -225,13 +224,13 @@ F32 LLInterp::getEndTime() const template -BOOL LLInterp::isDone() const +bool LLInterp::isDone() const { return mDone; } template -BOOL LLInterp::isActive() const +bool LLInterp::isActive() const { return mActive; } @@ -254,7 +253,7 @@ void LLInterpLinear::update(const F32 time) F32 dfrac = target_frac - this->mCurFrac; if (target_frac >= 0.f) { - this->mActive = TRUE; + this->mActive = true; } if (target_frac > 1.f) @@ -262,7 +261,7 @@ void LLInterpLinear::update(const F32 time) this->mCurVal = this->mEndVal; this->mCurFrac = 1.f; this->mCurTime = time; - this->mDone = TRUE; + this->mDone = true; return; } @@ -332,7 +331,7 @@ void LLInterpAttractor::update(const F32 time) { if (time > this->mStartTime) { - this->mActive = TRUE; + this->mActive = true; } else { @@ -340,7 +339,7 @@ void LLInterpAttractor::update(const F32 time) } if (time > this->mEndTime) { - this->mDone = TRUE; + this->mDone = true; return; } @@ -362,8 +361,8 @@ void LLInterpAttractor::update(const F32 time) template LLInterpFunc::LLInterpFunc() : LLInterp() { - mFunc = NULL; - mData = NULL; + mFunc = nullptr; + mData = nullptr; } template @@ -378,7 +377,7 @@ void LLInterpFunc::update(const F32 time) { if (time > this->mStartTime) { - this->mActive = TRUE; + this->mActive = true; } else { @@ -386,7 +385,7 @@ void LLInterpFunc::update(const F32 time) } if (time > this->mEndTime) { - this->mDone = TRUE; + this->mDone = true; return; } @@ -405,7 +404,7 @@ void LLInterpExp::update(const F32 time) F32 target_frac = (time - this->mStartTime) / this->mDuration; if (target_frac >= 0.f) { - this->mActive = TRUE; + this->mActive = true; } if (target_frac > 1.f) @@ -413,7 +412,7 @@ void LLInterpExp::update(const F32 time) this->mCurVal = this->mEndVal; this->mCurFrac = 1.f; this->mCurTime = time; - this->mDone = TRUE; + this->mDone = true; return; } diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index e4ccd81faf..efcc3882fc 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -59,34 +59,34 @@ #define tanf(x) ((F32)tan((F64)(x))) #endif*/ -const F32 GRAVITY = -9.8f; +constexpr F32 GRAVITY = -9.8f; // mathematical constants -const F32 F_PI = 3.1415926535897932384626433832795f; -const F32 F_TWO_PI = 6.283185307179586476925286766559f; -const F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; -const F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f; -const F32 F_E = 2.71828182845904523536f; -const F32 F_SQRT2 = 1.4142135623730950488016887242097f; -const F32 F_SQRT3 = 1.73205080756888288657986402541f; -const F32 OO_SQRT2 = 0.7071067811865475244008443621049f; -const F32 OO_SQRT3 = 0.577350269189625764509f; -const F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; -const F32 RAD_TO_DEG = 57.295779513082320876798154814105f; -const F32 F_APPROXIMATELY_ZERO = 0.00001f; -const F32 F_LN10 = 2.3025850929940456840179914546844f; -const F32 OO_LN10 = 0.43429448190325182765112891891661; -const F32 F_LN2 = 0.69314718056f; -const F32 OO_LN2 = 1.4426950408889634073599246810019f; - -const F32 F_ALMOST_ZERO = 0.0001f; -const F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; - -const F32 GIMBAL_THRESHOLD = 0.000436f; // sets the gimballock threshold 0.025 away from +/-90 degrees +constexpr F32 F_PI = 3.1415926535897932384626433832795f; +constexpr F32 F_TWO_PI = 6.283185307179586476925286766559f; +constexpr F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; +constexpr F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f; +constexpr F32 F_E = 2.71828182845904523536f; +constexpr F32 F_SQRT2 = 1.4142135623730950488016887242097f; +constexpr F32 F_SQRT3 = 1.73205080756888288657986402541f; +constexpr F32 OO_SQRT2 = 0.7071067811865475244008443621049f; +constexpr F32 OO_SQRT3 = 0.577350269189625764509f; +constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; +constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f; +constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f; +constexpr F32 F_LN10 = 2.3025850929940456840179914546844f; +constexpr F32 OO_LN10 = 0.43429448190325182765112891891661; +constexpr F32 F_LN2 = 0.69314718056f; +constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f; + +constexpr F32 F_ALMOST_ZERO = 0.0001f; +constexpr F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; + +constexpr F32 GIMBAL_THRESHOLD = 0.000436f; // sets the gimballock threshold 0.025 away from +/-90 degrees // formula: GIMBAL_THRESHOLD = sin(DEG_TO_RAD * gimbal_threshold_angle); // BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above? -const F32 FP_MAG_THRESHOLD = 0.0000001f; +constexpr F32 FP_MAG_THRESHOLD = 0.0000001f; // TODO: Replace with logic like is_approx_equal inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } @@ -123,13 +123,13 @@ inline bool is_zero(F32 x) inline bool is_approx_equal(F32 x, F32 y) { - const S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; + constexpr S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; return (std::abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); } inline bool is_approx_equal(F64 x, F64 y) { - const S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; + constexpr S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; return (std::abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); } @@ -272,8 +272,8 @@ inline F64 ll_round( F64 val, F64 nearest ) // peak error = -31.4 dB // RMS error = -28.1 dB -const F32 FAST_MAG_ALPHA = 0.960433870103f; -const F32 FAST_MAG_BETA = 0.397824734759f; +constexpr F32 FAST_MAG_ALPHA = 0.960433870103f; +constexpr F32 FAST_MAG_BETA = 0.397824734759f; // these provide minimum RMS error // @@ -281,8 +281,8 @@ const F32 FAST_MAG_BETA = 0.397824734759f; // peak error = -32.6 dB // RMS error = -25.7 dB // -//const F32 FAST_MAG_ALPHA = 0.948059448969f; -//const F32 FAST_MAG_BETA = 0.392699081699f; +//constexpr F32 FAST_MAG_ALPHA = 0.948059448969f; +//constexpr F32 FAST_MAG_BETA = 0.392699081699f; inline F32 fastMagnitude(F32 a, F32 b) { @@ -299,8 +299,8 @@ inline F32 fastMagnitude(F32 a, F32 b) // // Culled from www.stereopsis.com/FPU.html -const F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor -const S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation, +constexpr F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor +constexpr S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation, // Endian dependent code #ifdef LL_LITTLE_ENDIAN diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 318ee65cc0..2e9625fff7 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -548,7 +548,7 @@ public: } } - void addChild(oct_node* child, BOOL silent = FALSE) + void addChild(oct_node* child, bool silent = false) { #if LL_OCTREE_PARANOIA_CHECK @@ -591,7 +591,7 @@ public: } } - void removeChild(S32 index, BOOL destroy = FALSE) + void removeChild(S32 index, bool destroy = false) { for (U32 i = 0; i < this->getListenerCount(); i++) { @@ -638,7 +638,7 @@ public: { if (getChild(i) == node) { - removeChild(i, TRUE); + removeChild(i, true); return; } } @@ -707,7 +707,7 @@ public: //(don't notify listeners of addition) for (U32 i = 0; i < child->getChildCount(); i++) { - this->addChild(child->getChild(i), TRUE); + this->addChild(child->getChild(i), true); } //destroy child @@ -723,7 +723,7 @@ public: // LLOctreeRoot::insert bool insert(T* data) override { - if (data == NULL) + if (data == nullptr) { OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << LL_ENDL; return false; diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 1e7c39df65..0d1ffa5857 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -959,7 +959,7 @@ void LLQuaternion::unpackFromVector3( const LLVector3& vec ) } } -BOOL LLQuaternion::parseQuat(const std::string& buf, LLQuaternion* value) +bool LLQuaternion::parseQuat(const std::string& buf, LLQuaternion* value) { if( buf.empty() || value == NULL) { diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index 51ce163b4e..1c9da7c342 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -69,9 +69,9 @@ public: LLSD getValue() const; void setValue(const LLSD& sd); - BOOL isIdentity() const; - BOOL isNotIdentity() const; - BOOL isFinite() const; // checks to see if all values of LLQuaternion are finite + bool isIdentity() const; + bool isNotIdentity() const; + bool isFinite() const; // checks to see if all values of LLQuaternion are finite void quantize16(F32 lower, F32 upper); // changes the vector to reflect quatization void quantize8(F32 lower, F32 upper); // changes the vector to reflect quatization void loadIdentity(); // Loads the quaternion that represents the identity rotation @@ -167,7 +167,7 @@ public: friend const char *OrderToString( const Order order ); friend Order StringToOrder( const char *str ); - static BOOL parseQuat(const std::string& buf, LLQuaternion* value); + static bool parseQuat(const std::string& buf, LLQuaternion* value); // For debugging, only //static U32 mMultCount; @@ -192,12 +192,12 @@ inline void LLQuaternion::setValue(const LLSD& sd) } // checker -inline BOOL LLQuaternion::isFinite() const +inline bool LLQuaternion::isFinite() const { return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS])); } -inline BOOL LLQuaternion::isIdentity() const +inline bool LLQuaternion::isIdentity() const { return ( mQ[VX] == 0.f ) && @@ -206,7 +206,7 @@ inline BOOL LLQuaternion::isIdentity() const ( mQ[VS] == 1.f ); } -inline BOOL LLQuaternion::isNotIdentity() const +inline bool LLQuaternion::isNotIdentity() const { return ( mQ[VX] != 0.f ) || diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h index 58f02d4d2b..4da29482fd 100644 --- a/indra/llmath/llrect.h +++ b/indra/llmath/llrect.h @@ -83,14 +83,14 @@ public: } // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - BOOL pointInRect(const Type x, const Type y) const + bool pointInRect(const Type x, const Type y) const { return mLeft <= x && x < mRight && mBottom <= y && y < mTop; } //// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - BOOL localPointInRect(const Type x, const Type y) const + bool localPointInRect(const Type x, const Type y) const { return 0 <= x && x < getWidth() && 0 <= y && y < getHeight(); @@ -138,7 +138,7 @@ public: // Note: Does NOT follow GL_QUAD conventions: the top and right edges ARE considered part of the rect // returns TRUE if any part of rect is is inside this LLRect - BOOL overlaps(const LLRectBase& rect) const + bool overlaps(const LLRectBase& rect) const { return !(mLeft > rect.mRight || mRight < rect.mLeft @@ -146,7 +146,7 @@ public: || mTop < rect.mBottom); } - BOOL contains(const LLRectBase& rect) const + bool contains(const LLRectBase& rect) const { return mLeft <= rect.mLeft && mRight >= rect.mRight diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 838eb9c653..f9306d6bce 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -97,31 +97,31 @@ const S32 SCULPT_MIN_AREA_DETAIL = 1; BOOL gDebugGL = FALSE; // See settings.xml "RenderDebugGL" -BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) -{ +bool check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) +{ LLVector3 test = (pt2-pt1)%(pt3-pt2); //answer if(test * norm < 0) { - return FALSE; + return false; } else { - return TRUE; + return true; } } -BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) +bool LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) { return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV); } -BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size) +bool LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size) { - F32 fAWdU[3]; - F32 dir[3]; - F32 diff[3]; + F32 fAWdU[3]{}; + F32 dir[3]{}; + F32 diff[3]{}; for (U32 i = 0; i < 3; i++) { @@ -223,7 +223,7 @@ void calc_tangent_from_triangle( // and returns the intersection point along dir in intersection_t. // Moller-Trumbore algorithm -BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, +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) { @@ -285,15 +285,15 @@ BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, co intersection_a = u[0]; intersection_b = v[0]; intersection_t = t[0]; - return TRUE; + return true; } } } - return FALSE; + return false; } -BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, +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; @@ -316,7 +316,7 @@ BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& v if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) { - return FALSE; + return false; } F32 inv_det = 1.f / det; @@ -329,7 +329,7 @@ BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& v u = (tvec.dot3(pvec).getF32()) * inv_det; if (u < 0.f || u > 1.f) { - return FALSE; + return false; } /* prepare to test V parameter */ @@ -340,7 +340,7 @@ BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& v if (v < 0.f || u + v > 1.f) { - return FALSE; + return false; } /* calculate t, ray intersects triangle */ @@ -351,32 +351,9 @@ BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& v intersection_t = t; - return TRUE; + 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 { public: diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 9048118243..c27bc5e821 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1098,9 +1098,7 @@ private: F32 sculptGetSurfaceArea(); void sculptGenerateEmptyPlaceholder(); void sculptGenerateSpherePlaceholder(); - void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); - protected: BOOL generate(); void createVolumeFaces(); @@ -1142,18 +1140,13 @@ public: std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); -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); +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 LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, +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, +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); - - #endif diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index 6894d04d3c..cef4d66c04 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -27,7 +27,7 @@ #include "llvolumeoctree.h" #include "llvector4a.h" -BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size) +bool LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size) { LLVector4a fAWdU; LLVector4a dir; diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index 314255374a..c3956e9995 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -710,7 +710,7 @@ U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction, } -BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -751,7 +751,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, point5 = (point5 * prism_rotation) + prism_center; // test ray intersection for each face - BOOL b_hit = FALSE; + bool b_hit = false; LLVector3 face_intersection, face_normal; F32 distance_squared = 0.0f; F32 temp; @@ -761,14 +761,14 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, ray_quadrangle(ray_point, ray_direction, point5, point2, point0, intersection, intersection_normal)) { distance_squared = (ray_point - intersection).magVecSquared(); - b_hit = TRUE; + b_hit = true; } // face 1 if (ray_direction * ( (point0 - point3) % (point2 - point3)) < 0.0f && ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -783,7 +783,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -791,7 +791,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point1 - point4) % (point3 - point4)) < 0.0f && ray_quadrangle(ray_point, ray_direction, point3, point4, point1, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -806,7 +806,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -814,7 +814,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point5 - point4) % (point1 - point4)) < 0.0f && ray_triangle(ray_point, ray_direction, point1, point4, point5, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -829,7 +829,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -837,7 +837,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point4 - point5) % (point2 - point5)) < 0.0f && ray_quadrangle(ray_point, ray_direction, point2, point5, point4, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -852,7 +852,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -860,7 +860,7 @@ BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, } -BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -890,7 +890,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, point3 = (point3 * t_rotation) + t_center; // test ray intersection for each face - BOOL b_hit = FALSE; + bool b_hit = false; LLVector3 face_intersection, face_normal; F32 distance_squared = 1.0e12f; F32 temp; @@ -900,14 +900,14 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, ray_triangle(ray_point, ray_direction, point1, point2, point0, intersection, intersection_normal)) { distance_squared = (ray_point - intersection).magVecSquared(); - b_hit = TRUE; + b_hit = true; } // face 1 if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f && ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -922,7 +922,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -930,7 +930,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point1 - point3) % (point0 - point3)) < 0.0f && ray_triangle(ray_point, ray_direction, point3, point1, point0, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -945,7 +945,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -953,7 +953,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point2 - point3) % (point1 - point3)) < 0.0f && ray_triangle(ray_point, ray_direction, point3, point2, point1, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -966,7 +966,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, { intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -974,7 +974,7 @@ BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, } -BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -997,7 +997,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, point4 = (point4 * p_rotation) + p_center; // test ray intersection for each face - BOOL b_hit = FALSE; + bool b_hit = false; LLVector3 face_intersection, face_normal; F32 distance_squared = 1.0e12f; F32 temp; @@ -1007,14 +1007,14 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, ray_triangle(ray_point, ray_direction, point4, point1, point0, intersection, intersection_normal)) { distance_squared = (ray_point - intersection).magVecSquared(); - b_hit = TRUE; + b_hit = true; } // face 1 if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f && ray_triangle(ray_point, ray_direction, point1, point2, point0, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -1029,7 +1029,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -1037,7 +1037,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f && ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -1052,7 +1052,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -1060,7 +1060,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point4 - point3) % (point0 - point3)) < 0.0f && ray_triangle(ray_point, ray_direction, point3, point4, point0, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -1075,7 +1075,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, distance_squared = (ray_point - face_intersection).magVecSquared(); intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -1083,7 +1083,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (ray_direction * ( (point3 - point4) % (point2 - point4)) < 0.0f && ray_quadrangle(ray_point, ray_direction, point4, point3, point2, face_intersection, face_normal)) { - if (TRUE == b_hit) + if (b_hit) { temp = (ray_point - face_intersection).magVecSquared(); if (temp < distance_squared) @@ -1096,7 +1096,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, { intersection = face_intersection; intersection_normal = face_normal; - b_hit = TRUE; + b_hit = true; } } @@ -1104,7 +1104,7 @@ BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, } -BOOL linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, LLVector3 &intersection) { @@ -1115,14 +1115,14 @@ BOOL linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1133,14 +1133,14 @@ BOOL linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1151,14 +1151,14 @@ BOOL linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &sphere_center, F32 sphere_radius, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1169,14 +1169,14 @@ BOOL linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1187,10 +1187,10 @@ BOOL linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } @@ -1215,7 +1215,7 @@ U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b, } -BOOL linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1229,11 +1229,11 @@ BOOL linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, return true; } } - return FALSE; + return false; } -BOOL linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1244,14 +1244,14 @@ BOOL linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } -BOOL linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, LLVector3 &intersection, LLVector3 &intersection_normal) { @@ -1262,13 +1262,8 @@ BOOL linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, { if (segment_length >= (point_a - intersection).magVec()) { - return TRUE; + return true; } } - return FALSE; + return false; } - - - - - diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index 92bca45566..3f7014c1b9 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -129,17 +129,17 @@ BOOL ray_cone(const LLVector3 &ray_point, const LLVector3 &ray_direction, */ -BOOL ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); @@ -170,13 +170,13 @@ BOOL ray_hemicone(const LLVector3 &ray_point, const LLVector3 &ray_direction, */ -BOOL linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, LLVector3 &intersection); // point_0 through point_2 define the plane_normal via the right-hand rule: // circle from point_0 to point_2 with fingers ==> thumb points in direction of normal -BOOL linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal); @@ -185,19 +185,19 @@ BOOL linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, // right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right // ==> thumb points in direction of normal // assumes a parallelogram, so point_3 is determined by the other points -BOOL linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &sphere_center, F32 sphere_radius, LLVector3 &intersection, LLVector3 &intersection_normal); // finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom", // and by the cylinder radius "cyl_radius" -BOOL linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); @@ -213,20 +213,17 @@ U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, +bool linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); - - #endif - diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp index a24571f2c8..e86d8723a3 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -43,12 +43,12 @@ LLVector2 LLVector2::zero(0,0); // Sets all values to absolute value of their original values // Returns TRUE if data changed -BOOL LLVector2::abs() +bool LLVector2::abs() { - BOOL ret = FALSE; + bool ret{ false }; - if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = TRUE; } - if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = TRUE; } + if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } + if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } return ret; } @@ -67,7 +67,7 @@ F32 angle_between(const LLVector2& a, const LLVector2& b) return angle; } -BOOL are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon) +bool are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon) { LLVector2 an = a; LLVector2 bn = b; @@ -76,9 +76,9 @@ BOOL are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon) F32 dot = an * bn; if ( (1.0f - fabs(dot)) < epsilon) { - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index 2335a2e327..e455b8742c 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -78,12 +78,12 @@ class LLVector2 F32 magVecSquared() const; // deprecated F32 normVec(); // deprecated - BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed + bool abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed const LLVector2& scaleVec(const LLVector2& vec); // scales per component by vec - BOOL isNull(); // Returns TRUE if vector has a _very_small_ length - BOOL isExactlyZero() const { return !mV[VX] && !mV[VY]; } + bool isNull(); // Returns TRUE if vector has a _very_small_ length + bool isExactlyZero() const { return !mV[VX] && !mV[VY]; } F32 operator[](int idx) const { return mV[idx]; } F32 &operator[](int idx) { return mV[idx]; } @@ -114,7 +114,7 @@ class LLVector2 // Non-member functions F32 angle_between(const LLVector2 &a, const LLVector2 &b); // Returns angle (radians) between a and b -BOOL are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel +bool are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel F32 dist_vec(const LLVector2 &a, const LLVector2 &b); // Returns distance between a and b F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b ignoring Z component @@ -232,7 +232,7 @@ inline F32 LLVector2::lengthSquared(void) const return mV[0]*mV[0] + mV[1]*mV[1]; } -inline F32 LLVector2::normalize(void) +inline F32 LLVector2::normalize(void) { F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); F32 oomag; @@ -299,13 +299,13 @@ inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec) return *this; } -inline BOOL LLVector2::isNull() +inline bool LLVector2::isNull() { if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] ) { - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/indra/llmath/v3dmath.cpp b/indra/llmath/v3dmath.cpp index a50cb3c6ca..1be989d991 100644 --- a/indra/llmath/v3dmath.cpp +++ b/indra/llmath/v3dmath.cpp @@ -53,30 +53,30 @@ const LLVector3d LLVector3d::z_axis_neg(0, 0, -1); // Clamps each values to range (min,max). // Returns TRUE if data changed. -BOOL LLVector3d::clamp(F64 min, F64 max) +bool LLVector3d::clamp(F64 min, F64 max) { - BOOL ret = FALSE; + bool ret{ false }; - if (mdV[0] < min) { mdV[0] = min; ret = TRUE; } - if (mdV[1] < min) { mdV[1] = min; ret = TRUE; } - if (mdV[2] < min) { mdV[2] = min; ret = TRUE; } + if (mdV[0] < min) { mdV[0] = min; ret = true; } + if (mdV[1] < min) { mdV[1] = min; ret = true; } + if (mdV[2] < min) { mdV[2] = min; ret = true; } - if (mdV[0] > max) { mdV[0] = max; ret = TRUE; } - if (mdV[1] > max) { mdV[1] = max; ret = TRUE; } - if (mdV[2] > max) { mdV[2] = max; ret = TRUE; } + if (mdV[0] > max) { mdV[0] = max; ret = true; } + if (mdV[1] > max) { mdV[1] = max; ret = true; } + if (mdV[2] > max) { mdV[2] = max; ret = true; } return ret; } // Sets all values to absolute value of their original values // Returns TRUE if data changed -BOOL LLVector3d::abs() +bool LLVector3d::abs() { - BOOL ret = FALSE; + bool ret{ false }; - if (mdV[0] < 0.0) { mdV[0] = -mdV[0]; ret = TRUE; } - if (mdV[1] < 0.0) { mdV[1] = -mdV[1]; ret = TRUE; } - if (mdV[2] < 0.0) { mdV[2] = -mdV[2]; ret = TRUE; } + if (mdV[0] < 0.0) { mdV[0] = -mdV[0]; ret = true; } + if (mdV[1] < 0.0) { mdV[1] = -mdV[1]; ret = true; } + if (mdV[2] < 0.0) { mdV[2] = -mdV[2]; ret = true; } return ret; } @@ -127,11 +127,11 @@ const LLVector3d& LLVector3d::rotVec(F64 angle, F64 x, F64 y, F64 z) } -BOOL LLVector3d::parseVector3d(const std::string& buf, LLVector3d* value) +bool LLVector3d::parseVector3d(const std::string& buf, LLVector3d* value) { - if( buf.empty() || value == NULL) + if( buf.empty() || value == nullptr) { - return FALSE; + return false; } LLVector3d v; @@ -139,9 +139,9 @@ BOOL LLVector3d::parseVector3d(const std::string& buf, LLVector3d* value) if( 3 == count ) { value->setVec( v ); - return TRUE; + return true; } - return FALSE; + return false; } diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 4938273d5b..1d1a7c7512 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -68,9 +68,9 @@ class LLVector3d return ret; } - inline BOOL isFinite() const; // checks to see if all values of LLVector3d are finite - BOOL clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns TRUE if data changed - BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed + inline bool isFinite() const; // checks to see if all values of LLVector3d are finite + bool clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns TRUE if data changed + bool abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed inline const LLVector3d& clear(); // Clears LLVector3d to (0, 0, 0, 1) inline const LLVector3d& clearVec(); // deprecated @@ -98,8 +98,8 @@ class LLVector3d const LLVector3d& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat const LLVector3d& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q - BOOL isNull() const; // Returns TRUE if vector has a _very_small_ length - BOOL isExactlyZero() const { return !mdV[VX] && !mdV[VY] && !mdV[VZ]; } + bool isNull() const; // Returns TRUE if vector has a _very_small_ length + bool isExactlyZero() const { return !mdV[VX] && !mdV[VY] && !mdV[VZ]; } const LLVector3d& operator=(const LLVector4 &a); @@ -126,7 +126,7 @@ class LLVector3d friend std::ostream& operator<<(std::ostream& s, const LLVector3d& a); // Stream a - static BOOL parseVector3d(const std::string& buf, LLVector3d* value); + static bool parseVector3d(const std::string& buf, LLVector3d* value); }; @@ -189,7 +189,7 @@ inline LLVector3d::LLVector3d(const LLVector3d ©) // Destructors // checker -inline BOOL LLVector3d::isFinite() const +inline bool LLVector3d::isFinite() const { return (llfinite(mdV[VX]) && llfinite(mdV[VY]) && llfinite(mdV[VZ])); } @@ -472,13 +472,13 @@ inline LLVector3d lerp(const LLVector3d& a, const LLVector3d& b, const F64 u) } -inline BOOL LLVector3d::isNull() const +inline bool LLVector3d::isNull() const { if ( F_APPROXIMATELY_ZERO > mdV[VX]*mdV[VX] + mdV[VY]*mdV[VY] + mdV[VZ]*mdV[VZ] ) { - return TRUE; + return true; } - return FALSE; + return false; } @@ -495,7 +495,7 @@ inline F64 angle_between(const LLVector3d& a, const LLVector3d& b) return angle; } -inline BOOL are_parallel(const LLVector3d& a, const LLVector3d& b, const F64 epsilon) +inline bool are_parallel(const LLVector3d& a, const LLVector3d& b, const F64 epsilon) { LLVector3d an = a; LLVector3d bn = b; @@ -504,10 +504,9 @@ inline BOOL are_parallel(const LLVector3d& a, const LLVector3d& b, const F64 eps F64 dot = an * bn; if ( (1.0f - fabs(dot)) < epsilon) { - return TRUE; + return true; } - return FALSE; - + return false; } inline LLVector3d projected_vec(const LLVector3d& a, const LLVector3d& b) diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 93010d2250..4a82051f2e 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -54,26 +54,26 @@ const LLVector3 LLVector3::all_one(1.f,1.f,1.f); // Clamps each values to range (min,max). // Returns TRUE if data changed. -BOOL LLVector3::clamp(F32 min, F32 max) +bool LLVector3::clamp(F32 min, F32 max) { - BOOL ret = FALSE; + bool ret{ false }; - if (mV[0] < min) { mV[0] = min; ret = TRUE; } - if (mV[1] < min) { mV[1] = min; ret = TRUE; } - if (mV[2] < min) { mV[2] = min; ret = TRUE; } + if (mV[0] < min) { mV[0] = min; ret = true; } + if (mV[1] < min) { mV[1] = min; ret = true; } + if (mV[2] < min) { mV[2] = min; ret = true; } - if (mV[0] > max) { mV[0] = max; ret = TRUE; } - if (mV[1] > max) { mV[1] = max; ret = TRUE; } - if (mV[2] > max) { mV[2] = max; ret = TRUE; } + if (mV[0] > max) { mV[0] = max; ret = true; } + if (mV[1] > max) { mV[1] = max; ret = true; } + if (mV[2] > max) { mV[2] = max; ret = true; } return ret; } // Clamps length to an upper limit. // Returns TRUE if the data changed -BOOL LLVector3::clampLength( F32 length_limit ) +bool LLVector3::clampLength( F32 length_limit ) { - BOOL changed = FALSE; + bool changed{ false }; F32 len = length(); if (llfinite(len)) @@ -88,7 +88,7 @@ BOOL LLVector3::clampLength( F32 length_limit ) mV[0] *= length_limit; mV[1] *= length_limit; mV[2] *= length_limit; - changed = TRUE; + changed = true; } } else @@ -108,7 +108,7 @@ BOOL LLVector3::clampLength( F32 length_limit ) { // no it can't be salvaged --> clear it clear(); - changed = TRUE; + changed = true; break; } } @@ -134,17 +134,17 @@ BOOL LLVector3::clampLength( F32 length_limit ) return changed; } -BOOL LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec) +bool LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec) { - BOOL ret = FALSE; + bool ret{ false }; - if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = TRUE; } - if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = TRUE; } - if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = TRUE; } + if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = true; } + if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = true; } + if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = true; } - if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = TRUE; } - if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = TRUE; } - if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = TRUE; } + if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = true; } + if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = true; } + if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = true; } return ret; } @@ -152,13 +152,13 @@ BOOL LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec) // Sets all values to absolute value of their original values // Returns TRUE if data changed -BOOL LLVector3::abs() +bool LLVector3::abs() { - BOOL ret = FALSE; + bool ret{ false }; - if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = TRUE; } - if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = TRUE; } - if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = TRUE; } + if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } + if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } + if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = true; } return ret; } @@ -358,11 +358,11 @@ const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &rot) } // static -BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value) +bool LLVector3::parseVector3(const std::string& buf, LLVector3* value) { - if( buf.empty() || value == NULL) + if( buf.empty() || value == nullptr) { - return FALSE; + return false; } LLVector3 v; @@ -370,10 +370,10 @@ BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value) if( 3 == count ) { value->setVec( v ); - return TRUE; + return true; } - return FALSE; + return false; } // Displacement from query point to nearest neighbor point on bounding box. diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 31abf433a0..3d2365e04b 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -71,16 +71,16 @@ class LLVector3 void setValue(const LLSD& sd); - inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite - BOOL clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed - BOOL clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector - BOOL clampLength( F32 length_limit ); // Scales vector to limit length to a value + inline bool isFinite() const; // checks to see if all values of LLVector3 are finite + bool clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed + bool clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector + bool clampLength( F32 length_limit ); // Scales vector to limit length to a value void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization void quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization void snap(S32 sig_digits); // snaps x,y,z to sig_digits decimal places - BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed + bool abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed inline void clear(); // Clears LLVector3 to (0, 0, 0) inline void setZero(); // Clears LLVector3 to (0, 0, 0) @@ -108,7 +108,7 @@ class LLVector3 inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3 inline F32 normVec(); // deprecated - inline BOOL inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max + inline bool inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians @@ -120,7 +120,7 @@ class LLVector3 LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec bool isNull() const; // Returns TRUE if vector has a _very_small_ length - BOOL isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; } + bool isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; } F32 operator[](int idx) const { return mV[idx]; } F32 &operator[](int idx) { return mV[idx]; } @@ -149,7 +149,7 @@ class LLVector3 friend std::ostream& operator<<(std::ostream& s, const LLVector3 &a); // Stream a - static BOOL parseVector3(const std::string& buf, LLVector3* value); + static bool parseVector3(const std::string& buf, LLVector3* value); }; typedef LLVector3 LLSimLocalVec; @@ -157,7 +157,7 @@ typedef LLVector3 LLSimLocalVec; // Non-member functions F32 angle_between(const LLVector3 &a, const LLVector3 &b); // Returns angle (radians) between a and b -BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel +bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance between a and b F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b ignoring Z component @@ -202,7 +202,7 @@ inline LLVector3::LLVector3(const LLVector3 ©) // Destructors // checker -inline BOOL LLVector3::isFinite() const +inline bool LLVector3::isFinite() const { return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ])); } @@ -350,7 +350,7 @@ inline F32 LLVector3::magVecSquared(void) const return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; } -inline BOOL LLVector3::inRange( F32 min, F32 max ) const +inline bool LLVector3::inRange( F32 min, F32 max ) const { return mV[0] >= min && mV[0] <= max && mV[1] >= min && mV[1] <= max && @@ -589,7 +589,7 @@ inline F32 angle_between(const LLVector3& a, const LLVector3& b) return atan2f(sqrtf(c * c), ab); // return the angle } -inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) +inline bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) { LLVector3 an = a; LLVector3 bn = b; diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index a8768bda35..81d18285b9 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -385,18 +385,18 @@ void LLColor4::calcHSL(F32* hue, F32* saturation, F32* luminance) const } // static -BOOL LLColor4::parseColor(const std::string& buf, LLColor4* color) +bool LLColor4::parseColor(const std::string& buf, LLColor4* color) { - if( buf.empty() || color == NULL) + if( buf.empty() || color == nullptr) { - return FALSE; + return false; } boost_tokenizer tokens(buf, boost::char_separator(", ")); boost_tokenizer::iterator token_iter = tokens.begin(); if (token_iter == tokens.end()) { - return FALSE; + return false; } // Grab the first token into a string, since we don't know @@ -708,15 +708,15 @@ BOOL LLColor4::parseColor(const std::string& buf, LLColor4* color) } } - return TRUE; + return true; } // static -BOOL LLColor4::parseColor4(const std::string& buf, LLColor4* value) +bool LLColor4::parseColor4(const std::string& buf, LLColor4* value) { - if( buf.empty() || value == NULL) + if( buf.empty() || value == nullptr) { - return FALSE; + return false; } LLColor4 v; @@ -729,10 +729,10 @@ BOOL LLColor4::parseColor4(const std::string& buf, LLColor4* value) if( 4 == count ) { value->setVec( v ); - return TRUE; + return true; } - return FALSE; + return false; } // EOF diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index daa61594fb..498d4f7734 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -111,7 +111,7 @@ class LLColor4 F32 lengthSquared() const; // Returns magnitude squared of LLColor4 F32 normalize(); // deprecated -- use normalize() - BOOL isOpaque() { return mV[VALPHA] == 1.f; } + bool isOpaque() { return mV[VALPHA] == 1.f; } F32 operator[](int idx) const { return mV[idx]; } F32 &operator[](int idx) { return mV[idx]; } @@ -226,8 +226,8 @@ class LLColor4 static LLColor4 cyan5; static LLColor4 cyan6; - static BOOL parseColor(const std::string& buf, LLColor4* color); - static BOOL parseColor4(const std::string& buf, LLColor4* color); + static bool parseColor(const std::string& buf, LLColor4* color); + static bool parseColor4(const std::string& buf, LLColor4* color); inline void clamp(); }; diff --git a/indra/llmath/v4coloru.cpp b/indra/llmath/v4coloru.cpp index f1a2518cf3..d238d609b4 100644 --- a/indra/llmath/v4coloru.cpp +++ b/indra/llmath/v4coloru.cpp @@ -88,11 +88,11 @@ std::ostream& operator<<(std::ostream& s, const LLColor4U &a) } // static -BOOL LLColor4U::parseColor4U(const std::string& buf, LLColor4U* value) +bool LLColor4U::parseColor4U(const std::string& buf, LLColor4U* value) { - if( buf.empty() || value == NULL) + if( buf.empty() || value == nullptr) { - return FALSE; + return false; } U32 v[4]; @@ -104,17 +104,17 @@ BOOL LLColor4U::parseColor4U(const std::string& buf, LLColor4U* value) } if( 4 != count ) { - return FALSE; + return false; } for( S32 i = 0; i < 4; i++ ) { if( v[i] > U8_MAX ) { - return FALSE; + return false; } } value->set( U8(v[0]), U8(v[1]), U8(v[2]), U8(v[3]) ); - return TRUE; + return true; } diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index 0f2eff3d14..ca6a5425f9 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -112,12 +112,11 @@ public: LLColor4U addClampMax(const LLColor4U &color); // Add and clamp the max LLColor4U multAll(const F32 k); // Multiply ALL channels by scalar k - const LLColor4U& combine(); inline void setVecScaleClamp(const LLColor3 &color); inline void setVecScaleClamp(const LLColor4 &color); - static BOOL parseColor4U(const std::string& buf, LLColor4U* value); + static bool parseColor4U(const std::string& buf, LLColor4U* value); // conversion operator LLColor4() const diff --git a/indra/llmath/v4math.cpp b/indra/llmath/v4math.cpp index 2782cf2966..8388fbdbc4 100644 --- a/indra/llmath/v4math.cpp +++ b/indra/llmath/v4math.cpp @@ -36,28 +36,6 @@ // LLVector4 // Axis-Angle rotations - -/* -const LLVector4& LLVector4::rotVec(F32 angle, const LLVector4 &vec) -{ - if ( !vec.isExactlyZero() && angle ) - { - *this = *this * LLMatrix4(angle, vec); - } - return *this; -} - -const LLVector4& LLVector4::rotVec(F32 angle, F32 x, F32 y, F32 z) -{ - LLVector3 vec(x, y, z); - if ( !vec.isExactlyZero() && angle ) - { - *this = *this * LLMatrix4(angle, vec); - } - return *this; -} -*/ - const LLVector4& LLVector4::rotVec(const LLMatrix4 &mat) { *this = *this * mat; @@ -82,14 +60,14 @@ const LLVector4& LLVector4::scaleVec(const LLVector4& vec) // Sets all values to absolute value of their original values // Returns TRUE if data changed -BOOL LLVector4::abs() +bool LLVector4::abs() { - BOOL ret = FALSE; + bool ret{ false }; - if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = TRUE; } - if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = TRUE; } - if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = TRUE; } - if (mV[3] < 0.f) { mV[3] = -mV[3]; ret = TRUE; } + if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } + if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } + if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = true; } + if (mV[3] < 0.f) { mV[3] = -mV[3]; ret = true; } return ret; } @@ -117,7 +95,7 @@ F32 angle_between( const LLVector4& a, const LLVector4& b ) return angle; } -BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon) +bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon) { LLVector4 an = a; LLVector4 bn = b; @@ -125,8 +103,8 @@ BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon) bn.normalize(); F32 dot = an * bn; if ( (1.0f - fabs(dot)) < epsilon) - return TRUE; - return FALSE; + return true; + return false; } diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index b8835ba2e4..8a0a882cf0 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -74,7 +74,7 @@ class LLVector4 } - inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite + inline bool isFinite() const; // checks to see if all values of LLVector3 are finite inline void clear(); // Clears LLVector4 to (0, 0, 0, 1) inline void clearVec(); // deprecated @@ -102,13 +102,11 @@ class LLVector4 // Sets all values to absolute value of their original values // Returns TRUE if data changed - BOOL abs(); + bool abs(); - BOOL isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; } - BOOL isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; } + bool isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; } + bool isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; } - const LLVector4& rotVec(F32 angle, const LLVector4 &vec); // Rotates about vec by angle radians - const LLVector4& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q @@ -139,7 +137,7 @@ class LLVector4 // Non-member functions F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b -BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel +bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon = F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel F32 dist_vec(const LLVector4 &a, const LLVector4 &b); // Returns distance between a and b F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b); // Returns distance squared between a and b LLVector3 vec4to3(const LLVector4 &vec); @@ -226,7 +224,7 @@ inline LLVector4::LLVector4(const LLSD &sd) } -inline BOOL LLVector4::isFinite() const +inline bool LLVector4::isFinite() const { return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW])); } -- cgit v1.2.3 From 9e854b697a06abed2a0917fb6120445f176764f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Fri, 16 Feb 2024 19:29:51 +0100 Subject: misc: BOOL to bool --- indra/llmath/llvolume.cpp | 58 +++++++++++++++++++++++------------------------ indra/llmath/llvolume.h | 14 ++++++------ 2 files changed, 36 insertions(+), 36 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index f9306d6bce..5f0c668b33 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -803,16 +803,16 @@ S32 LLProfile::getNumPoints(const LLProfileParams& params, BOOL path_open,F32 de } -BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) +bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detail, S32 split, + bool is_sculpted, S32 sculpt_size) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME if ((!mDirty) && (!is_sculpted)) { - return FALSE; + return false; } - mDirty = FALSE; + mDirty = false; if (detail < MIN_LOD) { @@ -833,7 +833,7 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai if (begin > end - 0.01f) { LL_WARNS() << "LLProfile::generate() assertion failed (begin >= end)" << LL_ENDL; - return FALSE; + return false; } S32 face_num = 0; @@ -1014,11 +1014,11 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai } if (mOpen && !params.getHollow()) { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); + addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, false); } else { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); + addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, false); } if (hollow) @@ -1026,15 +1026,15 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai switch (hole_type) { case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 2, 0.5f, hollow, 0.5f, split); + addHole(params, true, 2, 0.5f, hollow, 0.5f, split); break; case LL_PCODE_HOLE_TRIANGLE: - addHole(params, TRUE, 3, 0.5f, hollow, 0.5f, split); + addHole(params, true, 3, 0.5f, hollow, 0.5f, split); break; case LL_PCODE_HOLE_CIRCLE: case LL_PCODE_HOLE_SAME: default: - addHole(params, FALSE, circle_detail, 0.5f, hollow, 0.5f); + addHole(params, false, circle_detail, 0.5f, hollow, 0.5f); break; } } @@ -1042,11 +1042,11 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai // Special case for openness of sphere if ((params.getEnd() - params.getBegin()) < 1.f) { - mOpen = TRUE; + mOpen = true; } else if (!hollow) { - mOpen = FALSE; + mOpen = false; mProfile.push_back(mProfile[0]); mTotal++; } @@ -1064,19 +1064,19 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai if ( mOpen) // interior edge caps { - addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, TRUE); + addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, true); if (hollow) { - addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, TRUE); + addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, true); } else { - addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE); + addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, true); } } - return TRUE; + return true; } @@ -1521,14 +1521,14 @@ S32 LLPath::getNumPoints(const LLPathParams& params, F32 detail) return np; } -BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) +bool LLPath::generate(const LLPathParams& params, F32 detail, S32 split, + bool is_sculpted, S32 sculpt_size) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME if ((!mDirty) && (!is_sculpted)) { - return FALSE; + return false; } if (detail < MIN_LOD) @@ -1537,11 +1537,11 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, detail = MIN_LOD; } - mDirty = FALSE; + mDirty = false; S32 np = 2; // hardcode for line mPath.resize(0); - mOpen = TRUE; + mOpen = true; // Is this 0xf0 mask really necessary? DK 03/02/05 switch (params.getCurveType() & 0xf0) @@ -1601,7 +1601,7 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, if (params.getEnd() - params.getBegin() >= 0.99f && params.getScaleX() >= .99f) { - mOpen = FALSE; + mOpen = false; } //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); @@ -1645,19 +1645,19 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, break; }; - if (params.getTwist() != params.getTwistBegin()) mOpen = TRUE; + if (params.getTwist() != params.getTwistBegin()) mOpen = true; //if ((int(fabsf(params.getTwist() - params.getTwistBegin())*100))%100 != 0) { - // mOpen = TRUE; + // mOpen = true; //} - return TRUE; + return true; } -BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) +bool LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, + bool is_sculpted, S32 sculpt_size) { - mOpen = TRUE; // Draw end caps + mOpen = true; // Draw end caps if (getPathLength() == 0) { // Path hasn't been generated yet. @@ -1676,7 +1676,7 @@ BOOL LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, } } - return TRUE; + return true; } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index c27bc5e821..0158ca9bcd 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -703,9 +703,9 @@ public: static S32 getNumPoints(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, BOOL is_sculpted = FALSE, S32 sculpt_size = 0); - BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); - BOOL isConcave() const { return mConcave; } + bool generate(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); + bool isConcave() const { return mConcave; } public: struct Face { @@ -792,8 +792,8 @@ public: static S32 getNumNGonPoints(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); - virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + virtual bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); BOOL isOpen() const { return mOpen; } F32 getStep() const { return mStep; } @@ -819,8 +819,8 @@ class LLDynamicPath : public LLPath { public: LLDynamicPath() : LLPath() { } - /*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + /*virtual*/ bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); }; // Yet another "face" class - caches volume-specific, but not instance-specific data for faces) -- cgit v1.2.3 From f1c97f4057833220a2e9ac045d701208e30457d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Sun, 18 Feb 2024 16:41:22 +0100 Subject: misc: BOOL to bool --- indra/llmath/llvolume.cpp | 172 +++++++++++++++++++++++----------------------- indra/llmath/llvolume.h | 50 +++++++------- indra/llmath/xform.cpp | 4 +- indra/llmath/xform.h | 14 ++-- 4 files changed, 120 insertions(+), 120 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 5f0c668b33..73569cfa07 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -95,7 +95,7 @@ const F32 SKEW_MAX = 0.95f; const F32 SCULPT_MIN_AREA = 0.002f; const S32 SCULPT_MIN_AREA_DETAIL = 1; -BOOL gDebugGL = FALSE; // See settings.xml "RenderDebugGL" +bool gDebugGL = FALSE; // See settings.xml "RenderDebugGL" bool check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) { @@ -1081,7 +1081,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai -BOOL LLProfileParams::importFile(LLFILE *fp) +bool LLProfileParams::importFile(LLFILE *fp) { const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ @@ -1139,11 +1139,11 @@ BOOL LLProfileParams::importFile(LLFILE *fp) } } - return TRUE; + return true; } -BOOL LLProfileParams::exportFile(LLFILE *fp) const +bool LLProfileParams::exportFile(LLFILE *fp) const { fprintf(fp,"\t\tprofile 0\n"); fprintf(fp,"\t\t{\n"); @@ -1152,11 +1152,11 @@ BOOL LLProfileParams::exportFile(LLFILE *fp) const fprintf(fp,"\t\t\tend\t%g\n", getEnd()); fprintf(fp,"\t\t\thollow\t%g\n", getHollow()); fprintf(fp, "\t\t}\n"); - return TRUE; + return true; } -BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) +bool LLProfileParams::importLegacyStream(std::istream& input_stream) { const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ @@ -1211,11 +1211,11 @@ BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) } } - return TRUE; + return true; } -BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const +bool LLProfileParams::exportLegacyStream(std::ostream& output_stream) const { output_stream <<"\t\tprofile 0\n"; output_stream <<"\t\t{\n"; @@ -1224,7 +1224,7 @@ BOOL LLProfileParams::exportLegacyStream(std::ostream& output_stream) const output_stream <<"\t\t\tend\t" << getEnd() << "\n"; output_stream <<"\t\t\thollow\t" << getHollow() << "\n"; output_stream << "\t\t}\n"; - return TRUE; + return true; } LLSD LLProfileParams::asLLSD() const @@ -1680,7 +1680,7 @@ bool LLDynamicPath::generate(const LLPathParams& params, F32 detail, S32 split, } -BOOL LLPathParams::importFile(LLFILE *fp) +bool LLPathParams::importFile(LLFILE *fp) { const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ @@ -1795,11 +1795,11 @@ BOOL LLPathParams::importFile(LLFILE *fp) LL_WARNS() << "unknown keyword " << " in path import" << LL_ENDL; } } - return TRUE; + return true; } -BOOL LLPathParams::exportFile(LLFILE *fp) const +bool LLPathParams::exportFile(LLFILE *fp) const { fprintf(fp, "\t\tpath 0\n"); fprintf(fp, "\t\t{\n"); @@ -1820,11 +1820,11 @@ BOOL LLPathParams::exportFile(LLFILE *fp) const fprintf(fp,"\t\t\tskew\t%g\n", getSkew()); fprintf(fp, "\t\t}\n"); - return TRUE; + return true; } -BOOL LLPathParams::importLegacyStream(std::istream& input_stream) +bool LLPathParams::importLegacyStream(std::istream& input_stream) { const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ @@ -1935,11 +1935,11 @@ BOOL LLPathParams::importLegacyStream(std::istream& input_stream) LL_WARNS() << "unknown keyword " << " in path import" << LL_ENDL; } } - return TRUE; + return true; } -BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const +bool LLPathParams::exportLegacyStream(std::ostream& output_stream) const { output_stream << "\t\tpath 0\n"; output_stream << "\t\t{\n"; @@ -1960,7 +1960,7 @@ BOOL LLPathParams::exportLegacyStream(std::ostream& output_stream) const output_stream <<"\t\t\tskew\t" << getSkew() << "\n"; output_stream << "\t\t}\n"; - return TRUE; + return true; } LLSD LLPathParams::asLLSD() const @@ -2099,7 +2099,7 @@ LLVolume::~LLVolume() mHullIndices = NULL; } -BOOL LLVolume::generate() +bool LLVolume::generate() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME @@ -2143,8 +2143,8 @@ BOOL LLVolume::generate() } } - BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); - BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); + bool regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); + bool regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); if (regenPath || regenProf ) { @@ -2207,11 +2207,11 @@ BOOL LLVolume::generate() mFaceMask |= id; } LL_CHECK_MEMORY - return TRUE; + return true; } LL_CHECK_MEMORY - return FALSE; + return false; } void LLVolumeFace::VertexData::init() @@ -3334,12 +3334,12 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, -BOOL LLVolume::isCap(S32 face) +bool LLVolume::isCap(S32 face) { return mProfilep->mFaces[face].mCap; } -BOOL LLVolume::isFlat(S32 face) +bool LLVolume::isFlat(S32 face) { return mProfilep->mFaces[face].mFlat; } @@ -4324,7 +4324,7 @@ BOOL equalTriangle(const S32 *a, const S32 *b) return FALSE; } -BOOL LLVolumeParams::importFile(LLFILE *fp) +bool LLVolumeParams::importFile(LLFILE *fp) { //LL_INFOS() << "importing volume" << LL_ENDL; const S32 BUFSIZE = 16384; @@ -4364,21 +4364,21 @@ BOOL LLVolumeParams::importFile(LLFILE *fp) } } - return TRUE; + return true; } -BOOL LLVolumeParams::exportFile(LLFILE *fp) const +bool LLVolumeParams::exportFile(LLFILE *fp) const { fprintf(fp,"\tshape 0\n"); fprintf(fp,"\t{\n"); mPathParams.exportFile(fp); mProfileParams.exportFile(fp); fprintf(fp, "\t}\n"); - return TRUE; + return true; } -BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) +bool LLVolumeParams::importLegacyStream(std::istream& input_stream) { //LL_INFOS() << "importing volume" << LL_ENDL; const S32 BUFSIZE = 16384; @@ -4414,17 +4414,17 @@ BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) } } - return TRUE; + return true; } -BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const +bool LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const { output_stream <<"\tshape 0\n"; output_stream <<"\t{\n"; mPathParams.exportLegacyStream(output_stream); mProfileParams.exportLegacyStream(output_stream); output_stream << "\t}\n"; - return TRUE; + return true; } LLSD LLVolumeParams::sculptAsLLSD() const @@ -4498,12 +4498,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity // returns TRUE if the shape can be approximated with a convex shape // for collison purposes -BOOL LLVolumeParams::isConvex() const +bool LLVolumeParams::isConvex() const { if (!getSculptID().isNull()) { // can't determine, be safe and say no: - return FALSE; + return false; } F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); @@ -4516,7 +4516,7 @@ BOOL LLVolumeParams::isConvex() const && LL_PCODE_PATH_LINE != path_type) ) ) { // twist along a "not too short" path is concave - return FALSE; + return false; } F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); @@ -4540,36 +4540,36 @@ BOOL LLVolumeParams::isConvex() const if (!convex_profile) { // profile is concave - return FALSE; + return false; } if ( LL_PCODE_PATH_LINE == path_type ) { // straight paths with convex profile - return TRUE; + return true; } - BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f); + bool concave_path = (path_length < 1.0f) && (path_length > 0.5f); if (concave_path) { - return FALSE; + return false; } // we're left with spheres, toroids and tubes if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) { // at this stage all spheres must be convex - return TRUE; + return true; } // it's a toroid or tube if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) { // effectively convex - return TRUE; + return true; } - return FALSE; + return false; } // debug @@ -4647,7 +4647,7 @@ LLFaceID LLVolume::generateFaceMask() return new_mask; } -BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) +bool LLVolume::isFaceMaskValid(LLFaceID face_mask) { LLFaceID test_mask = 0; for(S32 i = 0; i < getNumFaces(); i++) @@ -4658,7 +4658,7 @@ BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask) return test_mask == face_mask; } -BOOL LLVolume::isConvex() const +bool LLVolume::isConvex() const { // mParams.isConvex() may return FALSE even though the final // geometry is actually convex due to LOD approximations. @@ -4944,7 +4944,7 @@ void LLVolumeFace::freeData() destroyOctree(); } -BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) +bool LLVolumeFace::create(LLVolume* volume, BOOL partial_build) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME @@ -4952,7 +4952,7 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) destroyOctree(); LL_CHECK_MEMORY - BOOL ret = FALSE ; + bool ret = false ; if (mTypeMask & CAP_MASK) { ret = createCap(volume, partial_build); @@ -5768,7 +5768,7 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, vout.setNormal(v0.getNormal()); } -BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) +bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) { LL_CHECK_MEMORY @@ -6000,11 +6000,11 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) } LL_CHECK_MEMORY - return TRUE; + return true; } -BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) +bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) { if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK) && @@ -6210,36 +6210,36 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) (paV[0]*pbV[1] - pbV[0]*paV[1]) + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; + bool use_tri1a2 = true; + bool tri_1a2 = true; + bool tri_21b = true; if (area_1a2 < 0) { - tri_1a2 = FALSE; + tri_1a2 = false; } if (area_2ab < 0) { // Can't use, because it contains point b - tri_1a2 = FALSE; + tri_1a2 = false; } if (area_21b < 0) { - tri_21b = FALSE; + tri_21b = false; } if (area_1ba < 0) { // Can't use, because it contains point b - tri_21b = FALSE; + tri_21b = false; } if (!tri_1a2) { - use_tri1a2 = FALSE; + use_tri1a2 = false; } else if (!tri_21b) { - use_tri1a2 = TRUE; + use_tri1a2 = true; } else { @@ -6251,11 +6251,11 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) if (d1.dot3(d1) < d2.dot3(d2)) { - use_tri1a2 = TRUE; + use_tri1a2 = true; } else { - use_tri1a2 = FALSE; + use_tri1a2 = false; } } @@ -6316,36 +6316,36 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) (paV[0]*pbV[1] - pbV[0]*paV[1]) + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; + bool use_tri1a2 = true; + bool tri_1a2 = true; + bool tri_21b = true; if (area_1a2 < 0) { - tri_1a2 = FALSE; + tri_1a2 = false; } if (area_2ab < 0) { // Can't use, because it contains point b - tri_1a2 = FALSE; + tri_1a2 = false; } if (area_21b < 0) { - tri_21b = FALSE; + tri_21b = false; } if (area_1ba < 0) { // Can't use, because it contains point b - tri_21b = FALSE; + tri_21b = false; } if (!tri_1a2) { - use_tri1a2 = FALSE; + use_tri1a2 = false; } else if (!tri_21b) { - use_tri1a2 = TRUE; + use_tri1a2 = true; } else { @@ -6356,11 +6356,11 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) if (d1.dot3(d1) < d2.dot3(d2)) { - use_tri1a2 = TRUE; + use_tri1a2 = true; } else { - use_tri1a2 = FALSE; + use_tri1a2 = false; } } @@ -6439,7 +6439,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) norm[i].load4a(normal.getF32ptr()); } - return TRUE; + return true; } void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, @@ -6657,18 +6657,18 @@ void LLVolumeFace::fillFromLegacyData(std::vector& v, } } -BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) +bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LL_CHECK_MEMORY - BOOL flat = mTypeMask & FLAT_MASK; + bool flat = mTypeMask & FLAT_MASK; U8 sculpt_type = volume->getParams().getSculptType(); U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + bool sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + bool sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + bool sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR S32 num_vertices, num_indices; @@ -7039,10 +7039,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) LLVector4a top; top.setSub(pos[0], pos[mNumS*(mNumT-2)]); - BOOL s_bottom_converges = (top.dot3(top) < 0.000001f); + 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); + bool s_top_converges = (top.dot3(top) < 0.000001f); if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes { @@ -7090,20 +7090,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) } else // logic for sculpt volumes { - BOOL average_poles = FALSE; - BOOL wrap_s = FALSE; - BOOL wrap_t = FALSE; + bool average_poles = false; + bool wrap_s = false; + bool wrap_t = false; if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - average_poles = TRUE; + average_poles = true; if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - wrap_s = TRUE; + wrap_s = true; if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - wrap_t = TRUE; + wrap_t = true; if (average_poles) @@ -7168,7 +7168,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) LL_CHECK_MEMORY - return TRUE; + return true; } //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 diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 0158ca9bcd..4ea0604f26 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -201,7 +201,7 @@ const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; const S32 LL_SCULPT_MESH_MAX_FACES = 8; -extern BOOL gDebugGL; +extern bool gDebugGL; class LLProfileParams { @@ -254,11 +254,11 @@ public: void copyParams(const LLProfileParams ¶ms); - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; + bool importFile(LLFILE *fp); + bool exportFile(LLFILE *fp) const; - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; + bool importLegacyStream(std::istream& input_stream); + bool exportLegacyStream(std::ostream& output_stream) const; LLSD asLLSD() const; operator LLSD() const { return asLLSD(); } @@ -390,11 +390,11 @@ public: void copyParams(const LLPathParams ¶ms); - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; + bool importFile(LLFILE *fp); + bool exportFile(LLFILE *fp) const; - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; + bool importLegacyStream(std::istream& input_stream); + bool exportLegacyStream(std::ostream& output_stream) const; LLSD asLLSD() const; operator LLSD() const { return asLLSD(); } @@ -582,11 +582,11 @@ public: const LLPathParams &getPathParams() const {return mPathParams;} LLPathParams &getPathParams() {return mPathParams;} - BOOL importFile(LLFILE *fp); - BOOL exportFile(LLFILE *fp) const; + bool importFile(LLFILE *fp); + bool exportFile(LLFILE *fp) const; - BOOL importLegacyStream(std::istream& input_stream); - BOOL exportLegacyStream(std::ostream& output_stream) const; + bool importLegacyStream(std::istream& input_stream); + bool exportLegacyStream(std::ostream& output_stream) const; LLSD sculptAsLLSD() const; bool sculptFromLLSD(LLSD& sd); @@ -652,7 +652,7 @@ public: const U8& getSculptType() const { return mSculptType; } bool isSculpt() const; bool isMeshSculpt() const; - BOOL isConvex() const; + bool isConvex() const; // 'begin' and 'end' should be in range [0, 1] (they will be clamped) // (begin, end) = (0, 1) will not change the volume @@ -870,7 +870,7 @@ private: void freeData(); public: - BOOL create(LLVolume* volume, BOOL partial_build = FALSE); + bool create(LLVolume* volume, BOOL partial_build = FALSE); void createTangents(); void resizeVertices(S32 num_verts); @@ -990,9 +990,9 @@ private: LLOctreeNode* mOctree; LLVolumeTriangle* mOctreeTriangles; - BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); - BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE); - BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE); + bool createUnCutCubeCap(LLVolume* volume, bool partial_build = false); + bool createCap(LLVolume* volume, bool partial_build = false); + bool createSide(LLVolume* volume, bool partial_build = false); }; class LLVolume : public LLRefCount @@ -1036,10 +1036,10 @@ public: void regen(); void genTangents(S32 face); - BOOL isConvex() const; - BOOL isCap(S32 face); - BOOL isFlat(S32 face); - BOOL isUnique() const { return mUnique; } + bool isConvex() const; + bool isCap(S32 face); + bool isFlat(S32 face); + bool isUnique() const { return mUnique; } S32 getSculptLevel() const { return mSculptLevel; } void setSculptLevel(S32 level) { mSculptLevel = level; } @@ -1069,7 +1069,7 @@ public: LLFaceID generateFaceMask(); - BOOL isFaceMaskValid(LLFaceID face_mask); + bool isFaceMaskValid(LLFaceID face_mask); static S32 sNumMeshPoints; friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); @@ -1100,7 +1100,7 @@ private: void sculptGenerateSpherePlaceholder(); protected: - BOOL generate(); + bool generate(); void createVolumeFaces(); public: bool unpackVolumeFaces(std::istream& is, S32 size); @@ -1128,7 +1128,7 @@ public: LLAlignedArray mMesh; - BOOL mGenerateSingleFace; + bool mGenerateSingleFace; face_list_t mVolumeFaces; public: diff --git a/indra/llmath/xform.cpp b/indra/llmath/xform.cpp index 5d8b93d5e8..8999abda60 100644 --- a/indra/llmath/xform.cpp +++ b/indra/llmath/xform.cpp @@ -52,12 +52,12 @@ LLXform* LLXform::getRoot() const return (LLXform*)root; } -BOOL LLXform::isRoot() const +bool LLXform::isRoot() const { return (!mParent); } -BOOL LLXform::isRootEdit() const +bool LLXform::isRootEdit() const { return (!mParent); } diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 54b0f6d9ec..96c4ab4d51 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -86,7 +86,7 @@ public: void getLocalMat4(LLMatrix4 &mat) const { mat.initAll(mScale, mRotation, mPosition); } - inline BOOL setParent(LLXform *parent); + inline bool setParent(LLXform *parent); inline void setPosition(const LLVector3& pos); inline void setPosition(const F32 x, const F32 y, const F32 z); @@ -119,8 +119,8 @@ public: LLXform* getParent() const { return mParent; } LLXform* getRoot() const; - virtual BOOL isRoot() const; - virtual BOOL isRootEdit() const; + virtual bool isRoot() const; + virtual bool isRootEdit() const; const LLVector3& getPosition() const { return mPosition; } const LLVector3& getScale() const { return mScale; } @@ -159,12 +159,12 @@ protected: }; -BOOL LLXform::setParent(LLXform* parent) +bool LLXform::setParent(LLXform* parent) { // Validate and make sure we're not creating a loop if (parent == mParent) { - return TRUE; + return true; } if (parent) { @@ -174,13 +174,13 @@ BOOL LLXform::setParent(LLXform* parent) if (cur_par == this) { //warn("LLXform::setParent Creating loop when setting parent!"); - return FALSE; + return false; } cur_par = cur_par->mParent; } } mParent = parent; - return TRUE; + return true; } void LLXform::setPosition(const LLVector3& pos) -- cgit v1.2.3 From 18828dfa9891df5137221a7bd2522ceb731317de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Sun, 18 Feb 2024 16:48:29 +0100 Subject: fixed a FALSE I overlooked --- indra/llmath/llvolume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 73569cfa07..3f40d671a7 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -95,7 +95,7 @@ const F32 SKEW_MAX = 0.95f; const F32 SCULPT_MIN_AREA = 0.002f; const S32 SCULPT_MIN_AREA_DETAIL = 1; -bool gDebugGL = FALSE; // See settings.xml "RenderDebugGL" +bool gDebugGL = false; // See settings.xml "RenderDebugGL" bool check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) { -- cgit v1.2.3 From c3e6f7b1643076df35a6960f735024078ddbb353 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 19 Feb 2024 21:33:38 +0100 Subject: Convert remaining cases of BOOL to bool in llmath and llprimitive Changed the return values for LLPrimitive::packTEMessage methods from FALSE to true - these seemed to be strange and wrong, especially considering the following statement in LLVOAvatarSelf: bool success = packTEMessage(mesgsys); --- indra/llmath/llbbox.h | 4 +- indra/llmath/llquaternion.cpp | 6 +- indra/llmath/llvolume.cpp | 230 +++++++++++++++++++-------------------- indra/llmath/llvolume.h | 246 +++++++++++++++++++++--------------------- indra/llmath/m3math.cpp | 8 +- indra/llmath/m4math.cpp | 8 +- indra/llmath/raytrace.cpp | 2 +- indra/llmath/raytrace.h | 12 +-- indra/llmath/xform.cpp | 2 +- indra/llmath/xform.h | 26 ++--- 10 files changed, 270 insertions(+), 274 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index f15d4c2061..8ae5f221f7 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -37,13 +37,13 @@ class LLBBox { public: - LLBBox() {mEmpty = TRUE;} + LLBBox() {mEmpty = true;} LLBBox( const LLVector3& pos_agent, const LLQuaternion& rot, const LLVector3& min_local, const LLVector3& max_local ) : - mMinLocal( min_local ), mMaxLocal( max_local ), mPosAgent(pos_agent), mRotation( rot), mEmpty( TRUE ) + mMinLocal( min_local ), mMaxLocal( max_local ), mPosAgent(pos_agent), mRotation( rot), mEmpty( true ) {} // Default copy constructor is OK. diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 0d1ffa5857..dd3d552832 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -653,14 +653,14 @@ LLQuaternion slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b ) F32 cos_t = a.mQ[0]*b.mQ[0] + a.mQ[1]*b.mQ[1] + a.mQ[2]*b.mQ[2] + a.mQ[3]*b.mQ[3]; // if b is on opposite hemisphere from a, use -a instead - int bflip; + bool bflip; if (cos_t < 0.0f) { cos_t = -cos_t; - bflip = TRUE; + bflip = true; } else - bflip = FALSE; + bflip = false; // if B is (within precision limits) the same as A, // just linear interpolate between A and B. diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 3f40d671a7..292e8f1ff4 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -62,38 +62,38 @@ #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette #define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette -const F32 MIN_CUT_DELTA = 0.02f; +constexpr F32 MIN_CUT_DELTA = 0.02f; -const F32 HOLLOW_MIN = 0.f; -const F32 HOLLOW_MAX = 0.95f; -const F32 HOLLOW_MAX_SQUARE = 0.7f; +constexpr F32 HOLLOW_MIN = 0.f; +constexpr F32 HOLLOW_MAX = 0.95f; +constexpr F32 HOLLOW_MAX_SQUARE = 0.7f; -const F32 TWIST_MIN = -1.f; -const F32 TWIST_MAX = 1.f; +constexpr F32 TWIST_MIN = -1.f; +constexpr F32 TWIST_MAX = 1.f; -const F32 RATIO_MIN = 0.f; -const F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper +constexpr F32 RATIO_MIN = 0.f; +constexpr F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper -const F32 HOLE_X_MIN= 0.05f; -const F32 HOLE_X_MAX= 1.0f; +constexpr F32 HOLE_X_MIN= 0.05f; +constexpr F32 HOLE_X_MAX= 1.0f; -const F32 HOLE_Y_MIN= 0.05f; -const F32 HOLE_Y_MAX= 0.5f; +constexpr F32 HOLE_Y_MIN= 0.05f; +constexpr F32 HOLE_Y_MAX= 0.5f; -const F32 SHEAR_MIN = -0.5f; -const F32 SHEAR_MAX = 0.5f; +constexpr F32 SHEAR_MIN = -0.5f; +constexpr F32 SHEAR_MAX = 0.5f; -const F32 REV_MIN = 1.f; -const F32 REV_MAX = 4.f; +constexpr F32 REV_MIN = 1.f; +constexpr F32 REV_MAX = 4.f; -const F32 TAPER_MIN = -1.f; -const F32 TAPER_MAX = 1.f; +constexpr F32 TAPER_MIN = -1.f; +constexpr F32 TAPER_MAX = 1.f; -const F32 SKEW_MIN = -0.95f; -const F32 SKEW_MAX = 0.95f; +constexpr F32 SKEW_MIN = -0.95f; +constexpr F32 SKEW_MAX = 0.95f; -const F32 SCULPT_MIN_AREA = 0.002f; -const S32 SCULPT_MIN_AREA_DETAIL = 1; +constexpr F32 SCULPT_MIN_AREA = 0.002f; +constexpr S32 SCULPT_MIN_AREA_DETAIL = 1; bool gDebugGL = false; // See settings.xml "RenderDebugGL" @@ -439,12 +439,12 @@ LLProfile::Face* LLProfile::addCap(S16 faceID) face->mIndex = 0; face->mCount = mTotal; face->mScaleU= 1.0f; - face->mCap = TRUE; + face->mCap = true; face->mFaceID = faceID; return face; } -LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BOOL flat) +LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, bool flat) { Face *face = vector_append(mFaces, 1); @@ -453,7 +453,7 @@ LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BO face->mScaleU= scaleU; face->mFlat = flat; - face->mCap = FALSE; + face->mCap = false; face->mFaceID = faceID; return face; } @@ -528,7 +528,7 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 { // Generate an n-sided "circular" path. // 0 is (1,0), and we go counter-clockwise along a circular path from there. - static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + constexpr F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 scale = 0.5f; F32 t, t_step, t_first, t_fraction, ang, ang_step; LLVector4a pt1,pt2; @@ -628,13 +628,13 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 { if ((end - begin)*ang_scale > 0.5f) { - mConcave = TRUE; + mConcave = true; } else { - mConcave = FALSE; + mConcave = false; } - mOpen = TRUE; + mOpen = true; if (params.getHollow() <= 0) { // put center point if not hollow. @@ -644,8 +644,8 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 else { // The profile isn't open. - mOpen = FALSE; - mConcave = FALSE; + mOpen = false; + mConcave = false; } mTotal = mProfile.size(); @@ -654,7 +654,7 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 // Hollow is percent of the original bounding box, not of this particular // profile's geometry. Thus, a swept triangle needs lower hollow values than // a swept square. -LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) +LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, bool flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) { // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. @@ -693,8 +693,8 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3 } //static -S32 LLProfile::getNumPoints(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, - BOOL is_sculpted, S32 sculpt_size) +S32 LLProfile::getNumPoints(const LLProfileParams& params, bool path_open,F32 detail, S32 split, + bool is_sculpted, S32 sculpt_size) { // this is basically LLProfile::generate stripped down to only operations that influence the number of points if (detail < MIN_LOD) { @@ -850,7 +850,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++) { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); + addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, true); } LLVector4a scale(1,1,4,1); @@ -868,16 +868,16 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai { case LL_PCODE_HOLE_TRIANGLE: // This offset is not correct, but we can't change it now... DK 11/17/04 - addHole(params, TRUE, 3, -0.375f, hollow, 1.f, split); + addHole(params, true, 3, -0.375f, hollow, 1.f, split); break; case LL_PCODE_HOLE_CIRCLE: // TODO: Compute actual detail levels for cubes - addHole(params, FALSE, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); + addHole(params, false, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); break; case LL_PCODE_HOLE_SAME: case LL_PCODE_HOLE_SQUARE: default: - addHole(params, TRUE, 4, -0.375f, hollow, 1.f, split); + addHole(params, true, 4, -0.375f, hollow, 1.f, split); break; } } @@ -907,7 +907,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++) { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); + addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, true); } if (hollow) { @@ -919,15 +919,15 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai { case LL_PCODE_HOLE_CIRCLE: // TODO: Actually generate level of detail for triangles - addHole(params, FALSE, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); + addHole(params, false, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); break; case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 4, 0, triangle_hollow, 1.f, split); + addHole(params, true, 4, 0, triangle_hollow, 1.f, split); break; case LL_PCODE_HOLE_SAME: case LL_PCODE_HOLE_TRIANGLE: default: - addHole(params, TRUE, 3, 0, triangle_hollow, 1.f, split); + addHole(params, true, 3, 0, triangle_hollow, 1.f, split); break; } } @@ -964,11 +964,11 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai if (mOpen && !hollow) { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, FALSE); + addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, false); } else { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, FALSE); + addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, false); } if (hollow) @@ -976,15 +976,15 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai switch (hole_type) { case LL_PCODE_HOLE_SQUARE: - addHole(params, TRUE, 4, 0, hollow, 1.f, split); + addHole(params, true, 4, 0, hollow, 1.f, split); break; case LL_PCODE_HOLE_TRIANGLE: - addHole(params, TRUE, 3, 0, hollow, 1.f, split); + addHole(params, true, 3, 0, hollow, 1.f, split); break; case LL_PCODE_HOLE_CIRCLE: case LL_PCODE_HOLE_SAME: default: - addHole(params, FALSE, circle_detail, 0, hollow, 1.f); + addHole(params, true, circle_detail, 0, hollow, 1.f); break; } } @@ -1291,7 +1291,7 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. - static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + constexpr F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 revolutions = params.getRevolutions(); F32 skew = params.getSkew(); @@ -2025,7 +2025,7 @@ LLProfile::~LLProfile() S32 LLVolume::sNumMeshPoints = 0; -LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) +LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const bool generate_single_face, const bool is_unique) : mParams(params) { mUnique = is_unique; @@ -2036,8 +2036,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mIsMeshAssetLoaded = false; mIsMeshAssetUnavaliable = false; mLODScaleBias.setVec(1,1,1); - mHullPoints = NULL; - mHullIndices = NULL; + mHullPoints = nullptr; + mHullIndices = nullptr; mNumHullPoints = 0; mNumHullIndices = 0; @@ -2857,10 +2857,10 @@ void LLVolume::createVolumeFaces() else { S32 num_faces = getNumFaces(); - BOOL partial_build = TRUE; + bool partial_build = true; if (num_faces != mVolumeFaces.size()) { - partial_build = FALSE; + partial_build = false; mVolumeFaces.resize(num_faces); } // Initialize volume faces with parameter data @@ -3095,9 +3095,9 @@ void LLVolume::sculptGenerateSpherePlaceholder() void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) { U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + bool sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + bool sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + bool reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); @@ -3182,14 +3182,13 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 } -const S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square -const S32 SCULPT_REZ_2 = 8; -const S32 SCULPT_REZ_3 = 16; -const S32 SCULPT_REZ_4 = 32; +constexpr S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square +constexpr S32 SCULPT_REZ_2 = 8; +constexpr S32 SCULPT_REZ_3 = 16; +constexpr S32 SCULPT_REZ_4 = 32; S32 sculpt_sides(F32 detail) { - // detail is usually one of: 1, 1.5, 2.5, 4.0. if (detail <= 1.0) @@ -3252,12 +3251,12 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, { U8 sculpt_type = mParams.getSculptType(); - BOOL data_is_empty = FALSE; + bool data_is_empty = false; if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) { sculpt_level = -1; - data_is_empty = TRUE; + data_is_empty = true; } S32 requested_sizeS = 0; @@ -3265,8 +3264,8 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); - mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS); - mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT); + mPathp->generate(mParams.getPathParams(), mDetail, 0, true, requested_sizeS); + mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, true, requested_sizeT); S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got @@ -3297,7 +3296,7 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA) { - data_is_empty = TRUE; + data_is_empty = true; visible_placeholder = true; } } @@ -3316,8 +3315,6 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, } } - - for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) { mFaceMask |= mProfilep->mFaces[i].mFaceID; @@ -3402,7 +3399,7 @@ void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) } // Less restricitve approx 0 for volumes -const F32 APPROXIMATELY_ZERO = 0.001f; +constexpr F32 APPROXIMATELY_ZERO = 0.001f; bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) { return (f >= -tolerance) && (f <= tolerance); @@ -3658,7 +3655,7 @@ bool LLVolumeParams::setSkew(const F32 skew_value) return valid; } -bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type) +bool LLVolumeParams::setSculptID(const LLUUID& sculpt_id, U8 sculpt_type) { mSculptID = sculpt_id; mSculptType = sculpt_type; @@ -3888,7 +3885,6 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, } else { - //============================================== //DEBUG draw edge map instead of silhouette edge //============================================== @@ -3970,8 +3966,8 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, //DEBUG //============================================== - static const U8 AWAY = 0x01, - TOWARDS = 0x02; + constexpr U8 AWAY = 0x01, + TOWARDS = 0x02; //for each triangle std::vector fFacing; @@ -4241,7 +4237,7 @@ LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) mIndex = index; } -const F32 VERTEX_SLOP = 0.00001f; +constexpr F32 VERTEX_SLOP = 0.00001f; struct lessVertex { @@ -4251,32 +4247,32 @@ struct lessVertex if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) { - return TRUE; + return true; } else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) { - return FALSE; + return false; } if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) { - return TRUE; + return true; } else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) { - return FALSE; + return false; } if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) { - return TRUE; + return true; } else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) { - return FALSE; + return false; } - return FALSE; + return false; } }; @@ -4286,42 +4282,42 @@ struct lessTriangle { if (*a < *b) { - return TRUE; + return true; } else if (*a > *b) { - return FALSE; + return false; } if (*(a+1) < *(b+1)) { - return TRUE; + return true; } else if (*(a+1) > *(b+1)) { - return FALSE; + return false; } if (*(a+2) < *(b+2)) { - return TRUE; + return true; } else if (*(a+2) > *(b+2)) { - return FALSE; + return false; } - return FALSE; + return false; } }; -BOOL equalTriangle(const S32 *a, const S32 *b) +bool equalTriangle(const S32 *a, const S32 *b) { if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) { - return TRUE; + return true; } - return FALSE; + return false; } bool LLVolumeParams::importFile(LLFILE *fp) @@ -4520,7 +4516,7 @@ bool LLVolumeParams::isConvex() const } F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); - BOOL same_hole = hollow == 0.f + bool same_hole = hollow == 0.f || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; @@ -4531,7 +4527,7 @@ bool LLVolumeParams::isConvex() const min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; } - BOOL convex_profile = ( ( profile_length == 1.f + bool convex_profile = ( ( profile_length == 1.f || profile_length <= 0.5f ) && hollow == 0.f ) // trivially convex || ( profile_length <= min_profile_wedge @@ -4797,7 +4793,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) mJustWeights(NULL), mJointIndices(NULL), #endif - mWeightsScrubbed(FALSE), + mWeightsScrubbed(false), mOctree(NULL), mOctreeTriangles(NULL) { @@ -4864,14 +4860,14 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) { llassert(!mWeights); // don't orphan an old alloc here accidentally allocateWeights(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); + LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); mWeightsScrubbed = src.mWeightsScrubbed; } else { - ll_aligned_free_16(mWeights); - mWeights = NULL; - mWeightsScrubbed = FALSE; + ll_aligned_free_16(mWeights); + mWeights = NULL; + mWeightsScrubbed = false; } #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS @@ -4944,7 +4940,7 @@ void LLVolumeFace::freeData() destroyOctree(); } -bool LLVolumeFace::create(LLVolume* volume, BOOL partial_build) +bool LLVolumeFace::create(LLVolume* volume, bool partial_build) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME @@ -5088,7 +5084,7 @@ void LLVolumeFace::optimize(F32 angle_cutoff) LLVolumeFace::VertexData cv; getVertexData(index, cv); - BOOL found = FALSE; + bool found = false; LLVector4a pos; pos.setSub(mPositions[index], mExtents[0]); @@ -5109,7 +5105,7 @@ void LLVolumeFace::optimize(F32 angle_cutoff) LLVolumeFace::VertexData& tv = (point_iter->second)[j]; if (tv.compareNormal(cv, angle_cutoff)) { - found = TRUE; + found = true; new_face.pushIndex((point_iter->second)[j].mIndex); break; } @@ -5216,12 +5212,12 @@ public: } }; -const F64 FindVertexScore_CacheDecayPower = 1.5; -const F64 FindVertexScore_LastTriScore = 0.75; -const F64 FindVertexScore_ValenceBoostScale = 2.0; -const F64 FindVertexScore_ValenceBoostPower = 0.5; -const U32 MaxSizeVertexCache = 32; -const F64 FindVertexScore_Scaler = 1.0/(MaxSizeVertexCache-3); +constexpr F64 FindVertexScore_CacheDecayPower = 1.5; +constexpr F64 FindVertexScore_LastTriScore = 0.75; +constexpr F64 FindVertexScore_ValenceBoostScale = 2.0; +constexpr F64 FindVertexScore_ValenceBoostPower = 0.5; +constexpr U32 MaxSizeVertexCache = 32; +constexpr F64 FindVertexScore_Scaler = 1.0/(MaxSizeVertexCache-3); F64 find_vertex_score(LLVCacheVertexData& data) { @@ -5491,7 +5487,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { //optimize for vertex cache according to Forsyth method: LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; llassert(!mOptimized); - mOptimized = TRUE; + mOptimized = true; if (gen_tangents && mNormals && mTexCoords) { // generate mikkt space tangents before cache optimizing since the index buffer may change @@ -6161,7 +6157,7 @@ bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) //if (partial_build) //{ - // return TRUE; + // return true; //} if (mTypeMask & HOLLOW_MASK) @@ -6684,7 +6680,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) num_vertices = mNumS*mNumT; num_indices = (mNumS-1)*(mNumT-1)*6; - partial_build = (num_vertices > mNumVertices || num_indices > mNumIndices) ? FALSE : partial_build; + partial_build = (num_vertices > mNumVertices || num_indices > mNumIndices) ? false : partial_build; if (!partial_build) { @@ -6855,7 +6851,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) S32 cur_index = 0; S32 cur_edge = 0; - BOOL flat_face = mTypeMask & FLAT_MASK; + bool flat_face = mTypeMask & FLAT_MASK; if (!partial_build) { @@ -6875,7 +6871,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) if (t < mNumT-2) { //top right/top left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; } - else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor + else if (mNumT <= 3 || volume->getPath().isOpen() == true) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on T @@ -6884,7 +6880,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) if (s > 0) { //top left/bottom left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; } - else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor + else if (flat_face || volume->getProfile().isOpen() == true) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on S @@ -6894,7 +6890,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) if (t > 0) { //bottom left/bottom right neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; } - else if (mNumT <= 3 || volume->getPath().isOpen() == TRUE) { //no neighbor + else if (mNumT <= 3 || volume->getPath().isOpen() == true) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on T @@ -6903,7 +6899,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) if (s < mNumS-2) { //bottom right/top right neighbor face mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; } - else if (flat_face || volume->getProfile().isOpen() == TRUE) { //no neighbor + else if (flat_face || volume->getProfile().isOpen() == true) { //no neighbor mEdge[cur_edge++] = -1; } else { //wrap on S @@ -7046,7 +7042,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes { - if (volume->getPath().isOpen() == FALSE) + if (volume->getPath().isOpen() == false) { //wrap normals on T for (S32 i = 0; i < mNumS; i++) { @@ -7057,7 +7053,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) } } - if ((volume->getProfile().isOpen() == FALSE) && !(s_bottom_converges)) + if ((volume->getProfile().isOpen() == false) && !(s_bottom_converges)) { //wrap normals on S for (S32 i = 0; i < mNumT; i++) { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 4ea0604f26..0df46da9d0 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -62,144 +62,144 @@ class LLVolumeTriangle; //============================================================================ -const S32 MIN_DETAIL_FACES = 6; -const S32 MIN_LOD = 0; -const S32 MAX_LOD = 3; +constexpr S32 MIN_DETAIL_FACES = 6; +constexpr S32 MIN_LOD = 0; +constexpr S32 MAX_LOD = 3; // These are defined here but are not enforced at this level, // rather they are here for the convenience of code that uses // the LLVolume class. -const F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; -const F32 MIN_VOLUME_PATH_WIDTH = 0.05f; +constexpr F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; +constexpr F32 MIN_VOLUME_PATH_WIDTH = 0.05f; -const F32 CUT_QUANTA = 0.00002f; -const F32 SCALE_QUANTA = 0.01f; -const F32 SHEAR_QUANTA = 0.01f; -const F32 TAPER_QUANTA = 0.01f; -const F32 REV_QUANTA = 0.015f; -const F32 HOLLOW_QUANTA = 0.00002f; +constexpr F32 CUT_QUANTA = 0.00002f; +constexpr F32 SCALE_QUANTA = 0.01f; +constexpr F32 SHEAR_QUANTA = 0.01f; +constexpr F32 TAPER_QUANTA = 0.01f; +constexpr F32 REV_QUANTA = 0.015f; +constexpr F32 HOLLOW_QUANTA = 0.00002f; -const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; +constexpr S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; //============================================================================ // useful masks -const LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness -const LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) -const LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) -const LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum -const LLPCode LL_PCODE_BASE_MASK = 0x0F; +constexpr LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness +constexpr LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) +constexpr LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) +constexpr LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum +constexpr LLPCode LL_PCODE_BASE_MASK = 0x0F; // primitive shapes -const LLPCode LL_PCODE_CUBE = 1; -const LLPCode LL_PCODE_PRISM = 2; -const LLPCode LL_PCODE_TETRAHEDRON = 3; -const LLPCode LL_PCODE_PYRAMID = 4; -const LLPCode LL_PCODE_CYLINDER = 5; -const LLPCode LL_PCODE_CONE = 6; -const LLPCode LL_PCODE_SPHERE = 7; -const LLPCode LL_PCODE_TORUS = 8; -const LLPCode LL_PCODE_VOLUME = 9; +constexpr LLPCode LL_PCODE_CUBE = 1; +constexpr LLPCode LL_PCODE_PRISM = 2; +constexpr LLPCode LL_PCODE_TETRAHEDRON = 3; +constexpr LLPCode LL_PCODE_PYRAMID = 4; +constexpr LLPCode LL_PCODE_CYLINDER = 5; +constexpr LLPCode LL_PCODE_CONE = 6; +constexpr LLPCode LL_PCODE_SPHERE = 7; +constexpr LLPCode LL_PCODE_TORUS = 8; +constexpr LLPCode LL_PCODE_VOLUME = 9; // surfaces -//const LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; -//const LLPCode LL_PCODE_SURFACE_SQUARE = 11; -//const LLPCode LL_PCODE_SURFACE_DISC = 12; +//constexpr LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; +//constexpr LLPCode LL_PCODE_SURFACE_SQUARE = 11; +//constexpr LLPCode LL_PCODE_SURFACE_DISC = 12; -const LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) -const LLPCode LL_PCODE_LEGACY = 15; +constexpr LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) +constexpr LLPCode LL_PCODE_LEGACY = 15; // Pcodes for legacy objects -//const LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR -const LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER -//const LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD -//const LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON -const LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS -const LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees -//const LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE -const LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS -const LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK -//const LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT -//const LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; -//const LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE -//const LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK -const LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE -const LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE +//constexpr LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR +constexpr LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER +//constexpr LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD +//constexpr LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON +constexpr LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS +constexpr LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees +//constexpr LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE +constexpr LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS +constexpr LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK +//constexpr LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT +//constexpr LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; +//constexpr LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE +//constexpr LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK +constexpr LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE +constexpr LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE // hemis -const LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; -const LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; // Volumes consist of a profile at the base that is swept around // a path to make a volume. // The profile code -const U8 LL_PCODE_PROFILE_MASK = 0x0f; -const U8 LL_PCODE_PROFILE_MIN = 0x00; -const U8 LL_PCODE_PROFILE_CIRCLE = 0x00; -const U8 LL_PCODE_PROFILE_SQUARE = 0x01; -const U8 LL_PCODE_PROFILE_ISOTRI = 0x02; -const U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; -const U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; -const U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; -const U8 LL_PCODE_PROFILE_MAX = 0x05; +constexpr U8 LL_PCODE_PROFILE_MASK = 0x0f; +constexpr U8 LL_PCODE_PROFILE_MIN = 0x00; +constexpr U8 LL_PCODE_PROFILE_CIRCLE = 0x00; +constexpr U8 LL_PCODE_PROFILE_SQUARE = 0x01; +constexpr U8 LL_PCODE_PROFILE_ISOTRI = 0x02; +constexpr U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; +constexpr U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; +constexpr U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; +constexpr U8 LL_PCODE_PROFILE_MAX = 0x05; // Stored in the profile byte -const U8 LL_PCODE_HOLE_MASK = 0xf0; -const U8 LL_PCODE_HOLE_MIN = 0x00; -const U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile -const U8 LL_PCODE_HOLE_CIRCLE = 0x10; -const U8 LL_PCODE_HOLE_SQUARE = 0x20; -const U8 LL_PCODE_HOLE_TRIANGLE = 0x30; -const U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max - -const U8 LL_PCODE_PATH_IGNORE = 0x00; -const U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max -const U8 LL_PCODE_PATH_LINE = 0x10; -const U8 LL_PCODE_PATH_CIRCLE = 0x20; -const U8 LL_PCODE_PATH_CIRCLE2 = 0x30; -const U8 LL_PCODE_PATH_TEST = 0x40; -const U8 LL_PCODE_PATH_FLEXIBLE = 0x80; -const U8 LL_PCODE_PATH_MAX = 0x08; +constexpr U8 LL_PCODE_HOLE_MASK = 0xf0; +constexpr U8 LL_PCODE_HOLE_MIN = 0x00; +constexpr U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile +constexpr U8 LL_PCODE_HOLE_CIRCLE = 0x10; +constexpr U8 LL_PCODE_HOLE_SQUARE = 0x20; +constexpr U8 LL_PCODE_HOLE_TRIANGLE = 0x30; +constexpr U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max + +constexpr U8 LL_PCODE_PATH_IGNORE = 0x00; +constexpr U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max +constexpr U8 LL_PCODE_PATH_LINE = 0x10; +constexpr U8 LL_PCODE_PATH_CIRCLE = 0x20; +constexpr U8 LL_PCODE_PATH_CIRCLE2 = 0x30; +constexpr U8 LL_PCODE_PATH_TEST = 0x40; +constexpr U8 LL_PCODE_PATH_FLEXIBLE = 0x80; +constexpr U8 LL_PCODE_PATH_MAX = 0x08; //============================================================================ // face identifiers typedef U16 LLFaceID; -const LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; -const LLFaceID LL_FACE_PATH_END = 0x1 << 1; -const LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; -const LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; -const LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; -const LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; -const LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; -const LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; -const LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; +constexpr LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; +constexpr LLFaceID LL_FACE_PATH_END = 0x1 << 1; +constexpr LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; +constexpr LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; +constexpr LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; +constexpr LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; +constexpr LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; +constexpr LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; +constexpr LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; //============================================================================ // sculpt types + flags -const U8 LL_SCULPT_TYPE_NONE = 0; -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_MESH = 5; -const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | +constexpr U8 LL_SCULPT_TYPE_NONE = 0; +constexpr U8 LL_SCULPT_TYPE_SPHERE = 1; +constexpr U8 LL_SCULPT_TYPE_TORUS = 2; +constexpr U8 LL_SCULPT_TYPE_PLANE = 3; +constexpr U8 LL_SCULPT_TYPE_CYLINDER = 4; +constexpr U8 LL_SCULPT_TYPE_MESH = 5; +constexpr 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; // for value checks, assign new value after adding new types -const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; +constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; -const U8 LL_SCULPT_FLAG_INVERT = 64; -const U8 LL_SCULPT_FLAG_MIRROR = 128; -const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; +constexpr U8 LL_SCULPT_FLAG_INVERT = 64; +constexpr U8 LL_SCULPT_FLAG_MIRROR = 128; +constexpr U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; -const S32 LL_SCULPT_MESH_MAX_FACES = 8; +constexpr S32 LL_SCULPT_MESH_MAX_FACES = 8; extern bool gDebugGL; @@ -620,7 +620,7 @@ public: bool setRevolutions(const F32 revolutions); // 1 to 4 bool setRadiusOffset(const F32 radius_offset); bool setSkew(const F32 skew); - bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type); + bool setSculptID(const LLUUID& sculpt_id, U8 sculpt_type); static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, U8 path_curve, F32 path_begin, F32 path_end, @@ -697,12 +697,12 @@ public: S32 getTotal() const { return mTotal; } S32 getTotalOut() const { return mTotalOut; } // Total number of outside points - BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); } - BOOL isOpen() const { return mOpen; } - void setDirty() { mDirty = TRUE; } + bool isFlat(S32 face) const { return (mFaces[face].mCount == 2); } + bool isOpen() const { return mOpen; } + void setDirty() { mDirty = true; } - static S32 getNumPoints(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, - BOOL is_sculpted = FALSE, S32 sculpt_size = 0); + static S32 getNumPoints(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); bool generate(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, bool is_sculpted = false, S32 sculpt_size = 0); bool isConcave() const { return mConcave; } @@ -712,8 +712,8 @@ public: S32 mIndex; S32 mCount; F32 mScaleU; - BOOL mCap; - BOOL mFlat; + bool mCap; + bool mFlat; LLFaceID mFaceID; }; @@ -732,14 +732,14 @@ protected: static S32 getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); - Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); + Face* addHole(const LLProfileParams& params, bool flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); Face* addCap (S16 faceID); - Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat); + Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, bool flat); protected: - BOOL mOpen; - BOOL mConcave; - BOOL mDirty; + bool mOpen; + bool mConcave; + bool mDirty; S32 mTotalOut; S32 mTotal; @@ -795,9 +795,9 @@ public: virtual bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, bool is_sculpted = false, S32 sculpt_size = 0); - BOOL isOpen() const { return mOpen; } + bool isOpen() const { return mOpen; } F32 getStep() const { return mStep; } - void setDirty() { mDirty = TRUE; } + void setDirty() { mDirty = true; } S32 getPathLength() const { return (S32)mPath.size(); } @@ -809,9 +809,9 @@ public: LLAlignedArray mPath; protected: - BOOL mOpen; + bool mOpen; S32 mTotal; - BOOL mDirty; + bool mDirty; F32 mStep; }; @@ -870,7 +870,7 @@ private: void freeData(); public: - bool create(LLVolume* volume, BOOL partial_build = FALSE); + bool create(LLVolume* volume, bool partial_build = false); void createTangents(); void resizeVertices(S32 num_verts); @@ -972,14 +972,14 @@ public: U8* mJointIndices; #endif - mutable BOOL mWeightsScrubbed; + mutable bool mWeightsScrubbed; // Which joints are rigged to, and the bounding box of any rigged // vertices per joint. LLJointRiggingInfoTab mJointRiggingInfoTab; //whether or not face has been cache optimized - BOOL mOptimized; + bool mOptimized; // if this is a mesh asset, scale and translation that were applied // when encoding the source mesh into a unit cube @@ -1014,7 +1014,7 @@ public: S32 mCountT; }; - LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE); + LLVolume(const LLVolumeParams ¶ms, const F32 detail, const bool generate_single_face = false, const bool is_unique = false); U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } U8 getPathType() const { return mParams.getPathParams().getCurveType(); } @@ -1047,7 +1047,7 @@ public: static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts); - S32 getNumTriangles(S32* vcount = NULL) const; + S32 getNumTriangles(S32* vcount = nullptr) const; void generateSilhouetteVertices(std::vector &vertices, std::vector &normals, @@ -1061,10 +1061,10 @@ public: //Line segment must be in volume space. S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES - LLVector4a* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector4a* normal = NULL, // return the surface normal at the intersection point - LLVector4a* tangent = NULL // return the surface tangent at the intersection point + LLVector4a* intersection = nullptr, // return the intersection point + LLVector2* tex_coord = nullptr, // return the texture coordinates of the intersection point + LLVector4a* normal = nullptr, // return the surface normal at the intersection point + LLVector4a* tangent = nullptr // return the surface tangent at the intersection point ); LLFaceID generateFaceMask(); @@ -1115,7 +1115,7 @@ public: virtual bool isMeshAssetUnavaliable(); protected: - BOOL mUnique; + bool mUnique; F32 mDetail; S32 mSculptLevel; F32 mSurfaceArea; //unscaled surface area diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index 65eb3348de..c7777164c0 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -528,10 +528,10 @@ bool operator==(const LLMatrix3 &a, const LLMatrix3 &b) for (j = 0; j < NUM_VALUES_IN_MAT3; j++) { if (a.mMatrix[j][i] != b.mMatrix[j][i]) - return FALSE; + return false; } } - return TRUE; + return true; } bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b) @@ -542,10 +542,10 @@ bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b) for (j = 0; j < NUM_VALUES_IN_MAT3; j++) { if (a.mMatrix[j][i] != b.mMatrix[j][i]) - return TRUE; + return true; } } - return FALSE; + return false; } const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b) diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 6e40dae30b..ee4f607442 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -744,10 +744,10 @@ bool operator==(const LLMatrix4 &a, const LLMatrix4 &b) for (j = 0; j < NUM_VALUES_IN_MAT4; j++) { if (a.mMatrix[j][i] != b.mMatrix[j][i]) - return FALSE; + return false; } } - return TRUE; + return true; } bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b) @@ -758,10 +758,10 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b) for (j = 0; j < NUM_VALUES_IN_MAT4; j++) { if (a.mMatrix[j][i] != b.mMatrix[j][i]) - return TRUE; + return true; } } - return FALSE; + return false; } bool operator<(const LLMatrix4& a, const LLMatrix4 &b) diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index c3956e9995..125374a4c2 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -242,7 +242,7 @@ bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, if (dot > 0.0f) { // ray points away from cylinder bottom - return FALSE; + return false; } // ray hit bottom of cylinder from outside intersection = ray_point - shortest_distance * cyl_axis; diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index 3f7014c1b9..df14a9a487 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -117,12 +117,12 @@ U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction, /* TODO -BOOL ray_ellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_ellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_cone(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_cone(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &cone_tip, const LLVector3 &cone_bottom, const LLVector3 &cone_scale, const LLQuaternion &cone_rotation, LLVector3 &intersection, LLVector3 &intersection_normal); @@ -146,24 +146,24 @@ bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, /* TODO -BOOL ray_hemiellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_hemiellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation, const LLVector3 &e_cut_normal, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_hemisphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_hemisphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &sphere_center, F32 sphere_radius, const LLVector3 &sphere_cut_normal, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_hemicylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_hemicylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &cyl_top, const LLVector3 &cyl_bottom, F32 cyl_radius, const LLVector3 &cyl_cut_normal, LLVector3 &intersection, LLVector3 &intersection_normal); -BOOL ray_hemicone(const LLVector3 &ray_point, const LLVector3 &ray_direction, +bool ray_hemicone(const LLVector3 &ray_point, const LLVector3 &ray_direction, const LLVector3 &cone_tip, const LLVector3 &cone_bottom, const LLVector3 &cone_scale, const LLVector3 &cyl_cut_normal, LLVector3 &intersection, LLVector3 &intersection_normal); diff --git a/indra/llmath/xform.cpp b/indra/llmath/xform.cpp index 8999abda60..838dee0a54 100644 --- a/indra/llmath/xform.cpp +++ b/indra/llmath/xform.cpp @@ -86,7 +86,7 @@ void LLXformMatrix::update() } } -void LLXformMatrix::updateMatrix(BOOL update_bounds) +void LLXformMatrix::updateMatrix(bool update_bounds) { update(); diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 96c4ab4d51..a301e4ca47 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -30,12 +30,12 @@ #include "m4math.h" #include "llquaternion.h" -const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f -const F32 MIN_OBJECT_Z = -256.f; -const F32 DEFAULT_MAX_PRIM_SCALE = 64.f; -const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f; -const F32 MIN_PRIM_SCALE = 0.01f; -const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX +constexpr F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f +constexpr F32 MIN_OBJECT_Z = -256.f; +constexpr F32 DEFAULT_MAX_PRIM_SCALE = 64.f; +constexpr F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f; +constexpr F32 MIN_PRIM_SCALE = 0.01f; +constexpr F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX class LLXform { @@ -52,7 +52,7 @@ protected: LLXform* mParent; U32 mChanged; - BOOL mScaleChildOffset; + bool mScaleChildOffset; public: typedef enum e_changed_flags @@ -78,7 +78,7 @@ public: mScale. setVec(1,1,1); mWorldPosition.clearVec(); mWorldRotation.loadIdentity(); - mScaleChildOffset = FALSE; + mScaleChildOffset = false; } LLXform(); @@ -109,13 +109,13 @@ public: void warn(const char* const msg); void setChanged(const U32 bits) { mChanged |= bits; } - BOOL isChanged() const { return mChanged; } - BOOL isChanged(const U32 bits) const { return mChanged & bits; } + bool isChanged() const { return mChanged; } + bool isChanged(const U32 bits) const { return mChanged & bits; } void clearChanged() { mChanged = 0; } void clearChanged(U32 bits) { mChanged &= ~bits; } - void setScaleChildOffset(BOOL scale) { mScaleChildOffset = scale; } - BOOL getScaleChildOffset() { return mScaleChildOffset; } + void setScaleChildOffset(bool scale) { mScaleChildOffset = scale; } + bool getScaleChildOffset() { return mScaleChildOffset; } LLXform* getParent() const { return mParent; } LLXform* getRoot() const; @@ -149,7 +149,7 @@ public: } void update(); - void updateMatrix(BOOL update_bounds = TRUE); + void updateMatrix(bool update_bounds = true); void getMinMax(LLVector3& min,LLVector3& max) const; protected: -- cgit v1.2.3 From b2c271367296744fbbe2262e55d0ea4f8f5ccdc9 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 20 Feb 2024 00:50:39 +0100 Subject: Convert BOOL to bool in llrender --- indra/llmath/raytrace.h | 4 ++-- indra/llmath/tests/xform_test.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index df14a9a487..f620e48459 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -105,7 +105,7 @@ bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, LLVector3 &intersection, LLVector3 &intersection_normal); -// this function doesn't just return a BOOL because the return is currently +// this function doesn't just return a bool because the return is currently // used to decide how to break up boxes that have been hit by shots... // a hack that will probably be changed later // @@ -202,7 +202,7 @@ bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, LLVector3 &intersection, LLVector3 &intersection_normal); -// this function doesn't just return a BOOL because the return is currently +// this function doesn't just return a bool because the return is currently // used to decide how to break up boxes that have been hit by shots... // a hack that will probably be changed later // diff --git a/indra/llmath/tests/xform_test.cpp b/indra/llmath/tests/xform_test.cpp index 49870eef3c..50e24c9d4f 100644 --- a/indra/llmath/tests/xform_test.cpp +++ b/indra/llmath/tests/xform_test.cpp @@ -121,7 +121,7 @@ namespace tut // Is that the expected behavior? } - // test cases for inline BOOL setParent(LLXform *parent) and getParent() fn. + // test cases for inline bool setParent(LLXform *parent) and getParent() fn. template<> template<> void xform_test_object_t::test<3>() { -- cgit v1.2.3 From 60d3dd98a44230c21803c1606552ee098ed9fa7c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 21 Feb 2024 21:05:14 +0100 Subject: Convert remaining BOOL to bool --- indra/llmath/tests/llbbox_test.cpp | 20 ++++++++++---------- indra/llmath/tests/llrect_test.cpp | 28 ++++++++++++++-------------- indra/llmath/tests/v2math_test.cpp | 14 +++++++------- indra/llmath/tests/v3color_test.cpp | 2 +- indra/llmath/tests/v3dmath_test.cpp | 20 ++++++++++---------- indra/llmath/tests/v3math_test.cpp | 24 ++++++++++++------------ indra/llmath/tests/v4coloru_test.cpp | 4 ++-- indra/llmath/tests/v4math_test.cpp | 8 ++++---- indra/llmath/tests/xform_test.cpp | 4 ++-- 9 files changed, 62 insertions(+), 62 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/tests/llbbox_test.cpp b/indra/llmath/tests/llbbox_test.cpp index fd0dbb58fc..373e2d02a0 100644 --- a/indra/llmath/tests/llbbox_test.cpp +++ b/indra/llmath/tests/llbbox_test.cpp @@ -340,11 +340,11 @@ namespace tut LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); - ensure("containsPointLocal(0,0,0)", bbox1.containsPointLocal(LLVector3(0.0f, 0.0f, 0.0f)) == FALSE); - ensure("containsPointLocal(1,2,3)", bbox1.containsPointLocal(LLVector3(1.0f, 2.0f, 3.0f)) == TRUE); - ensure("containsPointLocal(0.999,2,3)", bbox1.containsPointLocal(LLVector3(0.999f, 2.0f, 3.0f)) == FALSE); - ensure("containsPointLocal(3,4,5)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.0f)) == TRUE); - ensure("containsPointLocal(3,4,5.001)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.001f)) == FALSE); + ensure("containsPointLocal(0,0,0)", bbox1.containsPointLocal(LLVector3(0.0f, 0.0f, 0.0f)) == false); + ensure("containsPointLocal(1,2,3)", bbox1.containsPointLocal(LLVector3(1.0f, 2.0f, 3.0f)) == true); + ensure("containsPointLocal(0.999,2,3)", bbox1.containsPointLocal(LLVector3(0.999f, 2.0f, 3.0f)) == false); + ensure("containsPointLocal(3,4,5)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.0f)) == true); + ensure("containsPointLocal(3,4,5.001)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.001f)) == false); } template<> template<> @@ -357,11 +357,11 @@ namespace tut LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); - ensure("containsPointAgent(0,0,0)", bbox1.containsPointAgent(LLVector3(0.0f, 0.0f, 0.0f)) == FALSE); - ensure("containsPointAgent(2,3,4)", bbox1.containsPointAgent(LLVector3(2.0f, 3.0f, 4.0f)) == TRUE); - ensure("containsPointAgent(2,2.999,4)", bbox1.containsPointAgent(LLVector3(2.0f, 2.999f, 4.0f)) == FALSE); - ensure("containsPointAgent(4,5,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.0f, 6.0f)) == TRUE); - ensure("containsPointAgent(4,5.001,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.001f, 6.0f)) == FALSE); + ensure("containsPointAgent(0,0,0)", bbox1.containsPointAgent(LLVector3(0.0f, 0.0f, 0.0f)) == false); + ensure("containsPointAgent(2,3,4)", bbox1.containsPointAgent(LLVector3(2.0f, 3.0f, 4.0f)) == true); + ensure("containsPointAgent(2,2.999,4)", bbox1.containsPointAgent(LLVector3(2.0f, 2.999f, 4.0f)) == false); + ensure("containsPointAgent(4,5,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.0f, 6.0f)) == true); + ensure("containsPointAgent(4,5.001,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.001f, 6.0f)) == false); } } diff --git a/indra/llmath/tests/llrect_test.cpp b/indra/llmath/tests/llrect_test.cpp index d740173e69..365f298636 100644 --- a/indra/llmath/tests/llrect_test.cpp +++ b/indra/llmath/tests/llrect_test.cpp @@ -471,13 +471,13 @@ namespace tut LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); - ensure("(0,0) not in rect", rect.pointInRect(0.0f, 0.0f) == FALSE); - ensure("(2,2) in rect", rect.pointInRect(2.0f, 2.0f) == TRUE); - ensure("(1,1) in rect", rect.pointInRect(1.0f, 1.0f) == TRUE); - ensure("(3,3) not in rect", rect.pointInRect(3.0f, 3.0f) == FALSE); - ensure("(2.999,2.999) in rect", rect.pointInRect(2.999f, 2.999f) == TRUE); - ensure("(2.999,3.0) not in rect", rect.pointInRect(2.999f, 3.0f) == FALSE); - ensure("(3.0,2.999) not in rect", rect.pointInRect(3.0f, 2.999f) == FALSE); + ensure("(0,0) not in rect", rect.pointInRect(0.0f, 0.0f) == false); + ensure("(2,2) in rect", rect.pointInRect(2.0f, 2.0f) == true); + ensure("(1,1) in rect", rect.pointInRect(1.0f, 1.0f) == true); + ensure("(3,3) not in rect", rect.pointInRect(3.0f, 3.0f) == false); + ensure("(2.999,2.999) in rect", rect.pointInRect(2.999f, 2.999f) == true); + ensure("(2.999,3.0) not in rect", rect.pointInRect(2.999f, 3.0f) == false); + ensure("(3.0,2.999) not in rect", rect.pointInRect(3.0f, 2.999f) == false); } template<> template<> @@ -489,13 +489,13 @@ namespace tut LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); - ensure("(0,0) in local rect", rect.localPointInRect(0.0f, 0.0f) == TRUE); - ensure("(-0.0001,-0.0001) not in local rect", rect.localPointInRect(-0.0001f, -0.001f) == FALSE); - ensure("(1,1) in local rect", rect.localPointInRect(1.0f, 1.0f) == TRUE); - ensure("(2,2) not in local rect", rect.localPointInRect(2.0f, 2.0f) == FALSE); - ensure("(1.999,1.999) in local rect", rect.localPointInRect(1.999f, 1.999f) == TRUE); - ensure("(1.999,2.0) not in local rect", rect.localPointInRect(1.999f, 2.0f) == FALSE); - ensure("(2.0,1.999) not in local rect", rect.localPointInRect(2.0f, 1.999f) == FALSE); + ensure("(0,0) in local rect", rect.localPointInRect(0.0f, 0.0f) == true); + ensure("(-0.0001,-0.0001) not in local rect", rect.localPointInRect(-0.0001f, -0.001f) == false); + ensure("(1,1) in local rect", rect.localPointInRect(1.0f, 1.0f) == true); + ensure("(2,2) not in local rect", rect.localPointInRect(2.0f, 2.0f) == false); + ensure("(1.999,1.999) in local rect", rect.localPointInRect(1.999f, 1.999f) == true); + ensure("(1.999,2.0) not in local rect", rect.localPointInRect(1.999f, 2.0f) == false); + ensure("(2.0,1.999) not in local rect", rect.localPointInRect(2.0f, 1.999f) == false); } template<> template<> diff --git a/indra/llmath/tests/v2math_test.cpp b/indra/llmath/tests/v2math_test.cpp index 4d6a2eca93..06e1292941 100644 --- a/indra/llmath/tests/v2math_test.cpp +++ b/indra/llmath/tests/v2math_test.cpp @@ -93,15 +93,15 @@ namespace tut { F32 x =-2.0f, y = -3.0f ; LLVector2 vec2(x,y); - ensure_equals("abs():Fail", vec2.abs(), TRUE); + ensure_equals("abs():Fail", vec2.abs(), true); ensure("abs() x", is_approx_equal(vec2.mV[VX], 2.f)); ensure("abs() y", is_approx_equal(vec2.mV[VY], 3.f)); - ensure("isNull():Fail ", FALSE == vec2.isNull()); //Returns TRUE if vector has a _very_small_ length + ensure("isNull():Fail ", false == vec2.isNull()); //Returns true if vector has a _very_small_ length x =.00000001f, y = .000001001f; vec2.setVec(x, y); - ensure("isNull(): Fail ", TRUE == vec2.isNull()); + ensure("isNull(): Fail ", true == vec2.isNull()); } template<> template<> @@ -111,12 +111,12 @@ namespace tut LLVector2 vec2(x, y), vec3; vec3 = vec3.scaleVec(vec2); ensure("scaleVec: Fail ", vec3.mV[VX] == 0. && vec3.mV[VY] == 0.); - ensure("isExactlyZero(): Fail", TRUE == vec3.isExactlyZero()); + ensure("isExactlyZero(): Fail", true == vec3.isExactlyZero()); vec3.setVec(2.f, 1.f); vec3 = vec3.scaleVec(vec2); ensure("scaleVec: Fail ", (2.f == vec3.mV[VX]) && (2.f == vec3.mV[VY])); - ensure("isExactlyZero():Fail", FALSE == vec3.isExactlyZero()); + ensure("isExactlyZero():Fail", false == vec3.isExactlyZero()); } template<> template<> @@ -254,7 +254,7 @@ namespace tut vec3.clearVec(); vec2.setVec(x1, y1); vec3.setVec(vec2); - ensure("2:operator!= failed", (FALSE == (vec2 != vec3))); + ensure("2:operator!= failed", (false == (vec2 != vec3))); } template<> template<> void v2math_object::test<13>() @@ -373,7 +373,7 @@ namespace tut x1 = 1.0f, y1 = 2.0f, x2 = 1.0f, y2 = 3.2234f; vec2.setVec(x1, y1); vec3.setVec(x2, y2); - ensure("2:operator < failed", (FALSE == (vec3 < vec2))); + ensure("2:operator < failed", (false == (vec3 < vec2))); } template<> template<> diff --git a/indra/llmath/tests/v3color_test.cpp b/indra/llmath/tests/v3color_test.cpp index 29d1c483ab..0fb52394a5 100644 --- a/indra/llmath/tests/v3color_test.cpp +++ b/indra/llmath/tests/v3color_test.cpp @@ -209,7 +209,7 @@ namespace tut ensure("1:operator!= failed",(llcolor3 != llcolor3a)); llcolor3.setToBlack(); llcolor3a.setVec(llcolor3); - ensure("2:operator!= failed", ( FALSE == (llcolor3a != llcolor3))); + ensure("2:operator!= failed", ( false == (llcolor3a != llcolor3))); } template<> template<> diff --git a/indra/llmath/tests/v3dmath_test.cpp b/indra/llmath/tests/v3dmath_test.cpp index c4744e1b25..0c8c01a77a 100644 --- a/indra/llmath/tests/v3dmath_test.cpp +++ b/indra/llmath/tests/v3dmath_test.cpp @@ -128,15 +128,15 @@ namespace tut LLVector3d vec3D(x,y,z); vec3D.abs(); ensure("1:abs:Fail ", ((-x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (-z == vec3D.mdV[VZ]))); - ensure("2:isNull():Fail ", (FALSE == vec3D.isNull())); + ensure("2:isNull():Fail ", (false == vec3D.isNull())); vec3D.clearVec(); x =.00000001, y = .000001001, z = .000001001; vec3D.setVec(x,y,z); - ensure("3:isNull():Fail ", (TRUE == vec3D.isNull())); - ensure("4:isExactlyZero():Fail ", (FALSE == vec3D.isExactlyZero())); + ensure("3:isNull():Fail ", (true == vec3D.isNull())); + ensure("4:isExactlyZero():Fail ", (false == vec3D.isExactlyZero())); x =.0000000, y = .00000000, z = .00000000; vec3D.setVec(x,y,z); - ensure("5:isExactlyZero():Fail ", (TRUE == vec3D.isExactlyZero())); + ensure("5:isExactlyZero():Fail ", (true == vec3D.isExactlyZero())); } template<> template<> @@ -353,7 +353,7 @@ namespace tut { F64 x1 = 1., y1 = 2., z1 = -1.1; LLVector3d vec3D(x1,y1,z1), vec3Da; - ensure("1:operator!= failed",(TRUE == (vec3D !=vec3Da))); + ensure("1:operator!= failed",(true == (vec3D !=vec3Da))); vec3Da = vec3D; ensure("2:operator== failed",(vec3D ==vec3Da)); vec3D.clearVec(); @@ -362,7 +362,7 @@ namespace tut vec3D.setVec(x1,y1,z1); vec3Da.setVec(x1,y1,z1); ensure("3:operator== failed",(vec3D ==vec3Da)); - ensure("4:operator!= failed",(FALSE == (vec3D !=vec3Da))); + ensure("4:operator!= failed",(false == (vec3D !=vec3Da))); } template<> template<> @@ -482,10 +482,10 @@ namespace tut F64 x = 2.32, y = 1.212, z = -.12; F64 min = 0.0001, max = 3.0; LLVector3d vec3d(x,y,z); - ensure("1:clamp:Fail ", (TRUE == (vec3d.clamp(min, max)))); + ensure("1:clamp:Fail ", (true == (vec3d.clamp(min, max)))); x = 0.000001f, z = 5.3f; vec3d.setVec(x,y,z); - ensure("2:clamp:Fail ", (TRUE == (vec3d.clamp(min, max)))); + ensure("2:clamp:Fail ", (true == (vec3d.clamp(min, max)))); } template<> template<> @@ -494,11 +494,11 @@ namespace tut F64 x = 10., y = 20., z = -15.; F64 epsilon = .23425; LLVector3d vec3Da(x,y,z), vec3Db(x,y,z); - ensure("1:are_parallel: Fail ", (TRUE == are_parallel(vec3Da,vec3Db,epsilon))); + ensure("1:are_parallel: Fail ", (true == are_parallel(vec3Da,vec3Db,epsilon))); F64 x1 = -12., y1 = -20., z1 = -100.; vec3Db.clearVec(); vec3Db.setVec(x1,y1,z1); - ensure("2:are_parallel: Fail ", (FALSE == are_parallel(vec3Da,vec3Db,epsilon))); + ensure("2:are_parallel: Fail ", (false == are_parallel(vec3Da,vec3Db,epsilon))); } template<> template<> diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp index e4ae1c10ef..b1831af1cc 100644 --- a/indra/llmath/tests/v3math_test.cpp +++ b/indra/llmath/tests/v3math_test.cpp @@ -99,7 +99,7 @@ namespace tut { F32 x = 2.32f, y = 1.212f, z = -.12f; LLVector3 vec3(x,y,z); - ensure("1:isFinite= Fail to initialize ", (TRUE == vec3.isFinite()));//need more test cases: + ensure("1:isFinite= Fail to initialize ", (true == vec3.isFinite()));//need more test cases: vec3.clearVec(); ensure("2:clearVec:Fail to set values ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); vec3.setVec(x,y,z); @@ -137,10 +137,10 @@ namespace tut F32 x = 2.32f, y = 3.212f, z = -.12f; F32 min = 0.0001f, max = 3.0f; LLVector3 vec3(x,y,z); - ensure("1:clamp:Fail ", TRUE == vec3.clamp(min, max) && x == vec3.mV[VX] && max == vec3.mV[VY] && min == vec3.mV[VZ]); + ensure("1:clamp:Fail ", true == vec3.clamp(min, max) && x == vec3.mV[VX] && max == vec3.mV[VY] && min == vec3.mV[VZ]); x = 1.f, y = 2.2f, z = 2.8f; vec3.setVec(x,y,z); - ensure("2:clamp:Fail ", FALSE == vec3.clamp(min, max)); + ensure("2:clamp:Fail ", false == vec3.clamp(min, max)); } template<> template<> @@ -157,11 +157,11 @@ namespace tut { F32 x =-2.0f, y = -3.0f, z = 1.23f ; LLVector3 vec3(x,y,z); - ensure("1:abs():Fail ", (TRUE == vec3.abs())); - ensure("2:isNull():Fail", (FALSE == vec3.isNull())); //Returns TRUE if vector has a _very_small_ length + ensure("1:abs():Fail ", (true == vec3.abs())); + ensure("2:isNull():Fail", (false == vec3.isNull())); //Returns TRUE if vector has a _very_small_ length x =.00000001f, y = .000001001f, z = .000001001f; vec3.setVec(x,y,z); - ensure("3:isNull(): Fail ", (TRUE == vec3.isNull())); + ensure("3:isNull(): Fail ", (true == vec3.isNull())); } template<> template<> @@ -169,13 +169,13 @@ namespace tut { F32 x =-2.0f, y = -3.0f, z = 1.f ; LLVector3 vec3(x,y,z),vec3a; - ensure("1:isExactlyZero():Fail ", (TRUE == vec3a.isExactlyZero())); + ensure("1:isExactlyZero():Fail ", (true == vec3a.isExactlyZero())); vec3a = vec3a.scaleVec(vec3); ensure("2:scaleVec: Fail ", vec3a.mV[VX] == 0.f && vec3a.mV[VY] == 0.f && vec3a.mV[VZ] == 0.f); vec3a.setVec(x,y,z); vec3a = vec3a.scaleVec(vec3); ensure("3:scaleVec: Fail ", ((4 == vec3a.mV[VX]) && (9 == vec3a.mV[VY]) &&(1 == vec3a.mV[VZ]))); - ensure("4:isExactlyZero():Fail ", (FALSE == vec3.isExactlyZero())); + ensure("4:isExactlyZero():Fail ", (false == vec3.isExactlyZero())); } template<> template<> @@ -356,7 +356,7 @@ namespace tut vec3.clearVec(); vec3.clearVec(); vec3a.setVec(vec3); - ensure("2:operator!= failed", ( FALSE == (vec3a != vec3))); + ensure("2:operator!= failed", ( false == (vec3a != vec3))); } template<> template<> @@ -454,15 +454,15 @@ namespace tut { F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.11f, z2 = 1234.234f; LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - ensure("1:operator< failed", (TRUE == (vec3 < vec3a))); + ensure("1:operator< failed", (true == (vec3 < vec3a))); x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 2.f, z2 = 1234.234f; vec3.setVec(x1,y1,z1); vec3a.setVec(x2,y2,z2); - ensure("2:operator< failed ", (TRUE == (vec3 < vec3a))); + ensure("2:operator< failed ", (true == (vec3 < vec3a))); x1 =2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, vec3.setVec(x1,y1,z1); vec3a.setVec(x2,y2,z2); - ensure("3:operator< failed ", (FALSE == (vec3 < vec3a))); + ensure("3:operator< failed ", (false == (vec3 < vec3a))); } template<> template<> diff --git a/indra/llmath/tests/v4coloru_test.cpp b/indra/llmath/tests/v4coloru_test.cpp index 12e607a820..1d3aa4c63d 100644 --- a/indra/llmath/tests/v4coloru_test.cpp +++ b/indra/llmath/tests/v4coloru_test.cpp @@ -287,10 +287,10 @@ namespace tut ensure("parseColor4U() failed to parse the color value ", ((12 == llcolor4u1.mV[VX]) && (23 == llcolor4u1.mV[VY]) && (132 == llcolor4u1.mV[VZ])&& (50 == llcolor4u1.mV[VW]))); color = "12, 23, 132"; - ensure("2:parseColor4U() failed to parse the color value ", (FALSE == LLColor4U::parseColor4U(color, &llcolor4u1))); + ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); color = "12"; - ensure("2:parseColor4U() failed to parse the color value ", (FALSE == LLColor4U::parseColor4U(color, &llcolor4u1))); + ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); } template<> template<> diff --git a/indra/llmath/tests/v4math_test.cpp b/indra/llmath/tests/v4math_test.cpp index 9779dfded3..5308e7efd4 100644 --- a/indra/llmath/tests/v4math_test.cpp +++ b/indra/llmath/tests/v4math_test.cpp @@ -123,9 +123,9 @@ namespace tut vec4.abs(); ensure("abs:Fail " ,((x == vec4.mV[VX]) && (-y == vec4.mV[VY]) && (-z == vec4.mV[VZ])&& (-w == vec4.mV[VW]))); vec4.clearVec(); - ensure("isExactlyClear:Fail " ,(TRUE == vec4.isExactlyClear())); + ensure("isExactlyClear:Fail " ,(true == vec4.isExactlyClear())); vec4.zeroVec(); - ensure("isExactlyZero:Fail " ,(TRUE == vec4.isExactlyZero())); + ensure("isExactlyZero:Fail " ,(true == vec4.isExactlyZero())); } template<> template<> @@ -303,11 +303,11 @@ namespace tut { F32 x = 1.f, y = 2.f, z = -1.1f,epsilon = .23425f; LLVector4 vec4(x,y,z), vec4a(x,y,z); - ensure("1:are_parallel: Fail " ,(TRUE == are_parallel(vec4a,vec4,epsilon))); + ensure("1:are_parallel: Fail " ,(true == are_parallel(vec4a,vec4,epsilon))); x = 21.f, y = 12.f, z = -123.1f; vec4a.clearVec(); vec4a.setVec(x,y,z); - ensure("2:are_parallel: Fail " ,(FALSE == are_parallel(vec4a,vec4,epsilon))); + ensure("2:are_parallel: Fail " ,(false == are_parallel(vec4a,vec4,epsilon))); } template<> template<> diff --git a/indra/llmath/tests/xform_test.cpp b/indra/llmath/tests/xform_test.cpp index 50e24c9d4f..6348b3225c 100644 --- a/indra/llmath/tests/xform_test.cpp +++ b/indra/llmath/tests/xform_test.cpp @@ -91,7 +91,7 @@ namespace tut xform_obj.setPositionZ(z); ensure("setPositionX/Y/Z failed: ", xform_obj.getPosition() == vec); - xform_obj.setScaleChildOffset(TRUE); + xform_obj.setScaleChildOffset(true); ensure("setScaleChildOffset failed: ", xform_obj.getScaleChildOffset()); vec.setVec(x, y, z); @@ -216,7 +216,7 @@ namespace tut parent.setPosition(llvecpospar); LLVector3 llvecparentscale(1.0, 2.0, 0); - parent.setScaleChildOffset(TRUE); + parent.setScaleChildOffset(true); parent.setScale(llvecparentscale); LLQuaternion quat(1, 2, 3, 4); -- cgit v1.2.3 From f9473e8afcb624cc1b101195bf15943ec372b56f Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 6 May 2024 16:52:34 +0200 Subject: secondlife/viewer#1333 BOOL to bool conversion leftovers: ternaries --- indra/llmath/llsphere.cpp | 9 ++++--- indra/llmath/lltreenode.h | 5 ++-- indra/llmath/llvolume.cpp | 52 +++++++++++++++++++++++++++-------------- indra/llmath/llvolumemgr.cpp | 2 +- indra/llmath/llvolumeoctree.cpp | 5 ++-- 5 files changed, 45 insertions(+), 28 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index 7292e3c0de..3f04ca704c 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -73,14 +73,14 @@ F32 LLSphere::getRadius() const bool LLSphere::contains(const LLSphere& other_sphere) const { F32 separation = (mCenter - other_sphere.mCenter).length(); - return (mRadius >= separation + other_sphere.mRadius) ? true : false; + return mRadius >= separation + other_sphere.mRadius; } // returns 'true' if this sphere completely contains other_sphere bool LLSphere::overlaps(const LLSphere& other_sphere) const { F32 separation = (mCenter - other_sphere.mCenter).length(); - return (separation <= mRadius + other_sphere.mRadius) ? true : false; + return mRadius >= separation - other_sphere.mRadius; } // returns overlap @@ -93,9 +93,8 @@ F32 LLSphere::getOverlap(const LLSphere& other_sphere) const bool LLSphere::operator==(const LLSphere& rhs) const { - // TODO? -- use approximate equality for centers? - return (mRadius == rhs.mRadius - && mCenter == rhs.mCenter); + return fabs(mRadius - rhs.mRadius) <= FLT_EPSILON && + (mCenter - rhs.mCenter).length() <= FLT_EPSILON; } std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere) diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index 0b479c4564..ce104b88a0 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -56,10 +56,11 @@ public: virtual bool insert(T* data); virtual bool remove(T* data); virtual void notifyRemoval(T* data); - virtual U32 getListenerCount() { return mListeners.size(); } + virtual U32 hasListeners() const { return !mListeners.empty(); } + virtual U32 getListenerCount() const { return mListeners.size(); } virtual LLTreeListener* getListener(U32 index) const { - if(index < mListeners.size()) + if (index < mListeners.size()) { return mListeners[index]; } diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 5375e2813b..a4b039fd55 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -6878,45 +6878,63 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) mIndices[cur_index++] = s+1 + mNumS*t; //bottom right mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - 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 + // bottom left/top right neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; + + if (t < mNumT-2) + { // top right/top left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; } - else if (mNumT <= 3 || volume->getPath().isOpen() == true) { //no neighbor + else if (mNumT <= 3 || volume->getPath().isOpen()) + { // no neighbor mEdge[cur_edge++] = -1; } - else { //wrap on T + else + { // wrap on T mEdge[cur_edge++] = s*2+1; } - if (s > 0) { //top left/bottom left neighbor face + + if (s > 0) + { // top left/bottom left neighbor face mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; } - else if (flat_face || volume->getProfile().isOpen() == true) { //no neighbor + else if (flat_face || volume->getProfile().isOpen()) + { // no neighbor mEdge[cur_edge++] = -1; } - else { //wrap on S + else + { // wrap on S mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; } - - if (t > 0) { //bottom left/bottom right neighbor face + + if (t > 0) + { // bottom left/bottom right neighbor face mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; } - else if (mNumT <= 3 || volume->getPath().isOpen() == true) { //no neighbor + else if (mNumT <= 3 || volume->getPath().isOpen()) + { // no neighbor mEdge[cur_edge++] = -1; } - else { //wrap on T + else + { // wrap on T mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; } - if (s < mNumS-2) { //bottom right/top right neighbor face + + if (s < mNumS-2) + { // bottom right/top right neighbor face mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; } - else if (flat_face || volume->getProfile().isOpen() == true) { //no neighbor + else if (flat_face || volume->getProfile().isOpen()) + { // no neighbor mEdge[cur_edge++] = -1; } - else { //wrap on S + else + { // wrap on S mEdge[cur_edge++] = (mNumS-1)*2*t; } - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; //top right/bottom left neighbor face + + // top right/bottom left neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; } } } @@ -7053,7 +7071,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes { - if (volume->getPath().isOpen() == false) + if (!volume->getPath().isOpen()) { //wrap normals on T for (S32 i = 0; i < mNumS; i++) { @@ -7064,7 +7082,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) } } - if ((volume->getProfile().isOpen() == false) && !(s_bottom_converges)) + if (!volume->getProfile().isOpen() && !s_bottom_converges) { //wrap normals on S for (S32 i = 0; i < mNumT; i++) { diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index d1e145cff1..06794fd23f 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -71,7 +71,7 @@ bool LLVolumeMgr::cleanup() iter != end; iter++) { LLVolumeLODGroup *volgroupp = iter->second; - if (volgroupp->cleanupRefs() == false) + if (!volgroupp->cleanupRefs()) { no_refs = false; } diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index cef4d66c04..61455affec 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -71,10 +71,9 @@ bool LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, c grt = f.greaterThan(rhs).getGatheredBits(); - return (grt & 0x7) ? false : true; + return (grt & 0x7) == 0; } - LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode* node) { node->addListener(this); @@ -84,7 +83,7 @@ LLVolumeOctreeListener::~LLVolumeOctreeListener() { } - + void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode* parent, LLOctreeNode* child) { -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/llmath/llbbox.cpp | 356 +- indra/llmath/llbbox.h | 202 +- indra/llmath/llcoordframe.h | 348 +- indra/llmath/llinterp.h | 850 +- indra/llmath/llmath.h | 1138 +-- indra/llmath/lloctree.h | 1716 ++-- indra/llmath/llquaternion.cpp | 1962 ++--- indra/llmath/llquaternion.h | 1234 +-- indra/llmath/llrect.h | 596 +- indra/llmath/llsphere.cpp | 740 +- indra/llmath/llsphere.h | 154 +- indra/llmath/lltreenode.h | 250 +- indra/llmath/llvolume.cpp | 14608 ++++++++++++++++----------------- indra/llmath/llvolume.h | 2304 +++--- indra/llmath/llvolumemgr.cpp | 816 +- indra/llmath/llvolumemgr.h | 224 +- indra/llmath/llvolumeoctree.cpp | 546 +- indra/llmath/m3math.cpp | 1180 +-- indra/llmath/m4math.cpp | 1746 ++-- indra/llmath/raytrace.cpp | 2538 +++--- indra/llmath/raytrace.h | 458 +- indra/llmath/tests/llbbox_test.cpp | 734 +- indra/llmath/tests/llrect_test.cpp | 1052 +-- indra/llmath/tests/mathmisc_test.cpp | 1446 ++-- indra/llmath/tests/v2math_test.cpp | 896 +- indra/llmath/tests/v3color_test.cpp | 618 +- indra/llmath/tests/v3dmath_test.cpp | 1062 +-- indra/llmath/tests/v3math_test.cpp | 1170 +-- indra/llmath/tests/v4coloru_test.cpp | 672 +- indra/llmath/tests/v4math_test.cpp | 766 +- indra/llmath/tests/xform_test.cpp | 490 +- indra/llmath/v2math.cpp | 252 +- indra/llmath/v2math.h | 880 +- indra/llmath/v3dmath.cpp | 294 +- indra/llmath/v3dmath.h | 1060 +-- indra/llmath/v3math.cpp | 826 +- indra/llmath/v3math.h | 1224 +-- indra/llmath/v4color.cpp | 1476 ++-- indra/llmath/v4color.h | 1446 ++-- indra/llmath/v4coloru.cpp | 240 +- indra/llmath/v4coloru.h | 1170 +-- indra/llmath/v4math.cpp | 240 +- indra/llmath/v4math.h | 1098 +-- indra/llmath/xform.cpp | 238 +- indra/llmath/xform.h | 630 +- 45 files changed, 26973 insertions(+), 26973 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index 728b222d09..fa1253e421 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -1,178 +1,178 @@ -/** - * @file llbbox.cpp - * @brief General purpose bounding box class (Not axis aligned) - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -// self include -#include "llbbox.h" - -// library includes -#include "m4math.h" - -void LLBBox::addPointLocal(const LLVector3& p) -{ - if (mEmpty) - { - mMinLocal = p; - mMaxLocal = p; - mEmpty = false; - } - else - { - mMinLocal.mV[VX] = llmin( p.mV[VX], mMinLocal.mV[VX] ); - mMinLocal.mV[VY] = llmin( p.mV[VY], mMinLocal.mV[VY] ); - mMinLocal.mV[VZ] = llmin( p.mV[VZ], mMinLocal.mV[VZ] ); - mMaxLocal.mV[VX] = llmax( p.mV[VX], mMaxLocal.mV[VX] ); - mMaxLocal.mV[VY] = llmax( p.mV[VY], mMaxLocal.mV[VY] ); - mMaxLocal.mV[VZ] = llmax( p.mV[VZ], mMaxLocal.mV[VZ] ); - } -} - -void LLBBox::addPointAgent( LLVector3 p) -{ - p -= mPosAgent; - p.rotVec( ~mRotation ); - addPointLocal( p ); -} - - -void LLBBox::addBBoxAgent(const LLBBox& b) -{ - if (mEmpty) - { - mPosAgent = b.mPosAgent; - mRotation = b.mRotation; - mMinLocal.clearVec(); - mMaxLocal.clearVec(); - } - LLVector3 vertex[8]; - vertex[0].setVec( b.mMinLocal.mV[VX], b.mMinLocal.mV[VY], b.mMinLocal.mV[VZ] ); - vertex[1].setVec( b.mMinLocal.mV[VX], b.mMinLocal.mV[VY], b.mMaxLocal.mV[VZ] ); - vertex[2].setVec( b.mMinLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMinLocal.mV[VZ] ); - vertex[3].setVec( b.mMinLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMaxLocal.mV[VZ] ); - vertex[4].setVec( b.mMaxLocal.mV[VX], b.mMinLocal.mV[VY], b.mMinLocal.mV[VZ] ); - vertex[5].setVec( b.mMaxLocal.mV[VX], b.mMinLocal.mV[VY], b.mMaxLocal.mV[VZ] ); - vertex[6].setVec( b.mMaxLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMinLocal.mV[VZ] ); - vertex[7].setVec( b.mMaxLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMaxLocal.mV[VZ] ); - - LLMatrix4 m( b.mRotation ); - m.translate( b.mPosAgent ); - m.translate( -mPosAgent ); - m.rotate( ~mRotation ); - - for( S32 i=0; i<8; i++ ) - { - addPointLocal( vertex[i] * m ); - } -} - -LLBBox LLBBox::getAxisAligned() const -{ - // no rotation = axis aligned rotation - LLBBox aligned(mPosAgent, LLQuaternion(), LLVector3(), LLVector3()); - - // add the center point so that it's not empty - aligned.addPointAgent(mPosAgent); - - // add our BBox - aligned.addBBoxAgent(*this); - - return aligned; -} - -void LLBBox::expand( F32 delta ) -{ - mMinLocal.mV[VX] -= delta; - mMinLocal.mV[VY] -= delta; - mMinLocal.mV[VZ] -= delta; - mMaxLocal.mV[VX] += delta; - mMaxLocal.mV[VY] += delta; - mMaxLocal.mV[VZ] += delta; -} - -LLVector3 LLBBox::localToAgent(const LLVector3& v) const -{ - LLMatrix4 m( mRotation ); - m.translate( mPosAgent ); - return v * m; -} - -LLVector3 LLBBox::agentToLocal(const LLVector3& v) const -{ - LLMatrix4 m; - m.translate( -mPosAgent ); - m.rotate( ~mRotation ); // inverse rotation - return v * m; -} - -LLVector3 LLBBox::localToAgentBasis(const LLVector3& v) const -{ - LLMatrix4 m( mRotation ); - return v * m; -} - -LLVector3 LLBBox::agentToLocalBasis(const LLVector3& v) const -{ - LLMatrix4 m( ~mRotation ); // inverse rotation - return v * m; -} - -bool LLBBox::containsPointLocal(const LLVector3& p) const -{ - if ( (p.mV[VX] < mMinLocal.mV[VX]) - ||(p.mV[VX] > mMaxLocal.mV[VX]) - ||(p.mV[VY] < mMinLocal.mV[VY]) - ||(p.mV[VY] > mMaxLocal.mV[VY]) - ||(p.mV[VZ] < mMinLocal.mV[VZ]) - ||(p.mV[VZ] > mMaxLocal.mV[VZ])) - { - return false; - } - return true; -} - -bool LLBBox::containsPointAgent(const LLVector3& p) const -{ - LLVector3 point_local = agentToLocal(p); - return containsPointLocal(point_local); -} - -LLVector3 LLBBox::getMinAgent() const -{ - return localToAgent(mMinLocal); -} - -LLVector3 LLBBox::getMaxAgent() const -{ - return localToAgent(mMaxLocal); -} - -/* -LLBBox operator*(const LLBBox &a, const LLMatrix4 &b) -{ - return LLBBox( a.mMin * b, a.mMax * b ); -} -*/ +/** + * @file llbbox.cpp + * @brief General purpose bounding box class (Not axis aligned) + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// self include +#include "llbbox.h" + +// library includes +#include "m4math.h" + +void LLBBox::addPointLocal(const LLVector3& p) +{ + if (mEmpty) + { + mMinLocal = p; + mMaxLocal = p; + mEmpty = false; + } + else + { + mMinLocal.mV[VX] = llmin( p.mV[VX], mMinLocal.mV[VX] ); + mMinLocal.mV[VY] = llmin( p.mV[VY], mMinLocal.mV[VY] ); + mMinLocal.mV[VZ] = llmin( p.mV[VZ], mMinLocal.mV[VZ] ); + mMaxLocal.mV[VX] = llmax( p.mV[VX], mMaxLocal.mV[VX] ); + mMaxLocal.mV[VY] = llmax( p.mV[VY], mMaxLocal.mV[VY] ); + mMaxLocal.mV[VZ] = llmax( p.mV[VZ], mMaxLocal.mV[VZ] ); + } +} + +void LLBBox::addPointAgent( LLVector3 p) +{ + p -= mPosAgent; + p.rotVec( ~mRotation ); + addPointLocal( p ); +} + + +void LLBBox::addBBoxAgent(const LLBBox& b) +{ + if (mEmpty) + { + mPosAgent = b.mPosAgent; + mRotation = b.mRotation; + mMinLocal.clearVec(); + mMaxLocal.clearVec(); + } + LLVector3 vertex[8]; + vertex[0].setVec( b.mMinLocal.mV[VX], b.mMinLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[1].setVec( b.mMinLocal.mV[VX], b.mMinLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + vertex[2].setVec( b.mMinLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[3].setVec( b.mMinLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + vertex[4].setVec( b.mMaxLocal.mV[VX], b.mMinLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[5].setVec( b.mMaxLocal.mV[VX], b.mMinLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + vertex[6].setVec( b.mMaxLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[7].setVec( b.mMaxLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + + LLMatrix4 m( b.mRotation ); + m.translate( b.mPosAgent ); + m.translate( -mPosAgent ); + m.rotate( ~mRotation ); + + for( S32 i=0; i<8; i++ ) + { + addPointLocal( vertex[i] * m ); + } +} + +LLBBox LLBBox::getAxisAligned() const +{ + // no rotation = axis aligned rotation + LLBBox aligned(mPosAgent, LLQuaternion(), LLVector3(), LLVector3()); + + // add the center point so that it's not empty + aligned.addPointAgent(mPosAgent); + + // add our BBox + aligned.addBBoxAgent(*this); + + return aligned; +} + +void LLBBox::expand( F32 delta ) +{ + mMinLocal.mV[VX] -= delta; + mMinLocal.mV[VY] -= delta; + mMinLocal.mV[VZ] -= delta; + mMaxLocal.mV[VX] += delta; + mMaxLocal.mV[VY] += delta; + mMaxLocal.mV[VZ] += delta; +} + +LLVector3 LLBBox::localToAgent(const LLVector3& v) const +{ + LLMatrix4 m( mRotation ); + m.translate( mPosAgent ); + return v * m; +} + +LLVector3 LLBBox::agentToLocal(const LLVector3& v) const +{ + LLMatrix4 m; + m.translate( -mPosAgent ); + m.rotate( ~mRotation ); // inverse rotation + return v * m; +} + +LLVector3 LLBBox::localToAgentBasis(const LLVector3& v) const +{ + LLMatrix4 m( mRotation ); + return v * m; +} + +LLVector3 LLBBox::agentToLocalBasis(const LLVector3& v) const +{ + LLMatrix4 m( ~mRotation ); // inverse rotation + return v * m; +} + +bool LLBBox::containsPointLocal(const LLVector3& p) const +{ + if ( (p.mV[VX] < mMinLocal.mV[VX]) + ||(p.mV[VX] > mMaxLocal.mV[VX]) + ||(p.mV[VY] < mMinLocal.mV[VY]) + ||(p.mV[VY] > mMaxLocal.mV[VY]) + ||(p.mV[VZ] < mMinLocal.mV[VZ]) + ||(p.mV[VZ] > mMaxLocal.mV[VZ])) + { + return false; + } + return true; +} + +bool LLBBox::containsPointAgent(const LLVector3& p) const +{ + LLVector3 point_local = agentToLocal(p); + return containsPointLocal(point_local); +} + +LLVector3 LLBBox::getMinAgent() const +{ + return localToAgent(mMinLocal); +} + +LLVector3 LLBBox::getMaxAgent() const +{ + return localToAgent(mMaxLocal); +} + +/* +LLBBox operator*(const LLBBox &a, const LLMatrix4 &b) +{ + return LLBBox( a.mMin * b, a.mMax * b ); +} +*/ diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index 988b95c54d..5617eaebde 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -1,101 +1,101 @@ -/** - * @file llbbox.h - * @brief General purpose bounding box class - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_BBOX_H -#define LL_BBOX_H - -#include "v3math.h" -#include "llquaternion.h" - -// Note: "local space" for an LLBBox is defined relative to agent space in terms of -// a translation followed by a rotation. There is no scale term since the LLBBox's min and -// max are not necessarily symetrical and define their own extents. - -class LLBBox -{ -public: - LLBBox() {mEmpty = true;} - LLBBox( const LLVector3& pos_agent, - const LLQuaternion& rot, - const LLVector3& min_local, - const LLVector3& max_local ) - : - mMinLocal( min_local ), mMaxLocal( max_local ), mPosAgent(pos_agent), mRotation( rot), mEmpty( true ) - {} - - // Default copy constructor is OK. - - const LLVector3& getPositionAgent() const { return mPosAgent; } - const LLQuaternion& getRotation() const { return mRotation; } - - LLVector3 getMinAgent() const; - const LLVector3& getMinLocal() const { return mMinLocal; } - void setMinLocal( const LLVector3& min ) { mMinLocal = min; } - - LLVector3 getMaxAgent() const; - const LLVector3& getMaxLocal() const { return mMaxLocal; } - void setMaxLocal( const LLVector3& max ) { mMaxLocal = max; } - - LLVector3 getCenterLocal() const { return (mMaxLocal - mMinLocal) * 0.5f + mMinLocal; } - LLVector3 getCenterAgent() const { return localToAgent( getCenterLocal() ); } - - LLVector3 getExtentLocal() const { return mMaxLocal - mMinLocal; } - - bool containsPointLocal(const LLVector3& p) const; - bool containsPointAgent(const LLVector3& p) const; - - void addPointAgent(LLVector3 p); - void addBBoxAgent(const LLBBox& b); - - void addPointLocal(const LLVector3& p); - void addBBoxLocal(const LLBBox& b) { addPointLocal( b.mMinLocal ); addPointLocal( b.mMaxLocal ); } - - void expand( F32 delta ); - - LLVector3 localToAgent( const LLVector3& v ) const; - LLVector3 agentToLocal( const LLVector3& v ) const; - - // Changes rotation but not position - LLVector3 localToAgentBasis(const LLVector3& v) const; - LLVector3 agentToLocalBasis(const LLVector3& v) const; - - // Get the smallest possible axis aligned bbox that contains this bbox - LLBBox getAxisAligned() const; - -// friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b); - -private: - LLVector3 mMinLocal; - LLVector3 mMaxLocal; - LLVector3 mPosAgent; // Position relative to Agent's Region - LLQuaternion mRotation; - bool mEmpty; // Nothing has been added to this bbox yet -}; - -//LLBBox operator*(const LLBBox &a, const LLMatrix4 &b); - - -#endif // LL_BBOX_H +/** + * @file llbbox.h + * @brief General purpose bounding box class + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_BBOX_H +#define LL_BBOX_H + +#include "v3math.h" +#include "llquaternion.h" + +// Note: "local space" for an LLBBox is defined relative to agent space in terms of +// a translation followed by a rotation. There is no scale term since the LLBBox's min and +// max are not necessarily symetrical and define their own extents. + +class LLBBox +{ +public: + LLBBox() {mEmpty = true;} + LLBBox( const LLVector3& pos_agent, + const LLQuaternion& rot, + const LLVector3& min_local, + const LLVector3& max_local ) + : + mMinLocal( min_local ), mMaxLocal( max_local ), mPosAgent(pos_agent), mRotation( rot), mEmpty( true ) + {} + + // Default copy constructor is OK. + + const LLVector3& getPositionAgent() const { return mPosAgent; } + const LLQuaternion& getRotation() const { return mRotation; } + + LLVector3 getMinAgent() const; + const LLVector3& getMinLocal() const { return mMinLocal; } + void setMinLocal( const LLVector3& min ) { mMinLocal = min; } + + LLVector3 getMaxAgent() const; + const LLVector3& getMaxLocal() const { return mMaxLocal; } + void setMaxLocal( const LLVector3& max ) { mMaxLocal = max; } + + LLVector3 getCenterLocal() const { return (mMaxLocal - mMinLocal) * 0.5f + mMinLocal; } + LLVector3 getCenterAgent() const { return localToAgent( getCenterLocal() ); } + + LLVector3 getExtentLocal() const { return mMaxLocal - mMinLocal; } + + bool containsPointLocal(const LLVector3& p) const; + bool containsPointAgent(const LLVector3& p) const; + + void addPointAgent(LLVector3 p); + void addBBoxAgent(const LLBBox& b); + + void addPointLocal(const LLVector3& p); + void addBBoxLocal(const LLBBox& b) { addPointLocal( b.mMinLocal ); addPointLocal( b.mMaxLocal ); } + + void expand( F32 delta ); + + LLVector3 localToAgent( const LLVector3& v ) const; + LLVector3 agentToLocal( const LLVector3& v ) const; + + // Changes rotation but not position + LLVector3 localToAgentBasis(const LLVector3& v) const; + LLVector3 agentToLocalBasis(const LLVector3& v) const; + + // Get the smallest possible axis aligned bbox that contains this bbox + LLBBox getAxisAligned() const; + +// friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b); + +private: + LLVector3 mMinLocal; + LLVector3 mMaxLocal; + LLVector3 mPosAgent; // Position relative to Agent's Region + LLQuaternion mRotation; + bool mEmpty; // Nothing has been added to this bbox yet +}; + +//LLBBox operator*(const LLBBox &a, const LLMatrix4 &b); + + +#endif // LL_BBOX_H diff --git a/indra/llmath/llcoordframe.h b/indra/llmath/llcoordframe.h index a21d39bbc0..aaa701f792 100644 --- a/indra/llmath/llcoordframe.h +++ b/indra/llmath/llcoordframe.h @@ -1,174 +1,174 @@ -/** - * @file llcoordframe.h - * @brief LLCoordFrame class header file. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_COORDFRAME_H -#define LL_COORDFRAME_H - -#include "v3math.h" -#include "v4math.h" -#include "llerror.h" - -// XXX : The constructors of the LLCoordFrame class assume that all vectors -// and quaternion being passed as arguments are normalized, and all matrix -// arguments are unitary. VERY BAD things will happen if these assumptions fail. -// Also, segfault hazzards exist in methods that accept F32* arguments. - - -class LLCoordFrame -{ -public: - LLCoordFrame(); // Inits at zero with identity rotation - explicit LLCoordFrame(const LLVector3 &origin); // Sets origin, and inits rotation = Identity - LLCoordFrame(const LLVector3 &x_axis, - const LLVector3 &y_axis, - const LLVector3 &z_axis); // Sets coordinate axes and inits origin at zero - LLCoordFrame(const LLVector3 &origin, - const LLVector3 &x_axis, - const LLVector3 &y_axis, - const LLVector3 &z_axis); // Sets the origin and coordinate axes - LLCoordFrame(const LLVector3 &origin, - const LLMatrix3 &rotation); // Sets axes to 3x3 matrix - LLCoordFrame(const LLVector3 &origin, - const LLVector3 &direction); // Sets origin and calls lookDir(direction) - explicit LLCoordFrame(const LLQuaternion &q); // Sets axes using q and inits mOrigin to zero - LLCoordFrame(const LLVector3 &origin, - const LLQuaternion &q); // Uses quaternion to init axes - explicit LLCoordFrame(const LLMatrix4 &mat); // Extracts frame from a 4x4 matrix - // The folowing two constructors are dangerous due to implicit casting and have been disabled - SJB - //LLCoordFrame(const F32 *origin, const F32 *rotation); // Assumes "origin" is 1x3 and "rotation" is 1x9 array - //LLCoordFrame(const F32 *origin_and_rotation); // Assumes "origin_and_rotation" is 1x12 array - - bool isFinite() { return mOrigin.isFinite() && mXAxis.isFinite() && mYAxis.isFinite() && mZAxis.isFinite(); } - - void reset(); - void resetAxes(); - - void setOrigin(F32 x, F32 y, F32 z); // Set mOrigin - void setOrigin(const LLVector3 &origin); - void setOrigin(const F32 *origin); - void setOrigin(const LLCoordFrame &frame); - - inline void setOriginX(F32 x) { mOrigin.mV[VX] = x; } - inline void setOriginY(F32 y) { mOrigin.mV[VY] = y; } - inline void setOriginZ(F32 z) { mOrigin.mV[VZ] = z; } - - void setAxes(const LLVector3 &x_axis, // Set axes - const LLVector3 &y_axis, - const LLVector3 &z_axis); - void setAxes(const LLMatrix3 &rotation_matrix); - void setAxes(const LLQuaternion &q); - void setAxes(const F32 *rotation_matrix); - void setAxes(const LLCoordFrame &frame); - - void translate(F32 x, F32 y, F32 z); // Move mOrgin - void translate(const LLVector3 &v); - void translate(const F32 *origin); - - void rotate(F32 angle, F32 x, F32 y, F32 z); // Move axes - void rotate(F32 angle, const LLVector3 &rotation_axis); - void rotate(const LLQuaternion &q); - void rotate(const LLMatrix3 &m); - - void orthonormalize(); // Makes sure axes are unitary and orthogonal. - - // These methods allow rotations in the LLCoordFrame's frame - void roll(F32 angle); // RH rotation about mXAxis, radians - void pitch(F32 angle); // RH rotation about mYAxis, radians - void yaw(F32 angle); // RH rotation about mZAxis, radians - - inline const LLVector3 &getOrigin() const { return mOrigin; } - - inline const LLVector3 &getXAxis() const { return mXAxis; } - inline const LLVector3 &getYAxis() const { return mYAxis; } - inline const LLVector3 &getZAxis() const { return mZAxis; } - - inline const LLVector3 &getAtAxis() const { return mXAxis; } - inline const LLVector3 &getLeftAxis() const { return mYAxis; } - inline const LLVector3 &getUpAxis() const { return mZAxis; } - - // These return representations of the rotation or orientation of the LLFrame - // it its absolute frame. That is, these rotations acting on the X-axis {1,0,0} - // will produce the mXAxis. - // LLMatrix3 getMatrix3() const; // Returns axes in 3x3 matrix - LLQuaternion getQuaternion() const; // Returns axes in quaternion form - - // Same as above, except it also includes the translation of the LLFrame - // LLMatrix4 getMatrix4() const; // Returns position and axes in 4x4 matrix - - // Returns matrix which expresses point in local frame in the parent frame - void getMatrixToParent(LLMatrix4 &mat) const; - // Returns matrix which expresses point in parent frame in the local frame - void getMatrixToLocal(LLMatrix4 &mat) const; // Returns matrix which expresses point in parent frame in the local frame - - void getRotMatrixToParent(LLMatrix4 &mat) const; - - // Copies mOrigin, then the three axes to buffer, returns number of bytes copied. - size_t writeOrientation(char *buffer) const; - - // Copies mOrigin, then the three axes from buffer, returns the number of bytes copied. - // Assumes the data in buffer is correct. - size_t readOrientation(const char *buffer); - - LLVector3 rotateToLocal(const LLVector3 &v) const; // Returns v' rotated to local - LLVector4 rotateToLocal(const LLVector4 &v) const; // Returns v' rotated to local - LLVector3 rotateToAbsolute(const LLVector3 &v) const; // Returns v' rotated to absolute - LLVector4 rotateToAbsolute(const LLVector4 &v) const; // Returns v' rotated to absolute - - LLVector3 transformToLocal(const LLVector3 &v) const; // Returns v' in local coord - LLVector4 transformToLocal(const LLVector4 &v) const; // Returns v' in local coord - LLVector3 transformToAbsolute(const LLVector3 &v) const; // Returns v' in absolute coord - LLVector4 transformToAbsolute(const LLVector4 &v) const; // Returns v' in absolute coord - - // Write coord frame orientation into provided array in OpenGL matrix format. - void getOpenGLTranslation(F32 *ogl_matrix) const; - void getOpenGLRotation(F32 *ogl_matrix) const; - void getOpenGLTransform(F32 *ogl_matrix) const; - - // lookDir orients to (xuv, presumed normalized) and does not affect origin - void lookDir(const LLVector3 &xuv, const LLVector3 &up); - void lookDir(const LLVector3 &xuv); // up = 0,0,1 - // lookAt orients to (point_of_interest - origin) and sets origin - void lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest, const LLVector3 &up); - void lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest); // up = 0,0,1 - - // deprecated - void setOriginAndLookAt(const LLVector3 &origin, const LLVector3 &up, const LLVector3 &point_of_interest) - { - lookAt(origin, point_of_interest, up); - } - - friend std::ostream& operator<<(std::ostream &s, const LLCoordFrame &C); - - // These vectors are in absolute frame - LLVector3 mOrigin; - LLVector3 mXAxis; - LLVector3 mYAxis; - LLVector3 mZAxis; -}; - - -#endif - +/** + * @file llcoordframe.h + * @brief LLCoordFrame class header file. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_COORDFRAME_H +#define LL_COORDFRAME_H + +#include "v3math.h" +#include "v4math.h" +#include "llerror.h" + +// XXX : The constructors of the LLCoordFrame class assume that all vectors +// and quaternion being passed as arguments are normalized, and all matrix +// arguments are unitary. VERY BAD things will happen if these assumptions fail. +// Also, segfault hazzards exist in methods that accept F32* arguments. + + +class LLCoordFrame +{ +public: + LLCoordFrame(); // Inits at zero with identity rotation + explicit LLCoordFrame(const LLVector3 &origin); // Sets origin, and inits rotation = Identity + LLCoordFrame(const LLVector3 &x_axis, + const LLVector3 &y_axis, + const LLVector3 &z_axis); // Sets coordinate axes and inits origin at zero + LLCoordFrame(const LLVector3 &origin, + const LLVector3 &x_axis, + const LLVector3 &y_axis, + const LLVector3 &z_axis); // Sets the origin and coordinate axes + LLCoordFrame(const LLVector3 &origin, + const LLMatrix3 &rotation); // Sets axes to 3x3 matrix + LLCoordFrame(const LLVector3 &origin, + const LLVector3 &direction); // Sets origin and calls lookDir(direction) + explicit LLCoordFrame(const LLQuaternion &q); // Sets axes using q and inits mOrigin to zero + LLCoordFrame(const LLVector3 &origin, + const LLQuaternion &q); // Uses quaternion to init axes + explicit LLCoordFrame(const LLMatrix4 &mat); // Extracts frame from a 4x4 matrix + // The folowing two constructors are dangerous due to implicit casting and have been disabled - SJB + //LLCoordFrame(const F32 *origin, const F32 *rotation); // Assumes "origin" is 1x3 and "rotation" is 1x9 array + //LLCoordFrame(const F32 *origin_and_rotation); // Assumes "origin_and_rotation" is 1x12 array + + bool isFinite() { return mOrigin.isFinite() && mXAxis.isFinite() && mYAxis.isFinite() && mZAxis.isFinite(); } + + void reset(); + void resetAxes(); + + void setOrigin(F32 x, F32 y, F32 z); // Set mOrigin + void setOrigin(const LLVector3 &origin); + void setOrigin(const F32 *origin); + void setOrigin(const LLCoordFrame &frame); + + inline void setOriginX(F32 x) { mOrigin.mV[VX] = x; } + inline void setOriginY(F32 y) { mOrigin.mV[VY] = y; } + inline void setOriginZ(F32 z) { mOrigin.mV[VZ] = z; } + + void setAxes(const LLVector3 &x_axis, // Set axes + const LLVector3 &y_axis, + const LLVector3 &z_axis); + void setAxes(const LLMatrix3 &rotation_matrix); + void setAxes(const LLQuaternion &q); + void setAxes(const F32 *rotation_matrix); + void setAxes(const LLCoordFrame &frame); + + void translate(F32 x, F32 y, F32 z); // Move mOrgin + void translate(const LLVector3 &v); + void translate(const F32 *origin); + + void rotate(F32 angle, F32 x, F32 y, F32 z); // Move axes + void rotate(F32 angle, const LLVector3 &rotation_axis); + void rotate(const LLQuaternion &q); + void rotate(const LLMatrix3 &m); + + void orthonormalize(); // Makes sure axes are unitary and orthogonal. + + // These methods allow rotations in the LLCoordFrame's frame + void roll(F32 angle); // RH rotation about mXAxis, radians + void pitch(F32 angle); // RH rotation about mYAxis, radians + void yaw(F32 angle); // RH rotation about mZAxis, radians + + inline const LLVector3 &getOrigin() const { return mOrigin; } + + inline const LLVector3 &getXAxis() const { return mXAxis; } + inline const LLVector3 &getYAxis() const { return mYAxis; } + inline const LLVector3 &getZAxis() const { return mZAxis; } + + inline const LLVector3 &getAtAxis() const { return mXAxis; } + inline const LLVector3 &getLeftAxis() const { return mYAxis; } + inline const LLVector3 &getUpAxis() const { return mZAxis; } + + // These return representations of the rotation or orientation of the LLFrame + // it its absolute frame. That is, these rotations acting on the X-axis {1,0,0} + // will produce the mXAxis. + // LLMatrix3 getMatrix3() const; // Returns axes in 3x3 matrix + LLQuaternion getQuaternion() const; // Returns axes in quaternion form + + // Same as above, except it also includes the translation of the LLFrame + // LLMatrix4 getMatrix4() const; // Returns position and axes in 4x4 matrix + + // Returns matrix which expresses point in local frame in the parent frame + void getMatrixToParent(LLMatrix4 &mat) const; + // Returns matrix which expresses point in parent frame in the local frame + void getMatrixToLocal(LLMatrix4 &mat) const; // Returns matrix which expresses point in parent frame in the local frame + + void getRotMatrixToParent(LLMatrix4 &mat) const; + + // Copies mOrigin, then the three axes to buffer, returns number of bytes copied. + size_t writeOrientation(char *buffer) const; + + // Copies mOrigin, then the three axes from buffer, returns the number of bytes copied. + // Assumes the data in buffer is correct. + size_t readOrientation(const char *buffer); + + LLVector3 rotateToLocal(const LLVector3 &v) const; // Returns v' rotated to local + LLVector4 rotateToLocal(const LLVector4 &v) const; // Returns v' rotated to local + LLVector3 rotateToAbsolute(const LLVector3 &v) const; // Returns v' rotated to absolute + LLVector4 rotateToAbsolute(const LLVector4 &v) const; // Returns v' rotated to absolute + + LLVector3 transformToLocal(const LLVector3 &v) const; // Returns v' in local coord + LLVector4 transformToLocal(const LLVector4 &v) const; // Returns v' in local coord + LLVector3 transformToAbsolute(const LLVector3 &v) const; // Returns v' in absolute coord + LLVector4 transformToAbsolute(const LLVector4 &v) const; // Returns v' in absolute coord + + // Write coord frame orientation into provided array in OpenGL matrix format. + void getOpenGLTranslation(F32 *ogl_matrix) const; + void getOpenGLRotation(F32 *ogl_matrix) const; + void getOpenGLTransform(F32 *ogl_matrix) const; + + // lookDir orients to (xuv, presumed normalized) and does not affect origin + void lookDir(const LLVector3 &xuv, const LLVector3 &up); + void lookDir(const LLVector3 &xuv); // up = 0,0,1 + // lookAt orients to (point_of_interest - origin) and sets origin + void lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest, const LLVector3 &up); + void lookAt(const LLVector3 &origin, const LLVector3 &point_of_interest); // up = 0,0,1 + + // deprecated + void setOriginAndLookAt(const LLVector3 &origin, const LLVector3 &up, const LLVector3 &point_of_interest) + { + lookAt(origin, point_of_interest, up); + } + + friend std::ostream& operator<<(std::ostream &s, const LLCoordFrame &C); + + // These vectors are in absolute frame + LLVector3 mOrigin; + LLVector3 mXAxis; + LLVector3 mYAxis; + LLVector3 mZAxis; +}; + + +#endif + diff --git a/indra/llmath/llinterp.h b/indra/llmath/llinterp.h index 2df3ae8561..f4faa82a82 100644 --- a/indra/llmath/llinterp.h +++ b/indra/llmath/llinterp.h @@ -1,425 +1,425 @@ -/** - * @file llinterp.h - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLINTERP_H -#define LL_LLINTERP_H - -#if defined(LL_WINDOWS) -// macro definitions for common math constants (e.g. M_PI) are declared under the _USE_MATH_DEFINES -// on Windows system. -// So, let's define _USE_MATH_DEFINES before including math.h - #define _USE_MATH_DEFINES -#endif - -#include "math.h" - -// Class from which different types of interpolators can be derived - -class LLInterpVal -{ -public: - virtual ~LLInterpVal() {} -}; - -template -class LLInterp -{ -public: - LLInterp(); - virtual ~LLInterp() {} - - virtual void start(); - virtual void update(const F32 time) = 0; - const Type &getCurVal() const; - - void setStartVal(const Type &start_val); - const Type &getStartVal() const; - - void setEndVal(const Type &target_val); - const Type &getEndVal() const; - - void setStartTime(const F32 time); - F32 getStartTime() const; - - void setEndTime(const F32 time); - F32 getEndTime() const; - - bool isActive() const; - bool isDone() const; - -protected: - F32 mStartTime; - F32 mEndTime; - F32 mDuration; - bool mActive; - bool mDone; - - Type mStartVal; - Type mEndVal; - - F32 mCurTime; - Type mCurVal; -}; - -template -class LLInterpLinear : public LLInterp -{ -public: - void start() override; - void update(const F32 time) override; - F32 getCurFrac() const; -protected: - F32 mCurFrac; -}; - -template -class LLInterpExp : public LLInterpLinear -{ -public: - void update(const F32 time); -protected: -}; - -template -class LLInterpAttractor : public LLInterp -{ -public: - LLInterpAttractor(); - void start() override; - void setStartVel(const Type &vel); - void setForce(const F32 force); - void update(const F32 time) override; -protected: - F32 mForce; - Type mStartVel; - Type mVelocity; -}; - -template -class LLInterpFunc : public LLInterp -{ -public: - LLInterpFunc(); - void update(const F32 time) override; - - void setFunc(Type (*)(const F32, void *data), void *data); -protected: - Type (*mFunc)(const F32 time, void *data); - void *mData; -}; - - -/////////////////////////////////// -// -// Implementation -// -// - -///////////////////////////////// -// -// LLInterp base class implementation -// - -template -LLInterp::LLInterp() -: mStartVal(Type()), mEndVal(Type()), mCurVal(Type()) -{ - mStartTime = 0.f; - mEndTime = 1.f; - mDuration = 1.f; - mCurTime = 0.f; - mDone = false; - mActive = false; -} - -template -void LLInterp::setStartVal(const Type &start_val) -{ - mStartVal = start_val; -} - -template -void LLInterp::start() -{ - mCurVal = mStartVal; - mCurTime = mStartTime; - mDone = false; - mActive = false; -} - -template -const Type &LLInterp::getStartVal() const -{ - return mStartVal; -} - -template -void LLInterp::setEndVal(const Type &end_val) -{ - mEndVal = end_val; -} - -template -const Type &LLInterp::getEndVal() const -{ - return mEndVal; -} - -template -const Type &LLInterp::getCurVal() const -{ - return mCurVal; -} - - -template -void LLInterp::setStartTime(const F32 start_time) -{ - mStartTime = start_time; - mDuration = mEndTime - mStartTime; -} - -template -F32 LLInterp::getStartTime() const -{ - return mStartTime; -} - - -template -void LLInterp::setEndTime(const F32 end_time) -{ - mEndTime = end_time; - mDuration = mEndTime - mStartTime; -} - - -template -F32 LLInterp::getEndTime() const -{ - return mEndTime; -} - - -template -bool LLInterp::isDone() const -{ - return mDone; -} - -template -bool LLInterp::isActive() const -{ - return mActive; -} - -////////////////////////////// -// -// LLInterpLinear derived class implementation. -// -template -void LLInterpLinear::start() -{ - LLInterp::start(); - mCurFrac = 0.f; -} - -template -void LLInterpLinear::update(const F32 time) -{ - F32 target_frac = (time - this->mStartTime) / this->mDuration; - F32 dfrac = target_frac - this->mCurFrac; - if (target_frac >= 0.f) - { - this->mActive = true; - } - - if (target_frac > 1.f) - { - this->mCurVal = this->mEndVal; - this->mCurFrac = 1.f; - this->mCurTime = time; - this->mDone = true; - return; - } - - target_frac = llmin(1.f, target_frac); - target_frac = llmax(0.f, target_frac); - - if (dfrac >= 0.f) - { - F32 total_frac = 1.f - this->mCurFrac; - F32 inc_frac = dfrac / total_frac; - this->mCurVal = inc_frac * this->mEndVal + (1.f - inc_frac) * this->mCurVal; - this->mCurTime = time; - } - else - { - F32 total_frac = this->mCurFrac - 1.f; - F32 inc_frac = dfrac / total_frac; - this->mCurVal = inc_frac * this->mStartVal + (1.f - inc_frac) * this->mCurVal; - this->mCurTime = time; - } - mCurFrac = target_frac; -} - -template -F32 LLInterpLinear::getCurFrac() const -{ - return mCurFrac; -} - - -////////////////////////////// -// -// LLInterpAttractor derived class implementation. -// - - -template -LLInterpAttractor::LLInterpAttractor() : LLInterp() -{ - mForce = 0.1f; - mVelocity *= 0.f; - mStartVel *= 0.f; -} - -template -void LLInterpAttractor::start() -{ - LLInterp::start(); - mVelocity = mStartVel; -} - - -template -void LLInterpAttractor::setStartVel(const Type &vel) -{ - mStartVel = vel; -} - -template -void LLInterpAttractor::setForce(const F32 force) -{ - mForce = force; -} - -template -void LLInterpAttractor::update(const F32 time) -{ - if (time > this->mStartTime) - { - this->mActive = true; - } - else - { - return; - } - if (time > this->mEndTime) - { - this->mDone = true; - return; - } - - F32 dt = time - this->mCurTime; - Type dist_val = this->mEndVal - this->mCurVal; - Type dv = 0.5*dt*dt*this->mForce*dist_val; - this->mVelocity += dv; - this->mCurVal += this->mVelocity * dt; - this->mCurTime = time; -} - - -////////////////////////////// -// -// LLInterpFucn derived class implementation. -// - - -template -LLInterpFunc::LLInterpFunc() : LLInterp() -{ - mFunc = nullptr; - mData = nullptr; -} - -template -void LLInterpFunc::setFunc(Type (*func)(const F32, void *data), void *data) -{ - mFunc = func; - mData = data; -} - -template -void LLInterpFunc::update(const F32 time) -{ - if (time > this->mStartTime) - { - this->mActive = true; - } - else - { - return; - } - if (time > this->mEndTime) - { - this->mDone = true; - return; - } - - this->mCurVal = (*mFunc)(time - this->mStartTime, mData); - this->mCurTime = time; -} - -////////////////////////////// -// -// LLInterpExp derived class implementation. -// - -template -void LLInterpExp::update(const F32 time) -{ - F32 target_frac = (time - this->mStartTime) / this->mDuration; - if (target_frac >= 0.f) - { - this->mActive = true; - } - - if (target_frac > 1.f) - { - this->mCurVal = this->mEndVal; - this->mCurFrac = 1.f; - this->mCurTime = time; - this->mDone = true; - return; - } - - this->mCurFrac = 1.f - (F32)(exp(-2.f*target_frac)); - this->mCurVal = this->mStartVal + this->mCurFrac * (this->mEndVal - this->mStartVal); - this->mCurTime = time; -} - -#endif // LL_LLINTERP_H - +/** + * @file llinterp.h + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLINTERP_H +#define LL_LLINTERP_H + +#if defined(LL_WINDOWS) +// macro definitions for common math constants (e.g. M_PI) are declared under the _USE_MATH_DEFINES +// on Windows system. +// So, let's define _USE_MATH_DEFINES before including math.h + #define _USE_MATH_DEFINES +#endif + +#include "math.h" + +// Class from which different types of interpolators can be derived + +class LLInterpVal +{ +public: + virtual ~LLInterpVal() {} +}; + +template +class LLInterp +{ +public: + LLInterp(); + virtual ~LLInterp() {} + + virtual void start(); + virtual void update(const F32 time) = 0; + const Type &getCurVal() const; + + void setStartVal(const Type &start_val); + const Type &getStartVal() const; + + void setEndVal(const Type &target_val); + const Type &getEndVal() const; + + void setStartTime(const F32 time); + F32 getStartTime() const; + + void setEndTime(const F32 time); + F32 getEndTime() const; + + bool isActive() const; + bool isDone() const; + +protected: + F32 mStartTime; + F32 mEndTime; + F32 mDuration; + bool mActive; + bool mDone; + + Type mStartVal; + Type mEndVal; + + F32 mCurTime; + Type mCurVal; +}; + +template +class LLInterpLinear : public LLInterp +{ +public: + void start() override; + void update(const F32 time) override; + F32 getCurFrac() const; +protected: + F32 mCurFrac; +}; + +template +class LLInterpExp : public LLInterpLinear +{ +public: + void update(const F32 time); +protected: +}; + +template +class LLInterpAttractor : public LLInterp +{ +public: + LLInterpAttractor(); + void start() override; + void setStartVel(const Type &vel); + void setForce(const F32 force); + void update(const F32 time) override; +protected: + F32 mForce; + Type mStartVel; + Type mVelocity; +}; + +template +class LLInterpFunc : public LLInterp +{ +public: + LLInterpFunc(); + void update(const F32 time) override; + + void setFunc(Type (*)(const F32, void *data), void *data); +protected: + Type (*mFunc)(const F32 time, void *data); + void *mData; +}; + + +/////////////////////////////////// +// +// Implementation +// +// + +///////////////////////////////// +// +// LLInterp base class implementation +// + +template +LLInterp::LLInterp() +: mStartVal(Type()), mEndVal(Type()), mCurVal(Type()) +{ + mStartTime = 0.f; + mEndTime = 1.f; + mDuration = 1.f; + mCurTime = 0.f; + mDone = false; + mActive = false; +} + +template +void LLInterp::setStartVal(const Type &start_val) +{ + mStartVal = start_val; +} + +template +void LLInterp::start() +{ + mCurVal = mStartVal; + mCurTime = mStartTime; + mDone = false; + mActive = false; +} + +template +const Type &LLInterp::getStartVal() const +{ + return mStartVal; +} + +template +void LLInterp::setEndVal(const Type &end_val) +{ + mEndVal = end_val; +} + +template +const Type &LLInterp::getEndVal() const +{ + return mEndVal; +} + +template +const Type &LLInterp::getCurVal() const +{ + return mCurVal; +} + + +template +void LLInterp::setStartTime(const F32 start_time) +{ + mStartTime = start_time; + mDuration = mEndTime - mStartTime; +} + +template +F32 LLInterp::getStartTime() const +{ + return mStartTime; +} + + +template +void LLInterp::setEndTime(const F32 end_time) +{ + mEndTime = end_time; + mDuration = mEndTime - mStartTime; +} + + +template +F32 LLInterp::getEndTime() const +{ + return mEndTime; +} + + +template +bool LLInterp::isDone() const +{ + return mDone; +} + +template +bool LLInterp::isActive() const +{ + return mActive; +} + +////////////////////////////// +// +// LLInterpLinear derived class implementation. +// +template +void LLInterpLinear::start() +{ + LLInterp::start(); + mCurFrac = 0.f; +} + +template +void LLInterpLinear::update(const F32 time) +{ + F32 target_frac = (time - this->mStartTime) / this->mDuration; + F32 dfrac = target_frac - this->mCurFrac; + if (target_frac >= 0.f) + { + this->mActive = true; + } + + if (target_frac > 1.f) + { + this->mCurVal = this->mEndVal; + this->mCurFrac = 1.f; + this->mCurTime = time; + this->mDone = true; + return; + } + + target_frac = llmin(1.f, target_frac); + target_frac = llmax(0.f, target_frac); + + if (dfrac >= 0.f) + { + F32 total_frac = 1.f - this->mCurFrac; + F32 inc_frac = dfrac / total_frac; + this->mCurVal = inc_frac * this->mEndVal + (1.f - inc_frac) * this->mCurVal; + this->mCurTime = time; + } + else + { + F32 total_frac = this->mCurFrac - 1.f; + F32 inc_frac = dfrac / total_frac; + this->mCurVal = inc_frac * this->mStartVal + (1.f - inc_frac) * this->mCurVal; + this->mCurTime = time; + } + mCurFrac = target_frac; +} + +template +F32 LLInterpLinear::getCurFrac() const +{ + return mCurFrac; +} + + +////////////////////////////// +// +// LLInterpAttractor derived class implementation. +// + + +template +LLInterpAttractor::LLInterpAttractor() : LLInterp() +{ + mForce = 0.1f; + mVelocity *= 0.f; + mStartVel *= 0.f; +} + +template +void LLInterpAttractor::start() +{ + LLInterp::start(); + mVelocity = mStartVel; +} + + +template +void LLInterpAttractor::setStartVel(const Type &vel) +{ + mStartVel = vel; +} + +template +void LLInterpAttractor::setForce(const F32 force) +{ + mForce = force; +} + +template +void LLInterpAttractor::update(const F32 time) +{ + if (time > this->mStartTime) + { + this->mActive = true; + } + else + { + return; + } + if (time > this->mEndTime) + { + this->mDone = true; + return; + } + + F32 dt = time - this->mCurTime; + Type dist_val = this->mEndVal - this->mCurVal; + Type dv = 0.5*dt*dt*this->mForce*dist_val; + this->mVelocity += dv; + this->mCurVal += this->mVelocity * dt; + this->mCurTime = time; +} + + +////////////////////////////// +// +// LLInterpFucn derived class implementation. +// + + +template +LLInterpFunc::LLInterpFunc() : LLInterp() +{ + mFunc = nullptr; + mData = nullptr; +} + +template +void LLInterpFunc::setFunc(Type (*func)(const F32, void *data), void *data) +{ + mFunc = func; + mData = data; +} + +template +void LLInterpFunc::update(const F32 time) +{ + if (time > this->mStartTime) + { + this->mActive = true; + } + else + { + return; + } + if (time > this->mEndTime) + { + this->mDone = true; + return; + } + + this->mCurVal = (*mFunc)(time - this->mStartTime, mData); + this->mCurTime = time; +} + +////////////////////////////// +// +// LLInterpExp derived class implementation. +// + +template +void LLInterpExp::update(const F32 time) +{ + F32 target_frac = (time - this->mStartTime) / this->mDuration; + if (target_frac >= 0.f) + { + this->mActive = true; + } + + if (target_frac > 1.f) + { + this->mCurVal = this->mEndVal; + this->mCurFrac = 1.f; + this->mCurTime = time; + this->mDone = true; + return; + } + + this->mCurFrac = 1.f - (F32)(exp(-2.f*target_frac)); + this->mCurVal = this->mStartVal + this->mCurFrac * (this->mEndVal - this->mStartVal); + this->mCurTime = time; +} + +#endif // LL_LLINTERP_H + diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index c60b90f301..4e8fc56de0 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -1,569 +1,569 @@ -/** - * @file llmath.h - * @brief Useful math constants and macros. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LLMATH_H -#define LLMATH_H - -#include -#include -#include -#include -#include "lldefs.h" -//#include "llstl.h" // *TODO: Remove when LLString is gone -//#include "llstring.h" // *TODO: Remove when LLString is gone -// lltut.h uses is_approx_equal_fraction(). This was moved to its own header -// file in llcommon so we can use lltut.h for llcommon tests without making -// llcommon depend on llmath. -#include "is_approx_equal_fraction.h" - -// work around for Windows & older gcc non-standard function names. -#if LL_WINDOWS -#include -#define llisnan(val) _isnan(val) -#define llfinite(val) _finite(val) -#elif (LL_LINUX && __GNUC__ <= 2) -#define llisnan(val) isnan(val) -#define llfinite(val) isfinite(val) -#else -#define llisnan(val) std::isnan(val) -#define llfinite(val) std::isfinite(val) -#endif - -// Single Precision Floating Point Routines -// (There used to be more defined here, but they appeared to be redundant and -// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09) -/*#ifndef tanf -#define tanf(x) ((F32)tan((F64)(x))) -#endif*/ - -constexpr F32 GRAVITY = -9.8f; - -// mathematical constants -constexpr F32 F_PI = 3.1415926535897932384626433832795f; -constexpr F32 F_TWO_PI = 6.283185307179586476925286766559f; -constexpr F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; -constexpr F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f; -constexpr F32 F_E = 2.71828182845904523536f; -constexpr F32 F_SQRT2 = 1.4142135623730950488016887242097f; -constexpr F32 F_SQRT3 = 1.73205080756888288657986402541f; -constexpr F32 OO_SQRT2 = 0.7071067811865475244008443621049f; -constexpr F32 OO_SQRT3 = 0.577350269189625764509f; -constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; -constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f; -constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f; -constexpr F32 F_LN10 = 2.3025850929940456840179914546844f; -constexpr F32 OO_LN10 = 0.43429448190325182765112891891661; -constexpr F32 F_LN2 = 0.69314718056f; -constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f; - -constexpr F32 F_ALMOST_ZERO = 0.0001f; -constexpr F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; - -constexpr F32 GIMBAL_THRESHOLD = 0.000436f; // sets the gimballock threshold 0.025 away from +/-90 degrees -// formula: GIMBAL_THRESHOLD = sin(DEG_TO_RAD * gimbal_threshold_angle); - -// BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above? -constexpr F32 FP_MAG_THRESHOLD = 0.0000001f; - -// TODO: Replace with logic like is_approx_equal -inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } - -// These functions work by interpreting sign+exp+mantissa as an unsigned -// integer. -// For example: -// x = 1 00000010 00000000000000000000000 -// y = 1 00000001 11111111111111111111111 -// -// interpreted as ints = -// x = 10000001000000000000000000000000 -// y = 10000000111111111111111111111111 -// which is clearly a different of 1 in the least significant bit -// Values with the same exponent can be trivially shown to work. -// -// WARNING: Denormals of opposite sign do not work -// x = 1 00000000 00000000000000000000001 -// y = 0 00000000 00000000000000000000001 -// Although these values differ by 2 in the LSB, the sign bit makes -// the int comparison fail. -// -// WARNING: NaNs can compare equal -// There is no special treatment of exceptional values like NaNs -// -// WARNING: Infinity is comparable with F32_MAX and negative -// infinity is comparable with F32_MIN - -// handles negative and positive zeros -inline bool is_zero(F32 x) -{ - return (*(U32*)(&x) & 0x7fffffff) == 0; -} - -inline bool is_approx_equal(F32 x, F32 y) -{ - constexpr S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; - return (std::abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); -} - -inline bool is_approx_equal(F64 x, F64 y) -{ - constexpr S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; - return (std::abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); -} - -inline S32 llabs(const S32 a) -{ - return S32(std::labs(a)); -} - -inline F32 llabs(const F32 a) -{ - return F32(std::fabs(a)); -} - -inline F64 llabs(const F64 a) -{ - return F64(std::fabs(a)); -} - -inline S32 lltrunc( F32 f ) -{ -#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && (ADDRESS_SIZE == 32) - // Avoids changing the floating point control word. - // Add or subtract 0.5 - epsilon and then round - const static U32 zpfp[] = { 0xBEFFFFFF, 0x3EFFFFFF }; - S32 result; - __asm { - fld f - mov eax, f - shr eax, 29 - and eax, 4 - fadd dword ptr [zpfp + eax] - fistp result - } - return result; -#else - return (S32)f; -#endif -} - -inline S32 lltrunc( F64 f ) -{ - return (S32)f; -} - -inline S32 llfloor( F32 f ) -{ -#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && (ADDRESS_SIZE == 32) - // Avoids changing the floating point control word. - // Accurate (unlike Stereopsis version) for all values between S32_MIN and S32_MAX and slightly faster than Stereopsis version. - // Add -(0.5 - epsilon) and then round - const U32 zpfp = 0xBEFFFFFF; - S32 result; - __asm { - fld f - fadd dword ptr [zpfp] - fistp result - } - return result; -#else - return (S32)floor(f); -#endif -} - - -inline S32 llceil( F32 f ) -{ - // This could probably be optimized, but this works. - return (S32)ceil(f); -} - - -#ifndef BOGUS_ROUND -// Use this round. Does an arithmetic round (0.5 always rounds up) -inline S32 ll_round(const F32 val) -{ - return llfloor(val + 0.5f); -} - -#else // BOGUS_ROUND -// Old ll_round implementation - does banker's round (toward nearest even in the case of a 0.5. -// Not using this because we don't have a consistent implementation on both platforms, use -// llfloor(val + 0.5f), which is consistent on all platforms. -inline S32 ll_round(const F32 val) -{ - #if LL_WINDOWS - // Note: assumes that the floating point control word is set to rounding mode (the default) - S32 ret_val; - _asm fld val - _asm fistp ret_val; - return ret_val; - #elif LL_LINUX - // Note: assumes that the floating point control word is set - // to rounding mode (the default) - S32 ret_val; - __asm__ __volatile__( "flds %1 \n\t" - "fistpl %0 \n\t" - : "=m" (ret_val) - : "m" (val) ); - return ret_val; - #else - return llfloor(val + 0.5f); - #endif -} - -// A fast arithmentic round on intel, from Laurent de Soras http://ldesoras.free.fr -inline int round_int(double x) -{ - const float round_to_nearest = 0.5f; - int i; - __asm - { - fld x - fadd st, st (0) - fadd round_to_nearest - fistp i - sar i, 1 - } - return (i); -} -#endif // BOGUS_ROUND - -inline F64 ll_round(const F64 val) -{ - return F64(floor(val + 0.5f)); -} - -inline F32 ll_round( F32 val, F32 nearest ) -{ - return F32(floor(val * (1.0f / nearest) + 0.5f)) * nearest; -} - -inline F64 ll_round( F64 val, F64 nearest ) -{ - return F64(floor(val * (1.0 / nearest) + 0.5)) * nearest; -} - -// these provide minimum peak error -// -// avg error = -0.013049 -// peak error = -31.4 dB -// RMS error = -28.1 dB - -constexpr F32 FAST_MAG_ALPHA = 0.960433870103f; -constexpr F32 FAST_MAG_BETA = 0.397824734759f; - -// these provide minimum RMS error -// -// avg error = 0.000003 -// peak error = -32.6 dB -// RMS error = -25.7 dB -// -//constexpr F32 FAST_MAG_ALPHA = 0.948059448969f; -//constexpr F32 FAST_MAG_BETA = 0.392699081699f; - -inline F32 fastMagnitude(F32 a, F32 b) -{ - a = (a > 0) ? a : -a; - b = (b > 0) ? b : -b; - return(FAST_MAG_ALPHA * llmax(a,b) + FAST_MAG_BETA * llmin(a,b)); -} - - - -//////////////////// -// -// Fast F32/S32 conversions -// -// Culled from www.stereopsis.com/FPU.html - -constexpr F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor -constexpr S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation, - -// Endian dependent code -#ifdef LL_LITTLE_ENDIAN - #define LL_EXP_INDEX 1 - #define LL_MAN_INDEX 0 -#else - #define LL_EXP_INDEX 0 - #define LL_MAN_INDEX 1 -#endif - -//////////////////////////////////////////////// -// -// Fast exp and log -// - -// Implementation of fast exp() approximation (from a paper by Nicol N. Schraudolph -// http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf -static union -{ - double d; - struct - { -#ifdef LL_LITTLE_ENDIAN - S32 j, i; -#else - S32 i, j; -#endif - } n; -} LLECO; // not sure what the name means - -#define LL_EXP_A (1048576 * OO_LN2) // use 1512775 for integer -#define LL_EXP_C (60801) // this value of C good for -4 < y < 4 - -#define LL_FAST_EXP(y) (LLECO.n.i = ll_round(F32(LL_EXP_A*(y))) + (1072693248 - LL_EXP_C), LLECO.d) - -inline F32 llfastpow(const F32 x, const F32 y) -{ - return (F32)(LL_FAST_EXP(y * log(x))); -} - - -inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs) -{ - // compute the power of ten - F32 bar = 1.f; - for (S32 i = 0; i < sig_figs; i++) - { - bar *= 10.f; - } - - F32 sign = (foo > 0.f) ? 1.f : -1.f; - F32 new_foo = F32( S64(foo * bar + sign * 0.5f)); - new_foo /= bar; - - return new_foo; -} - -inline F32 lerp(F32 a, F32 b, F32 u) -{ - return a + ((b - a) * u); -} - -inline F32 lerp2d(F32 x00, F32 x01, F32 x10, F32 x11, F32 u, F32 v) -{ - F32 a = x00 + (x01-x00)*u; - F32 b = x10 + (x11-x10)*u; - F32 r = a + (b-a)*v; - return r; -} - -inline F32 ramp(F32 x, F32 a, F32 b) -{ - return (a == b) ? 0.0f : ((a - x) / (a - b)); -} - -inline F32 rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2) -{ - return lerp(y1, y2, ramp(x, x1, x2)); -} - -inline F32 clamp_rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2) -{ - if (y1 < y2) - { - return llclamp(rescale(x,x1,x2,y1,y2),y1,y2); - } - else - { - return llclamp(rescale(x,x1,x2,y1,y2),y2,y1); - } -} - - -inline F32 cubic_step( F32 x, F32 x0, F32 x1, F32 s0, F32 s1 ) -{ - if (x <= x0) - return s0; - - if (x >= x1) - return s1; - - F32 f = (x - x0) / (x1 - x0); - - return s0 + (s1 - s0) * (f * f) * (3.0f - 2.0f * f); -} - -inline F32 cubic_step( F32 x ) -{ - x = llclampf(x); - - return (x * x) * (3.0f - 2.0f * x); -} - -inline F32 quadratic_step( F32 x, F32 x0, F32 x1, F32 s0, F32 s1 ) -{ - if (x <= x0) - return s0; - - if (x >= x1) - return s1; - - F32 f = (x - x0) / (x1 - x0); - F32 f_squared = f * f; - - return (s0 * (1.f - f_squared)) + ((s1 - s0) * f_squared); -} - -inline F32 llsimple_angle(F32 angle) -{ - while(angle <= -F_PI) - angle += F_TWO_PI; - while(angle > F_PI) - angle -= F_TWO_PI; - return angle; -} - -//SDK - Renamed this to get_lower_power_two, since this is what this actually does. -inline U32 get_lower_power_two(U32 val, U32 max_power_two) -{ - if(!max_power_two) - { - max_power_two = 1 << 31 ; - } - if(max_power_two & (max_power_two - 1)) - { - return 0 ; - } - - for(; val < max_power_two ; max_power_two >>= 1) ; - - return max_power_two ; -} - -// calculate next highest power of two, limited by max_power_two -// This is taken from a brilliant little code snipped on http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html -// Basically we convert the binary to a solid string of 1's with the same -// number of digits, then add one. We subtract 1 initially to handle -// the case where the number passed in is actually a power of two. -// WARNING: this only works with 32 bit ints. -inline U32 get_next_power_two(U32 val, U32 max_power_two) -{ - if(!max_power_two) - { - max_power_two = 1 << 31 ; - } - - if(val >= max_power_two) - { - return max_power_two; - } - - val--; - val = (val >> 1) | val; - val = (val >> 2) | val; - val = (val >> 4) | val; - val = (val >> 8) | val; - val = (val >> 16) | val; - val++; - - return val; -} - -//get the gaussian value given the linear distance from axis x and guassian value o -inline F32 llgaussian(F32 x, F32 o) -{ - return 1.f/(F_SQRT_TWO_PI*o)*powf(F_E, -(x*x)/(2*o*o)); -} - -//helper function for removing outliers -template -inline void ll_remove_outliers(std::vector& data, F32 k) -{ - if (data.size() < 100) - { //not enough samples - return; - } - - VEC_TYPE Q1 = data[data.size()/4]; - VEC_TYPE Q3 = data[data.size()-data.size()/4-1]; - - if ((F32)(Q3-Q1) < 1.f) - { - // not enough variation to detect outliers - return; - } - - - VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1)); - VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1)); - - U32 i = 0; - while (i < data.size() && data[i] < min) - { - i++; - } - - S32 j = data.size()-1; - while (j > 0 && data[j] > max) - { - j--; - } - - if (j < data.size()-1) - { - data.erase(data.begin()+j, data.end()); - } - - if (i > 0) - { - data.erase(data.begin(), data.begin()+i); - } -} - -// Converts given value from a linear RGB floating point value (0..1) to a gamma corrected (sRGB) value. -// Some shaders require color values in linear space, while others require color values in gamma corrected (sRGB) space. -// Note: in our code, values labeled as sRGB are ALWAYS gamma corrected linear values, NOT linear values with monitor gamma applied -// Note: stored color values should always be gamma corrected linear (i.e. the values returned from an on-screen color swatch) -// Note: DO NOT cache the conversion. This leads to error prone synchronization and is actually slower in the typical case due to cache misses -inline float linearTosRGB(const float val) { - if (val < 0.0031308f) { - return val * 12.92f; - } - else { - return 1.055f * pow(val, 1.0f / 2.4f) - 0.055f; - } -} - -// Converts given value from a gamma corrected (sRGB) floating point value (0..1) to a linear color value. -// Some shaders require color values in linear space, while others require color values in gamma corrected (sRGB) space. -// Note: In our code, values labeled as sRGB are gamma corrected linear values, NOT linear values with monitor gamma applied -// Note: Stored color values should generally be gamma corrected sRGB. -// If you're serializing the return value of this function, you're probably doing it wrong. -// Note: DO NOT cache the conversion. This leads to error prone synchronization and is actually slower in the typical case due to cache misses. -inline float sRGBtoLinear(const float val) { - if (val < 0.04045f) { - return val / 12.92f; - } - else { - return pow((val + 0.055f) / 1.055f, 2.4f); - } -} - -// Include simd math header -#include "llsimdmath.h" - -#endif +/** + * @file llmath.h + * @brief Useful math constants and macros. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLMATH_H +#define LLMATH_H + +#include +#include +#include +#include +#include "lldefs.h" +//#include "llstl.h" // *TODO: Remove when LLString is gone +//#include "llstring.h" // *TODO: Remove when LLString is gone +// lltut.h uses is_approx_equal_fraction(). This was moved to its own header +// file in llcommon so we can use lltut.h for llcommon tests without making +// llcommon depend on llmath. +#include "is_approx_equal_fraction.h" + +// work around for Windows & older gcc non-standard function names. +#if LL_WINDOWS +#include +#define llisnan(val) _isnan(val) +#define llfinite(val) _finite(val) +#elif (LL_LINUX && __GNUC__ <= 2) +#define llisnan(val) isnan(val) +#define llfinite(val) isfinite(val) +#else +#define llisnan(val) std::isnan(val) +#define llfinite(val) std::isfinite(val) +#endif + +// Single Precision Floating Point Routines +// (There used to be more defined here, but they appeared to be redundant and +// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09) +/*#ifndef tanf +#define tanf(x) ((F32)tan((F64)(x))) +#endif*/ + +constexpr F32 GRAVITY = -9.8f; + +// mathematical constants +constexpr F32 F_PI = 3.1415926535897932384626433832795f; +constexpr F32 F_TWO_PI = 6.283185307179586476925286766559f; +constexpr F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; +constexpr F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f; +constexpr F32 F_E = 2.71828182845904523536f; +constexpr F32 F_SQRT2 = 1.4142135623730950488016887242097f; +constexpr F32 F_SQRT3 = 1.73205080756888288657986402541f; +constexpr F32 OO_SQRT2 = 0.7071067811865475244008443621049f; +constexpr F32 OO_SQRT3 = 0.577350269189625764509f; +constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; +constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f; +constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f; +constexpr F32 F_LN10 = 2.3025850929940456840179914546844f; +constexpr F32 OO_LN10 = 0.43429448190325182765112891891661; +constexpr F32 F_LN2 = 0.69314718056f; +constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f; + +constexpr F32 F_ALMOST_ZERO = 0.0001f; +constexpr F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; + +constexpr F32 GIMBAL_THRESHOLD = 0.000436f; // sets the gimballock threshold 0.025 away from +/-90 degrees +// formula: GIMBAL_THRESHOLD = sin(DEG_TO_RAD * gimbal_threshold_angle); + +// BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above? +constexpr F32 FP_MAG_THRESHOLD = 0.0000001f; + +// TODO: Replace with logic like is_approx_equal +inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } + +// These functions work by interpreting sign+exp+mantissa as an unsigned +// integer. +// For example: +// x = 1 00000010 00000000000000000000000 +// y = 1 00000001 11111111111111111111111 +// +// interpreted as ints = +// x = 10000001000000000000000000000000 +// y = 10000000111111111111111111111111 +// which is clearly a different of 1 in the least significant bit +// Values with the same exponent can be trivially shown to work. +// +// WARNING: Denormals of opposite sign do not work +// x = 1 00000000 00000000000000000000001 +// y = 0 00000000 00000000000000000000001 +// Although these values differ by 2 in the LSB, the sign bit makes +// the int comparison fail. +// +// WARNING: NaNs can compare equal +// There is no special treatment of exceptional values like NaNs +// +// WARNING: Infinity is comparable with F32_MAX and negative +// infinity is comparable with F32_MIN + +// handles negative and positive zeros +inline bool is_zero(F32 x) +{ + return (*(U32*)(&x) & 0x7fffffff) == 0; +} + +inline bool is_approx_equal(F32 x, F32 y) +{ + constexpr S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; + return (std::abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); +} + +inline bool is_approx_equal(F64 x, F64 y) +{ + constexpr S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; + return (std::abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); +} + +inline S32 llabs(const S32 a) +{ + return S32(std::labs(a)); +} + +inline F32 llabs(const F32 a) +{ + return F32(std::fabs(a)); +} + +inline F64 llabs(const F64 a) +{ + return F64(std::fabs(a)); +} + +inline S32 lltrunc( F32 f ) +{ +#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && (ADDRESS_SIZE == 32) + // Avoids changing the floating point control word. + // Add or subtract 0.5 - epsilon and then round + const static U32 zpfp[] = { 0xBEFFFFFF, 0x3EFFFFFF }; + S32 result; + __asm { + fld f + mov eax, f + shr eax, 29 + and eax, 4 + fadd dword ptr [zpfp + eax] + fistp result + } + return result; +#else + return (S32)f; +#endif +} + +inline S32 lltrunc( F64 f ) +{ + return (S32)f; +} + +inline S32 llfloor( F32 f ) +{ +#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && (ADDRESS_SIZE == 32) + // Avoids changing the floating point control word. + // Accurate (unlike Stereopsis version) for all values between S32_MIN and S32_MAX and slightly faster than Stereopsis version. + // Add -(0.5 - epsilon) and then round + const U32 zpfp = 0xBEFFFFFF; + S32 result; + __asm { + fld f + fadd dword ptr [zpfp] + fistp result + } + return result; +#else + return (S32)floor(f); +#endif +} + + +inline S32 llceil( F32 f ) +{ + // This could probably be optimized, but this works. + return (S32)ceil(f); +} + + +#ifndef BOGUS_ROUND +// Use this round. Does an arithmetic round (0.5 always rounds up) +inline S32 ll_round(const F32 val) +{ + return llfloor(val + 0.5f); +} + +#else // BOGUS_ROUND +// Old ll_round implementation - does banker's round (toward nearest even in the case of a 0.5. +// Not using this because we don't have a consistent implementation on both platforms, use +// llfloor(val + 0.5f), which is consistent on all platforms. +inline S32 ll_round(const F32 val) +{ + #if LL_WINDOWS + // Note: assumes that the floating point control word is set to rounding mode (the default) + S32 ret_val; + _asm fld val + _asm fistp ret_val; + return ret_val; + #elif LL_LINUX + // Note: assumes that the floating point control word is set + // to rounding mode (the default) + S32 ret_val; + __asm__ __volatile__( "flds %1 \n\t" + "fistpl %0 \n\t" + : "=m" (ret_val) + : "m" (val) ); + return ret_val; + #else + return llfloor(val + 0.5f); + #endif +} + +// A fast arithmentic round on intel, from Laurent de Soras http://ldesoras.free.fr +inline int round_int(double x) +{ + const float round_to_nearest = 0.5f; + int i; + __asm + { + fld x + fadd st, st (0) + fadd round_to_nearest + fistp i + sar i, 1 + } + return (i); +} +#endif // BOGUS_ROUND + +inline F64 ll_round(const F64 val) +{ + return F64(floor(val + 0.5f)); +} + +inline F32 ll_round( F32 val, F32 nearest ) +{ + return F32(floor(val * (1.0f / nearest) + 0.5f)) * nearest; +} + +inline F64 ll_round( F64 val, F64 nearest ) +{ + return F64(floor(val * (1.0 / nearest) + 0.5)) * nearest; +} + +// these provide minimum peak error +// +// avg error = -0.013049 +// peak error = -31.4 dB +// RMS error = -28.1 dB + +constexpr F32 FAST_MAG_ALPHA = 0.960433870103f; +constexpr F32 FAST_MAG_BETA = 0.397824734759f; + +// these provide minimum RMS error +// +// avg error = 0.000003 +// peak error = -32.6 dB +// RMS error = -25.7 dB +// +//constexpr F32 FAST_MAG_ALPHA = 0.948059448969f; +//constexpr F32 FAST_MAG_BETA = 0.392699081699f; + +inline F32 fastMagnitude(F32 a, F32 b) +{ + a = (a > 0) ? a : -a; + b = (b > 0) ? b : -b; + return(FAST_MAG_ALPHA * llmax(a,b) + FAST_MAG_BETA * llmin(a,b)); +} + + + +//////////////////// +// +// Fast F32/S32 conversions +// +// Culled from www.stereopsis.com/FPU.html + +constexpr F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor +constexpr S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation, + +// Endian dependent code +#ifdef LL_LITTLE_ENDIAN + #define LL_EXP_INDEX 1 + #define LL_MAN_INDEX 0 +#else + #define LL_EXP_INDEX 0 + #define LL_MAN_INDEX 1 +#endif + +//////////////////////////////////////////////// +// +// Fast exp and log +// + +// Implementation of fast exp() approximation (from a paper by Nicol N. Schraudolph +// http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf +static union +{ + double d; + struct + { +#ifdef LL_LITTLE_ENDIAN + S32 j, i; +#else + S32 i, j; +#endif + } n; +} LLECO; // not sure what the name means + +#define LL_EXP_A (1048576 * OO_LN2) // use 1512775 for integer +#define LL_EXP_C (60801) // this value of C good for -4 < y < 4 + +#define LL_FAST_EXP(y) (LLECO.n.i = ll_round(F32(LL_EXP_A*(y))) + (1072693248 - LL_EXP_C), LLECO.d) + +inline F32 llfastpow(const F32 x, const F32 y) +{ + return (F32)(LL_FAST_EXP(y * log(x))); +} + + +inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs) +{ + // compute the power of ten + F32 bar = 1.f; + for (S32 i = 0; i < sig_figs; i++) + { + bar *= 10.f; + } + + F32 sign = (foo > 0.f) ? 1.f : -1.f; + F32 new_foo = F32( S64(foo * bar + sign * 0.5f)); + new_foo /= bar; + + return new_foo; +} + +inline F32 lerp(F32 a, F32 b, F32 u) +{ + return a + ((b - a) * u); +} + +inline F32 lerp2d(F32 x00, F32 x01, F32 x10, F32 x11, F32 u, F32 v) +{ + F32 a = x00 + (x01-x00)*u; + F32 b = x10 + (x11-x10)*u; + F32 r = a + (b-a)*v; + return r; +} + +inline F32 ramp(F32 x, F32 a, F32 b) +{ + return (a == b) ? 0.0f : ((a - x) / (a - b)); +} + +inline F32 rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2) +{ + return lerp(y1, y2, ramp(x, x1, x2)); +} + +inline F32 clamp_rescale(F32 x, F32 x1, F32 x2, F32 y1, F32 y2) +{ + if (y1 < y2) + { + return llclamp(rescale(x,x1,x2,y1,y2),y1,y2); + } + else + { + return llclamp(rescale(x,x1,x2,y1,y2),y2,y1); + } +} + + +inline F32 cubic_step( F32 x, F32 x0, F32 x1, F32 s0, F32 s1 ) +{ + if (x <= x0) + return s0; + + if (x >= x1) + return s1; + + F32 f = (x - x0) / (x1 - x0); + + return s0 + (s1 - s0) * (f * f) * (3.0f - 2.0f * f); +} + +inline F32 cubic_step( F32 x ) +{ + x = llclampf(x); + + return (x * x) * (3.0f - 2.0f * x); +} + +inline F32 quadratic_step( F32 x, F32 x0, F32 x1, F32 s0, F32 s1 ) +{ + if (x <= x0) + return s0; + + if (x >= x1) + return s1; + + F32 f = (x - x0) / (x1 - x0); + F32 f_squared = f * f; + + return (s0 * (1.f - f_squared)) + ((s1 - s0) * f_squared); +} + +inline F32 llsimple_angle(F32 angle) +{ + while(angle <= -F_PI) + angle += F_TWO_PI; + while(angle > F_PI) + angle -= F_TWO_PI; + return angle; +} + +//SDK - Renamed this to get_lower_power_two, since this is what this actually does. +inline U32 get_lower_power_two(U32 val, U32 max_power_two) +{ + if(!max_power_two) + { + max_power_two = 1 << 31 ; + } + if(max_power_two & (max_power_two - 1)) + { + return 0 ; + } + + for(; val < max_power_two ; max_power_two >>= 1) ; + + return max_power_two ; +} + +// calculate next highest power of two, limited by max_power_two +// This is taken from a brilliant little code snipped on http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html +// Basically we convert the binary to a solid string of 1's with the same +// number of digits, then add one. We subtract 1 initially to handle +// the case where the number passed in is actually a power of two. +// WARNING: this only works with 32 bit ints. +inline U32 get_next_power_two(U32 val, U32 max_power_two) +{ + if(!max_power_two) + { + max_power_two = 1 << 31 ; + } + + if(val >= max_power_two) + { + return max_power_two; + } + + val--; + val = (val >> 1) | val; + val = (val >> 2) | val; + val = (val >> 4) | val; + val = (val >> 8) | val; + val = (val >> 16) | val; + val++; + + return val; +} + +//get the gaussian value given the linear distance from axis x and guassian value o +inline F32 llgaussian(F32 x, F32 o) +{ + return 1.f/(F_SQRT_TWO_PI*o)*powf(F_E, -(x*x)/(2*o*o)); +} + +//helper function for removing outliers +template +inline void ll_remove_outliers(std::vector& data, F32 k) +{ + if (data.size() < 100) + { //not enough samples + return; + } + + VEC_TYPE Q1 = data[data.size()/4]; + VEC_TYPE Q3 = data[data.size()-data.size()/4-1]; + + if ((F32)(Q3-Q1) < 1.f) + { + // not enough variation to detect outliers + return; + } + + + VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1)); + VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1)); + + U32 i = 0; + while (i < data.size() && data[i] < min) + { + i++; + } + + S32 j = data.size()-1; + while (j > 0 && data[j] > max) + { + j--; + } + + if (j < data.size()-1) + { + data.erase(data.begin()+j, data.end()); + } + + if (i > 0) + { + data.erase(data.begin(), data.begin()+i); + } +} + +// Converts given value from a linear RGB floating point value (0..1) to a gamma corrected (sRGB) value. +// Some shaders require color values in linear space, while others require color values in gamma corrected (sRGB) space. +// Note: in our code, values labeled as sRGB are ALWAYS gamma corrected linear values, NOT linear values with monitor gamma applied +// Note: stored color values should always be gamma corrected linear (i.e. the values returned from an on-screen color swatch) +// Note: DO NOT cache the conversion. This leads to error prone synchronization and is actually slower in the typical case due to cache misses +inline float linearTosRGB(const float val) { + if (val < 0.0031308f) { + return val * 12.92f; + } + else { + return 1.055f * pow(val, 1.0f / 2.4f) - 0.055f; + } +} + +// Converts given value from a gamma corrected (sRGB) floating point value (0..1) to a linear color value. +// Some shaders require color values in linear space, while others require color values in gamma corrected (sRGB) space. +// Note: In our code, values labeled as sRGB are gamma corrected linear values, NOT linear values with monitor gamma applied +// Note: Stored color values should generally be gamma corrected sRGB. +// If you're serializing the return value of this function, you're probably doing it wrong. +// Note: DO NOT cache the conversion. This leads to error prone synchronization and is actually slower in the typical case due to cache misses. +inline float sRGBtoLinear(const float val) { + if (val < 0.04045f) { + return val / 12.92f; + } + else { + return pow((val + 0.055f) / 1.055f, 2.4f); + } +} + +// Include simd math header +#include "llsimdmath.h" + +#endif diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 6e43646b60..475ce20ae6 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -1,858 +1,858 @@ -/** - * @file lloctree.h - * @brief Octree declaration. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLOCTREE_H -#define LL_LLOCTREE_H - -#include "lltreenode.h" -#include "v3math.h" -#include "llvector4a.h" -#include - -#define OCT_ERRS LL_WARNS("OctreeErrors") - -#define OCTREE_DEBUG_COLOR_REMOVE 0x0000FF // r -#define OCTREE_DEBUG_COLOR_INSERT 0x00FF00 // g -#define OCTREE_DEBUG_COLOR_BALANCE 0xFF0000 // b - -extern U32 gOctreeMaxCapacity; -extern float gOctreeMinSize; - -/*#define LL_OCTREE_PARANOIA_CHECK 0 -#if LL_DARWIN -#define LL_OCTREE_MAX_CAPACITY 32 -#else -#define LL_OCTREE_MAX_CAPACITY 128 -#endif*/ - -// T is the type of the element referenced by the octree node. -// T_PTR determines how pointers to elements are stored internally. -// LLOctreeNode> assumes ownership of inserted elements and -// deletes elements removed from the tree. -// LLOctreeNode doesn't take ownership of inserted elements, so the API -// user is responsible for managing the storage lifecycle of elements added to -// the tree. -template class LLOctreeNode; - -template -class LLOctreeListener: public LLTreeListener -{ -public: - typedef LLTreeListener BaseType; - typedef LLOctreeNode oct_node; - - virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0; - virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0; -}; - -template -class LLOctreeTraveler -{ -public: - virtual void traverse(const LLOctreeNode* node); - virtual void visit(const LLOctreeNode* branch) = 0; -}; - -template -class LLOctreeTravelerDepthFirst : public LLOctreeTraveler -{ -public: - virtual void traverse(const LLOctreeNode* node) override; -}; - -template -class alignas(16) LLOctreeNode : public LLTreeNode -{ - LL_ALIGN_NEW -public: - - typedef LLOctreeTraveler oct_traveler; - typedef LLTreeTraveler tree_traveler; - typedef std::vector element_list; - typedef typename element_list::iterator element_iter; - typedef typename element_list::const_iterator const_element_iter; - typedef typename std::vector*>::iterator tree_listener_iter; - typedef LLOctreeNode** child_list; - typedef LLOctreeNode** child_iter; - - typedef LLTreeNode BaseType; - typedef LLOctreeNode oct_node; - typedef LLOctreeListener oct_listener; - - enum - { - NO_CHILD_NODES = 255 // Note: This is an U8 to match the max value in mChildMap[] - }; - - LLOctreeNode( const LLVector4a& center, - const LLVector4a& size, - BaseType* parent, - U8 octant = NO_CHILD_NODES) - : mParent((oct_node*)parent), - mOctant(octant) - { - llassert(size[0] >= gOctreeMinSize*0.5f); - - mCenter = center; - mSize = size; - - updateMinMax(); - if ((mOctant == NO_CHILD_NODES) && mParent) - { - mOctant = ((oct_node*) mParent)->getOctant(mCenter); - } - - clearChildren(); - } - - virtual ~LLOctreeNode() - { - BaseType::destroyListeners(); - - const U32 element_count = getElementCount(); - for (U32 i = 0; i < element_count; ++i) - { - mData[i]->setBinIndex(-1); - mData[i] = NULL; - } - - mData.clear(); - - for (U32 i = 0; i < getChildCount(); i++) - { - delete getChild(i); - } - } - - inline const BaseType* getParent() const { return mParent; } - inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; } - inline const LLVector4a& getCenter() const { return mCenter; } - inline const LLVector4a& getSize() const { return mSize; } - inline void setCenter(const LLVector4a& center) { mCenter = center; } - inline void setSize(const LLVector4a& size) { mSize = size; } - inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); } - inline U8 getOctant() const { return mOctant; } - inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); } - inline oct_node* getOctParent() { return (oct_node*) getParent(); } - - U8 getOctant(const LLVector4a& pos) const //get the octant pos is in - { - return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7); - } - - inline bool isInside(const LLVector4a& pos, const F32& rad) const - { - return rad <= mSize[0]*2.f && isInside(pos); - } - - inline bool isInside(T* data) const - { - return isInside(data->getPositionGroup(), data->getBinRadius()); - } - - bool isInside(const LLVector4a& pos) const - { - S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7; - if (gt) - { - return false; - } - - S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7; - if (lt) - { - return false; - } - - return true; - } - - void updateMinMax() - { - mMax.setAdd(mCenter, mSize); - mMin.setSub(mCenter, mSize); - } - - inline oct_listener* getOctListener(U32 index) - { - return (oct_listener*) BaseType::getListener(index); - } - - inline bool contains(T* xform) - { - return contains(xform->getBinRadius()); - } - - bool contains(F32 radius) - { - if (mParent == NULL) - { //root node contains nothing - return false; - } - - F32 size = mSize[0]; - F32 p_size = size * 2.f; - - return (radius <= gOctreeMinSize && size <= gOctreeMinSize) || - (radius <= p_size && radius > size); - } - - static void pushCenter(LLVector4a ¢er, const LLVector4a &size, const T* data) - { - const LLVector4a& pos = data->getPositionGroup(); - - LLVector4Logical gt = pos.greaterThan(center); - - LLVector4a up; - up = _mm_and_ps(size, gt); - - LLVector4a down; - down = _mm_andnot_ps(gt, size); - - center.add(up); - center.sub(down); - } - - void accept(oct_traveler* visitor) { visitor->visit(this); } - virtual bool isLeaf() const { return mChildCount == 0; } - - U32 getElementCount() const { return (U32)mData.size(); } - bool isEmpty() const { return mData.empty(); } - element_iter getDataBegin() { return mData.begin(); } - element_iter getDataEnd() { return mData.end(); } - const_element_iter getDataBegin() const { return mData.cbegin(); } - const_element_iter getDataEnd() const { return mData.cend(); } - - U32 getChildCount() const { return mChildCount; } - oct_node* getChild(U32 index) { return mChild[index]; } - const oct_node* getChild(U32 index) const { return mChild[index]; } - child_list& getChildren() { return mChild; } - const child_list& getChildren() const { return mChild; } - - void accept(tree_traveler* visitor) const { visitor->visit(this); } - void accept(oct_traveler* visitor) const { visitor->visit(this); } - - void validateChildMap() - { - for (U32 i = 0; i < 8; i++) - { - U8 idx = mChildMap[i]; - if (idx != NO_CHILD_NODES) - { - oct_node* child = mChild[idx]; - - if (child->getOctant() != i) - { - LL_ERRS() << "Invalid child map, bad octant data." << LL_ENDL; - } - - if (getOctant(child->getCenter()) != child->getOctant()) - { - LL_ERRS() << "Invalid child octant compared to position data." << LL_ENDL; - } - } - } - } - - - oct_node* getNodeAt(const LLVector4a& pos, const F32& rad) - { - oct_node* node = this; - - if (node->isInside(pos, rad)) - { - //do a quick search by octant - U8 octant = node->getOctant(pos); - - //traverse the tree until we find a node that has no node - //at the appropriate octant or is smaller than the object. - //by definition, that node is the smallest node that contains - // the data - U8 next_node = node->mChildMap[octant]; - - while (next_node != NO_CHILD_NODES && node->getSize()[0] >= rad) - { - node = node->getChild(next_node); - octant = node->getOctant(pos); - next_node = node->mChildMap[octant]; - } - } - else if (!node->contains(rad) && node->getParent()) - { //if we got here, data does not exist in this node - return ((oct_node*) node->getParent())->getNodeAt(pos, rad); - } - - return node; - } - - virtual bool insert(T* data) - { - //LL_PROFILE_ZONE_NAMED_COLOR("Octree::insert()",OCTREE_DEBUG_COLOR_INSERT); - - if (data == NULL || data->getBinIndex() != -1) - { - OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL; - return false; - } - oct_node* parent = getOctParent(); - - //is it here? - if (isInside(data->getPositionGroup())) - { - if ((((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius())) || - (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) - { //it belongs here - mData.push_back(data); - data->setBinIndex(getElementCount() - 1); - BaseType::insert(data); - return true; - } - else - { - //find a child to give it to - oct_node* child = NULL; - for (U32 i = 0; i < getChildCount(); i++) - { - child = getChild(i); - if (child->isInside(data->getPositionGroup())) - { - child->insert(data); - return false; - } - } - - //it's here, but no kids are in the right place, make a new kid - LLVector4a center = getCenter(); - LLVector4a size = getSize(); - size.mul(0.5f); - - //push center in direction of data - oct_node::pushCenter(center, size, data); - - // handle case where floating point number gets too small - LLVector4a val; - val.setSub(center, getCenter()); - val.setAbs(val); - LLVector4a min_diff(gOctreeMinSize); - - S32 lt = val.lessThan(min_diff).getGatheredBits() & 0x7; - - if( lt == 0x7 ) - { - mData.push_back(data); - data->setBinIndex(getElementCount() - 1); - BaseType::insert(data); - return true; - } - -#if LL_OCTREE_PARANOIA_CHECK - if (getChildCount() == 8) - { - //this really isn't possible, something bad has happened - OCT_ERRS << "Octree detected floating point error and gave up." << LL_ENDL; - return false; - } - - //make sure no existing node matches this position - for (U32 i = 0; i < getChildCount(); i++) - { - if (mChild[i]->getCenter().equals3(center)) - { - OCT_ERRS << "Octree detected duplicate child center and gave up." << LL_ENDL; - return false; - } - } -#endif - - llassert(size[0] >= gOctreeMinSize*0.5f); - //make the new kid - child = new oct_node(center, size, this); - addChild(child); - - child->insert(data); - } - } - else if (parent) - { - //it's not in here, give it to the root - OCT_ERRS << "Octree insertion failed, starting over from root!" << LL_ENDL; - - oct_node* node = this; - - while (parent) - { - node = parent; - parent = node->getOctParent(); - } - - node->insert(data); - } - else - { - // It's not in here, and we are root. - // LLOctreeRoot::insert() should have expanded - // root by now, something is wrong - OCT_ERRS << "Octree insertion failed! Root expansion failed." << LL_ENDL; - } - - return false; - } - - void _remove(T* data, S32 i) - { //precondition -- getElementCount() > 0, idx is in range [0, getElementCount()) - - data->setBinIndex(-1); - - const U32 new_element_count = getElementCount() - 1; - if (new_element_count > 0) - { - if (new_element_count != i) - { - mData[i] = mData[new_element_count]; //might unref data, do not access data after this point - mData[i]->setBinIndex(i); - } - - mData[new_element_count] = NULL; - mData.pop_back(); - } - else - { - mData.clear(); - } - - this->notifyRemoval(data); - checkAlive(); - } - - bool remove(T* data) - { - //LL_PROFILE_ZONE_NAMED_COLOR("Octree::remove()", OCTREE_DEBUG_COLOR_REMOVE); - - S32 i = data->getBinIndex(); - - if (i >= 0 && i < getElementCount()) - { - if (mData[i] == data) - { //found it - _remove(data, i); - llassert(data->getBinIndex() == -1); - return true; - } - } - - if (isInside(data)) - { - oct_node* dest = getNodeAt(data); - - if (dest != this) - { - bool ret = dest->remove(data); - llassert(data->getBinIndex() == -1); - return ret; - } - } - - //SHE'S GONE MISSING... - //none of the children have it, let's just brute force this bastard out - //starting with the root node (UGLY CODE COMETH!) - oct_node* parent = getOctParent(); - oct_node* node = this; - - while (parent != NULL) - { - node = parent; - parent = node->getOctParent(); - } - - //node is now root - LL_WARNS() << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << LL_ENDL; - node->removeByAddress(data); - llassert(data->getBinIndex() == -1); - return true; - } - - void removeByAddress(T* data) - { - const U32 element_count = getElementCount(); - for (U32 i = 0; i < element_count; ++i) - { - if (mData[i] == data) - { //we have data - _remove(data, i); - LL_WARNS() << "FOUND!" << LL_ENDL; - return; - } - } - - for (U32 i = 0; i < getChildCount(); i++) - { //we don't contain data, so pass this guy down - oct_node* child = (oct_node*) getChild(i); - child->removeByAddress(data); - } - } - - void clearChildren() - { - mChildCount = 0; - memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap)); - } - - void validate() - { -#if LL_OCTREE_PARANOIA_CHECK - for (U32 i = 0; i < getChildCount(); i++) - { - mChild[i]->validate(); - if (mChild[i]->getParent() != this) - { - LL_ERRS() << "Octree child has invalid parent." << LL_ENDL; - } - } -#endif - } - - virtual bool balance() - { - return false; - } - - void destroy() - { - for (U32 i = 0; i < getChildCount(); i++) - { - mChild[i]->destroy(); - delete mChild[i]; - } - } - - void addChild(oct_node* child, bool silent = false) - { -#if LL_OCTREE_PARANOIA_CHECK - - if (child->getSize().equals3(getSize())) - { - OCT_ERRS << "Child size is same as parent size!" << LL_ENDL; - } - - for (U32 i = 0; i < getChildCount(); i++) - { - if(!mChild[i]->getSize().equals3(child->getSize())) - { - OCT_ERRS <<"Invalid octree child size." << LL_ENDL; - } - if (mChild[i]->getCenter().equals3(child->getCenter())) - { - OCT_ERRS <<"Duplicate octree child position." << LL_ENDL; - } - } - - if (mChild.size() >= 8) - { - OCT_ERRS <<"Octree node has too many children... why?" << LL_ENDL; - } -#endif - - mChildMap[child->getOctant()] = mChildCount; - - mChild[mChildCount] = child; - ++mChildCount; - child->setParent(this); - - if (!silent) - { - for (U32 i = 0; i < this->getListenerCount(); i++) - { - oct_listener* listener = getOctListener(i); - listener->handleChildAddition(this, child); - } - } - } - - void removeChild(S32 index, bool destroy = false) - { - for (U32 i = 0; i < this->getListenerCount(); i++) - { - oct_listener* listener = getOctListener(i); - listener->handleChildRemoval(this, getChild(index)); - } - - if (destroy) - { - mChild[index]->destroy(); - delete mChild[index]; - } - - --mChildCount; - - mChild[index] = mChild[mChildCount]; - - //rebuild child map - memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap)); - - for (U32 i = 0; i < mChildCount; ++i) - { - mChildMap[mChild[i]->getOctant()] = i; - } - - checkAlive(); - } - - void checkAlive() - { - if (getChildCount() == 0 && getElementCount() == 0) - { - oct_node* parent = getOctParent(); - if (parent) - { - parent->deleteChild(this); - } - } - } - - void deleteChild(oct_node* node) - { - for (U32 i = 0; i < getChildCount(); i++) - { - if (getChild(i) == node) - { - removeChild(i, true); - return; - } - } - - OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL; - } - -protected: - typedef enum - { - CENTER = 0, - SIZE = 1, - MAX = 2, - MIN = 3 - } eDName; - - LLVector4a mCenter; - LLVector4a mSize; - LLVector4a mMax; - LLVector4a mMin; - - oct_node* mParent; - U8 mOctant; - - oct_node* mChild[8]; - U8 mChildMap[8]; - U32 mChildCount; - - element_list mData; -}; - -//just like a regular node, except it might expand on insert and compress on balance -template -class LLOctreeRoot : public LLOctreeNode -{ -public: - typedef LLOctreeNode BaseType; - typedef LLOctreeNode oct_node; - - LLOctreeRoot(const LLVector4a& center, - const LLVector4a& size, - BaseType* parent) - : BaseType(center, size, parent) - { - } - - bool balance() override - { - //LL_PROFILE_ZONE_NAMED_COLOR("Octree::balance()",OCTREE_DEBUG_COLOR_BALANCE); - - if (this->getChildCount() == 1 && - !(this->mChild[0]->isLeaf()) && - this->mChild[0]->getElementCount() == 0) - { //if we have only one child and that child is an empty branch, make that child the root - oct_node* child = this->mChild[0]; - - //make the root node look like the child - this->setCenter(this->mChild[0]->getCenter()); - this->setSize(this->mChild[0]->getSize()); - this->updateMinMax(); - - //reset root node child list - this->clearChildren(); - - //copy the child's children into the root node silently - //(don't notify listeners of addition) - for (U32 i = 0; i < child->getChildCount(); i++) - { - this->addChild(child->getChild(i), true); - } - - //destroy child - child->clearChildren(); - delete child; - - return false; - } - - return true; - } - - // LLOctreeRoot::insert - bool insert(T* data) override - { - if (data == nullptr) - { - OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << LL_ENDL; - return false; - } - - if (data->getBinRadius() > 4096.0) - { - OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << LL_ENDL; - return false; - } - - LLVector4a MAX_MAG; - MAX_MAG.splat(1024.f*1024.f); - - const LLVector4a& v = data->getPositionGroup(); - - LLVector4a val; - val.setSub(v, BaseType::mCenter); - val.setAbs(val); - S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7; - - if (lt != 0x7) - { - //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << LL_ENDL; - return false; - } - - if (this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup())) - { - //we got it, just act like a branch - oct_node* node = this->getNodeAt(data); - if (node == this) - { - oct_node::insert(data); - } - else if (node->isInside(data->getPositionGroup())) - { - node->insert(data); - } - else - { - // calling node->insert(data) will return us to root - OCT_ERRS << "Failed to insert data at child node" << LL_ENDL; - } - } - else if (this->getChildCount() == 0) - { - //first object being added, just wrap it up - while (!(this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup()))) - { - LLVector4a center, size; - center = this->getCenter(); - size = this->getSize(); - oct_node::pushCenter(center, size, data); - this->setCenter(center); - size.mul(2.f); - this->setSize(size); - this->updateMinMax(); - } - oct_node::insert(data); - } - else - { - while (!(this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup()))) - { - //the data is outside the root node, we need to grow - LLVector4a center(this->getCenter()); - LLVector4a size(this->getSize()); - - //expand this node - LLVector4a newcenter(center); - oct_node::pushCenter(newcenter, size, data); - this->setCenter(newcenter); - LLVector4a size2 = size; - size2.mul(2.f); - this->setSize(size2); - this->updateMinMax(); - - llassert(size[0] >= gOctreeMinSize); - - //copy our children to a new branch - oct_node* newnode = new oct_node(center, size, this); - - for (U32 i = 0; i < this->getChildCount(); i++) - { - oct_node* child = this->getChild(i); - newnode->addChild(child); - } - - //clear our children and add the root copy - this->clearChildren(); - this->addChild(newnode); - } - - //insert the data - insert(data); - } - - return false; - } - - bool isLeaf() const override - { - // root can't be a leaf - return false; - } -}; - -//======================== -// LLOctreeTraveler -//======================== -template -void LLOctreeTraveler::traverse(const LLOctreeNode* node) -{ - node->accept(this); - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - } -} - -template -void LLOctreeTravelerDepthFirst::traverse(const LLOctreeNode* node) -{ - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - } - node->accept(this); -} - -#endif +/** + * @file lloctree.h + * @brief Octree declaration. + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLOCTREE_H +#define LL_LLOCTREE_H + +#include "lltreenode.h" +#include "v3math.h" +#include "llvector4a.h" +#include + +#define OCT_ERRS LL_WARNS("OctreeErrors") + +#define OCTREE_DEBUG_COLOR_REMOVE 0x0000FF // r +#define OCTREE_DEBUG_COLOR_INSERT 0x00FF00 // g +#define OCTREE_DEBUG_COLOR_BALANCE 0xFF0000 // b + +extern U32 gOctreeMaxCapacity; +extern float gOctreeMinSize; + +/*#define LL_OCTREE_PARANOIA_CHECK 0 +#if LL_DARWIN +#define LL_OCTREE_MAX_CAPACITY 32 +#else +#define LL_OCTREE_MAX_CAPACITY 128 +#endif*/ + +// T is the type of the element referenced by the octree node. +// T_PTR determines how pointers to elements are stored internally. +// LLOctreeNode> assumes ownership of inserted elements and +// deletes elements removed from the tree. +// LLOctreeNode doesn't take ownership of inserted elements, so the API +// user is responsible for managing the storage lifecycle of elements added to +// the tree. +template class LLOctreeNode; + +template +class LLOctreeListener: public LLTreeListener +{ +public: + typedef LLTreeListener BaseType; + typedef LLOctreeNode oct_node; + + virtual void handleChildAddition(const oct_node* parent, oct_node* child) = 0; + virtual void handleChildRemoval(const oct_node* parent, const oct_node* child) = 0; +}; + +template +class LLOctreeTraveler +{ +public: + virtual void traverse(const LLOctreeNode* node); + virtual void visit(const LLOctreeNode* branch) = 0; +}; + +template +class LLOctreeTravelerDepthFirst : public LLOctreeTraveler +{ +public: + virtual void traverse(const LLOctreeNode* node) override; +}; + +template +class alignas(16) LLOctreeNode : public LLTreeNode +{ + LL_ALIGN_NEW +public: + + typedef LLOctreeTraveler oct_traveler; + typedef LLTreeTraveler tree_traveler; + typedef std::vector element_list; + typedef typename element_list::iterator element_iter; + typedef typename element_list::const_iterator const_element_iter; + typedef typename std::vector*>::iterator tree_listener_iter; + typedef LLOctreeNode** child_list; + typedef LLOctreeNode** child_iter; + + typedef LLTreeNode BaseType; + typedef LLOctreeNode oct_node; + typedef LLOctreeListener oct_listener; + + enum + { + NO_CHILD_NODES = 255 // Note: This is an U8 to match the max value in mChildMap[] + }; + + LLOctreeNode( const LLVector4a& center, + const LLVector4a& size, + BaseType* parent, + U8 octant = NO_CHILD_NODES) + : mParent((oct_node*)parent), + mOctant(octant) + { + llassert(size[0] >= gOctreeMinSize*0.5f); + + mCenter = center; + mSize = size; + + updateMinMax(); + if ((mOctant == NO_CHILD_NODES) && mParent) + { + mOctant = ((oct_node*) mParent)->getOctant(mCenter); + } + + clearChildren(); + } + + virtual ~LLOctreeNode() + { + BaseType::destroyListeners(); + + const U32 element_count = getElementCount(); + for (U32 i = 0; i < element_count; ++i) + { + mData[i]->setBinIndex(-1); + mData[i] = NULL; + } + + mData.clear(); + + for (U32 i = 0; i < getChildCount(); i++) + { + delete getChild(i); + } + } + + inline const BaseType* getParent() const { return mParent; } + inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; } + inline const LLVector4a& getCenter() const { return mCenter; } + inline const LLVector4a& getSize() const { return mSize; } + inline void setCenter(const LLVector4a& center) { mCenter = center; } + inline void setSize(const LLVector4a& size) { mSize = size; } + inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); } + inline U8 getOctant() const { return mOctant; } + inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); } + inline oct_node* getOctParent() { return (oct_node*) getParent(); } + + U8 getOctant(const LLVector4a& pos) const //get the octant pos is in + { + return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7); + } + + inline bool isInside(const LLVector4a& pos, const F32& rad) const + { + return rad <= mSize[0]*2.f && isInside(pos); + } + + inline bool isInside(T* data) const + { + return isInside(data->getPositionGroup(), data->getBinRadius()); + } + + bool isInside(const LLVector4a& pos) const + { + S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7; + if (gt) + { + return false; + } + + S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7; + if (lt) + { + return false; + } + + return true; + } + + void updateMinMax() + { + mMax.setAdd(mCenter, mSize); + mMin.setSub(mCenter, mSize); + } + + inline oct_listener* getOctListener(U32 index) + { + return (oct_listener*) BaseType::getListener(index); + } + + inline bool contains(T* xform) + { + return contains(xform->getBinRadius()); + } + + bool contains(F32 radius) + { + if (mParent == NULL) + { //root node contains nothing + return false; + } + + F32 size = mSize[0]; + F32 p_size = size * 2.f; + + return (radius <= gOctreeMinSize && size <= gOctreeMinSize) || + (radius <= p_size && radius > size); + } + + static void pushCenter(LLVector4a ¢er, const LLVector4a &size, const T* data) + { + const LLVector4a& pos = data->getPositionGroup(); + + LLVector4Logical gt = pos.greaterThan(center); + + LLVector4a up; + up = _mm_and_ps(size, gt); + + LLVector4a down; + down = _mm_andnot_ps(gt, size); + + center.add(up); + center.sub(down); + } + + void accept(oct_traveler* visitor) { visitor->visit(this); } + virtual bool isLeaf() const { return mChildCount == 0; } + + U32 getElementCount() const { return (U32)mData.size(); } + bool isEmpty() const { return mData.empty(); } + element_iter getDataBegin() { return mData.begin(); } + element_iter getDataEnd() { return mData.end(); } + const_element_iter getDataBegin() const { return mData.cbegin(); } + const_element_iter getDataEnd() const { return mData.cend(); } + + U32 getChildCount() const { return mChildCount; } + oct_node* getChild(U32 index) { return mChild[index]; } + const oct_node* getChild(U32 index) const { return mChild[index]; } + child_list& getChildren() { return mChild; } + const child_list& getChildren() const { return mChild; } + + void accept(tree_traveler* visitor) const { visitor->visit(this); } + void accept(oct_traveler* visitor) const { visitor->visit(this); } + + void validateChildMap() + { + for (U32 i = 0; i < 8; i++) + { + U8 idx = mChildMap[i]; + if (idx != NO_CHILD_NODES) + { + oct_node* child = mChild[idx]; + + if (child->getOctant() != i) + { + LL_ERRS() << "Invalid child map, bad octant data." << LL_ENDL; + } + + if (getOctant(child->getCenter()) != child->getOctant()) + { + LL_ERRS() << "Invalid child octant compared to position data." << LL_ENDL; + } + } + } + } + + + oct_node* getNodeAt(const LLVector4a& pos, const F32& rad) + { + oct_node* node = this; + + if (node->isInside(pos, rad)) + { + //do a quick search by octant + U8 octant = node->getOctant(pos); + + //traverse the tree until we find a node that has no node + //at the appropriate octant or is smaller than the object. + //by definition, that node is the smallest node that contains + // the data + U8 next_node = node->mChildMap[octant]; + + while (next_node != NO_CHILD_NODES && node->getSize()[0] >= rad) + { + node = node->getChild(next_node); + octant = node->getOctant(pos); + next_node = node->mChildMap[octant]; + } + } + else if (!node->contains(rad) && node->getParent()) + { //if we got here, data does not exist in this node + return ((oct_node*) node->getParent())->getNodeAt(pos, rad); + } + + return node; + } + + virtual bool insert(T* data) + { + //LL_PROFILE_ZONE_NAMED_COLOR("Octree::insert()",OCTREE_DEBUG_COLOR_INSERT); + + if (data == NULL || data->getBinIndex() != -1) + { + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL; + return false; + } + oct_node* parent = getOctParent(); + + //is it here? + if (isInside(data->getPositionGroup())) + { + if ((((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius())) || + (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) + { //it belongs here + mData.push_back(data); + data->setBinIndex(getElementCount() - 1); + BaseType::insert(data); + return true; + } + else + { + //find a child to give it to + oct_node* child = NULL; + for (U32 i = 0; i < getChildCount(); i++) + { + child = getChild(i); + if (child->isInside(data->getPositionGroup())) + { + child->insert(data); + return false; + } + } + + //it's here, but no kids are in the right place, make a new kid + LLVector4a center = getCenter(); + LLVector4a size = getSize(); + size.mul(0.5f); + + //push center in direction of data + oct_node::pushCenter(center, size, data); + + // handle case where floating point number gets too small + LLVector4a val; + val.setSub(center, getCenter()); + val.setAbs(val); + LLVector4a min_diff(gOctreeMinSize); + + S32 lt = val.lessThan(min_diff).getGatheredBits() & 0x7; + + if( lt == 0x7 ) + { + mData.push_back(data); + data->setBinIndex(getElementCount() - 1); + BaseType::insert(data); + return true; + } + +#if LL_OCTREE_PARANOIA_CHECK + if (getChildCount() == 8) + { + //this really isn't possible, something bad has happened + OCT_ERRS << "Octree detected floating point error and gave up." << LL_ENDL; + return false; + } + + //make sure no existing node matches this position + for (U32 i = 0; i < getChildCount(); i++) + { + if (mChild[i]->getCenter().equals3(center)) + { + OCT_ERRS << "Octree detected duplicate child center and gave up." << LL_ENDL; + return false; + } + } +#endif + + llassert(size[0] >= gOctreeMinSize*0.5f); + //make the new kid + child = new oct_node(center, size, this); + addChild(child); + + child->insert(data); + } + } + else if (parent) + { + //it's not in here, give it to the root + OCT_ERRS << "Octree insertion failed, starting over from root!" << LL_ENDL; + + oct_node* node = this; + + while (parent) + { + node = parent; + parent = node->getOctParent(); + } + + node->insert(data); + } + else + { + // It's not in here, and we are root. + // LLOctreeRoot::insert() should have expanded + // root by now, something is wrong + OCT_ERRS << "Octree insertion failed! Root expansion failed." << LL_ENDL; + } + + return false; + } + + void _remove(T* data, S32 i) + { //precondition -- getElementCount() > 0, idx is in range [0, getElementCount()) + + data->setBinIndex(-1); + + const U32 new_element_count = getElementCount() - 1; + if (new_element_count > 0) + { + if (new_element_count != i) + { + mData[i] = mData[new_element_count]; //might unref data, do not access data after this point + mData[i]->setBinIndex(i); + } + + mData[new_element_count] = NULL; + mData.pop_back(); + } + else + { + mData.clear(); + } + + this->notifyRemoval(data); + checkAlive(); + } + + bool remove(T* data) + { + //LL_PROFILE_ZONE_NAMED_COLOR("Octree::remove()", OCTREE_DEBUG_COLOR_REMOVE); + + S32 i = data->getBinIndex(); + + if (i >= 0 && i < getElementCount()) + { + if (mData[i] == data) + { //found it + _remove(data, i); + llassert(data->getBinIndex() == -1); + return true; + } + } + + if (isInside(data)) + { + oct_node* dest = getNodeAt(data); + + if (dest != this) + { + bool ret = dest->remove(data); + llassert(data->getBinIndex() == -1); + return ret; + } + } + + //SHE'S GONE MISSING... + //none of the children have it, let's just brute force this bastard out + //starting with the root node (UGLY CODE COMETH!) + oct_node* parent = getOctParent(); + oct_node* node = this; + + while (parent != NULL) + { + node = parent; + parent = node->getOctParent(); + } + + //node is now root + LL_WARNS() << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << LL_ENDL; + node->removeByAddress(data); + llassert(data->getBinIndex() == -1); + return true; + } + + void removeByAddress(T* data) + { + const U32 element_count = getElementCount(); + for (U32 i = 0; i < element_count; ++i) + { + if (mData[i] == data) + { //we have data + _remove(data, i); + LL_WARNS() << "FOUND!" << LL_ENDL; + return; + } + } + + for (U32 i = 0; i < getChildCount(); i++) + { //we don't contain data, so pass this guy down + oct_node* child = (oct_node*) getChild(i); + child->removeByAddress(data); + } + } + + void clearChildren() + { + mChildCount = 0; + memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap)); + } + + void validate() + { +#if LL_OCTREE_PARANOIA_CHECK + for (U32 i = 0; i < getChildCount(); i++) + { + mChild[i]->validate(); + if (mChild[i]->getParent() != this) + { + LL_ERRS() << "Octree child has invalid parent." << LL_ENDL; + } + } +#endif + } + + virtual bool balance() + { + return false; + } + + void destroy() + { + for (U32 i = 0; i < getChildCount(); i++) + { + mChild[i]->destroy(); + delete mChild[i]; + } + } + + void addChild(oct_node* child, bool silent = false) + { +#if LL_OCTREE_PARANOIA_CHECK + + if (child->getSize().equals3(getSize())) + { + OCT_ERRS << "Child size is same as parent size!" << LL_ENDL; + } + + for (U32 i = 0; i < getChildCount(); i++) + { + if(!mChild[i]->getSize().equals3(child->getSize())) + { + OCT_ERRS <<"Invalid octree child size." << LL_ENDL; + } + if (mChild[i]->getCenter().equals3(child->getCenter())) + { + OCT_ERRS <<"Duplicate octree child position." << LL_ENDL; + } + } + + if (mChild.size() >= 8) + { + OCT_ERRS <<"Octree node has too many children... why?" << LL_ENDL; + } +#endif + + mChildMap[child->getOctant()] = mChildCount; + + mChild[mChildCount] = child; + ++mChildCount; + child->setParent(this); + + if (!silent) + { + for (U32 i = 0; i < this->getListenerCount(); i++) + { + oct_listener* listener = getOctListener(i); + listener->handleChildAddition(this, child); + } + } + } + + void removeChild(S32 index, bool destroy = false) + { + for (U32 i = 0; i < this->getListenerCount(); i++) + { + oct_listener* listener = getOctListener(i); + listener->handleChildRemoval(this, getChild(index)); + } + + if (destroy) + { + mChild[index]->destroy(); + delete mChild[index]; + } + + --mChildCount; + + mChild[index] = mChild[mChildCount]; + + //rebuild child map + memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap)); + + for (U32 i = 0; i < mChildCount; ++i) + { + mChildMap[mChild[i]->getOctant()] = i; + } + + checkAlive(); + } + + void checkAlive() + { + if (getChildCount() == 0 && getElementCount() == 0) + { + oct_node* parent = getOctParent(); + if (parent) + { + parent->deleteChild(this); + } + } + } + + void deleteChild(oct_node* node) + { + for (U32 i = 0; i < getChildCount(); i++) + { + if (getChild(i) == node) + { + removeChild(i, true); + return; + } + } + + OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL; + } + +protected: + typedef enum + { + CENTER = 0, + SIZE = 1, + MAX = 2, + MIN = 3 + } eDName; + + LLVector4a mCenter; + LLVector4a mSize; + LLVector4a mMax; + LLVector4a mMin; + + oct_node* mParent; + U8 mOctant; + + oct_node* mChild[8]; + U8 mChildMap[8]; + U32 mChildCount; + + element_list mData; +}; + +//just like a regular node, except it might expand on insert and compress on balance +template +class LLOctreeRoot : public LLOctreeNode +{ +public: + typedef LLOctreeNode BaseType; + typedef LLOctreeNode oct_node; + + LLOctreeRoot(const LLVector4a& center, + const LLVector4a& size, + BaseType* parent) + : BaseType(center, size, parent) + { + } + + bool balance() override + { + //LL_PROFILE_ZONE_NAMED_COLOR("Octree::balance()",OCTREE_DEBUG_COLOR_BALANCE); + + if (this->getChildCount() == 1 && + !(this->mChild[0]->isLeaf()) && + this->mChild[0]->getElementCount() == 0) + { //if we have only one child and that child is an empty branch, make that child the root + oct_node* child = this->mChild[0]; + + //make the root node look like the child + this->setCenter(this->mChild[0]->getCenter()); + this->setSize(this->mChild[0]->getSize()); + this->updateMinMax(); + + //reset root node child list + this->clearChildren(); + + //copy the child's children into the root node silently + //(don't notify listeners of addition) + for (U32 i = 0; i < child->getChildCount(); i++) + { + this->addChild(child->getChild(i), true); + } + + //destroy child + child->clearChildren(); + delete child; + + return false; + } + + return true; + } + + // LLOctreeRoot::insert + bool insert(T* data) override + { + if (data == nullptr) + { + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << LL_ENDL; + return false; + } + + if (data->getBinRadius() > 4096.0) + { + OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << LL_ENDL; + return false; + } + + LLVector4a MAX_MAG; + MAX_MAG.splat(1024.f*1024.f); + + const LLVector4a& v = data->getPositionGroup(); + + LLVector4a val; + val.setSub(v, BaseType::mCenter); + val.setAbs(val); + S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7; + + if (lt != 0x7) + { + //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << LL_ENDL; + return false; + } + + if (this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup())) + { + //we got it, just act like a branch + oct_node* node = this->getNodeAt(data); + if (node == this) + { + oct_node::insert(data); + } + else if (node->isInside(data->getPositionGroup())) + { + node->insert(data); + } + else + { + // calling node->insert(data) will return us to root + OCT_ERRS << "Failed to insert data at child node" << LL_ENDL; + } + } + else if (this->getChildCount() == 0) + { + //first object being added, just wrap it up + while (!(this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup()))) + { + LLVector4a center, size; + center = this->getCenter(); + size = this->getSize(); + oct_node::pushCenter(center, size, data); + this->setCenter(center); + size.mul(2.f); + this->setSize(size); + this->updateMinMax(); + } + oct_node::insert(data); + } + else + { + while (!(this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup()))) + { + //the data is outside the root node, we need to grow + LLVector4a center(this->getCenter()); + LLVector4a size(this->getSize()); + + //expand this node + LLVector4a newcenter(center); + oct_node::pushCenter(newcenter, size, data); + this->setCenter(newcenter); + LLVector4a size2 = size; + size2.mul(2.f); + this->setSize(size2); + this->updateMinMax(); + + llassert(size[0] >= gOctreeMinSize); + + //copy our children to a new branch + oct_node* newnode = new oct_node(center, size, this); + + for (U32 i = 0; i < this->getChildCount(); i++) + { + oct_node* child = this->getChild(i); + newnode->addChild(child); + } + + //clear our children and add the root copy + this->clearChildren(); + this->addChild(newnode); + } + + //insert the data + insert(data); + } + + return false; + } + + bool isLeaf() const override + { + // root can't be a leaf + return false; + } +}; + +//======================== +// LLOctreeTraveler +//======================== +template +void LLOctreeTraveler::traverse(const LLOctreeNode* node) +{ + node->accept(this); + for (U32 i = 0; i < node->getChildCount(); i++) + { + traverse(node->getChild(i)); + } +} + +template +void LLOctreeTravelerDepthFirst::traverse(const LLOctreeNode* node) +{ + for (U32 i = 0; i < node->getChildCount(); i++) + { + traverse(node->getChild(i)); + } + node->accept(this); +} + +#endif diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 90d908c07c..aefb82b2f0 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -1,981 +1,981 @@ -/** - * @file llquaternion.cpp - * @brief LLQuaternion class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llmath.h" // for F_PI - -#include "llquaternion.h" - -//#include "vmath.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquantize.h" - -// WARNING: Don't use this for global const definitions! using this -// at the top of a *.cpp file might not give you what you think. -const LLQuaternion LLQuaternion::DEFAULT; - -// Constructors - -LLQuaternion::LLQuaternion(const LLMatrix4 &mat) -{ - *this = mat.quaternion(); - normalize(); -} - -LLQuaternion::LLQuaternion(const LLMatrix3 &mat) -{ - *this = mat.quaternion(); - normalize(); -} - -LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec) -{ - F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = vec.mV[VX] * s; - mQ[VY] = vec.mV[VY] * s; - mQ[VZ] = vec.mV[VZ] * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } -} - -LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec) -{ - F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = vec.mV[VX] * s; - mQ[VY] = vec.mV[VY] * s; - mQ[VZ] = vec.mV[VZ] * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } -} - -LLQuaternion::LLQuaternion(const LLVector3 &x_axis, - const LLVector3 &y_axis, - const LLVector3 &z_axis) -{ - LLMatrix3 mat; - mat.setRows(x_axis, y_axis, z_axis); - *this = mat.quaternion(); - normalize(); -} - -LLQuaternion::LLQuaternion(const LLSD &sd) -{ - setValue(sd); -} - -// Quatizations -void LLQuaternion::quantize16(F32 lower, F32 upper) -{ - F32 x = mQ[VX]; - F32 y = mQ[VY]; - F32 z = mQ[VZ]; - F32 s = mQ[VS]; - - x = U16_to_F32(F32_to_U16_ROUND(x, lower, upper), lower, upper); - y = U16_to_F32(F32_to_U16_ROUND(y, lower, upper), lower, upper); - z = U16_to_F32(F32_to_U16_ROUND(z, lower, upper), lower, upper); - s = U16_to_F32(F32_to_U16_ROUND(s, lower, upper), lower, upper); - - mQ[VX] = x; - mQ[VY] = y; - mQ[VZ] = z; - mQ[VS] = s; - - normalize(); -} - -void LLQuaternion::quantize8(F32 lower, F32 upper) -{ - mQ[VX] = U8_to_F32(F32_to_U8_ROUND(mQ[VX], lower, upper), lower, upper); - mQ[VY] = U8_to_F32(F32_to_U8_ROUND(mQ[VY], lower, upper), lower, upper); - mQ[VZ] = U8_to_F32(F32_to_U8_ROUND(mQ[VZ], lower, upper), lower, upper); - mQ[VS] = U8_to_F32(F32_to_U8_ROUND(mQ[VS], lower, upper), lower, upper); - - normalize(); -} - -// LLVector3 Magnitude and Normalization Functions - - -// Set LLQuaternion routines - -const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, F32 x, F32 y, F32 z) -{ - F32 mag = sqrtf(x * x + y * y + z * z); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = x * s; - mQ[VY] = y * s; - mQ[VZ] = z * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } - return (*this); -} - -const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector3 &vec) -{ - F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = vec.mV[VX] * s; - mQ[VY] = vec.mV[VY] * s; - mQ[VZ] = vec.mV[VZ] * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } - return (*this); -} - -const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector4 &vec) -{ - F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = vec.mV[VX] * s; - mQ[VY] = vec.mV[VY] * s; - mQ[VZ] = vec.mV[VZ] * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } - return (*this); -} - -const LLQuaternion& LLQuaternion::setEulerAngles(F32 roll, F32 pitch, F32 yaw) -{ - LLMatrix3 rot_mat(roll, pitch, yaw); - rot_mat.orthogonalize(); - *this = rot_mat.quaternion(); - - normalize(); - return (*this); -} - -// deprecated -const LLQuaternion& LLQuaternion::set(const LLMatrix3 &mat) -{ - *this = mat.quaternion(); - normalize(); - return (*this); -} - -// deprecated -const LLQuaternion& LLQuaternion::set(const LLMatrix4 &mat) -{ - *this = mat.quaternion(); - normalize(); - return (*this); -} - -// deprecated -const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z) -{ - F32 mag = sqrtf(x * x + y * y + z * z); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = x * s; - mQ[VY] = y * s; - mQ[VZ] = z * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } - return (*this); -} - -// deprecated -const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec) -{ - F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = vec.mV[VX] * s; - mQ[VY] = vec.mV[VY] * s; - mQ[VZ] = vec.mV[VZ] * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } - return (*this); -} - -const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec) -{ - F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); - if (mag > FP_MAG_THRESHOLD) - { - angle *= 0.5; - F32 c = cosf(angle); - F32 s = sinf(angle) / mag; - mQ[VX] = vec.mV[VX] * s; - mQ[VY] = vec.mV[VY] * s; - mQ[VZ] = vec.mV[VZ] * s; - mQ[VW] = c; - } - else - { - loadIdentity(); - } - return (*this); -} - -const LLQuaternion& LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw) -{ - roll *= 0.5f; - pitch *= 0.5f; - yaw *= 0.5f; - F32 sinX = sinf(roll); - F32 cosX = cosf(roll); - F32 sinY = sinf(pitch); - F32 cosY = cosf(pitch); - F32 sinZ = sinf(yaw); - F32 cosZ = cosf(yaw); - mQ[VW] = cosX * cosY * cosZ - sinX * sinY * sinZ; - mQ[VX] = sinX * cosY * cosZ + cosX * sinY * sinZ; - mQ[VY] = cosX * sinY * cosZ - sinX * cosY * sinZ; - mQ[VZ] = cosX * cosY * sinZ + sinX * sinY * cosZ; - return (*this); -} - -const LLQuaternion& LLQuaternion::setQuat(const LLMatrix3 &mat) -{ - *this = mat.quaternion(); - normalize(); - return (*this); -} - -const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat) -{ - *this = mat.quaternion(); - normalize(); - return (*this); -//#if 1 -// // NOTE: LLQuaternion's are actually inverted with respect to -// // the matrices, so this code also assumes inverted quaternions -// // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied -// // in reverse order (yaw,pitch,roll). -// F64 cosX = cos(roll); -// F64 cosY = cos(pitch); -// F64 cosZ = cos(yaw); -// -// F64 sinX = sin(roll); -// F64 sinY = sin(pitch); -// F64 sinZ = sin(yaw); -// -// mQ[VW] = (F32)sqrt(cosY*cosZ - sinX*sinY*sinZ + cosX*cosZ + cosX*cosY + 1.0)*.5; -// if (fabs(mQ[VW]) < F_APPROXIMATELY_ZERO) -// { -// // null rotation, any axis will do -// mQ[VX] = 0.0f; -// mQ[VY] = 1.0f; -// mQ[VZ] = 0.0f; -// } -// else -// { -// F32 inv_s = 1.0f / (4.0f * mQ[VW]); -// mQ[VX] = (F32)-(-sinX*cosY - cosX*sinY*sinZ - sinX*cosZ) * inv_s; -// mQ[VY] = (F32)-(-cosX*sinY*cosZ + sinX*sinZ - sinY) * inv_s; -// mQ[VZ] = (F32)-(-cosY*sinZ - sinX*sinY*cosZ - cosX*sinZ) * inv_s; -// } -// -//#else // This only works on a certain subset of roll/pitch/yaw -// -// F64 cosX = cosf(roll/2.0); -// F64 cosY = cosf(pitch/2.0); -// F64 cosZ = cosf(yaw/2.0); -// -// F64 sinX = sinf(roll/2.0); -// F64 sinY = sinf(pitch/2.0); -// F64 sinZ = sinf(yaw/2.0); -// -// mQ[VW] = (F32)(cosX*cosY*cosZ + sinX*sinY*sinZ); -// mQ[VX] = (F32)(sinX*cosY*cosZ - cosX*sinY*sinZ); -// mQ[VY] = (F32)(cosX*sinY*cosZ + sinX*cosY*sinZ); -// mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ); -//#endif -// -// normalize(); -// return (*this); -} - -// SJB: This code is correct for a logicly stored (non-transposed) matrix; -// Our matrices are stored transposed, OpenGL style, so this generates the -// INVERSE matrix, or the CORRECT matrix form an INVERSE quaternion. -// Because we use similar logic in LLMatrix3::quaternion(), -// we are internally consistant so everything works OK :) -LLMatrix3 LLQuaternion::getMatrix3(void) const -{ - LLMatrix3 mat; - F32 xx, xy, xz, xw, yy, yz, yw, zz, zw; - - xx = mQ[VX] * mQ[VX]; - xy = mQ[VX] * mQ[VY]; - xz = mQ[VX] * mQ[VZ]; - xw = mQ[VX] * mQ[VW]; - - yy = mQ[VY] * mQ[VY]; - yz = mQ[VY] * mQ[VZ]; - yw = mQ[VY] * mQ[VW]; - - zz = mQ[VZ] * mQ[VZ]; - zw = mQ[VZ] * mQ[VW]; - - mat.mMatrix[0][0] = 1.f - 2.f * ( yy + zz ); - mat.mMatrix[0][1] = 2.f * ( xy + zw ); - mat.mMatrix[0][2] = 2.f * ( xz - yw ); - - mat.mMatrix[1][0] = 2.f * ( xy - zw ); - mat.mMatrix[1][1] = 1.f - 2.f * ( xx + zz ); - mat.mMatrix[1][2] = 2.f * ( yz + xw ); - - mat.mMatrix[2][0] = 2.f * ( xz + yw ); - mat.mMatrix[2][1] = 2.f * ( yz - xw ); - mat.mMatrix[2][2] = 1.f - 2.f * ( xx + yy ); - - return mat; -} - -LLMatrix4 LLQuaternion::getMatrix4(void) const -{ - LLMatrix4 mat; - F32 xx, xy, xz, xw, yy, yz, yw, zz, zw; - - xx = mQ[VX] * mQ[VX]; - xy = mQ[VX] * mQ[VY]; - xz = mQ[VX] * mQ[VZ]; - xw = mQ[VX] * mQ[VW]; - - yy = mQ[VY] * mQ[VY]; - yz = mQ[VY] * mQ[VZ]; - yw = mQ[VY] * mQ[VW]; - - zz = mQ[VZ] * mQ[VZ]; - zw = mQ[VZ] * mQ[VW]; - - mat.mMatrix[0][0] = 1.f - 2.f * ( yy + zz ); - mat.mMatrix[0][1] = 2.f * ( xy + zw ); - mat.mMatrix[0][2] = 2.f * ( xz - yw ); - - mat.mMatrix[1][0] = 2.f * ( xy - zw ); - mat.mMatrix[1][1] = 1.f - 2.f * ( xx + zz ); - mat.mMatrix[1][2] = 2.f * ( yz + xw ); - - mat.mMatrix[2][0] = 2.f * ( xz + yw ); - mat.mMatrix[2][1] = 2.f * ( yz - xw ); - mat.mMatrix[2][2] = 1.f - 2.f * ( xx + yy ); - - // TODO -- should we set the translation portion to zero? - - return mat; -} - - - - -// Other useful methods - - -// calculate the shortest rotation from a to b -void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b) -{ - F32 ab = a * b; // dotproduct - LLVector3 c = a % b; // crossproduct - F32 cc = c * c; // squared length of the crossproduct - if (ab * ab + cc) // test if the arguments have sufficient magnitude - { - if (cc > 0.0f) // test if the arguments are (anti)parallel - { - F32 s = sqrtf(ab * ab + cc) + ab; // note: don't try to optimize this line - F32 m = 1.0f / sqrtf(cc + s * s); // the inverted magnitude of the quaternion - mQ[VX] = c.mV[VX] * m; - mQ[VY] = c.mV[VY] * m; - mQ[VZ] = c.mV[VZ] * m; - mQ[VW] = s * m; - return; - } - if (ab < 0.0f) // test if the angle is bigger than PI/2 (anti parallel) - { - c = a - b; // the arguments are anti-parallel, we have to choose an axis - F32 m = sqrtf(c.mV[VX] * c.mV[VX] + c.mV[VY] * c.mV[VY]); // the length projected on the XY-plane - if (m > FP_MAG_THRESHOLD) - { - mQ[VX] = -c.mV[VY] / m; // return the quaternion with the axis in the XY-plane - mQ[VY] = c.mV[VX] / m; - mQ[VZ] = 0.0f; - mQ[VW] = 0.0f; - return; - } - else // the vectors are parallel to the Z-axis - { - mQ[VX] = 1.0f; // rotate around the X-axis - mQ[VY] = 0.0f; - mQ[VZ] = 0.0f; - mQ[VW] = 0.0f; - return; - } - } - } - loadIdentity(); -} - -// constrains rotation to a cone angle specified in radians -const LLQuaternion &LLQuaternion::constrain(F32 radians) -{ - const F32 cos_angle_lim = cosf( radians/2 ); // mQ[VW] limit - const F32 sin_angle_lim = sinf( radians/2 ); // rotation axis length limit - - if (mQ[VW] < 0.f) - { - mQ[VX] *= -1.f; - mQ[VY] *= -1.f; - mQ[VZ] *= -1.f; - mQ[VW] *= -1.f; - } - - // if rotation angle is greater than limit (cos is less than limit) - if( mQ[VW] < cos_angle_lim ) - { - mQ[VW] = cos_angle_lim; - F32 axis_len = sqrtf( mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] ); // sin(theta/2) - F32 axis_mult_fact = sin_angle_lim / axis_len; - mQ[VX] *= axis_mult_fact; - mQ[VY] *= axis_mult_fact; - mQ[VZ] *= axis_mult_fact; - } - - return *this; -} - -// Operators - -std::ostream& operator<<(std::ostream &s, const LLQuaternion &a) -{ - s << "{ " - << a.mQ[VX] << ", " << a.mQ[VY] << ", " << a.mQ[VZ] << ", " << a.mQ[VW] - << " }"; - return s; -} - - -// Does NOT renormalize the result -LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b) -{ -// LLQuaternion::mMultCount++; - - LLQuaternion q( - b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1], - b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2], - b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0], - b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2] - ); - return q; -} - -/* -LLMatrix4 operator*(const LLMatrix4 &m, const LLQuaternion &q) -{ - LLMatrix4 qmat(q); - return (m*qmat); -} -*/ - - - -LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) -{ - F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; - F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY]; - F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ]; - F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX]; - - F32 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; - F32 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; - F32 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; - - return LLVector4(nx, ny, nz, a.mV[VW]); -} - -LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) -{ - F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; - F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY]; - F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ]; - F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX]; - - F32 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; - F32 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; - F32 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; - - return LLVector3(nx, ny, nz); -} - -LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot) -{ - F64 rw = - rot.mQ[VX] * a.mdV[VX] - rot.mQ[VY] * a.mdV[VY] - rot.mQ[VZ] * a.mdV[VZ]; - F64 rx = rot.mQ[VW] * a.mdV[VX] + rot.mQ[VY] * a.mdV[VZ] - rot.mQ[VZ] * a.mdV[VY]; - F64 ry = rot.mQ[VW] * a.mdV[VY] + rot.mQ[VZ] * a.mdV[VX] - rot.mQ[VX] * a.mdV[VZ]; - F64 rz = rot.mQ[VW] * a.mdV[VZ] + rot.mQ[VX] * a.mdV[VY] - rot.mQ[VY] * a.mdV[VX]; - - F64 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; - F64 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; - F64 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; - - return LLVector3d(nx, ny, nz); -} - -F32 dot(const LLQuaternion &a, const LLQuaternion &b) -{ - return a.mQ[VX] * b.mQ[VX] + - a.mQ[VY] * b.mQ[VY] + - a.mQ[VZ] * b.mQ[VZ] + - a.mQ[VW] * b.mQ[VW]; -} - -// DEMO HACK: This lerp is probably inocrrect now due intermediate normalization -// it should look more like the lerp below -#if 0 -// linear interpolation -LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q) -{ - LLQuaternion r; - r = t * (q - p) + p; - r.normalize(); - return r; -} -#endif - -// lerp from identity to q -LLQuaternion lerp(F32 t, const LLQuaternion &q) -{ - LLQuaternion r; - r.mQ[VX] = t * q.mQ[VX]; - r.mQ[VY] = t * q.mQ[VY]; - r.mQ[VZ] = t * q.mQ[VZ]; - r.mQ[VW] = t * (q.mQ[VZ] - 1.f) + 1.f; - r.normalize(); - return r; -} - -LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q) -{ - LLQuaternion r; - F32 inv_t; - - inv_t = 1.f - t; - - r.mQ[VX] = t * q.mQ[VX] + (inv_t * p.mQ[VX]); - r.mQ[VY] = t * q.mQ[VY] + (inv_t * p.mQ[VY]); - r.mQ[VZ] = t * q.mQ[VZ] + (inv_t * p.mQ[VZ]); - r.mQ[VW] = t * q.mQ[VW] + (inv_t * p.mQ[VW]); - r.normalize(); - return r; -} - - -// spherical linear interpolation -LLQuaternion slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b ) -{ - // cosine theta = dot product of a and b - F32 cos_t = a.mQ[0]*b.mQ[0] + a.mQ[1]*b.mQ[1] + a.mQ[2]*b.mQ[2] + a.mQ[3]*b.mQ[3]; - - // if b is on opposite hemisphere from a, use -a instead - bool bflip; - if (cos_t < 0.0f) - { - cos_t = -cos_t; - bflip = true; - } - else - bflip = false; - - // if B is (within precision limits) the same as A, - // just linear interpolate between A and B. - F32 alpha; // interpolant - F32 beta; // 1 - interpolant - if (1.0f - cos_t < 0.00001f) - { - beta = 1.0f - u; - alpha = u; - } - else - { - F32 theta = acosf(cos_t); - F32 sin_t = sinf(theta); - beta = sinf(theta - u*theta) / sin_t; - alpha = sinf(u*theta) / sin_t; - } - - if (bflip) - beta = -beta; - - // interpolate - LLQuaternion ret; - ret.mQ[0] = beta*a.mQ[0] + alpha*b.mQ[0]; - ret.mQ[1] = beta*a.mQ[1] + alpha*b.mQ[1]; - ret.mQ[2] = beta*a.mQ[2] + alpha*b.mQ[2]; - ret.mQ[3] = beta*a.mQ[3] + alpha*b.mQ[3]; - - return ret; -} - -// lerp whenever possible -LLQuaternion nlerp(F32 t, const LLQuaternion &a, const LLQuaternion &b) -{ - if (dot(a, b) < 0.f) - { - return slerp(t, a, b); - } - else - { - return lerp(t, a, b); - } -} - -LLQuaternion nlerp(F32 t, const LLQuaternion &q) -{ - if (q.mQ[VW] < 0.f) - { - return slerp(t, q); - } - else - { - return lerp(t, q); - } -} - -// slerp from identity quaternion to another quaternion -LLQuaternion slerp(F32 t, const LLQuaternion &q) -{ - F32 c = q.mQ[VW]; - if (1.0f == t || 1.0f == c) - { - // the trivial cases - return q; - } - - LLQuaternion r; - F32 s, angle, stq, stp; - - s = (F32) sqrt(1.f - c*c); - - if (c < 0.0f) - { - // when c < 0.0 then theta > PI/2 - // since quat and -quat are the same rotation we invert one of - // p or q to reduce unecessary spins - // A equivalent way to do it is to convert acos(c) as if it had - // been negative, and to negate stp - angle = (F32) acos(-c); - stp = -(F32) sin(angle * (1.f - t)); - stq = (F32) sin(angle * t); - } - else - { - angle = (F32) acos(c); - stp = (F32) sin(angle * (1.f - t)); - stq = (F32) sin(angle * t); - } - - r.mQ[VX] = (q.mQ[VX] * stq) / s; - r.mQ[VY] = (q.mQ[VY] * stq) / s; - r.mQ[VZ] = (q.mQ[VZ] * stq) / s; - r.mQ[VW] = (stp + q.mQ[VW] * stq) / s; - - return r; -} - -LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) -{ - LLQuaternion xQ( xRot*DEG_TO_RAD, LLVector3(1.0f, 0.0f, 0.0f) ); - LLQuaternion yQ( yRot*DEG_TO_RAD, LLVector3(0.0f, 1.0f, 0.0f) ); - LLQuaternion zQ( zRot*DEG_TO_RAD, LLVector3(0.0f, 0.0f, 1.0f) ); - LLQuaternion ret; - switch( order ) - { - case LLQuaternion::XYZ: - ret = xQ * yQ * zQ; - break; - case LLQuaternion::YZX: - ret = yQ * zQ * xQ; - break; - case LLQuaternion::ZXY: - ret = zQ * xQ * yQ; - break; - case LLQuaternion::XZY: - ret = xQ * zQ * yQ; - break; - case LLQuaternion::YXZ: - ret = yQ * xQ * zQ; - break; - case LLQuaternion::ZYX: - ret = zQ * yQ * xQ; - break; - } - return ret; -} - -const char *OrderToString( const LLQuaternion::Order order ) -{ - const char *p = NULL; - switch( order ) - { - default: - case LLQuaternion::XYZ: - p = "XYZ"; - break; - case LLQuaternion::YZX: - p = "YZX"; - break; - case LLQuaternion::ZXY: - p = "ZXY"; - break; - case LLQuaternion::XZY: - p = "XZY"; - break; - case LLQuaternion::YXZ: - p = "YXZ"; - break; - case LLQuaternion::ZYX: - p = "ZYX"; - break; - } - return p; -} - -LLQuaternion::Order StringToOrder( const char *str ) -{ - if (strncmp(str, "XYZ", 3)==0 || strncmp(str, "xyz", 3)==0) - return LLQuaternion::XYZ; - - if (strncmp(str, "YZX", 3)==0 || strncmp(str, "yzx", 3)==0) - return LLQuaternion::YZX; - - if (strncmp(str, "ZXY", 3)==0 || strncmp(str, "zxy", 3)==0) - return LLQuaternion::ZXY; - - if (strncmp(str, "XZY", 3)==0 || strncmp(str, "xzy", 3)==0) - return LLQuaternion::XZY; - - if (strncmp(str, "YXZ", 3)==0 || strncmp(str, "yxz", 3)==0) - return LLQuaternion::YXZ; - - if (strncmp(str, "ZYX", 3)==0 || strncmp(str, "zyx", 3)==0) - return LLQuaternion::ZYX; - - return LLQuaternion::XYZ; -} - -void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const -{ - F32 v = sqrtf(mQ[VX] * mQ[VX] + mQ[VY] * mQ[VY] + mQ[VZ] * mQ[VZ]); // length of the vector-component - if (v > FP_MAG_THRESHOLD) - { - F32 oomag = 1.0f / v; - F32 w = mQ[VW]; - if (mQ[VW] < 0.0f) - { - w = -w; // make VW positive - oomag = -oomag; // invert the axis - } - vec.mV[VX] = mQ[VX] * oomag; // normalize the axis - vec.mV[VY] = mQ[VY] * oomag; - vec.mV[VZ] = mQ[VZ] * oomag; - *angle = 2.0f * atan2f(v, w); // get the angle - } - else - { - *angle = 0.0f; // no rotation - vec.mV[VX] = 0.0f; // around some dummy axis - vec.mV[VY] = 0.0f; - vec.mV[VZ] = 1.0f; - } -} - -const LLQuaternion& LLQuaternion::setFromAzimuthAndAltitude(F32 azimuthRadians, F32 altitudeRadians) -{ - // euler angle inputs are complements of azimuth/altitude which are measured from zenith - F32 pitch = llclamp(F_PI_BY_TWO - altitudeRadians, 0.0f, F_PI_BY_TWO); - F32 yaw = llclamp(F_PI_BY_TWO - azimuthRadians, 0.0f, F_PI_BY_TWO); - setEulerAngles(0.0f, pitch, yaw); - return *this; -} - -void LLQuaternion::getAzimuthAndAltitude(F32 &azimuthRadians, F32 &altitudeRadians) -{ - F32 rick_roll; - F32 pitch; - F32 yaw; - getEulerAngles(&rick_roll, &pitch, &yaw); - // make these measured from zenith - altitudeRadians = llclamp(F_PI_BY_TWO - pitch, 0.0f, F_PI_BY_TWO); - azimuthRadians = llclamp(F_PI_BY_TWO - yaw, 0.0f, F_PI_BY_TWO); -} - -// quaternion does not need to be normalized -void LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const -{ - F32 sx = 2 * (mQ[VX] * mQ[VW] - mQ[VY] * mQ[VZ]); // sine of the roll - F32 sy = 2 * (mQ[VY] * mQ[VW] + mQ[VX] * mQ[VZ]); // sine of the pitch - F32 ys = mQ[VW] * mQ[VW] - mQ[VY] * mQ[VY]; // intermediate cosine 1 - F32 xz = mQ[VX] * mQ[VX] - mQ[VZ] * mQ[VZ]; // intermediate cosine 2 - F32 cx = ys - xz; // cosine of the roll - F32 cy = sqrtf(sx * sx + cx * cx); // cosine of the pitch - if (cy > GIMBAL_THRESHOLD) // no gimbal lock - { - *roll = atan2f(sx, cx); - *pitch = atan2f(sy, cy); - *yaw = atan2f(2 * (mQ[VZ] * mQ[VW] - mQ[VX] * mQ[VY]), ys + xz); - } - else // gimbal lock - { - if (sy > 0) - { - *pitch = F_PI_BY_TWO; - *yaw = 2 * atan2f(mQ[VZ] + mQ[VX], mQ[VW] + mQ[VY]); - } - else - { - *pitch = -F_PI_BY_TWO; - *yaw = 2 * atan2f(mQ[VZ] - mQ[VX], mQ[VW] - mQ[VY]); - } - *roll = 0; - } -} - -// Saves space by using the fact that our quaternions are normalized -LLVector3 LLQuaternion::packToVector3() const -{ - F32 x = mQ[VX]; - F32 y = mQ[VY]; - F32 z = mQ[VZ]; - F32 w = mQ[VW]; - F32 mag = sqrtf(x * x + y * y + z * z + w * w); - if (mag > FP_MAG_THRESHOLD) - { - x /= mag; - y /= mag; - z /= mag; // no need to normalize w, it's not used - } - if( mQ[VW] >= 0 ) - { - return LLVector3( x, y , z ); - } - else - { - return LLVector3( -x, -y, -z ); - } -} - -// Saves space by using the fact that our quaternions are normalized -void LLQuaternion::unpackFromVector3( const LLVector3& vec ) -{ - mQ[VX] = vec.mV[VX]; - mQ[VY] = vec.mV[VY]; - mQ[VZ] = vec.mV[VZ]; - F32 t = 1.f - vec.magVecSquared(); - if( t > 0 ) - { - mQ[VW] = sqrt( t ); - } - else - { - // Need this to avoid trying to find the square root of a negative number due - // to floating point error. - mQ[VW] = 0; - } -} - -bool LLQuaternion::parseQuat(const std::string& buf, LLQuaternion* value) -{ - if( buf.empty() || value == NULL) - { - return false; - } - - LLQuaternion quat; - S32 count = sscanf( buf.c_str(), "%f %f %f %f", quat.mQ + 0, quat.mQ + 1, quat.mQ + 2, quat.mQ + 3 ); - if( 4 == count ) - { - value->set( quat ); - return true; - } - - return false; -} - - -// End +/** + * @file llquaternion.cpp + * @brief LLQuaternion class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llmath.h" // for F_PI + +#include "llquaternion.h" + +//#include "vmath.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquantize.h" + +// WARNING: Don't use this for global const definitions! using this +// at the top of a *.cpp file might not give you what you think. +const LLQuaternion LLQuaternion::DEFAULT; + +// Constructors + +LLQuaternion::LLQuaternion(const LLMatrix4 &mat) +{ + *this = mat.quaternion(); + normalize(); +} + +LLQuaternion::LLQuaternion(const LLMatrix3 &mat) +{ + *this = mat.quaternion(); + normalize(); +} + +LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec) +{ + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } +} + +LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec) +{ + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } +} + +LLQuaternion::LLQuaternion(const LLVector3 &x_axis, + const LLVector3 &y_axis, + const LLVector3 &z_axis) +{ + LLMatrix3 mat; + mat.setRows(x_axis, y_axis, z_axis); + *this = mat.quaternion(); + normalize(); +} + +LLQuaternion::LLQuaternion(const LLSD &sd) +{ + setValue(sd); +} + +// Quatizations +void LLQuaternion::quantize16(F32 lower, F32 upper) +{ + F32 x = mQ[VX]; + F32 y = mQ[VY]; + F32 z = mQ[VZ]; + F32 s = mQ[VS]; + + x = U16_to_F32(F32_to_U16_ROUND(x, lower, upper), lower, upper); + y = U16_to_F32(F32_to_U16_ROUND(y, lower, upper), lower, upper); + z = U16_to_F32(F32_to_U16_ROUND(z, lower, upper), lower, upper); + s = U16_to_F32(F32_to_U16_ROUND(s, lower, upper), lower, upper); + + mQ[VX] = x; + mQ[VY] = y; + mQ[VZ] = z; + mQ[VS] = s; + + normalize(); +} + +void LLQuaternion::quantize8(F32 lower, F32 upper) +{ + mQ[VX] = U8_to_F32(F32_to_U8_ROUND(mQ[VX], lower, upper), lower, upper); + mQ[VY] = U8_to_F32(F32_to_U8_ROUND(mQ[VY], lower, upper), lower, upper); + mQ[VZ] = U8_to_F32(F32_to_U8_ROUND(mQ[VZ], lower, upper), lower, upper); + mQ[VS] = U8_to_F32(F32_to_U8_ROUND(mQ[VS], lower, upper), lower, upper); + + normalize(); +} + +// LLVector3 Magnitude and Normalization Functions + + +// Set LLQuaternion routines + +const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, F32 x, F32 y, F32 z) +{ + F32 mag = sqrtf(x * x + y * y + z * z); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = x * s; + mQ[VY] = y * s; + mQ[VZ] = z * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } + return (*this); +} + +const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector3 &vec) +{ + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } + return (*this); +} + +const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector4 &vec) +{ + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } + return (*this); +} + +const LLQuaternion& LLQuaternion::setEulerAngles(F32 roll, F32 pitch, F32 yaw) +{ + LLMatrix3 rot_mat(roll, pitch, yaw); + rot_mat.orthogonalize(); + *this = rot_mat.quaternion(); + + normalize(); + return (*this); +} + +// deprecated +const LLQuaternion& LLQuaternion::set(const LLMatrix3 &mat) +{ + *this = mat.quaternion(); + normalize(); + return (*this); +} + +// deprecated +const LLQuaternion& LLQuaternion::set(const LLMatrix4 &mat) +{ + *this = mat.quaternion(); + normalize(); + return (*this); +} + +// deprecated +const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z) +{ + F32 mag = sqrtf(x * x + y * y + z * z); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = x * s; + mQ[VY] = y * s; + mQ[VZ] = z * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } + return (*this); +} + +// deprecated +const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec) +{ + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } + return (*this); +} + +const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec) +{ + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } + return (*this); +} + +const LLQuaternion& LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw) +{ + roll *= 0.5f; + pitch *= 0.5f; + yaw *= 0.5f; + F32 sinX = sinf(roll); + F32 cosX = cosf(roll); + F32 sinY = sinf(pitch); + F32 cosY = cosf(pitch); + F32 sinZ = sinf(yaw); + F32 cosZ = cosf(yaw); + mQ[VW] = cosX * cosY * cosZ - sinX * sinY * sinZ; + mQ[VX] = sinX * cosY * cosZ + cosX * sinY * sinZ; + mQ[VY] = cosX * sinY * cosZ - sinX * cosY * sinZ; + mQ[VZ] = cosX * cosY * sinZ + sinX * sinY * cosZ; + return (*this); +} + +const LLQuaternion& LLQuaternion::setQuat(const LLMatrix3 &mat) +{ + *this = mat.quaternion(); + normalize(); + return (*this); +} + +const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat) +{ + *this = mat.quaternion(); + normalize(); + return (*this); +//#if 1 +// // NOTE: LLQuaternion's are actually inverted with respect to +// // the matrices, so this code also assumes inverted quaternions +// // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied +// // in reverse order (yaw,pitch,roll). +// F64 cosX = cos(roll); +// F64 cosY = cos(pitch); +// F64 cosZ = cos(yaw); +// +// F64 sinX = sin(roll); +// F64 sinY = sin(pitch); +// F64 sinZ = sin(yaw); +// +// mQ[VW] = (F32)sqrt(cosY*cosZ - sinX*sinY*sinZ + cosX*cosZ + cosX*cosY + 1.0)*.5; +// if (fabs(mQ[VW]) < F_APPROXIMATELY_ZERO) +// { +// // null rotation, any axis will do +// mQ[VX] = 0.0f; +// mQ[VY] = 1.0f; +// mQ[VZ] = 0.0f; +// } +// else +// { +// F32 inv_s = 1.0f / (4.0f * mQ[VW]); +// mQ[VX] = (F32)-(-sinX*cosY - cosX*sinY*sinZ - sinX*cosZ) * inv_s; +// mQ[VY] = (F32)-(-cosX*sinY*cosZ + sinX*sinZ - sinY) * inv_s; +// mQ[VZ] = (F32)-(-cosY*sinZ - sinX*sinY*cosZ - cosX*sinZ) * inv_s; +// } +// +//#else // This only works on a certain subset of roll/pitch/yaw +// +// F64 cosX = cosf(roll/2.0); +// F64 cosY = cosf(pitch/2.0); +// F64 cosZ = cosf(yaw/2.0); +// +// F64 sinX = sinf(roll/2.0); +// F64 sinY = sinf(pitch/2.0); +// F64 sinZ = sinf(yaw/2.0); +// +// mQ[VW] = (F32)(cosX*cosY*cosZ + sinX*sinY*sinZ); +// mQ[VX] = (F32)(sinX*cosY*cosZ - cosX*sinY*sinZ); +// mQ[VY] = (F32)(cosX*sinY*cosZ + sinX*cosY*sinZ); +// mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ); +//#endif +// +// normalize(); +// return (*this); +} + +// SJB: This code is correct for a logicly stored (non-transposed) matrix; +// Our matrices are stored transposed, OpenGL style, so this generates the +// INVERSE matrix, or the CORRECT matrix form an INVERSE quaternion. +// Because we use similar logic in LLMatrix3::quaternion(), +// we are internally consistant so everything works OK :) +LLMatrix3 LLQuaternion::getMatrix3(void) const +{ + LLMatrix3 mat; + F32 xx, xy, xz, xw, yy, yz, yw, zz, zw; + + xx = mQ[VX] * mQ[VX]; + xy = mQ[VX] * mQ[VY]; + xz = mQ[VX] * mQ[VZ]; + xw = mQ[VX] * mQ[VW]; + + yy = mQ[VY] * mQ[VY]; + yz = mQ[VY] * mQ[VZ]; + yw = mQ[VY] * mQ[VW]; + + zz = mQ[VZ] * mQ[VZ]; + zw = mQ[VZ] * mQ[VW]; + + mat.mMatrix[0][0] = 1.f - 2.f * ( yy + zz ); + mat.mMatrix[0][1] = 2.f * ( xy + zw ); + mat.mMatrix[0][2] = 2.f * ( xz - yw ); + + mat.mMatrix[1][0] = 2.f * ( xy - zw ); + mat.mMatrix[1][1] = 1.f - 2.f * ( xx + zz ); + mat.mMatrix[1][2] = 2.f * ( yz + xw ); + + mat.mMatrix[2][0] = 2.f * ( xz + yw ); + mat.mMatrix[2][1] = 2.f * ( yz - xw ); + mat.mMatrix[2][2] = 1.f - 2.f * ( xx + yy ); + + return mat; +} + +LLMatrix4 LLQuaternion::getMatrix4(void) const +{ + LLMatrix4 mat; + F32 xx, xy, xz, xw, yy, yz, yw, zz, zw; + + xx = mQ[VX] * mQ[VX]; + xy = mQ[VX] * mQ[VY]; + xz = mQ[VX] * mQ[VZ]; + xw = mQ[VX] * mQ[VW]; + + yy = mQ[VY] * mQ[VY]; + yz = mQ[VY] * mQ[VZ]; + yw = mQ[VY] * mQ[VW]; + + zz = mQ[VZ] * mQ[VZ]; + zw = mQ[VZ] * mQ[VW]; + + mat.mMatrix[0][0] = 1.f - 2.f * ( yy + zz ); + mat.mMatrix[0][1] = 2.f * ( xy + zw ); + mat.mMatrix[0][2] = 2.f * ( xz - yw ); + + mat.mMatrix[1][0] = 2.f * ( xy - zw ); + mat.mMatrix[1][1] = 1.f - 2.f * ( xx + zz ); + mat.mMatrix[1][2] = 2.f * ( yz + xw ); + + mat.mMatrix[2][0] = 2.f * ( xz + yw ); + mat.mMatrix[2][1] = 2.f * ( yz - xw ); + mat.mMatrix[2][2] = 1.f - 2.f * ( xx + yy ); + + // TODO -- should we set the translation portion to zero? + + return mat; +} + + + + +// Other useful methods + + +// calculate the shortest rotation from a to b +void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b) +{ + F32 ab = a * b; // dotproduct + LLVector3 c = a % b; // crossproduct + F32 cc = c * c; // squared length of the crossproduct + if (ab * ab + cc) // test if the arguments have sufficient magnitude + { + if (cc > 0.0f) // test if the arguments are (anti)parallel + { + F32 s = sqrtf(ab * ab + cc) + ab; // note: don't try to optimize this line + F32 m = 1.0f / sqrtf(cc + s * s); // the inverted magnitude of the quaternion + mQ[VX] = c.mV[VX] * m; + mQ[VY] = c.mV[VY] * m; + mQ[VZ] = c.mV[VZ] * m; + mQ[VW] = s * m; + return; + } + if (ab < 0.0f) // test if the angle is bigger than PI/2 (anti parallel) + { + c = a - b; // the arguments are anti-parallel, we have to choose an axis + F32 m = sqrtf(c.mV[VX] * c.mV[VX] + c.mV[VY] * c.mV[VY]); // the length projected on the XY-plane + if (m > FP_MAG_THRESHOLD) + { + mQ[VX] = -c.mV[VY] / m; // return the quaternion with the axis in the XY-plane + mQ[VY] = c.mV[VX] / m; + mQ[VZ] = 0.0f; + mQ[VW] = 0.0f; + return; + } + else // the vectors are parallel to the Z-axis + { + mQ[VX] = 1.0f; // rotate around the X-axis + mQ[VY] = 0.0f; + mQ[VZ] = 0.0f; + mQ[VW] = 0.0f; + return; + } + } + } + loadIdentity(); +} + +// constrains rotation to a cone angle specified in radians +const LLQuaternion &LLQuaternion::constrain(F32 radians) +{ + const F32 cos_angle_lim = cosf( radians/2 ); // mQ[VW] limit + const F32 sin_angle_lim = sinf( radians/2 ); // rotation axis length limit + + if (mQ[VW] < 0.f) + { + mQ[VX] *= -1.f; + mQ[VY] *= -1.f; + mQ[VZ] *= -1.f; + mQ[VW] *= -1.f; + } + + // if rotation angle is greater than limit (cos is less than limit) + if( mQ[VW] < cos_angle_lim ) + { + mQ[VW] = cos_angle_lim; + F32 axis_len = sqrtf( mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] ); // sin(theta/2) + F32 axis_mult_fact = sin_angle_lim / axis_len; + mQ[VX] *= axis_mult_fact; + mQ[VY] *= axis_mult_fact; + mQ[VZ] *= axis_mult_fact; + } + + return *this; +} + +// Operators + +std::ostream& operator<<(std::ostream &s, const LLQuaternion &a) +{ + s << "{ " + << a.mQ[VX] << ", " << a.mQ[VY] << ", " << a.mQ[VZ] << ", " << a.mQ[VW] + << " }"; + return s; +} + + +// Does NOT renormalize the result +LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b) +{ +// LLQuaternion::mMultCount++; + + LLQuaternion q( + b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1], + b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2], + b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0], + b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2] + ); + return q; +} + +/* +LLMatrix4 operator*(const LLMatrix4 &m, const LLQuaternion &q) +{ + LLMatrix4 qmat(q); + return (m*qmat); +} +*/ + + + +LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) +{ + F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; + F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY]; + F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ]; + F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX]; + + F32 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; + F32 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; + F32 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; + + return LLVector4(nx, ny, nz, a.mV[VW]); +} + +LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) +{ + F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; + F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY]; + F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ]; + F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX]; + + F32 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; + F32 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; + F32 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; + + return LLVector3(nx, ny, nz); +} + +LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot) +{ + F64 rw = - rot.mQ[VX] * a.mdV[VX] - rot.mQ[VY] * a.mdV[VY] - rot.mQ[VZ] * a.mdV[VZ]; + F64 rx = rot.mQ[VW] * a.mdV[VX] + rot.mQ[VY] * a.mdV[VZ] - rot.mQ[VZ] * a.mdV[VY]; + F64 ry = rot.mQ[VW] * a.mdV[VY] + rot.mQ[VZ] * a.mdV[VX] - rot.mQ[VX] * a.mdV[VZ]; + F64 rz = rot.mQ[VW] * a.mdV[VZ] + rot.mQ[VX] * a.mdV[VY] - rot.mQ[VY] * a.mdV[VX]; + + F64 nx = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; + F64 ny = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; + F64 nz = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; + + return LLVector3d(nx, ny, nz); +} + +F32 dot(const LLQuaternion &a, const LLQuaternion &b) +{ + return a.mQ[VX] * b.mQ[VX] + + a.mQ[VY] * b.mQ[VY] + + a.mQ[VZ] * b.mQ[VZ] + + a.mQ[VW] * b.mQ[VW]; +} + +// DEMO HACK: This lerp is probably inocrrect now due intermediate normalization +// it should look more like the lerp below +#if 0 +// linear interpolation +LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q) +{ + LLQuaternion r; + r = t * (q - p) + p; + r.normalize(); + return r; +} +#endif + +// lerp from identity to q +LLQuaternion lerp(F32 t, const LLQuaternion &q) +{ + LLQuaternion r; + r.mQ[VX] = t * q.mQ[VX]; + r.mQ[VY] = t * q.mQ[VY]; + r.mQ[VZ] = t * q.mQ[VZ]; + r.mQ[VW] = t * (q.mQ[VZ] - 1.f) + 1.f; + r.normalize(); + return r; +} + +LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q) +{ + LLQuaternion r; + F32 inv_t; + + inv_t = 1.f - t; + + r.mQ[VX] = t * q.mQ[VX] + (inv_t * p.mQ[VX]); + r.mQ[VY] = t * q.mQ[VY] + (inv_t * p.mQ[VY]); + r.mQ[VZ] = t * q.mQ[VZ] + (inv_t * p.mQ[VZ]); + r.mQ[VW] = t * q.mQ[VW] + (inv_t * p.mQ[VW]); + r.normalize(); + return r; +} + + +// spherical linear interpolation +LLQuaternion slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b ) +{ + // cosine theta = dot product of a and b + F32 cos_t = a.mQ[0]*b.mQ[0] + a.mQ[1]*b.mQ[1] + a.mQ[2]*b.mQ[2] + a.mQ[3]*b.mQ[3]; + + // if b is on opposite hemisphere from a, use -a instead + bool bflip; + if (cos_t < 0.0f) + { + cos_t = -cos_t; + bflip = true; + } + else + bflip = false; + + // if B is (within precision limits) the same as A, + // just linear interpolate between A and B. + F32 alpha; // interpolant + F32 beta; // 1 - interpolant + if (1.0f - cos_t < 0.00001f) + { + beta = 1.0f - u; + alpha = u; + } + else + { + F32 theta = acosf(cos_t); + F32 sin_t = sinf(theta); + beta = sinf(theta - u*theta) / sin_t; + alpha = sinf(u*theta) / sin_t; + } + + if (bflip) + beta = -beta; + + // interpolate + LLQuaternion ret; + ret.mQ[0] = beta*a.mQ[0] + alpha*b.mQ[0]; + ret.mQ[1] = beta*a.mQ[1] + alpha*b.mQ[1]; + ret.mQ[2] = beta*a.mQ[2] + alpha*b.mQ[2]; + ret.mQ[3] = beta*a.mQ[3] + alpha*b.mQ[3]; + + return ret; +} + +// lerp whenever possible +LLQuaternion nlerp(F32 t, const LLQuaternion &a, const LLQuaternion &b) +{ + if (dot(a, b) < 0.f) + { + return slerp(t, a, b); + } + else + { + return lerp(t, a, b); + } +} + +LLQuaternion nlerp(F32 t, const LLQuaternion &q) +{ + if (q.mQ[VW] < 0.f) + { + return slerp(t, q); + } + else + { + return lerp(t, q); + } +} + +// slerp from identity quaternion to another quaternion +LLQuaternion slerp(F32 t, const LLQuaternion &q) +{ + F32 c = q.mQ[VW]; + if (1.0f == t || 1.0f == c) + { + // the trivial cases + return q; + } + + LLQuaternion r; + F32 s, angle, stq, stp; + + s = (F32) sqrt(1.f - c*c); + + if (c < 0.0f) + { + // when c < 0.0 then theta > PI/2 + // since quat and -quat are the same rotation we invert one of + // p or q to reduce unecessary spins + // A equivalent way to do it is to convert acos(c) as if it had + // been negative, and to negate stp + angle = (F32) acos(-c); + stp = -(F32) sin(angle * (1.f - t)); + stq = (F32) sin(angle * t); + } + else + { + angle = (F32) acos(c); + stp = (F32) sin(angle * (1.f - t)); + stq = (F32) sin(angle * t); + } + + r.mQ[VX] = (q.mQ[VX] * stq) / s; + r.mQ[VY] = (q.mQ[VY] * stq) / s; + r.mQ[VZ] = (q.mQ[VZ] * stq) / s; + r.mQ[VW] = (stp + q.mQ[VW] * stq) / s; + + return r; +} + +LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) +{ + LLQuaternion xQ( xRot*DEG_TO_RAD, LLVector3(1.0f, 0.0f, 0.0f) ); + LLQuaternion yQ( yRot*DEG_TO_RAD, LLVector3(0.0f, 1.0f, 0.0f) ); + LLQuaternion zQ( zRot*DEG_TO_RAD, LLVector3(0.0f, 0.0f, 1.0f) ); + LLQuaternion ret; + switch( order ) + { + case LLQuaternion::XYZ: + ret = xQ * yQ * zQ; + break; + case LLQuaternion::YZX: + ret = yQ * zQ * xQ; + break; + case LLQuaternion::ZXY: + ret = zQ * xQ * yQ; + break; + case LLQuaternion::XZY: + ret = xQ * zQ * yQ; + break; + case LLQuaternion::YXZ: + ret = yQ * xQ * zQ; + break; + case LLQuaternion::ZYX: + ret = zQ * yQ * xQ; + break; + } + return ret; +} + +const char *OrderToString( const LLQuaternion::Order order ) +{ + const char *p = NULL; + switch( order ) + { + default: + case LLQuaternion::XYZ: + p = "XYZ"; + break; + case LLQuaternion::YZX: + p = "YZX"; + break; + case LLQuaternion::ZXY: + p = "ZXY"; + break; + case LLQuaternion::XZY: + p = "XZY"; + break; + case LLQuaternion::YXZ: + p = "YXZ"; + break; + case LLQuaternion::ZYX: + p = "ZYX"; + break; + } + return p; +} + +LLQuaternion::Order StringToOrder( const char *str ) +{ + if (strncmp(str, "XYZ", 3)==0 || strncmp(str, "xyz", 3)==0) + return LLQuaternion::XYZ; + + if (strncmp(str, "YZX", 3)==0 || strncmp(str, "yzx", 3)==0) + return LLQuaternion::YZX; + + if (strncmp(str, "ZXY", 3)==0 || strncmp(str, "zxy", 3)==0) + return LLQuaternion::ZXY; + + if (strncmp(str, "XZY", 3)==0 || strncmp(str, "xzy", 3)==0) + return LLQuaternion::XZY; + + if (strncmp(str, "YXZ", 3)==0 || strncmp(str, "yxz", 3)==0) + return LLQuaternion::YXZ; + + if (strncmp(str, "ZYX", 3)==0 || strncmp(str, "zyx", 3)==0) + return LLQuaternion::ZYX; + + return LLQuaternion::XYZ; +} + +void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const +{ + F32 v = sqrtf(mQ[VX] * mQ[VX] + mQ[VY] * mQ[VY] + mQ[VZ] * mQ[VZ]); // length of the vector-component + if (v > FP_MAG_THRESHOLD) + { + F32 oomag = 1.0f / v; + F32 w = mQ[VW]; + if (mQ[VW] < 0.0f) + { + w = -w; // make VW positive + oomag = -oomag; // invert the axis + } + vec.mV[VX] = mQ[VX] * oomag; // normalize the axis + vec.mV[VY] = mQ[VY] * oomag; + vec.mV[VZ] = mQ[VZ] * oomag; + *angle = 2.0f * atan2f(v, w); // get the angle + } + else + { + *angle = 0.0f; // no rotation + vec.mV[VX] = 0.0f; // around some dummy axis + vec.mV[VY] = 0.0f; + vec.mV[VZ] = 1.0f; + } +} + +const LLQuaternion& LLQuaternion::setFromAzimuthAndAltitude(F32 azimuthRadians, F32 altitudeRadians) +{ + // euler angle inputs are complements of azimuth/altitude which are measured from zenith + F32 pitch = llclamp(F_PI_BY_TWO - altitudeRadians, 0.0f, F_PI_BY_TWO); + F32 yaw = llclamp(F_PI_BY_TWO - azimuthRadians, 0.0f, F_PI_BY_TWO); + setEulerAngles(0.0f, pitch, yaw); + return *this; +} + +void LLQuaternion::getAzimuthAndAltitude(F32 &azimuthRadians, F32 &altitudeRadians) +{ + F32 rick_roll; + F32 pitch; + F32 yaw; + getEulerAngles(&rick_roll, &pitch, &yaw); + // make these measured from zenith + altitudeRadians = llclamp(F_PI_BY_TWO - pitch, 0.0f, F_PI_BY_TWO); + azimuthRadians = llclamp(F_PI_BY_TWO - yaw, 0.0f, F_PI_BY_TWO); +} + +// quaternion does not need to be normalized +void LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const +{ + F32 sx = 2 * (mQ[VX] * mQ[VW] - mQ[VY] * mQ[VZ]); // sine of the roll + F32 sy = 2 * (mQ[VY] * mQ[VW] + mQ[VX] * mQ[VZ]); // sine of the pitch + F32 ys = mQ[VW] * mQ[VW] - mQ[VY] * mQ[VY]; // intermediate cosine 1 + F32 xz = mQ[VX] * mQ[VX] - mQ[VZ] * mQ[VZ]; // intermediate cosine 2 + F32 cx = ys - xz; // cosine of the roll + F32 cy = sqrtf(sx * sx + cx * cx); // cosine of the pitch + if (cy > GIMBAL_THRESHOLD) // no gimbal lock + { + *roll = atan2f(sx, cx); + *pitch = atan2f(sy, cy); + *yaw = atan2f(2 * (mQ[VZ] * mQ[VW] - mQ[VX] * mQ[VY]), ys + xz); + } + else // gimbal lock + { + if (sy > 0) + { + *pitch = F_PI_BY_TWO; + *yaw = 2 * atan2f(mQ[VZ] + mQ[VX], mQ[VW] + mQ[VY]); + } + else + { + *pitch = -F_PI_BY_TWO; + *yaw = 2 * atan2f(mQ[VZ] - mQ[VX], mQ[VW] - mQ[VY]); + } + *roll = 0; + } +} + +// Saves space by using the fact that our quaternions are normalized +LLVector3 LLQuaternion::packToVector3() const +{ + F32 x = mQ[VX]; + F32 y = mQ[VY]; + F32 z = mQ[VZ]; + F32 w = mQ[VW]; + F32 mag = sqrtf(x * x + y * y + z * z + w * w); + if (mag > FP_MAG_THRESHOLD) + { + x /= mag; + y /= mag; + z /= mag; // no need to normalize w, it's not used + } + if( mQ[VW] >= 0 ) + { + return LLVector3( x, y , z ); + } + else + { + return LLVector3( -x, -y, -z ); + } +} + +// Saves space by using the fact that our quaternions are normalized +void LLQuaternion::unpackFromVector3( const LLVector3& vec ) +{ + mQ[VX] = vec.mV[VX]; + mQ[VY] = vec.mV[VY]; + mQ[VZ] = vec.mV[VZ]; + F32 t = 1.f - vec.magVecSquared(); + if( t > 0 ) + { + mQ[VW] = sqrt( t ); + } + else + { + // Need this to avoid trying to find the square root of a negative number due + // to floating point error. + mQ[VW] = 0; + } +} + +bool LLQuaternion::parseQuat(const std::string& buf, LLQuaternion* value) +{ + if( buf.empty() || value == NULL) + { + return false; + } + + LLQuaternion quat; + S32 count = sscanf( buf.c_str(), "%f %f %f %f", quat.mQ + 0, quat.mQ + 1, quat.mQ + 2, quat.mQ + 3 ); + if( 4 == count ) + { + value->set( quat ); + return true; + } + + return false; +} + + +// End diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index 7a245475c1..2caa993007 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -1,617 +1,617 @@ -/** - * @file llquaternion.h - * @brief LLQuaternion class header file. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LLQUATERNION_H -#define LLQUATERNION_H - -#include -#include "llsd.h" - -#ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies -#error "Please include llmath.h first." -#endif - -class LLVector4; -class LLVector3; -class LLVector3d; -class LLMatrix4; -class LLMatrix3; - -// NOTA BENE: Quaternion code is written assuming Unit Quaternions!!!! -// Moreover, it is written assuming that all vectors and matricies -// passed as arguments are normalized and unitary respectively. -// VERY VERY VERY VERY BAD THINGS will happen if these assumptions fail. - -static const U32 LENGTHOFQUAT = 4; - -class LLQuaternion -{ -public: - F32 mQ[LENGTHOFQUAT]; - - static const LLQuaternion DEFAULT; - - LLQuaternion(); // Initializes Quaternion to (0,0,0,1) - explicit LLQuaternion(const LLMatrix4 &mat); // Initializes Quaternion from Matrix4 - explicit LLQuaternion(const LLMatrix3 &mat); // Initializes Quaternion from Matrix3 - LLQuaternion(F32 x, F32 y, F32 z, F32 w); // Initializes Quaternion to normalize(x, y, z, w) - LLQuaternion(F32 angle, const LLVector4 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec) - LLQuaternion(F32 angle, const LLVector3 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec) - LLQuaternion(const F32 *q); // Initializes Quaternion to normalize(x, y, z, w) - LLQuaternion(const LLVector3 &x_axis, - const LLVector3 &y_axis, - const LLVector3 &z_axis); // Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis] - explicit LLQuaternion(const LLSD &sd); // Initializes Quaternion from LLSD array. - - LLSD getValue() const; - void setValue(const LLSD& sd); - - bool isIdentity() const; - bool isNotIdentity() const; - bool isFinite() const; // checks to see if all values of LLQuaternion are finite - void quantize16(F32 lower, F32 upper); // changes the vector to reflect quatization - void quantize8(F32 lower, F32 upper); // changes the vector to reflect quatization - void loadIdentity(); // Loads the quaternion that represents the identity rotation - - bool isEqualEps(const LLQuaternion &quat, F32 epsilon) const; - bool isNotEqualEps(const LLQuaternion &quat, F32 epsilon) const; - - const LLQuaternion& set(F32 x, F32 y, F32 z, F32 w); // Sets Quaternion to normalize(x, y, z, w) - const LLQuaternion& set(const LLQuaternion &quat); // Copies Quaternion - const LLQuaternion& set(const F32 *q); // Sets Quaternion to normalize(quat[VX], quat[VY], quat[VZ], quat[VW]) - const LLQuaternion& set(const LLMatrix3 &mat); // Sets Quaternion to mat2quat(mat) - const LLQuaternion& set(const LLMatrix4 &mat); // Sets Quaternion to mat2quat(mat) - const LLQuaternion& setFromAzimuthAndAltitude(F32 azimuth, F32 altitude); - - const LLQuaternion& setAngleAxis(F32 angle, F32 x, F32 y, F32 z); // Sets Quaternion to axis_angle2quat(angle, x, y, z) - const LLQuaternion& setAngleAxis(F32 angle, const LLVector3 &vec); // Sets Quaternion to axis_angle2quat(angle, vec) - const LLQuaternion& setAngleAxis(F32 angle, const LLVector4 &vec); // Sets Quaternion to axis_angle2quat(angle, vec) - const LLQuaternion& setEulerAngles(F32 roll, F32 pitch, F32 yaw); // Sets Quaternion to euler2quat(pitch, yaw, roll) - - const LLQuaternion& setQuatInit(F32 x, F32 y, F32 z, F32 w); // deprecated - const LLQuaternion& setQuat(const LLQuaternion &quat); // deprecated - const LLQuaternion& setQuat(const F32 *q); // deprecated - const LLQuaternion& setQuat(const LLMatrix3 &mat); // deprecated - const LLQuaternion& setQuat(const LLMatrix4 &mat); // deprecated - const LLQuaternion& setQuat(F32 angle, F32 x, F32 y, F32 z); // deprecated - const LLQuaternion& setQuat(F32 angle, const LLVector3 &vec); // deprecated - const LLQuaternion& setQuat(F32 angle, const LLVector4 &vec); // deprecated - const LLQuaternion& setQuat(F32 roll, F32 pitch, F32 yaw); // deprecated - - LLMatrix4 getMatrix4(void) const; // Returns the Matrix4 equivalent of Quaternion - LLMatrix3 getMatrix3(void) const; // Returns the Matrix3 equivalent of Quaternion - void getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const; // returns rotation in radians about axis x,y,z - void getAngleAxis(F32* angle, LLVector3 &vec) const; - void getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const; - void getAzimuthAndAltitude(F32 &azimuth, F32 &altitude); - - F32 normalize(); // Normalizes Quaternion and returns magnitude - F32 normQuat(); // deprecated - - const LLQuaternion& conjugate(void); // Conjugates Quaternion and returns result - const LLQuaternion& conjQuat(void); // deprecated - - // Other useful methods - const LLQuaternion& transpose(); // transpose (same as conjugate) - const LLQuaternion& transQuat(); // deprecated - - void shortestArc(const LLVector3 &a, const LLVector3 &b); // shortest rotation from a to b - const LLQuaternion& constrain(F32 radians); // constrains rotation to a cone angle specified in radians - - // Standard operators - friend std::ostream& operator<<(std::ostream &s, const LLQuaternion &a); // Prints a - friend LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b); // Addition - friend LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b); // Subtraction - friend LLQuaternion operator-(const LLQuaternion &a); // Negation - friend LLQuaternion operator*(F32 a, const LLQuaternion &q); // Scale - friend LLQuaternion operator*(const LLQuaternion &q, F32 b); // Scale - friend LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b); // Returns a * b - friend LLQuaternion operator~(const LLQuaternion &a); // Returns a* (Conjugate of a) - bool operator==(const LLQuaternion &b) const; // Returns a == b - bool operator!=(const LLQuaternion &b) const; // Returns a != b - - friend const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b); // Returns a * b - - friend LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot); // Rotates a by rot - friend LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot); // Rotates a by rot - friend LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot); // Rotates a by rot - - // Non-standard operators - friend F32 dot(const LLQuaternion &a, const LLQuaternion &b); - friend LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // linear interpolation (t = 0 to 1) from p to q - friend LLQuaternion lerp(F32 t, const LLQuaternion &q); // linear interpolation (t = 0 to 1) from identity to q - friend LLQuaternion slerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // spherical linear interpolation from p to q - friend LLQuaternion slerp(F32 t, const LLQuaternion &q); // spherical linear interpolation from identity to q - friend LLQuaternion nlerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // normalized linear interpolation from p to q - friend LLQuaternion nlerp(F32 t, const LLQuaternion &q); // normalized linear interpolation from p to q - - LLVector3 packToVector3() const; // Saves space by using the fact that our quaternions are normalized - void unpackFromVector3(const LLVector3& vec); // Saves space by using the fact that our quaternions are normalized - - enum Order { - XYZ = 0, - YZX = 1, - ZXY = 2, - XZY = 3, - YXZ = 4, - ZYX = 5 - }; - // Creates a quaternions from maya's rotation representation, - // which is 3 rotations (in DEGREES) in the specified order - friend LLQuaternion mayaQ(F32 x, F32 y, F32 z, Order order); - - // Conversions between Order and strings like "xyz" or "ZYX" - friend const char *OrderToString( const Order order ); - friend Order StringToOrder( const char *str ); - - static bool parseQuat(const std::string& buf, LLQuaternion* value); - - // For debugging, only - //static U32 mMultCount; -}; - -inline LLSD LLQuaternion::getValue() const -{ - LLSD ret; - ret[0] = mQ[0]; - ret[1] = mQ[1]; - ret[2] = mQ[2]; - ret[3] = mQ[3]; - return ret; -} - -inline void LLQuaternion::setValue(const LLSD& sd) -{ - mQ[0] = sd[0].asReal(); - mQ[1] = sd[1].asReal(); - mQ[2] = sd[2].asReal(); - mQ[3] = sd[3].asReal(); -} - -// checker -inline bool LLQuaternion::isFinite() const -{ - return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS])); -} - -inline bool LLQuaternion::isIdentity() const -{ - return - ( mQ[VX] == 0.f ) && - ( mQ[VY] == 0.f ) && - ( mQ[VZ] == 0.f ) && - ( mQ[VS] == 1.f ); -} - -inline bool LLQuaternion::isNotIdentity() const -{ - return - ( mQ[VX] != 0.f ) || - ( mQ[VY] != 0.f ) || - ( mQ[VZ] != 0.f ) || - ( mQ[VS] != 1.f ); -} - - - -inline LLQuaternion::LLQuaternion(void) -{ - mQ[VX] = 0.f; - mQ[VY] = 0.f; - mQ[VZ] = 0.f; - mQ[VS] = 1.f; -} - -inline LLQuaternion::LLQuaternion(F32 x, F32 y, F32 z, F32 w) -{ - mQ[VX] = x; - mQ[VY] = y; - mQ[VZ] = z; - mQ[VS] = w; - - //RN: don't normalize this case as its used mainly for temporaries during calculations - //normalize(); - /* - F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); - mag -= 1.f; - mag = fabs(mag); - llassert(mag < 10.f*FP_MAG_THRESHOLD); - */ -} - -inline LLQuaternion::LLQuaternion(const F32 *q) -{ - mQ[VX] = q[VX]; - mQ[VY] = q[VY]; - mQ[VZ] = q[VZ]; - mQ[VS] = q[VW]; - - normalize(); - /* - F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); - mag -= 1.f; - mag = fabs(mag); - llassert(mag < FP_MAG_THRESHOLD); - */ -} - - -inline void LLQuaternion::loadIdentity() -{ - mQ[VX] = 0.0f; - mQ[VY] = 0.0f; - mQ[VZ] = 0.0f; - mQ[VW] = 1.0f; -} - -inline bool LLQuaternion::isEqualEps(const LLQuaternion &quat, F32 epsilon) const -{ - return ( fabs(mQ[VX] - quat.mQ[VX]) < epsilon - && fabs(mQ[VY] - quat.mQ[VY]) < epsilon - && fabs(mQ[VZ] - quat.mQ[VZ]) < epsilon - && fabs(mQ[VS] - quat.mQ[VS]) < epsilon ); -} - -inline bool LLQuaternion::isNotEqualEps(const LLQuaternion &quat, F32 epsilon) const -{ - return ( fabs(mQ[VX] - quat.mQ[VX]) > epsilon - || fabs(mQ[VY] - quat.mQ[VY]) > epsilon - || fabs(mQ[VZ] - quat.mQ[VZ]) > epsilon - || fabs(mQ[VS] - quat.mQ[VS]) > epsilon ); -} - -inline const LLQuaternion& LLQuaternion::set(F32 x, F32 y, F32 z, F32 w) -{ - mQ[VX] = x; - mQ[VY] = y; - mQ[VZ] = z; - mQ[VS] = w; - normalize(); - return (*this); -} - -inline const LLQuaternion& LLQuaternion::set(const LLQuaternion &quat) -{ - mQ[VX] = quat.mQ[VX]; - mQ[VY] = quat.mQ[VY]; - mQ[VZ] = quat.mQ[VZ]; - mQ[VW] = quat.mQ[VW]; - normalize(); - return (*this); -} - -inline const LLQuaternion& LLQuaternion::set(const F32 *q) -{ - mQ[VX] = q[VX]; - mQ[VY] = q[VY]; - mQ[VZ] = q[VZ]; - mQ[VS] = q[VW]; - normalize(); - return (*this); -} - - -// deprecated -inline const LLQuaternion& LLQuaternion::setQuatInit(F32 x, F32 y, F32 z, F32 w) -{ - mQ[VX] = x; - mQ[VY] = y; - mQ[VZ] = z; - mQ[VS] = w; - normalize(); - return (*this); -} - -// deprecated -inline const LLQuaternion& LLQuaternion::setQuat(const LLQuaternion &quat) -{ - mQ[VX] = quat.mQ[VX]; - mQ[VY] = quat.mQ[VY]; - mQ[VZ] = quat.mQ[VZ]; - mQ[VW] = quat.mQ[VW]; - normalize(); - return (*this); -} - -// deprecated -inline const LLQuaternion& LLQuaternion::setQuat(const F32 *q) -{ - mQ[VX] = q[VX]; - mQ[VY] = q[VY]; - mQ[VZ] = q[VZ]; - mQ[VS] = q[VW]; - normalize(); - return (*this); -} - -inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const -{ - F32 v = sqrtf(mQ[VX] * mQ[VX] + mQ[VY] * mQ[VY] + mQ[VZ] * mQ[VZ]); // length of the vector-component - if (v > FP_MAG_THRESHOLD) - { - F32 oomag = 1.0f / v; - F32 w = mQ[VW]; - if (w < 0.0f) - { - w = -w; // make VW positive - oomag = -oomag; // invert the axis - } - *x = mQ[VX] * oomag; // normalize the axis - *y = mQ[VY] * oomag; - *z = mQ[VZ] * oomag; - *angle = 2.0f * atan2f(v, w); // get the angle - } - else - { - *angle = 0.0f; // no rotation - *x = 0.0f; // around some dummy axis - *y = 0.0f; - *z = 1.0f; - } -} - -inline const LLQuaternion& LLQuaternion::conjugate() -{ - mQ[VX] *= -1.f; - mQ[VY] *= -1.f; - mQ[VZ] *= -1.f; - return (*this); -} - -inline const LLQuaternion& LLQuaternion::conjQuat() -{ - mQ[VX] *= -1.f; - mQ[VY] *= -1.f; - mQ[VZ] *= -1.f; - return (*this); -} - -// Transpose -inline const LLQuaternion& LLQuaternion::transpose() -{ - mQ[VX] *= -1.f; - mQ[VY] *= -1.f; - mQ[VZ] *= -1.f; - return (*this); -} - -// deprecated -inline const LLQuaternion& LLQuaternion::transQuat() -{ - mQ[VX] *= -1.f; - mQ[VY] *= -1.f; - mQ[VZ] *= -1.f; - return (*this); -} - - -inline LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b) -{ - return LLQuaternion( - a.mQ[VX] + b.mQ[VX], - a.mQ[VY] + b.mQ[VY], - a.mQ[VZ] + b.mQ[VZ], - a.mQ[VW] + b.mQ[VW] ); -} - - -inline LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b) -{ - return LLQuaternion( - a.mQ[VX] - b.mQ[VX], - a.mQ[VY] - b.mQ[VY], - a.mQ[VZ] - b.mQ[VZ], - a.mQ[VW] - b.mQ[VW] ); -} - - -inline LLQuaternion operator-(const LLQuaternion &a) -{ - return LLQuaternion( - -a.mQ[VX], - -a.mQ[VY], - -a.mQ[VZ], - -a.mQ[VW] ); -} - - -inline LLQuaternion operator*(F32 a, const LLQuaternion &q) -{ - return LLQuaternion( - a * q.mQ[VX], - a * q.mQ[VY], - a * q.mQ[VZ], - a * q.mQ[VW] ); -} - - -inline LLQuaternion operator*(const LLQuaternion &q, F32 a) -{ - return LLQuaternion( - a * q.mQ[VX], - a * q.mQ[VY], - a * q.mQ[VZ], - a * q.mQ[VW] ); -} - -inline LLQuaternion operator~(const LLQuaternion &a) -{ - LLQuaternion q(a); - q.conjQuat(); - return q; -} - -inline bool LLQuaternion::operator==(const LLQuaternion &b) const -{ - return ( (mQ[VX] == b.mQ[VX]) - &&(mQ[VY] == b.mQ[VY]) - &&(mQ[VZ] == b.mQ[VZ]) - &&(mQ[VS] == b.mQ[VS])); -} - -inline bool LLQuaternion::operator!=(const LLQuaternion &b) const -{ - return ( (mQ[VX] != b.mQ[VX]) - ||(mQ[VY] != b.mQ[VY]) - ||(mQ[VZ] != b.mQ[VZ]) - ||(mQ[VS] != b.mQ[VS])); -} - -inline const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b) -{ -#if 1 - LLQuaternion q( - b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1], - b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2], - b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0], - b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2] - ); - a = q; -#else - a = a * b; -#endif - return a; -} - -const F32 ONE_PART_IN_A_MILLION = 0.000001f; - -inline F32 LLQuaternion::normalize() -{ - F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); - - if (mag > FP_MAG_THRESHOLD) - { - // Floating point error can prevent some quaternions from achieving - // exact unity length. When trying to renormalize such quaternions we - // can oscillate between multiple quantized states. To prevent such - // drifts we only renomalize if the length is far enough from unity. - if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) - { - F32 oomag = 1.f/mag; - mQ[VX] *= oomag; - mQ[VY] *= oomag; - mQ[VZ] *= oomag; - mQ[VS] *= oomag; - } - } - else - { - // we were given a very bad quaternion so we set it to identity - mQ[VX] = 0.f; - mQ[VY] = 0.f; - mQ[VZ] = 0.f; - mQ[VS] = 1.f; - } - - return mag; -} - -// deprecated -inline F32 LLQuaternion::normQuat() -{ - F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); - - if (mag > FP_MAG_THRESHOLD) - { - if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) - { - // only renormalize if length not close enough to 1.0 already - F32 oomag = 1.f/mag; - mQ[VX] *= oomag; - mQ[VY] *= oomag; - mQ[VZ] *= oomag; - mQ[VS] *= oomag; - } - } - else - { - mQ[VX] = 0.f; - mQ[VY] = 0.f; - mQ[VZ] = 0.f; - mQ[VS] = 1.f; - } - - return mag; -} - -LLQuaternion::Order StringToOrder( const char *str ); - -// Some notes about Quaternions - -// What is a Quaternion? -// --------------------- -// A quaternion is a point in 4-dimensional complex space. -// Q = { Qx, Qy, Qz, Qw } -// -// -// Why Quaternions? -// ---------------- -// The set of quaternions that make up the the 4-D unit sphere -// can be mapped to the set of all rotations in 3-D space. Sometimes -// it is easier to describe/manipulate rotations in quaternion space -// than rotation-matrix space. -// -// -// How Quaternions? -// ---------------- -// In order to take advantage of quaternions we need to know how to -// go from rotation-matricies to quaternions and back. We also have -// to agree what variety of rotations we're generating. -// -// Consider the equation... v' = v * R -// -// There are two ways to think about rotations of vectors. -// 1) v' is the same vector in a different reference frame -// 2) v' is a new vector in the same reference frame -// -// bookmark -- which way are we using? -// -// -// Quaternion from Angle-Axis: -// --------------------------- -// Suppose we wanted to represent a rotation of some angle (theta) -// about some axis ({Ax, Ay, Az})... -// -// axis of rotation = {Ax, Ay, Az} -// angle_of_rotation = theta -// -// s = sin(0.5 * theta) -// c = cos(0.5 * theta) -// Q = { s * Ax, s * Ay, s * Az, c } -// -// -// 3x3 Matrix from Quaternion -// -------------------------- -// -// | | -// | 1 - 2 * (y^2 + z^2) 2 * (x * y + z * w) 2 * (y * w - x * z) | -// | | -// M = | 2 * (x * y - z * w) 1 - 2 * (x^2 + z^2) 2 * (y * z + x * w) | -// | | -// | 2 * (x * z + y * w) 2 * (y * z - x * w) 1 - 2 * (x^2 + y^2) | -// | | - -#endif +/** + * @file llquaternion.h + * @brief LLQuaternion class header file. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLQUATERNION_H +#define LLQUATERNION_H + +#include +#include "llsd.h" + +#ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies +#error "Please include llmath.h first." +#endif + +class LLVector4; +class LLVector3; +class LLVector3d; +class LLMatrix4; +class LLMatrix3; + +// NOTA BENE: Quaternion code is written assuming Unit Quaternions!!!! +// Moreover, it is written assuming that all vectors and matricies +// passed as arguments are normalized and unitary respectively. +// VERY VERY VERY VERY BAD THINGS will happen if these assumptions fail. + +static const U32 LENGTHOFQUAT = 4; + +class LLQuaternion +{ +public: + F32 mQ[LENGTHOFQUAT]; + + static const LLQuaternion DEFAULT; + + LLQuaternion(); // Initializes Quaternion to (0,0,0,1) + explicit LLQuaternion(const LLMatrix4 &mat); // Initializes Quaternion from Matrix4 + explicit LLQuaternion(const LLMatrix3 &mat); // Initializes Quaternion from Matrix3 + LLQuaternion(F32 x, F32 y, F32 z, F32 w); // Initializes Quaternion to normalize(x, y, z, w) + LLQuaternion(F32 angle, const LLVector4 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec) + LLQuaternion(F32 angle, const LLVector3 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec) + LLQuaternion(const F32 *q); // Initializes Quaternion to normalize(x, y, z, w) + LLQuaternion(const LLVector3 &x_axis, + const LLVector3 &y_axis, + const LLVector3 &z_axis); // Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis] + explicit LLQuaternion(const LLSD &sd); // Initializes Quaternion from LLSD array. + + LLSD getValue() const; + void setValue(const LLSD& sd); + + bool isIdentity() const; + bool isNotIdentity() const; + bool isFinite() const; // checks to see if all values of LLQuaternion are finite + void quantize16(F32 lower, F32 upper); // changes the vector to reflect quatization + void quantize8(F32 lower, F32 upper); // changes the vector to reflect quatization + void loadIdentity(); // Loads the quaternion that represents the identity rotation + + bool isEqualEps(const LLQuaternion &quat, F32 epsilon) const; + bool isNotEqualEps(const LLQuaternion &quat, F32 epsilon) const; + + const LLQuaternion& set(F32 x, F32 y, F32 z, F32 w); // Sets Quaternion to normalize(x, y, z, w) + const LLQuaternion& set(const LLQuaternion &quat); // Copies Quaternion + const LLQuaternion& set(const F32 *q); // Sets Quaternion to normalize(quat[VX], quat[VY], quat[VZ], quat[VW]) + const LLQuaternion& set(const LLMatrix3 &mat); // Sets Quaternion to mat2quat(mat) + const LLQuaternion& set(const LLMatrix4 &mat); // Sets Quaternion to mat2quat(mat) + const LLQuaternion& setFromAzimuthAndAltitude(F32 azimuth, F32 altitude); + + const LLQuaternion& setAngleAxis(F32 angle, F32 x, F32 y, F32 z); // Sets Quaternion to axis_angle2quat(angle, x, y, z) + const LLQuaternion& setAngleAxis(F32 angle, const LLVector3 &vec); // Sets Quaternion to axis_angle2quat(angle, vec) + const LLQuaternion& setAngleAxis(F32 angle, const LLVector4 &vec); // Sets Quaternion to axis_angle2quat(angle, vec) + const LLQuaternion& setEulerAngles(F32 roll, F32 pitch, F32 yaw); // Sets Quaternion to euler2quat(pitch, yaw, roll) + + const LLQuaternion& setQuatInit(F32 x, F32 y, F32 z, F32 w); // deprecated + const LLQuaternion& setQuat(const LLQuaternion &quat); // deprecated + const LLQuaternion& setQuat(const F32 *q); // deprecated + const LLQuaternion& setQuat(const LLMatrix3 &mat); // deprecated + const LLQuaternion& setQuat(const LLMatrix4 &mat); // deprecated + const LLQuaternion& setQuat(F32 angle, F32 x, F32 y, F32 z); // deprecated + const LLQuaternion& setQuat(F32 angle, const LLVector3 &vec); // deprecated + const LLQuaternion& setQuat(F32 angle, const LLVector4 &vec); // deprecated + const LLQuaternion& setQuat(F32 roll, F32 pitch, F32 yaw); // deprecated + + LLMatrix4 getMatrix4(void) const; // Returns the Matrix4 equivalent of Quaternion + LLMatrix3 getMatrix3(void) const; // Returns the Matrix3 equivalent of Quaternion + void getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const; // returns rotation in radians about axis x,y,z + void getAngleAxis(F32* angle, LLVector3 &vec) const; + void getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const; + void getAzimuthAndAltitude(F32 &azimuth, F32 &altitude); + + F32 normalize(); // Normalizes Quaternion and returns magnitude + F32 normQuat(); // deprecated + + const LLQuaternion& conjugate(void); // Conjugates Quaternion and returns result + const LLQuaternion& conjQuat(void); // deprecated + + // Other useful methods + const LLQuaternion& transpose(); // transpose (same as conjugate) + const LLQuaternion& transQuat(); // deprecated + + void shortestArc(const LLVector3 &a, const LLVector3 &b); // shortest rotation from a to b + const LLQuaternion& constrain(F32 radians); // constrains rotation to a cone angle specified in radians + + // Standard operators + friend std::ostream& operator<<(std::ostream &s, const LLQuaternion &a); // Prints a + friend LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b); // Addition + friend LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b); // Subtraction + friend LLQuaternion operator-(const LLQuaternion &a); // Negation + friend LLQuaternion operator*(F32 a, const LLQuaternion &q); // Scale + friend LLQuaternion operator*(const LLQuaternion &q, F32 b); // Scale + friend LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b); // Returns a * b + friend LLQuaternion operator~(const LLQuaternion &a); // Returns a* (Conjugate of a) + bool operator==(const LLQuaternion &b) const; // Returns a == b + bool operator!=(const LLQuaternion &b) const; // Returns a != b + + friend const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b); // Returns a * b + + friend LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot); // Rotates a by rot + friend LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot); // Rotates a by rot + friend LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot); // Rotates a by rot + + // Non-standard operators + friend F32 dot(const LLQuaternion &a, const LLQuaternion &b); + friend LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // linear interpolation (t = 0 to 1) from p to q + friend LLQuaternion lerp(F32 t, const LLQuaternion &q); // linear interpolation (t = 0 to 1) from identity to q + friend LLQuaternion slerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // spherical linear interpolation from p to q + friend LLQuaternion slerp(F32 t, const LLQuaternion &q); // spherical linear interpolation from identity to q + friend LLQuaternion nlerp(F32 t, const LLQuaternion &p, const LLQuaternion &q); // normalized linear interpolation from p to q + friend LLQuaternion nlerp(F32 t, const LLQuaternion &q); // normalized linear interpolation from p to q + + LLVector3 packToVector3() const; // Saves space by using the fact that our quaternions are normalized + void unpackFromVector3(const LLVector3& vec); // Saves space by using the fact that our quaternions are normalized + + enum Order { + XYZ = 0, + YZX = 1, + ZXY = 2, + XZY = 3, + YXZ = 4, + ZYX = 5 + }; + // Creates a quaternions from maya's rotation representation, + // which is 3 rotations (in DEGREES) in the specified order + friend LLQuaternion mayaQ(F32 x, F32 y, F32 z, Order order); + + // Conversions between Order and strings like "xyz" or "ZYX" + friend const char *OrderToString( const Order order ); + friend Order StringToOrder( const char *str ); + + static bool parseQuat(const std::string& buf, LLQuaternion* value); + + // For debugging, only + //static U32 mMultCount; +}; + +inline LLSD LLQuaternion::getValue() const +{ + LLSD ret; + ret[0] = mQ[0]; + ret[1] = mQ[1]; + ret[2] = mQ[2]; + ret[3] = mQ[3]; + return ret; +} + +inline void LLQuaternion::setValue(const LLSD& sd) +{ + mQ[0] = sd[0].asReal(); + mQ[1] = sd[1].asReal(); + mQ[2] = sd[2].asReal(); + mQ[3] = sd[3].asReal(); +} + +// checker +inline bool LLQuaternion::isFinite() const +{ + return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS])); +} + +inline bool LLQuaternion::isIdentity() const +{ + return + ( mQ[VX] == 0.f ) && + ( mQ[VY] == 0.f ) && + ( mQ[VZ] == 0.f ) && + ( mQ[VS] == 1.f ); +} + +inline bool LLQuaternion::isNotIdentity() const +{ + return + ( mQ[VX] != 0.f ) || + ( mQ[VY] != 0.f ) || + ( mQ[VZ] != 0.f ) || + ( mQ[VS] != 1.f ); +} + + + +inline LLQuaternion::LLQuaternion(void) +{ + mQ[VX] = 0.f; + mQ[VY] = 0.f; + mQ[VZ] = 0.f; + mQ[VS] = 1.f; +} + +inline LLQuaternion::LLQuaternion(F32 x, F32 y, F32 z, F32 w) +{ + mQ[VX] = x; + mQ[VY] = y; + mQ[VZ] = z; + mQ[VS] = w; + + //RN: don't normalize this case as its used mainly for temporaries during calculations + //normalize(); + /* + F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); + mag -= 1.f; + mag = fabs(mag); + llassert(mag < 10.f*FP_MAG_THRESHOLD); + */ +} + +inline LLQuaternion::LLQuaternion(const F32 *q) +{ + mQ[VX] = q[VX]; + mQ[VY] = q[VY]; + mQ[VZ] = q[VZ]; + mQ[VS] = q[VW]; + + normalize(); + /* + F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); + mag -= 1.f; + mag = fabs(mag); + llassert(mag < FP_MAG_THRESHOLD); + */ +} + + +inline void LLQuaternion::loadIdentity() +{ + mQ[VX] = 0.0f; + mQ[VY] = 0.0f; + mQ[VZ] = 0.0f; + mQ[VW] = 1.0f; +} + +inline bool LLQuaternion::isEqualEps(const LLQuaternion &quat, F32 epsilon) const +{ + return ( fabs(mQ[VX] - quat.mQ[VX]) < epsilon + && fabs(mQ[VY] - quat.mQ[VY]) < epsilon + && fabs(mQ[VZ] - quat.mQ[VZ]) < epsilon + && fabs(mQ[VS] - quat.mQ[VS]) < epsilon ); +} + +inline bool LLQuaternion::isNotEqualEps(const LLQuaternion &quat, F32 epsilon) const +{ + return ( fabs(mQ[VX] - quat.mQ[VX]) > epsilon + || fabs(mQ[VY] - quat.mQ[VY]) > epsilon + || fabs(mQ[VZ] - quat.mQ[VZ]) > epsilon + || fabs(mQ[VS] - quat.mQ[VS]) > epsilon ); +} + +inline const LLQuaternion& LLQuaternion::set(F32 x, F32 y, F32 z, F32 w) +{ + mQ[VX] = x; + mQ[VY] = y; + mQ[VZ] = z; + mQ[VS] = w; + normalize(); + return (*this); +} + +inline const LLQuaternion& LLQuaternion::set(const LLQuaternion &quat) +{ + mQ[VX] = quat.mQ[VX]; + mQ[VY] = quat.mQ[VY]; + mQ[VZ] = quat.mQ[VZ]; + mQ[VW] = quat.mQ[VW]; + normalize(); + return (*this); +} + +inline const LLQuaternion& LLQuaternion::set(const F32 *q) +{ + mQ[VX] = q[VX]; + mQ[VY] = q[VY]; + mQ[VZ] = q[VZ]; + mQ[VS] = q[VW]; + normalize(); + return (*this); +} + + +// deprecated +inline const LLQuaternion& LLQuaternion::setQuatInit(F32 x, F32 y, F32 z, F32 w) +{ + mQ[VX] = x; + mQ[VY] = y; + mQ[VZ] = z; + mQ[VS] = w; + normalize(); + return (*this); +} + +// deprecated +inline const LLQuaternion& LLQuaternion::setQuat(const LLQuaternion &quat) +{ + mQ[VX] = quat.mQ[VX]; + mQ[VY] = quat.mQ[VY]; + mQ[VZ] = quat.mQ[VZ]; + mQ[VW] = quat.mQ[VW]; + normalize(); + return (*this); +} + +// deprecated +inline const LLQuaternion& LLQuaternion::setQuat(const F32 *q) +{ + mQ[VX] = q[VX]; + mQ[VY] = q[VY]; + mQ[VZ] = q[VZ]; + mQ[VS] = q[VW]; + normalize(); + return (*this); +} + +inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const +{ + F32 v = sqrtf(mQ[VX] * mQ[VX] + mQ[VY] * mQ[VY] + mQ[VZ] * mQ[VZ]); // length of the vector-component + if (v > FP_MAG_THRESHOLD) + { + F32 oomag = 1.0f / v; + F32 w = mQ[VW]; + if (w < 0.0f) + { + w = -w; // make VW positive + oomag = -oomag; // invert the axis + } + *x = mQ[VX] * oomag; // normalize the axis + *y = mQ[VY] * oomag; + *z = mQ[VZ] * oomag; + *angle = 2.0f * atan2f(v, w); // get the angle + } + else + { + *angle = 0.0f; // no rotation + *x = 0.0f; // around some dummy axis + *y = 0.0f; + *z = 1.0f; + } +} + +inline const LLQuaternion& LLQuaternion::conjugate() +{ + mQ[VX] *= -1.f; + mQ[VY] *= -1.f; + mQ[VZ] *= -1.f; + return (*this); +} + +inline const LLQuaternion& LLQuaternion::conjQuat() +{ + mQ[VX] *= -1.f; + mQ[VY] *= -1.f; + mQ[VZ] *= -1.f; + return (*this); +} + +// Transpose +inline const LLQuaternion& LLQuaternion::transpose() +{ + mQ[VX] *= -1.f; + mQ[VY] *= -1.f; + mQ[VZ] *= -1.f; + return (*this); +} + +// deprecated +inline const LLQuaternion& LLQuaternion::transQuat() +{ + mQ[VX] *= -1.f; + mQ[VY] *= -1.f; + mQ[VZ] *= -1.f; + return (*this); +} + + +inline LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b) +{ + return LLQuaternion( + a.mQ[VX] + b.mQ[VX], + a.mQ[VY] + b.mQ[VY], + a.mQ[VZ] + b.mQ[VZ], + a.mQ[VW] + b.mQ[VW] ); +} + + +inline LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b) +{ + return LLQuaternion( + a.mQ[VX] - b.mQ[VX], + a.mQ[VY] - b.mQ[VY], + a.mQ[VZ] - b.mQ[VZ], + a.mQ[VW] - b.mQ[VW] ); +} + + +inline LLQuaternion operator-(const LLQuaternion &a) +{ + return LLQuaternion( + -a.mQ[VX], + -a.mQ[VY], + -a.mQ[VZ], + -a.mQ[VW] ); +} + + +inline LLQuaternion operator*(F32 a, const LLQuaternion &q) +{ + return LLQuaternion( + a * q.mQ[VX], + a * q.mQ[VY], + a * q.mQ[VZ], + a * q.mQ[VW] ); +} + + +inline LLQuaternion operator*(const LLQuaternion &q, F32 a) +{ + return LLQuaternion( + a * q.mQ[VX], + a * q.mQ[VY], + a * q.mQ[VZ], + a * q.mQ[VW] ); +} + +inline LLQuaternion operator~(const LLQuaternion &a) +{ + LLQuaternion q(a); + q.conjQuat(); + return q; +} + +inline bool LLQuaternion::operator==(const LLQuaternion &b) const +{ + return ( (mQ[VX] == b.mQ[VX]) + &&(mQ[VY] == b.mQ[VY]) + &&(mQ[VZ] == b.mQ[VZ]) + &&(mQ[VS] == b.mQ[VS])); +} + +inline bool LLQuaternion::operator!=(const LLQuaternion &b) const +{ + return ( (mQ[VX] != b.mQ[VX]) + ||(mQ[VY] != b.mQ[VY]) + ||(mQ[VZ] != b.mQ[VZ]) + ||(mQ[VS] != b.mQ[VS])); +} + +inline const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b) +{ +#if 1 + LLQuaternion q( + b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1], + b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2], + b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0], + b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2] + ); + a = q; +#else + a = a * b; +#endif + return a; +} + +const F32 ONE_PART_IN_A_MILLION = 0.000001f; + +inline F32 LLQuaternion::normalize() +{ + F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); + + if (mag > FP_MAG_THRESHOLD) + { + // Floating point error can prevent some quaternions from achieving + // exact unity length. When trying to renormalize such quaternions we + // can oscillate between multiple quantized states. To prevent such + // drifts we only renomalize if the length is far enough from unity. + if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) + { + F32 oomag = 1.f/mag; + mQ[VX] *= oomag; + mQ[VY] *= oomag; + mQ[VZ] *= oomag; + mQ[VS] *= oomag; + } + } + else + { + // we were given a very bad quaternion so we set it to identity + mQ[VX] = 0.f; + mQ[VY] = 0.f; + mQ[VZ] = 0.f; + mQ[VS] = 1.f; + } + + return mag; +} + +// deprecated +inline F32 LLQuaternion::normQuat() +{ + F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); + + if (mag > FP_MAG_THRESHOLD) + { + if (fabs(1.f - mag) > ONE_PART_IN_A_MILLION) + { + // only renormalize if length not close enough to 1.0 already + F32 oomag = 1.f/mag; + mQ[VX] *= oomag; + mQ[VY] *= oomag; + mQ[VZ] *= oomag; + mQ[VS] *= oomag; + } + } + else + { + mQ[VX] = 0.f; + mQ[VY] = 0.f; + mQ[VZ] = 0.f; + mQ[VS] = 1.f; + } + + return mag; +} + +LLQuaternion::Order StringToOrder( const char *str ); + +// Some notes about Quaternions + +// What is a Quaternion? +// --------------------- +// A quaternion is a point in 4-dimensional complex space. +// Q = { Qx, Qy, Qz, Qw } +// +// +// Why Quaternions? +// ---------------- +// The set of quaternions that make up the the 4-D unit sphere +// can be mapped to the set of all rotations in 3-D space. Sometimes +// it is easier to describe/manipulate rotations in quaternion space +// than rotation-matrix space. +// +// +// How Quaternions? +// ---------------- +// In order to take advantage of quaternions we need to know how to +// go from rotation-matricies to quaternions and back. We also have +// to agree what variety of rotations we're generating. +// +// Consider the equation... v' = v * R +// +// There are two ways to think about rotations of vectors. +// 1) v' is the same vector in a different reference frame +// 2) v' is a new vector in the same reference frame +// +// bookmark -- which way are we using? +// +// +// Quaternion from Angle-Axis: +// --------------------------- +// Suppose we wanted to represent a rotation of some angle (theta) +// about some axis ({Ax, Ay, Az})... +// +// axis of rotation = {Ax, Ay, Az} +// angle_of_rotation = theta +// +// s = sin(0.5 * theta) +// c = cos(0.5 * theta) +// Q = { s * Ax, s * Ay, s * Az, c } +// +// +// 3x3 Matrix from Quaternion +// -------------------------- +// +// | | +// | 1 - 2 * (y^2 + z^2) 2 * (x * y + z * w) 2 * (y * w - x * z) | +// | | +// M = | 2 * (x * y - z * w) 1 - 2 * (x^2 + z^2) 2 * (y * z + x * w) | +// | | +// | 2 * (x * z + y * w) 2 * (y * z - x * w) 1 - 2 * (x^2 + y^2) | +// | | + +#endif diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h index 5ec3ca0dff..317578da06 100644 --- a/indra/llmath/llrect.h +++ b/indra/llmath/llrect.h @@ -1,298 +1,298 @@ -/** - * @file llrect.h - * @brief A rectangle in GL coordinates, with bottom,left = 0,0 - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#ifndef LL_LLRECT_H -#define LL_LLRECT_H - -#include -#include "llmath.h" -#include "llsd.h" - -// Top > Bottom due to GL coords -template class LLRectBase -{ -public: - typedef Type tCoordType; - Type mLeft; - Type mTop; - Type mRight; - Type mBottom; - - // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - Type getWidth() const { return mRight - mLeft; } - Type getHeight() const { return mTop - mBottom; } - Type getCenterX() const { return (mLeft + mRight) / 2; } - Type getCenterY() const { return (mTop + mBottom) / 2; } - - LLRectBase(): mLeft(0), mTop(0), mRight(0), mBottom(0) - {} - - LLRectBase(const LLRectBase &r): - mLeft(r.mLeft), mTop(r.mTop), mRight(r.mRight), mBottom(r.mBottom) - {} - - LLRectBase(Type left, Type top, Type right, Type bottom): - mLeft(left), mTop(top), mRight(right), mBottom(bottom) - {} - - explicit LLRectBase(const LLSD& sd) - { - setValue(sd); - } - - void setValue(const LLSD& sd) - { - mLeft = (Type)sd[0].asInteger(); - mTop = (Type)sd[1].asInteger(); - mRight = (Type)sd[2].asInteger(); - mBottom = (Type)sd[3].asInteger(); - } - - LLSD getValue() const - { - LLSD ret; - ret[0] = mLeft; - ret[1] = mTop; - ret[2] = mRight; - ret[3] = mBottom; - return ret; - } - - // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - bool pointInRect(const Type x, const Type y) const - { - return mLeft <= x && x < mRight && - mBottom <= y && y < mTop; - } - - //// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - bool localPointInRect(const Type x, const Type y) const - { - return 0 <= x && x < getWidth() && - 0 <= y && y < getHeight(); - } - - void clampPointToRect(Type& x, Type& y) - { - x = llclamp(x, mLeft, mRight); - y = llclamp(y, mBottom, mTop); - } - - void clipPointToRect(const Type start_x, const Type start_y, Type& end_x, Type& end_y) - { - if (!pointInRect(start_x, start_y)) - { - return; - } - Type clip_x = 0; - Type clip_y = 0; - Type delta_x = end_x - start_x; - Type delta_y = end_y - start_y; - if (end_x > mRight) clip_x = end_x - mRight; - if (end_x < mLeft) clip_x = end_x - mLeft; - if (end_y > mTop) clip_y = end_y - mTop; - if (end_y < mBottom) clip_y = end_y - mBottom; - // clip_? and delta_? should have same sign, since starting point is in rect - // so ratios will be positive - F32 ratio_x = 0; - F32 ratio_y = 0; - if (delta_x != 0) ratio_x = ((F32)clip_x / (F32)delta_x); - if (delta_y != 0) ratio_y = ((F32)clip_y / (F32)delta_y); - if (ratio_x > ratio_y) - { - // clip along x direction - end_x -= (Type)(clip_x); - end_y -= (Type)(delta_y * ratio_x); - } - else - { - // clip along y direction - end_x -= (Type)(delta_x * ratio_y); - end_y -= (Type)clip_y; - } - } - - // Note: Does NOT follow GL_QUAD conventions: the top and right edges ARE considered part of the rect - // returns true if any part of rect is is inside this LLRect - bool overlaps(const LLRectBase& rect) const - { - return !(mLeft > rect.mRight - || mRight < rect.mLeft - || mBottom > rect.mTop - || mTop < rect.mBottom); - } - - bool contains(const LLRectBase& rect) const - { - return mLeft <= rect.mLeft - && mRight >= rect.mRight - && mBottom <= rect.mBottom - && mTop >= rect.mTop; - } - - LLRectBase& set(Type left, Type top, Type right, Type bottom) - { - mLeft = left; - mTop = top; - mRight = right; - mBottom = bottom; - return *this; - } - - // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - LLRectBase& setOriginAndSize( Type left, Type bottom, Type width, Type height) - { - mLeft = left; - mTop = bottom + height; - mRight = left + width; - mBottom = bottom; - return *this; - } - - // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect - LLRectBase& setLeftTopAndSize( Type left, Type top, Type width, Type height) - { - mLeft = left; - mTop = top; - mRight = left + width; - mBottom = top - height; - return *this; - } - - LLRectBase& setCenterAndSize(Type x, Type y, Type width, Type height) - { - // width and height could be odd, so favor top, right with extra pixel - mLeft = x - width/2; - mBottom = y - height/2; - mTop = mBottom + height; - mRight = mLeft + width; - return *this; - } - - - LLRectBase& translate(Type horiz, Type vertical) - { - mLeft += horiz; - mRight += horiz; - mTop += vertical; - mBottom += vertical; - return *this; - } - - LLRectBase& stretch( Type dx, Type dy) - { - mLeft -= dx; - mRight += dx; - mTop += dy; - mBottom -= dy; - return makeValid(); - } - - LLRectBase& stretch( Type delta ) - { - stretch(delta, delta); - return *this; - } - - LLRectBase& makeValid() - { - mLeft = llmin(mLeft, mRight); - mBottom = llmin(mBottom, mTop); - return *this; - } - - bool isValid() const - { - return mLeft <= mRight && mBottom <= mTop; - } - - bool isEmpty() const - { - return mLeft == mRight || mBottom == mTop; - } - - bool notEmpty() const - { - return !isEmpty(); - } - - void unionWith(const LLRectBase &other) - { - mLeft = llmin(mLeft, other.mLeft); - mRight = llmax(mRight, other.mRight); - mBottom = llmin(mBottom, other.mBottom); - mTop = llmax(mTop, other.mTop); - } - - void intersectWith(const LLRectBase &other) - { - mLeft = llmax(mLeft, other.mLeft); - mRight = llmin(mRight, other.mRight); - mBottom = llmax(mBottom, other.mBottom); - mTop = llmin(mTop, other.mTop); - if (mLeft > mRight) - { - mLeft = mRight; - } - if (mBottom > mTop) - { - mBottom = mTop; - } - } - - friend std::ostream &operator<<(std::ostream &s, const LLRectBase &rect) - { - s << "{ L " << rect.mLeft << " B " << rect.mBottom - << " W " << rect.getWidth() << " H " << rect.getHeight() << " }"; - return s; - } - - bool operator==(const LLRectBase &b) const - { - return ((mLeft == b.mLeft) && - (mTop == b.mTop) && - (mRight == b.mRight) && - (mBottom == b.mBottom)); - } - - bool operator!=(const LLRectBase &b) const - { - return ((mLeft != b.mLeft) || - (mTop != b.mTop) || - (mRight != b.mRight) || - (mBottom != b.mBottom)); - } - - static LLRectBase null; -}; - -template LLRectBase LLRectBase::null(0,0,0,0); - -typedef LLRectBase LLRect; -typedef LLRectBase LLRectf; - -#endif +/** + * @file llrect.h + * @brief A rectangle in GL coordinates, with bottom,left = 0,0 + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLRECT_H +#define LL_LLRECT_H + +#include +#include "llmath.h" +#include "llsd.h" + +// Top > Bottom due to GL coords +template class LLRectBase +{ +public: + typedef Type tCoordType; + Type mLeft; + Type mTop; + Type mRight; + Type mBottom; + + // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect + Type getWidth() const { return mRight - mLeft; } + Type getHeight() const { return mTop - mBottom; } + Type getCenterX() const { return (mLeft + mRight) / 2; } + Type getCenterY() const { return (mTop + mBottom) / 2; } + + LLRectBase(): mLeft(0), mTop(0), mRight(0), mBottom(0) + {} + + LLRectBase(const LLRectBase &r): + mLeft(r.mLeft), mTop(r.mTop), mRight(r.mRight), mBottom(r.mBottom) + {} + + LLRectBase(Type left, Type top, Type right, Type bottom): + mLeft(left), mTop(top), mRight(right), mBottom(bottom) + {} + + explicit LLRectBase(const LLSD& sd) + { + setValue(sd); + } + + void setValue(const LLSD& sd) + { + mLeft = (Type)sd[0].asInteger(); + mTop = (Type)sd[1].asInteger(); + mRight = (Type)sd[2].asInteger(); + mBottom = (Type)sd[3].asInteger(); + } + + LLSD getValue() const + { + LLSD ret; + ret[0] = mLeft; + ret[1] = mTop; + ret[2] = mRight; + ret[3] = mBottom; + return ret; + } + + // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect + bool pointInRect(const Type x, const Type y) const + { + return mLeft <= x && x < mRight && + mBottom <= y && y < mTop; + } + + //// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect + bool localPointInRect(const Type x, const Type y) const + { + return 0 <= x && x < getWidth() && + 0 <= y && y < getHeight(); + } + + void clampPointToRect(Type& x, Type& y) + { + x = llclamp(x, mLeft, mRight); + y = llclamp(y, mBottom, mTop); + } + + void clipPointToRect(const Type start_x, const Type start_y, Type& end_x, Type& end_y) + { + if (!pointInRect(start_x, start_y)) + { + return; + } + Type clip_x = 0; + Type clip_y = 0; + Type delta_x = end_x - start_x; + Type delta_y = end_y - start_y; + if (end_x > mRight) clip_x = end_x - mRight; + if (end_x < mLeft) clip_x = end_x - mLeft; + if (end_y > mTop) clip_y = end_y - mTop; + if (end_y < mBottom) clip_y = end_y - mBottom; + // clip_? and delta_? should have same sign, since starting point is in rect + // so ratios will be positive + F32 ratio_x = 0; + F32 ratio_y = 0; + if (delta_x != 0) ratio_x = ((F32)clip_x / (F32)delta_x); + if (delta_y != 0) ratio_y = ((F32)clip_y / (F32)delta_y); + if (ratio_x > ratio_y) + { + // clip along x direction + end_x -= (Type)(clip_x); + end_y -= (Type)(delta_y * ratio_x); + } + else + { + // clip along y direction + end_x -= (Type)(delta_x * ratio_y); + end_y -= (Type)clip_y; + } + } + + // Note: Does NOT follow GL_QUAD conventions: the top and right edges ARE considered part of the rect + // returns true if any part of rect is is inside this LLRect + bool overlaps(const LLRectBase& rect) const + { + return !(mLeft > rect.mRight + || mRight < rect.mLeft + || mBottom > rect.mTop + || mTop < rect.mBottom); + } + + bool contains(const LLRectBase& rect) const + { + return mLeft <= rect.mLeft + && mRight >= rect.mRight + && mBottom <= rect.mBottom + && mTop >= rect.mTop; + } + + LLRectBase& set(Type left, Type top, Type right, Type bottom) + { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + return *this; + } + + // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect + LLRectBase& setOriginAndSize( Type left, Type bottom, Type width, Type height) + { + mLeft = left; + mTop = bottom + height; + mRight = left + width; + mBottom = bottom; + return *this; + } + + // Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect + LLRectBase& setLeftTopAndSize( Type left, Type top, Type width, Type height) + { + mLeft = left; + mTop = top; + mRight = left + width; + mBottom = top - height; + return *this; + } + + LLRectBase& setCenterAndSize(Type x, Type y, Type width, Type height) + { + // width and height could be odd, so favor top, right with extra pixel + mLeft = x - width/2; + mBottom = y - height/2; + mTop = mBottom + height; + mRight = mLeft + width; + return *this; + } + + + LLRectBase& translate(Type horiz, Type vertical) + { + mLeft += horiz; + mRight += horiz; + mTop += vertical; + mBottom += vertical; + return *this; + } + + LLRectBase& stretch( Type dx, Type dy) + { + mLeft -= dx; + mRight += dx; + mTop += dy; + mBottom -= dy; + return makeValid(); + } + + LLRectBase& stretch( Type delta ) + { + stretch(delta, delta); + return *this; + } + + LLRectBase& makeValid() + { + mLeft = llmin(mLeft, mRight); + mBottom = llmin(mBottom, mTop); + return *this; + } + + bool isValid() const + { + return mLeft <= mRight && mBottom <= mTop; + } + + bool isEmpty() const + { + return mLeft == mRight || mBottom == mTop; + } + + bool notEmpty() const + { + return !isEmpty(); + } + + void unionWith(const LLRectBase &other) + { + mLeft = llmin(mLeft, other.mLeft); + mRight = llmax(mRight, other.mRight); + mBottom = llmin(mBottom, other.mBottom); + mTop = llmax(mTop, other.mTop); + } + + void intersectWith(const LLRectBase &other) + { + mLeft = llmax(mLeft, other.mLeft); + mRight = llmin(mRight, other.mRight); + mBottom = llmax(mBottom, other.mBottom); + mTop = llmin(mTop, other.mTop); + if (mLeft > mRight) + { + mLeft = mRight; + } + if (mBottom > mTop) + { + mBottom = mTop; + } + } + + friend std::ostream &operator<<(std::ostream &s, const LLRectBase &rect) + { + s << "{ L " << rect.mLeft << " B " << rect.mBottom + << " W " << rect.getWidth() << " H " << rect.getHeight() << " }"; + return s; + } + + bool operator==(const LLRectBase &b) const + { + return ((mLeft == b.mLeft) && + (mTop == b.mTop) && + (mRight == b.mRight) && + (mBottom == b.mBottom)); + } + + bool operator!=(const LLRectBase &b) const + { + return ((mLeft != b.mLeft) || + (mTop != b.mTop) || + (mRight != b.mRight) || + (mBottom != b.mBottom)); + } + + static LLRectBase null; +}; + +template LLRectBase LLRectBase::null(0,0,0,0); + +typedef LLRectBase LLRect; +typedef LLRectBase LLRectf; + +#endif diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index b68743ea6e..89349af6c8 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -1,370 +1,370 @@ -/** - * @file llsphere.cpp - * @author Andrew Meadows - * @brief Simple line class that can compute nearest approach between two lines - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llsphere.h" - -LLSphere::LLSphere() -: mCenter(0.f, 0.f, 0.f), - mRadius(0.f) -{ } - -LLSphere::LLSphere( const LLVector3& center, F32 radius) -{ - set(center, radius); -} - -void LLSphere::set( const LLVector3& center, F32 radius ) -{ - mCenter = center; - setRadius(radius); -} - -void LLSphere::setCenter( const LLVector3& center) -{ - mCenter = center; -} - -void LLSphere::setRadius( F32 radius) -{ - if (radius < 0.f) - { - radius = -radius; - } - mRadius = radius; -} - -const LLVector3& LLSphere::getCenter() const -{ - return mCenter; -} - -F32 LLSphere::getRadius() const -{ - return mRadius; -} - -// returns 'true' if this sphere completely contains other_sphere -bool LLSphere::contains(const LLSphere& other_sphere) const -{ - F32 separation = (mCenter - other_sphere.mCenter).length(); - return mRadius >= separation + other_sphere.mRadius; -} - -// returns 'true' if this sphere completely contains other_sphere -bool LLSphere::overlaps(const LLSphere& other_sphere) const -{ - F32 separation = (mCenter - other_sphere.mCenter).length(); - return mRadius >= separation - other_sphere.mRadius; -} - -// returns overlap -// negative overlap is closest approach -F32 LLSphere::getOverlap(const LLSphere& other_sphere) const -{ - // separation is distance from other_sphere's edge and this center - return (mCenter - other_sphere.mCenter).length() - mRadius - other_sphere.mRadius; -} - -bool LLSphere::operator==(const LLSphere& rhs) const -{ - return fabs(mRadius - rhs.mRadius) <= FLT_EPSILON && - (mCenter - rhs.mCenter).length() <= FLT_EPSILON; -} - -std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere) -{ - output_stream << "{center=" << sphere.mCenter << "," << "radius=" << sphere.mRadius << "}"; - return output_stream; -} - -// static -// removes any spheres that are contained in others -void LLSphere::collapse(std::vector& sphere_list) -{ - std::vector::iterator first_itr = sphere_list.begin(); - while (first_itr != sphere_list.end()) - { - bool delete_from_front = false; - - std::vector::iterator second_itr = first_itr; - ++second_itr; - while (second_itr != sphere_list.end()) - { - if (second_itr->contains(*first_itr)) - { - delete_from_front = true; - break; - } - else if (first_itr->contains(*second_itr)) - { - sphere_list.erase(second_itr++); - } - else - { - ++second_itr; - } - } - - if (delete_from_front) - { - sphere_list.erase(first_itr++); - } - else - { - ++first_itr; - } - } -} - -// static -// returns the bounding sphere that contains both spheres -LLSphere LLSphere::getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere) -{ - LLVector3 direction = second_sphere.mCenter - first_sphere.mCenter; - - // HACK -- it is possible to get enough floating point error in the - // other getBoundingSphere() method that we have to add some slop - // at the end. Unfortunately, this breaks the link-order invarience - // for the linkability tests... unless we also apply the same slop - // here. - F32 half_milimeter = 0.0005f; - - F32 distance = direction.length(); - if (0.f == distance) - { - direction.setVec(1.f, 0.f, 0.f); - } - else - { - direction.normVec(); - } - // the 'edge' is measured from the first_sphere's center - F32 max_edge = 0.f; - F32 min_edge = 0.f; - - max_edge = llmax(max_edge + first_sphere.getRadius(), max_edge + distance + second_sphere.getRadius() + half_milimeter); - min_edge = llmin(min_edge - first_sphere.getRadius(), min_edge + distance - second_sphere.getRadius() - half_milimeter); - F32 radius = 0.5f * (max_edge - min_edge); - LLVector3 center = first_sphere.mCenter + (0.5f * (max_edge + min_edge)) * direction; - return LLSphere(center, radius); -} - -// static -// returns the bounding sphere that contains an arbitrary set of spheres -LLSphere LLSphere::getBoundingSphere(const std::vector& sphere_list) -{ - // this algorithm can get relatively inaccurate when the sphere - // collection is 'small' (contained within a bounding sphere of about - // 2 meters or less) - // TODO -- improve the accuracy for small collections of spheres - - LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f ); - S32 sphere_count = sphere_list.size(); - if (1 == sphere_count) - { - // trivial case -- single sphere - std::vector::const_iterator sphere_itr = sphere_list.begin(); - bounding_sphere = *sphere_itr; - } - else if (2 == sphere_count) - { - // trivial case -- two spheres - std::vector::const_iterator first_sphere = sphere_list.begin(); - std::vector::const_iterator second_sphere = first_sphere; - ++second_sphere; - bounding_sphere = LLSphere::getBoundingSphere(*first_sphere, *second_sphere); - } - else if (sphere_count > 0) - { - // non-trivial case -- we will approximate the solution - // - // NOTE -- there is a fancy/fast way to do this for large - // numbers of arbirary N-dimensional spheres -- you can look it - // up on the net. We're dealing with 3D spheres at collection - // sizes of 256 spheres or smaller, so we just use this - // brute force method. - - // TODO -- perhaps would be worthwile to test for the solution where - // the largest spanning radius just happens to work. That is, where - // there are really two spheres that determine the bounding sphere, - // and all others are contained therein. - - // compute the AABB - std::vector::const_iterator first_itr = sphere_list.begin(); - LLVector3 max_corner = first_itr->getCenter() + first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); - LLVector3 min_corner = first_itr->getCenter() - first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); - { - std::vector::const_iterator sphere_itr = sphere_list.begin(); - for (++sphere_itr; sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 center = sphere_itr->getCenter(); - F32 radius = sphere_itr->getRadius(); - for (S32 i=0; i<3; ++i) - { - if (center.mV[i] + radius > max_corner.mV[i]) - { - max_corner.mV[i] = center.mV[i] + radius; - } - if (center.mV[i] - radius < min_corner.mV[i]) - { - min_corner.mV[i] = center.mV[i] - radius; - } - } - } - } - - // get the starting center and radius from the AABB - LLVector3 diagonal = max_corner - min_corner; - F32 bounding_radius = 0.5f * diagonal.length(); - LLVector3 bounding_center = 0.5f * (max_corner + min_corner); - - // compute the starting step-size - F32 minimum_radius = 0.5f * llmin(diagonal.mV[VX], llmin(diagonal.mV[VY], diagonal.mV[VZ])); - F32 step_length = bounding_radius - minimum_radius; - //S32 step_count = 0; - //S32 max_step_count = 12; - F32 half_milimeter = 0.0005f; - - // wander the center around in search of tighter solutions - S32 last_dx = 2; // 2 is out of bounds --> no match - S32 last_dy = 2; - S32 last_dz = 2; - - while (step_length > half_milimeter - /*&& step_count < max_step_count*/) - { - // the algorithm for testing the maximum radius could be expensive enough - // that it makes sense to NOT duplicate testing when possible, so we keep - // track of where we last tested, and only test the new points - - S32 best_dx = 0; - S32 best_dy = 0; - S32 best_dz = 0; - - // sample near the center of the box - bool found_better_center = false; - for (S32 dx = -1; dx < 2; ++dx) - { - for (S32 dy = -1; dy < 2; ++dy) - { - for (S32 dz = -1; dz < 2; ++dz) - { - if (dx == 0 && dy == 0 && dz == 0) - { - continue; - } - - // count the number of indecies that match the last_*'s - S32 match_count = 0; - if (last_dx == dx) ++match_count; - if (last_dy == dy) ++match_count; - if (last_dz == dz) ++match_count; - if (match_count == 2) - { - // we've already tested this point - continue; - } - - LLVector3 center = bounding_center; - center.mV[VX] += (F32) dx * step_length; - center.mV[VY] += (F32) dy * step_length; - center.mV[VZ] += (F32) dz * step_length; - - // compute the radius of the bounding sphere - F32 max_radius = 0.f; - std::vector::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - F32 radius = (sphere_itr->getCenter() - center).length() + sphere_itr->getRadius(); - if (radius > max_radius) - { - max_radius = radius; - } - } - if (max_radius < bounding_radius) - { - best_dx = dx; - best_dy = dy; - best_dz = dz; - bounding_center = center; - bounding_radius = max_radius; - found_better_center = true; - } - } - } - } - if (found_better_center) - { - // remember where we came from so we can avoid retesting - last_dx = -best_dx; - last_dy = -best_dy; - last_dz = -best_dz; - } - else - { - // reduce the step size - step_length *= 0.5f; - //++step_count; - // reset the last_*'s - last_dx = 2; // 2 is out of bounds --> no match - last_dy = 2; - last_dz = 2; - } - } - - // HACK -- it is possible to get enough floating point error for the - // bounding sphere to too small on the order of 10e-6, but we only need - // it to be accurate to within about half a millimeter - bounding_radius += half_milimeter; - - // this algorithm can get relatively inaccurate when the sphere - // collection is 'small' (contained within a bounding sphere of about - // 2 meters or less) - // TODO -- fix this - /* debug code - { - std::vector::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - F32 radius = (sphere_itr->getCenter() - bounding_center).length() + sphere_itr->getRadius(); - if (radius + 0.1f > bounding_radius) - { - std::cout << " rad = " << radius << " bounding - rad = " << (bounding_radius - radius) << std::endl; - } - } - std::cout << "\n" << std::endl; - } - */ - - bounding_sphere.set(bounding_center, bounding_radius); - } - return bounding_sphere; -} - - +/** + * @file llsphere.cpp + * @author Andrew Meadows + * @brief Simple line class that can compute nearest approach between two lines + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llsphere.h" + +LLSphere::LLSphere() +: mCenter(0.f, 0.f, 0.f), + mRadius(0.f) +{ } + +LLSphere::LLSphere( const LLVector3& center, F32 radius) +{ + set(center, radius); +} + +void LLSphere::set( const LLVector3& center, F32 radius ) +{ + mCenter = center; + setRadius(radius); +} + +void LLSphere::setCenter( const LLVector3& center) +{ + mCenter = center; +} + +void LLSphere::setRadius( F32 radius) +{ + if (radius < 0.f) + { + radius = -radius; + } + mRadius = radius; +} + +const LLVector3& LLSphere::getCenter() const +{ + return mCenter; +} + +F32 LLSphere::getRadius() const +{ + return mRadius; +} + +// returns 'true' if this sphere completely contains other_sphere +bool LLSphere::contains(const LLSphere& other_sphere) const +{ + F32 separation = (mCenter - other_sphere.mCenter).length(); + return mRadius >= separation + other_sphere.mRadius; +} + +// returns 'true' if this sphere completely contains other_sphere +bool LLSphere::overlaps(const LLSphere& other_sphere) const +{ + F32 separation = (mCenter - other_sphere.mCenter).length(); + return mRadius >= separation - other_sphere.mRadius; +} + +// returns overlap +// negative overlap is closest approach +F32 LLSphere::getOverlap(const LLSphere& other_sphere) const +{ + // separation is distance from other_sphere's edge and this center + return (mCenter - other_sphere.mCenter).length() - mRadius - other_sphere.mRadius; +} + +bool LLSphere::operator==(const LLSphere& rhs) const +{ + return fabs(mRadius - rhs.mRadius) <= FLT_EPSILON && + (mCenter - rhs.mCenter).length() <= FLT_EPSILON; +} + +std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere) +{ + output_stream << "{center=" << sphere.mCenter << "," << "radius=" << sphere.mRadius << "}"; + return output_stream; +} + +// static +// removes any spheres that are contained in others +void LLSphere::collapse(std::vector& sphere_list) +{ + std::vector::iterator first_itr = sphere_list.begin(); + while (first_itr != sphere_list.end()) + { + bool delete_from_front = false; + + std::vector::iterator second_itr = first_itr; + ++second_itr; + while (second_itr != sphere_list.end()) + { + if (second_itr->contains(*first_itr)) + { + delete_from_front = true; + break; + } + else if (first_itr->contains(*second_itr)) + { + sphere_list.erase(second_itr++); + } + else + { + ++second_itr; + } + } + + if (delete_from_front) + { + sphere_list.erase(first_itr++); + } + else + { + ++first_itr; + } + } +} + +// static +// returns the bounding sphere that contains both spheres +LLSphere LLSphere::getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere) +{ + LLVector3 direction = second_sphere.mCenter - first_sphere.mCenter; + + // HACK -- it is possible to get enough floating point error in the + // other getBoundingSphere() method that we have to add some slop + // at the end. Unfortunately, this breaks the link-order invarience + // for the linkability tests... unless we also apply the same slop + // here. + F32 half_milimeter = 0.0005f; + + F32 distance = direction.length(); + if (0.f == distance) + { + direction.setVec(1.f, 0.f, 0.f); + } + else + { + direction.normVec(); + } + // the 'edge' is measured from the first_sphere's center + F32 max_edge = 0.f; + F32 min_edge = 0.f; + + max_edge = llmax(max_edge + first_sphere.getRadius(), max_edge + distance + second_sphere.getRadius() + half_milimeter); + min_edge = llmin(min_edge - first_sphere.getRadius(), min_edge + distance - second_sphere.getRadius() - half_milimeter); + F32 radius = 0.5f * (max_edge - min_edge); + LLVector3 center = first_sphere.mCenter + (0.5f * (max_edge + min_edge)) * direction; + return LLSphere(center, radius); +} + +// static +// returns the bounding sphere that contains an arbitrary set of spheres +LLSphere LLSphere::getBoundingSphere(const std::vector& sphere_list) +{ + // this algorithm can get relatively inaccurate when the sphere + // collection is 'small' (contained within a bounding sphere of about + // 2 meters or less) + // TODO -- improve the accuracy for small collections of spheres + + LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f ); + S32 sphere_count = sphere_list.size(); + if (1 == sphere_count) + { + // trivial case -- single sphere + std::vector::const_iterator sphere_itr = sphere_list.begin(); + bounding_sphere = *sphere_itr; + } + else if (2 == sphere_count) + { + // trivial case -- two spheres + std::vector::const_iterator first_sphere = sphere_list.begin(); + std::vector::const_iterator second_sphere = first_sphere; + ++second_sphere; + bounding_sphere = LLSphere::getBoundingSphere(*first_sphere, *second_sphere); + } + else if (sphere_count > 0) + { + // non-trivial case -- we will approximate the solution + // + // NOTE -- there is a fancy/fast way to do this for large + // numbers of arbirary N-dimensional spheres -- you can look it + // up on the net. We're dealing with 3D spheres at collection + // sizes of 256 spheres or smaller, so we just use this + // brute force method. + + // TODO -- perhaps would be worthwile to test for the solution where + // the largest spanning radius just happens to work. That is, where + // there are really two spheres that determine the bounding sphere, + // and all others are contained therein. + + // compute the AABB + std::vector::const_iterator first_itr = sphere_list.begin(); + LLVector3 max_corner = first_itr->getCenter() + first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); + LLVector3 min_corner = first_itr->getCenter() - first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); + { + std::vector::const_iterator sphere_itr = sphere_list.begin(); + for (++sphere_itr; sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 center = sphere_itr->getCenter(); + F32 radius = sphere_itr->getRadius(); + for (S32 i=0; i<3; ++i) + { + if (center.mV[i] + radius > max_corner.mV[i]) + { + max_corner.mV[i] = center.mV[i] + radius; + } + if (center.mV[i] - radius < min_corner.mV[i]) + { + min_corner.mV[i] = center.mV[i] - radius; + } + } + } + } + + // get the starting center and radius from the AABB + LLVector3 diagonal = max_corner - min_corner; + F32 bounding_radius = 0.5f * diagonal.length(); + LLVector3 bounding_center = 0.5f * (max_corner + min_corner); + + // compute the starting step-size + F32 minimum_radius = 0.5f * llmin(diagonal.mV[VX], llmin(diagonal.mV[VY], diagonal.mV[VZ])); + F32 step_length = bounding_radius - minimum_radius; + //S32 step_count = 0; + //S32 max_step_count = 12; + F32 half_milimeter = 0.0005f; + + // wander the center around in search of tighter solutions + S32 last_dx = 2; // 2 is out of bounds --> no match + S32 last_dy = 2; + S32 last_dz = 2; + + while (step_length > half_milimeter + /*&& step_count < max_step_count*/) + { + // the algorithm for testing the maximum radius could be expensive enough + // that it makes sense to NOT duplicate testing when possible, so we keep + // track of where we last tested, and only test the new points + + S32 best_dx = 0; + S32 best_dy = 0; + S32 best_dz = 0; + + // sample near the center of the box + bool found_better_center = false; + for (S32 dx = -1; dx < 2; ++dx) + { + for (S32 dy = -1; dy < 2; ++dy) + { + for (S32 dz = -1; dz < 2; ++dz) + { + if (dx == 0 && dy == 0 && dz == 0) + { + continue; + } + + // count the number of indecies that match the last_*'s + S32 match_count = 0; + if (last_dx == dx) ++match_count; + if (last_dy == dy) ++match_count; + if (last_dz == dz) ++match_count; + if (match_count == 2) + { + // we've already tested this point + continue; + } + + LLVector3 center = bounding_center; + center.mV[VX] += (F32) dx * step_length; + center.mV[VY] += (F32) dy * step_length; + center.mV[VZ] += (F32) dz * step_length; + + // compute the radius of the bounding sphere + F32 max_radius = 0.f; + std::vector::const_iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + F32 radius = (sphere_itr->getCenter() - center).length() + sphere_itr->getRadius(); + if (radius > max_radius) + { + max_radius = radius; + } + } + if (max_radius < bounding_radius) + { + best_dx = dx; + best_dy = dy; + best_dz = dz; + bounding_center = center; + bounding_radius = max_radius; + found_better_center = true; + } + } + } + } + if (found_better_center) + { + // remember where we came from so we can avoid retesting + last_dx = -best_dx; + last_dy = -best_dy; + last_dz = -best_dz; + } + else + { + // reduce the step size + step_length *= 0.5f; + //++step_count; + // reset the last_*'s + last_dx = 2; // 2 is out of bounds --> no match + last_dy = 2; + last_dz = 2; + } + } + + // HACK -- it is possible to get enough floating point error for the + // bounding sphere to too small on the order of 10e-6, but we only need + // it to be accurate to within about half a millimeter + bounding_radius += half_milimeter; + + // this algorithm can get relatively inaccurate when the sphere + // collection is 'small' (contained within a bounding sphere of about + // 2 meters or less) + // TODO -- fix this + /* debug code + { + std::vector::const_iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + F32 radius = (sphere_itr->getCenter() - bounding_center).length() + sphere_itr->getRadius(); + if (radius + 0.1f > bounding_radius) + { + std::cout << " rad = " << radius << " bounding - rad = " << (bounding_radius - radius) << std::endl; + } + } + std::cout << "\n" << std::endl; + } + */ + + bounding_sphere.set(bounding_center, bounding_radius); + } + return bounding_sphere; +} + + diff --git a/indra/llmath/llsphere.h b/indra/llmath/llsphere.h index 413a307543..cb923dcd3c 100644 --- a/indra/llmath/llsphere.h +++ b/indra/llmath/llsphere.h @@ -1,77 +1,77 @@ -// llsphere.h -/** - * @file llsphere.cpp - * @author Andrew Meadows - * @brief Simple sphere implementation for basic geometric operations - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_SPHERE_H -#define LL_SPHERE_H - -#include "stdtypes.h" -#include "v3math.h" -#include -#include - -class LLSphere -{ -public: - LLSphere(); - LLSphere( const LLVector3& center, F32 radius ); - - void set( const LLVector3& center, F32 radius ); - void setCenter( const LLVector3& center ); - void setRadius( F32 radius ); - - const LLVector3& getCenter() const; - F32 getRadius() const; - - // returns true if this sphere completely contains other_sphere - bool contains(const LLSphere& other_sphere) const; - - // returns true if this sphere overlaps other_sphere - bool overlaps(const LLSphere& other_sphere) const; - - // returns overlap distance - // negative overlap is closest approach - F32 getOverlap(const LLSphere& other_sphere) const; - - // removes any spheres that are contained in others - static void collapse(std::vector& sphere_list); - - // returns minimum sphere bounding sphere for a set of spheres - static LLSphere getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere); - static LLSphere getBoundingSphere(const std::vector& sphere_list); - - bool operator==(const LLSphere& rhs) const; - - friend std::ostream& operator<<( std::ostream& output_stream, const LLSphere& line ); - -protected: - LLVector3 mCenter; - F32 mRadius; -}; - - -#endif +// llsphere.h +/** + * @file llsphere.cpp + * @author Andrew Meadows + * @brief Simple sphere implementation for basic geometric operations + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_SPHERE_H +#define LL_SPHERE_H + +#include "stdtypes.h" +#include "v3math.h" +#include +#include + +class LLSphere +{ +public: + LLSphere(); + LLSphere( const LLVector3& center, F32 radius ); + + void set( const LLVector3& center, F32 radius ); + void setCenter( const LLVector3& center ); + void setRadius( F32 radius ); + + const LLVector3& getCenter() const; + F32 getRadius() const; + + // returns true if this sphere completely contains other_sphere + bool contains(const LLSphere& other_sphere) const; + + // returns true if this sphere overlaps other_sphere + bool overlaps(const LLSphere& other_sphere) const; + + // returns overlap distance + // negative overlap is closest approach + F32 getOverlap(const LLSphere& other_sphere) const; + + // removes any spheres that are contained in others + static void collapse(std::vector& sphere_list); + + // returns minimum sphere bounding sphere for a set of spheres + static LLSphere getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere); + static LLSphere getBoundingSphere(const std::vector& sphere_list); + + bool operator==(const LLSphere& rhs) const; + + friend std::ostream& operator<<( std::ostream& output_stream, const LLSphere& line ); + +protected: + LLVector3 mCenter; + F32 mRadius; +}; + + +#endif diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index 5875e9e8e0..f648a114ca 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -1,125 +1,125 @@ -/** - * @file lltreenode.h - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLTREENODE_H -#define LL_LLTREENODE_H - -#include "stdtypes.h" -#include "xform.h" -#include "llpointer.h" -#include "llrefcount.h" - -#include - -template class LLTreeNode; -template class LLTreeTraveler; -template class LLTreeListener; - -template -class LLTreeListener: public LLRefCount -{ -public: - virtual void handleInsertion(const LLTreeNode* node, T* data) = 0; - virtual void handleRemoval(const LLTreeNode* node, T* data) = 0; - virtual void handleDestruction(const LLTreeNode* node) = 0; - virtual void handleStateChange(const LLTreeNode* node) = 0; -}; - -template -class LLTreeNode -{ -public: - virtual ~LLTreeNode(); - - virtual bool insert(T* data); - virtual bool remove(T* data); - virtual void notifyRemoval(T* data); - virtual U32 hasListeners() const { return !mListeners.empty(); } - virtual U32 getListenerCount() const { return mListeners.size(); } - virtual LLTreeListener* getListener(U32 index) const - { - if (index < mListeners.size()) - { - return mListeners[index]; - } - return NULL; - } - virtual void addListener(LLTreeListener* listener) { mListeners.push_back(listener); } - -protected: - void destroyListeners() - { - for (U32 i = 0; i < mListeners.size(); i++) - { - mListeners[i]->handleDestruction(this); - } - mListeners.clear(); - } - -public: - std::vector > > mListeners; -}; - -template -class LLTreeTraveler -{ -public: - virtual ~LLTreeTraveler() { }; - virtual void traverse(const LLTreeNode* node) = 0; - virtual void visit(const LLTreeNode* node) = 0; -}; - -template -LLTreeNode::~LLTreeNode() -{ - destroyListeners(); -}; - -template -bool LLTreeNode::insert(T* data) -{ - for (U32 i = 0; i < mListeners.size(); i++) - { - mListeners[i]->handleInsertion(this, data); - } - return true; -}; - -template -bool LLTreeNode::remove(T* data) -{ - return true; -}; - -template -void LLTreeNode::notifyRemoval(T* data) -{ - for (U32 i = 0; i < mListeners.size(); i++) - { - mListeners[i]->handleRemoval(this, data); - } -} - -#endif +/** + * @file lltreenode.h + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTREENODE_H +#define LL_LLTREENODE_H + +#include "stdtypes.h" +#include "xform.h" +#include "llpointer.h" +#include "llrefcount.h" + +#include + +template class LLTreeNode; +template class LLTreeTraveler; +template class LLTreeListener; + +template +class LLTreeListener: public LLRefCount +{ +public: + virtual void handleInsertion(const LLTreeNode* node, T* data) = 0; + virtual void handleRemoval(const LLTreeNode* node, T* data) = 0; + virtual void handleDestruction(const LLTreeNode* node) = 0; + virtual void handleStateChange(const LLTreeNode* node) = 0; +}; + +template +class LLTreeNode +{ +public: + virtual ~LLTreeNode(); + + virtual bool insert(T* data); + virtual bool remove(T* data); + virtual void notifyRemoval(T* data); + virtual U32 hasListeners() const { return !mListeners.empty(); } + virtual U32 getListenerCount() const { return mListeners.size(); } + virtual LLTreeListener* getListener(U32 index) const + { + if (index < mListeners.size()) + { + return mListeners[index]; + } + return NULL; + } + virtual void addListener(LLTreeListener* listener) { mListeners.push_back(listener); } + +protected: + void destroyListeners() + { + for (U32 i = 0; i < mListeners.size(); i++) + { + mListeners[i]->handleDestruction(this); + } + mListeners.clear(); + } + +public: + std::vector > > mListeners; +}; + +template +class LLTreeTraveler +{ +public: + virtual ~LLTreeTraveler() { }; + virtual void traverse(const LLTreeNode* node) = 0; + virtual void visit(const LLTreeNode* node) = 0; +}; + +template +LLTreeNode::~LLTreeNode() +{ + destroyListeners(); +}; + +template +bool LLTreeNode::insert(T* data) +{ + for (U32 i = 0; i < mListeners.size(); i++) + { + mListeners[i]->handleInsertion(this, data); + } + return true; +}; + +template +bool LLTreeNode::remove(T* data) +{ + return true; +}; + +template +void LLTreeNode::notifyRemoval(T* data) +{ + for (U32 i = 0; i < mListeners.size(); i++) + { + mListeners[i]->handleRemoval(this, data); + } +} + +#endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index f9f4aea77b..e6001626f3 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,7304 +1,7304 @@ -/** - * @file llvolume.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llmemory.h" -#include "llmath.h" - -#include -#if !LL_WINDOWS -#include -#endif -#include -#include - -#include "llerror.h" - -#include "llvolumemgr.h" -#include "v2math.h" -#include "v3math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llmatrix3a.h" -#include "lloctree.h" -#include "llvolume.h" -#include "llvolumeoctree.h" -#include "llstl.h" -#include "llsdserialize.h" -#include "llvector4a.h" -#include "llmatrix4a.h" -#include "llmeshoptimizer.h" -#include "lltimer.h" - -#include "mikktspace/mikktspace.h" -#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file - -#include "meshoptimizer/meshoptimizer.h" - -#define DEBUG_SILHOUETTE_BINORMALS 0 -#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette -#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette - -constexpr F32 MIN_CUT_DELTA = 0.02f; - -constexpr F32 HOLLOW_MIN = 0.f; -constexpr F32 HOLLOW_MAX = 0.95f; -constexpr F32 HOLLOW_MAX_SQUARE = 0.7f; - -constexpr F32 TWIST_MIN = -1.f; -constexpr F32 TWIST_MAX = 1.f; - -constexpr F32 RATIO_MIN = 0.f; -constexpr F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper - -constexpr F32 HOLE_X_MIN= 0.05f; -constexpr F32 HOLE_X_MAX= 1.0f; - -constexpr F32 HOLE_Y_MIN= 0.05f; -constexpr F32 HOLE_Y_MAX= 0.5f; - -constexpr F32 SHEAR_MIN = -0.5f; -constexpr F32 SHEAR_MAX = 0.5f; - -constexpr F32 REV_MIN = 1.f; -constexpr F32 REV_MAX = 4.f; - -constexpr F32 TAPER_MIN = -1.f; -constexpr F32 TAPER_MAX = 1.f; - -constexpr F32 SKEW_MIN = -0.95f; -constexpr F32 SKEW_MAX = 0.95f; - -constexpr F32 SCULPT_MIN_AREA = 0.002f; -constexpr S32 SCULPT_MIN_AREA_DETAIL = 1; - -bool gDebugGL = false; // See settings.xml "RenderDebugGL" - -bool check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) -{ - LLVector3 test = (pt2-pt1)%(pt3-pt2); - - //answer - if(test * norm < 0) - { - return false; - } - else - { - return true; - } -} - -bool LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) -{ - 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[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[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; -} - -// 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) - : ((rd > 0.0f) ? 1024.f : -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. -// 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 LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_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); - - /* if determinant is near zero, ray lies in plane of triangle */ - LLVector4a det; - det.setAllDot3(edge1, pvec); - - if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7) - { - /* calculate distance from vert0 to ray origin */ - LLVector4a tvec; - tvec.setSub(orig, vert0); - - /* calculate U parameter and test bounds */ - LLVector4a u; - u.setAllDot3(tvec,pvec); - - if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) && - (u.lessEqual(det).getGatheredBits() & 0x7)) - { - /* 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.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7; - S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 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; - } - } - } - - 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); - - /* if determinant is near zero, ray lies in plane of triangle */ - F32 det = edge1.dot3(pvec).getF32(); - - - 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); - - /* calculate U parameter and test bounds */ - u = (tvec.dot3(pvec).getF32()) * inv_det; - if (u < 0.f || u > 1.f) - { - return false; - } - - /* prepare to test V parameter */ - tvec.sub(edge1); - - /* calculate V parameter and test bounds */ - v = (dir.dot3(tvec).getF32()) * inv_det; - - if (v < 0.f || u + v > 1.f) - { - return false; - } - - /* calculate t, ray intersects triangle */ - t = (edge2.dot3(tvec).getF32()) * inv_det; - - intersection_a = u; - intersection_b = v; - intersection_t = t; - - - return true; -} - -class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst -{ -public: - const LLVolumeFace* mFace; - - LLVolumeOctreeRebound(const LLVolumeFace* face) - { - mFace = face; - } - - virtual void visit(const LLOctreeNode* branch) - { //this is a depth first traversal, so it's safe to assum all children have complete - //bounding data - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); - - LLVector4a& min = node->mExtents[0]; - LLVector4a& max = node->mExtents[1]; - - if (!branch->isEmpty()) - { //node has data, find AABB that binds data set - const LLVolumeTriangle* tri = *(branch->getDataBegin()); - - //initialize min/max to first available vertex - min = *(tri->mV[0]); - max = *(tri->mV[0]); - - for (LLOctreeNode::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter) - { //for each triangle in node - - //stretch by triangles in node - tri = *iter; - - min.setMin(min, *tri->mV[0]); - min.setMin(min, *tri->mV[1]); - min.setMin(min, *tri->mV[2]); - - max.setMax(max, *tri->mV[0]); - max.setMax(max, *tri->mV[1]); - max.setMax(max, *tri->mV[2]); - } - } - else if (branch->getChildCount() > 0) - { //no data, but child nodes exist - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); - - //initialize min/max to extents of first child - min = child->mExtents[0]; - max = child->mExtents[1]; - } - else - { - llassert(!branch->isLeaf()); // Empty leaf - } - - for (S32 i = 0; i < branch->getChildCount(); ++i) - { //stretch by child extents - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); - min.setMin(min, child->mExtents[0]); - max.setMax(max, child->mExtents[1]); - } - - node->mBounds[0].setAdd(min, max); - node->mBounds[0].mul(0.5f); - - node->mBounds[1].setSub(max,min); - node->mBounds[1].mul(0.5f); - } -}; - -//------------------------------------------------------------------- -// statics -//------------------------------------------------------------------- - - -//---------------------------------------------------- - -LLProfile::Face* LLProfile::addCap(S16 faceID) -{ - Face *face = vector_append(mFaces, 1); - - face->mIndex = 0; - face->mCount = mTotal; - face->mScaleU= 1.0f; - face->mCap = true; - face->mFaceID = faceID; - return face; -} - -LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, bool flat) -{ - Face *face = vector_append(mFaces, 1); - - face->mIndex = i; - face->mCount = count; - face->mScaleU= scaleU; - - face->mFlat = flat; - face->mCap = false; - face->mFaceID = faceID; - return face; -} - -//static -S32 LLProfile::getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) -{ // this is basically LLProfile::genNGon stripped down to only the operations that influence the number of points - S32 np = 0; - - // Generate an n-sided "circular" path. - // 0 is (1,0), and we go counter-clockwise along a circular path from there. - F32 t, t_step, t_first, t_fraction; - - F32 begin = params.getBegin(); - F32 end = params.getEnd(); - - t_step = 1.0f / sides; - - t_first = floor(begin * sides) / (F32)sides; - - // pt1 is the first point on the fractional face. - // Starting t and ang values for the first face - t = t_first; - - // Increment to the next point. - // pt2 is the end point on the fractional face - t += t_step; - - t_fraction = (begin - t_first)*sides; - - // Only use if it's not almost exactly on an edge. - if (t_fraction < 0.9999f) - { - np++; - } - - // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 - while (t < end) - { - // Iterate through all the integer steps of t. - np++; - - t += t_step; - } - - t_fraction = (end - (t - t_step))*sides; - - // Find the fraction that we need to add to the end point. - t_fraction = (end - (t - t_step))*sides; - if (t_fraction > 0.0001f) - { - np++; - } - - // If we're sliced, the profile is open. - if ((end - begin)*ang_scale < 0.99f) - { - if (params.getHollow() <= 0) - { - // put center point if not hollow. - np++; - } - } - - return np; -} - -// What is the bevel parameter used for? - DJS 04/05/02 -// Bevel parameter is currently unused but presumedly would support -// filleted and chamfered corners -void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) -{ - // Generate an n-sided "circular" path. - // 0 is (1,0), and we go counter-clockwise along a circular path from there. - constexpr F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - F32 scale = 0.5f; - F32 t, t_step, t_first, t_fraction, ang, ang_step; - LLVector4a pt1,pt2; - - F32 begin = params.getBegin(); - F32 end = params.getEnd(); - - t_step = 1.0f / sides; - ang_step = 2.0f*F_PI*t_step*ang_scale; - - // Scale to have size "match" scale. Compensates to get object to generally fill bounding box. - - S32 total_sides = ll_round(sides / ang_scale); // Total number of sides all around - - if (total_sides < 8) - { - scale = tableScale[total_sides]; - } - - t_first = floor(begin * sides) / (F32)sides; - - // pt1 is the first point on the fractional face. - // Starting t and ang values for the first face - t = t_first; - ang = 2.0f*F_PI*(t*ang_scale + offset); - pt1.set(cos(ang)*scale,sin(ang)*scale, t); - - // Increment to the next point. - // pt2 is the end point on the fractional face - t += t_step; - ang += ang_step; - pt2.set(cos(ang)*scale,sin(ang)*scale,t); - - t_fraction = (begin - t_first)*sides; - - // Only use if it's not almost exactly on an edge. - if (t_fraction < 0.9999f) - { - LLVector4a new_pt; - new_pt.setLerp(pt1, pt2, t_fraction); - mProfile.push_back(new_pt); - } - - // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 - while (t < end) - { - // Iterate through all the integer steps of t. - pt1.set(cos(ang)*scale,sin(ang)*scale,t); - - if (mProfile.size() > 0) { - LLVector4a p = mProfile[mProfile.size()-1]; - for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - //mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); - LLVector4a new_pt; - new_pt.setSub(pt1, p); - new_pt.mul(1.0f/(float)(split+1) * (float)(i+1)); - new_pt.add(p); - mProfile.push_back(new_pt); - } - } - mProfile.push_back(pt1); - - t += t_step; - ang += ang_step; - } - - t_fraction = (end - (t - t_step))*sides; - - // pt1 is the first point on the fractional face - // pt2 is the end point on the fractional face - pt2.set(cos(ang)*scale,sin(ang)*scale,t); - - // Find the fraction that we need to add to the end point. - t_fraction = (end - (t - t_step))*sides; - if (t_fraction > 0.0001f) - { - LLVector4a new_pt; - new_pt.setLerp(pt1, pt2, t_fraction); - - if (mProfile.size() > 0) { - LLVector4a p = mProfile[mProfile.size()-1]; - for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - //mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); - - LLVector4a pt1; - pt1.setSub(new_pt, p); - pt1.mul(1.0f/(float)(split+1) * (float)(i+1)); - pt1.add(p); - mProfile.push_back(pt1); - } - } - mProfile.push_back(new_pt); - } - - // If we're sliced, the profile is open. - if ((end - begin)*ang_scale < 0.99f) - { - if ((end - begin)*ang_scale > 0.5f) - { - mConcave = true; - } - else - { - mConcave = false; - } - mOpen = true; - if (params.getHollow() <= 0) - { - // put center point if not hollow. - mProfile.push_back(LLVector4a(0,0,0)); - } - } - else - { - // The profile isn't open. - mOpen = false; - mConcave = false; - } - - mTotal = mProfile.size(); -} - -// Hollow is percent of the original bounding box, not of this particular -// profile's geometry. Thus, a swept triangle needs lower hollow values than -// a swept square. -LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, bool flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) -{ - // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. - - // Total add has number of vertices on outside. - mTotalOut = mTotal; - - // Why is the "bevel" parameter -1? DJS 04/05/02 - genNGon(params, llfloor(sides),offset,-1, ang_scale, split); - - Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); - - static thread_local LLAlignedArray pt; - pt.resize(mTotal) ; - - for (S32 i=mTotalOut;i end - 0.01f) - { - LL_WARNS() << "LLProfile::generate() assertion failed (begin >= end)" << LL_ENDL; - return false; - } - - S32 face_num = 0; - - switch (params.getCurveType() & LL_PCODE_PROFILE_MASK) - { - case LL_PCODE_PROFILE_SQUARE: - { - genNGon(params, 4,-0.375, 0, 1, split); - if (path_open) - { - addCap (LL_FACE_PATH_BEGIN); - } - - for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++) - { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, true); - } - - LLVector4a scale(1,1,4,1); - - for (i = 0; i <(S32) mProfile.size(); i++) - { - // Scale by 4 to generate proper tex coords. - mProfile[i].mul(scale); - llassert(mProfile[i].isFinite3()); - } - - if (hollow) - { - switch (params.getCurveType() & LL_PCODE_HOLE_MASK) - { - case LL_PCODE_HOLE_TRIANGLE: - // This offset is not correct, but we can't change it now... DK 11/17/04 - addHole(params, true, 3, -0.375f, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - // TODO: Compute actual detail levels for cubes - addHole(params, false, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); - break; - case LL_PCODE_HOLE_SAME: - case LL_PCODE_HOLE_SQUARE: - default: - addHole(params, true, 4, -0.375f, hollow, 1.f, split); - break; - } - } - - if (path_open) { - mFaces[0].mCount = mTotal; - } - } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_RIGHTTRI: - case LL_PCODE_PROFILE_EQUALTRI: - { - genNGon(params, 3,0, 0, 1, split); - LLVector4a scale(1,1,3,1); - for (i = 0; i <(S32) mProfile.size(); i++) - { - // Scale by 3 to generate proper tex coords. - mProfile[i].mul(scale); - llassert(mProfile[i].isFinite3()); - } - - if (path_open) - { - addCap(LL_FACE_PATH_BEGIN); - } - - for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++) - { - addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, true); - } - if (hollow) - { - // Swept triangles need smaller hollowness values, - // because the triangle doesn't fill the bounding box. - F32 triangle_hollow = hollow / 2.f; - - switch (params.getCurveType() & LL_PCODE_HOLE_MASK) - { - case LL_PCODE_HOLE_CIRCLE: - // TODO: Actually generate level of detail for triangles - addHole(params, false, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); - break; - case LL_PCODE_HOLE_SQUARE: - addHole(params, true, 4, 0, triangle_hollow, 1.f, split); - break; - case LL_PCODE_HOLE_SAME: - case LL_PCODE_HOLE_TRIANGLE: - default: - addHole(params, true, 3, 0, triangle_hollow, 1.f, split); - break; - } - } - } - break; - case LL_PCODE_PROFILE_CIRCLE: - { - // If this has a square hollow, we should adjust the - // number of faces a bit so that the geometry lines up. - U8 hole_type=0; - F32 circle_detail = MIN_DETAIL_FACES * detail; - if (hollow) - { - hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; - if (hole_type == LL_PCODE_HOLE_SQUARE) - { - // Snap to the next multiple of four sides, - // so that corners line up. - circle_detail = llceil(circle_detail / 4.0f) * 4.0f; - } - } - - S32 sides = (S32)circle_detail; - - if (is_sculpted) - sides = sculpt_size; - - genNGon(params, sides); - - if (path_open) - { - addCap (LL_FACE_PATH_BEGIN); - } - - if (mOpen && !hollow) - { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, false); - } - else - { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, false); - } - - if (hollow) - { - switch (hole_type) - { - case LL_PCODE_HOLE_SQUARE: - addHole(params, true, 4, 0, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_TRIANGLE: - addHole(params, true, 3, 0, hollow, 1.f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - case LL_PCODE_HOLE_SAME: - default: - addHole(params, true, circle_detail, 0, hollow, 1.f); - break; - } - } - } - break; - case LL_PCODE_PROFILE_CIRCLE_HALF: - { - // If this has a square hollow, we should adjust the - // number of faces a bit so that the geometry lines up. - U8 hole_type=0; - // Number of faces is cut in half because it's only a half-circle. - F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f; - if (hollow) - { - hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; - if (hole_type == LL_PCODE_HOLE_SQUARE) - { - // Snap to the next multiple of four sides (div 2), - // so that corners line up. - circle_detail = llceil(circle_detail / 2.0f) * 2.0f; - } - } - genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f); - if (path_open) - { - addCap(LL_FACE_PATH_BEGIN); - } - if (mOpen && !params.getHollow()) - { - addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, false); - } - else - { - addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, false); - } - - if (hollow) - { - switch (hole_type) - { - case LL_PCODE_HOLE_SQUARE: - addHole(params, true, 2, 0.5f, hollow, 0.5f, split); - break; - case LL_PCODE_HOLE_TRIANGLE: - addHole(params, true, 3, 0.5f, hollow, 0.5f, split); - break; - case LL_PCODE_HOLE_CIRCLE: - case LL_PCODE_HOLE_SAME: - default: - addHole(params, false, circle_detail, 0.5f, hollow, 0.5f); - break; - } - } - - // Special case for openness of sphere - if ((params.getEnd() - params.getBegin()) < 1.f) - { - mOpen = true; - } - else if (!hollow) - { - mOpen = false; - mProfile.push_back(mProfile[0]); - mTotal++; - } - } - break; - default: - LL_ERRS() << "Unknown profile: getCurveType()=" << params.getCurveType() << LL_ENDL; - break; - }; - - if (path_open) - { - addCap(LL_FACE_PATH_END); // bottom - } - - if ( mOpen) // interior edge caps - { - addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, true); - - if (hollow) - { - addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, true); - } - else - { - addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, true); - } - } - - return true; -} - - - -bool LLProfileParams::importFile(LLFILE *fp) -{ - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - F32 tempF32; - U32 tempU32; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("hollow",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setHollow(tempF32); - } - else - { - LL_WARNS() << "unknown keyword " << keyword << " in profile import" << LL_ENDL; - } - } - - return true; -} - - -bool LLProfileParams::exportFile(LLFILE *fp) const -{ - fprintf(fp,"\t\tprofile 0\n"); - fprintf(fp,"\t\t{\n"); - fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType()); - fprintf(fp,"\t\t\tbegin\t%g\n", getBegin()); - fprintf(fp,"\t\t\tend\t%g\n", getEnd()); - fprintf(fp,"\t\t\thollow\t%g\n", getHollow()); - fprintf(fp, "\t\t}\n"); - return true; -} - - -bool LLProfileParams::importLegacyStream(std::istream& input_stream) -{ - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of these buffers will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - char valuestr[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - valuestr[0] = 0; - F32 tempF32; - U32 tempU32; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf( /* Flawfinder: ignore */ - buffer, - " %255s %255s", - keyword, - valuestr); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("curve", keyword)) - { - sscanf(valuestr,"%d",&tempU32); - setCurveType((U8) tempU32); - } - else if (!strcmp("begin",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setBegin(tempF32); - } - else if (!strcmp("end",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setEnd(tempF32); - } - else if (!strcmp("hollow",keyword)) - { - sscanf(valuestr,"%g",&tempF32); - setHollow(tempF32); - } - else - { - LL_WARNS() << "unknown keyword " << keyword << " in profile import" << LL_ENDL; - } - } - - return true; -} - - -bool LLProfileParams::exportLegacyStream(std::ostream& output_stream) const -{ - output_stream <<"\t\tprofile 0\n"; - output_stream <<"\t\t{\n"; - output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n"; - output_stream <<"\t\t\tbegin\t" << getBegin() << "\n"; - output_stream <<"\t\t\tend\t" << getEnd() << "\n"; - output_stream <<"\t\t\thollow\t" << getHollow() << "\n"; - output_stream << "\t\t}\n"; - return true; -} - -LLSD LLProfileParams::asLLSD() const -{ - LLSD sd; - - sd["curve"] = getCurveType(); - sd["begin"] = getBegin(); - sd["end"] = getEnd(); - sd["hollow"] = getHollow(); - return sd; -} - -bool LLProfileParams::fromLLSD(LLSD& sd) -{ - setCurveType(sd["curve"].asInteger()); - setBegin((F32)sd["begin"].asReal()); - setEnd((F32)sd["end"].asReal()); - setHollow((F32)sd["hollow"].asReal()); - return true; -} - -void LLProfileParams::copyParams(const LLProfileParams ¶ms) -{ - setCurveType(params.getCurveType()); - setBegin(params.getBegin()); - setEnd(params.getEnd()); - setHollow(params.getHollow()); -} - - -LLPath::~LLPath() -{ -} - -S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) -{ //this is basically LLPath::genNGon stripped down to only operations that influence the number of points added - S32 ret = 0; - - F32 step= 1.0f / sides; - F32 t = params.getBegin(); - ret = 1; - - t+=step; - - // Snap to a quantized parameter, so that cut does not - // affect most sample points. - t = ((S32)(t * sides)) / (F32)sides; - - // Run through the non-cut dependent points. - while (t < params.getEnd()) - { - ret++; - t+=step; - } - - ret++; - - return ret; -} - -void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. - constexpr F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; - - F32 revolutions = params.getRevolutions(); - F32 skew = params.getSkew(); - F32 skew_mag = fabs(skew); - F32 hole_x = params.getScaleX() * (1.0f - skew_mag); - F32 hole_y = params.getScaleY(); - - // Calculate taper begin/end for x,y (Negative means taper the beginning) - F32 taper_x_begin = 1.0f; - F32 taper_x_end = 1.0f - params.getTaperX(); - F32 taper_y_begin = 1.0f; - F32 taper_y_end = 1.0f - params.getTaperY(); - - if ( taper_x_end > 1.0f ) - { - // Flip tapering. - taper_x_begin = 2.0f - taper_x_end; - taper_x_end = 1.0f; - } - if ( taper_y_end > 1.0f ) - { - // Flip tapering. - taper_y_begin = 2.0f - taper_y_end; - taper_y_end = 1.0f; - } - - // For spheres, the radius is usually zero. - F32 radius_start = 0.5f; - if (sides < 8) - { - radius_start = tableScale[sides]; - } - - // Scale the radius to take the hole size into account. - radius_start *= 1.0f - hole_y; - - // Now check the radius offset to calculate the start,end radius. (Negative means - // decrease the start radius instead). - F32 radius_end = radius_start; - F32 radius_offset = params.getRadiusOffset(); - if (radius_offset < 0.f) - { - radius_start *= 1.f + radius_offset; - } - else - { - radius_end *= 1.f - radius_offset; - } - - // Is the path NOT a closed loop? - mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) || - (skew_mag > 0.001f) || - (fabs(taper_x_end - taper_x_begin) > 0.001f) || - (fabs(taper_y_end - taper_y_begin) > 0.001f) || - (fabs(radius_end - radius_start) > 0.001f) ); - - F32 ang, c, s; - LLQuaternion twist, qang; - PathPt *pt; - LLVector3 path_axis (1.f, 0.f, 0.f); - //LLVector3 twist_axis(0.f, 0.f, 1.f); - F32 twist_begin = params.getTwistBegin() * twist_scale; - F32 twist_end = params.getTwist() * twist_scale; - - // We run through this once before the main loop, to make sure - // the path begins at the correct cut. - F32 step= 1.0f / sides; - F32 t = params.getBegin(); - pt = mPath.append(1); - ang = 2.0f*F_PI*revolutions * t; - s = sin(ang)*lerp(radius_start, radius_end, t); - c = cos(ang)*lerp(radius_start, radius_end, t); - - - pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), - hole_y * lerp(taper_y_begin, taper_y_end, t), - 0,1); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - - LLMatrix3 rot(twist * qang); - - pt->mRot.loadu(rot); - - t+=step; - - // Snap to a quantized parameter, so that cut does not - // affect most sample points. - t = ((S32)(t * sides)) / (F32)sides; - - // Run through the non-cut dependent points. - while (t < params.getEnd()) - { - pt = mPath.append(1); - - ang = 2.0f*F_PI*revolutions * t; - c = cos(ang)*lerp(radius_start, radius_end, t); - s = sin(ang)*lerp(radius_start, radius_end, t); - - pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - - pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), - hole_y * lerp(taper_y_begin, taper_y_end, t), - 0,1); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - LLMatrix3 tmp(twist*qang); - pt->mRot.loadu(tmp); - - t+=step; - } - - // Make one final pass for the end cut. - t = params.getEnd(); - pt = mPath.append(1); - ang = 2.0f*F_PI*revolutions * t; - c = cos(ang)*lerp(radius_start, radius_end, t); - s = sin(ang)*lerp(radius_start, radius_end, t); - - pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) - + lerp(-skew ,skew, t) * 0.5f, - c + lerp(0,params.getShear().mV[1],s), - s); - pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), - hole_y * lerp(taper_y_begin, taper_y_end, t), - 0,1); - pt->mTexT = t; - - // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 - twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); - // Rotate the point around the circle's center. - qang.setQuat (ang,path_axis); - LLMatrix3 tmp(twist*qang); - pt->mRot.loadu(tmp); - - mTotal = mPath.size(); -} - -const LLVector2 LLPathParams::getBeginScale() const -{ - LLVector2 begin_scale(1.f, 1.f); - if (getScaleX() > 1) - { - begin_scale.mV[0] = 2-getScaleX(); - } - if (getScaleY() > 1) - { - begin_scale.mV[1] = 2-getScaleY(); - } - return begin_scale; -} - -const LLVector2 LLPathParams::getEndScale() const -{ - LLVector2 end_scale(1.f, 1.f); - if (getScaleX() < 1) - { - end_scale.mV[0] = getScaleX(); - } - if (getScaleY() < 1) - { - end_scale.mV[1] = getScaleY(); - } - return end_scale; -} - -S32 LLPath::getNumPoints(const LLPathParams& params, F32 detail) -{ // this is basically LLPath::generate stripped down to only the operations that influence the number of points - if (detail < MIN_LOD) - { - detail = MIN_LOD; - } - - S32 np = 2; // hardcode for line - - // Is this 0xf0 mask really necessary? DK 03/02/05 - - switch (params.getCurveType() & 0xf0) - { - default: - case LL_PCODE_PATH_LINE: - { - // Take the begin/end twist into account for detail. - np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; - } - break; - - case LL_PCODE_PATH_CIRCLE: - { - // Increase the detail as the revolutions and twist increase. - F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist()); - - S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions()); - - np = sides; - } - break; - - case LL_PCODE_PATH_CIRCLE2: - { - //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); - np = getNumNGonPoints(params, llfloor(MIN_DETAIL_FACES * detail)); - } - break; - - case LL_PCODE_PATH_TEST: - - np = 5; - break; - }; - - return np; -} - -bool LLPath::generate(const LLPathParams& params, F32 detail, S32 split, - bool is_sculpted, S32 sculpt_size) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - if ((!mDirty) && (!is_sculpted)) - { - return false; - } - - if (detail < MIN_LOD) - { - LL_INFOS() << "Generating path with LOD < MIN! Clamping to 1" << LL_ENDL; - detail = MIN_LOD; - } - - mDirty = false; - S32 np = 2; // hardcode for line - - mPath.resize(0); - mOpen = true; - - // Is this 0xf0 mask really necessary? DK 03/02/05 - switch (params.getCurveType() & 0xf0) - { - default: - case LL_PCODE_PATH_LINE: - { - // Take the begin/end twist into account for detail. - np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; - if (np < split+2) - { - np = split+2; - } - - mStep = 1.0f / (np-1); - - mPath.resize(np); - - LLVector2 start_scale = params.getBeginScale(); - LLVector2 end_scale = params.getEndScale(); - - for (S32 i=0;i= 0.99f && - params.getScaleX() >= .99f) - { - mOpen = false; - } - - //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); - genNGon(params, llfloor(MIN_DETAIL_FACES * detail)); - - F32 toggle = 0.5f; - for (S32 i=0;i<(S32)mPath.size();i++) - { - mPath[i].mPos.getF32ptr()[0] = toggle; - if (toggle == 0.5f) - toggle = -0.5f; - else - toggle = 0.5f; - } - } - - break; - - case LL_PCODE_PATH_TEST: - - np = 5; - mStep = 1.0f / (np-1); - - mPath.resize(np); - - for (S32 i=0;iresizePath(length); - mVolumeFaces.clear(); - setDirty(); -} - -void LLVolume::regen() -{ - generate(); - createVolumeFaces(); -} - -void LLVolume::genTangents(S32 face) -{ - // generate legacy tangents for the specified face - llassert(!isMeshAssetLoaded() || mVolumeFaces[face].mTangents != nullptr); // if this is a complete mesh asset, we should already have tangents - mVolumeFaces[face].createTangents(); -} - -LLVolume::~LLVolume() -{ - sNumMeshPoints -= mMesh.size(); - delete mPathp; - - delete mProfilep; - - mPathp = NULL; - mProfilep = NULL; - mVolumeFaces.clear(); - - ll_aligned_free_16(mHullPoints); - mHullPoints = NULL; - ll_aligned_free_16(mHullIndices); - mHullIndices = NULL; -} - -bool LLVolume::generate() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - LL_CHECK_MEMORY - llassert_always(mProfilep); - - //Added 10.03.05 Dave Parks - // Split is a parameter to LLProfile::generate that tesselates edges on the profile - // to prevent lighting and texture interpolation errors on triangles that are - // stretched due to twisting or scaling on the path. - S32 split = (S32) ((mDetail)*0.66f); - - if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && - (mParams.getPathParams().getScale().mV[0] != 1.0f || - mParams.getPathParams().getScale().mV[1] != 1.0f) && - (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI || - mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) - { - split = 0; - } - - mLODScaleBias.setVec(0.5f, 0.5f, 0.5f); - - F32 profile_detail = mDetail; - F32 path_detail = mDetail; - - if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) - { - U8 path_type = mParams.getPathParams().getCurveType(); - U8 profile_type = mParams.getProfileParams().getCurveType(); - if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) - { - //cylinders don't care about Z-Axis - mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); - } - else if (path_type == LL_PCODE_PATH_CIRCLE) - { - mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); - } - } - - bool regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); - bool regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); - - if (regenPath || regenProf ) - { - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeT * sizeS); - sNumMeshPoints += mMesh.size(); - - //generate vertex positions - - // Run along the path. - LLVector4a* dst = mMesh.mArray; - - for (S32 s = 0; s < sizeS; ++s) - { - F32* scale = mPathp->mPath[s].mScale.getF32ptr(); - - F32 sc [] = - { scale[0], 0, 0, 0, - 0, scale[1], 0, 0, - 0, 0, scale[2], 0, - 0, 0, 0, 1 }; - - LLMatrix4 rot((F32*) mPathp->mPath[s].mRot.mMatrix); - LLMatrix4 scale_mat(sc); - - scale_mat *= rot; - - LLMatrix4a rot_mat; - rot_mat.loadu(scale_mat); - - LLVector4a* profile = mProfilep->mProfile.mArray; - LLVector4a* end_profile = profile+sizeT; - LLVector4a offset = mPathp->mPath[s].mPos; - - // hack to work around MAINT-5660 for debug until we can suss out - // what is wrong with the path generated that inserts NaNs... - if (!offset.isFinite3()) - { - offset.clear(); - } - - LLVector4a tmp; - - // Run along the profile. - while (profile < end_profile) - { - rot_mat.rotate(*profile++, tmp); - dst->setAdd(tmp,offset); - ++dst; - } - } - - for (std::vector::iterator iter = mProfilep->mFaces.begin(); - iter != mProfilep->mFaces.end(); ++iter) - { - LLFaceID id = iter->mFaceID; - mFaceMask |= id; - } - LL_CHECK_MEMORY - return true; - } - - LL_CHECK_MEMORY - return false; -} - -void LLVolumeFace::VertexData::init() -{ - if (!mData) - { - mData = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2); - } -} - -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, 2*sizeof(LLVector4a)); - mTexCoord = rhs.mTexCoord; - } - return *this; -} - -LLVolumeFace::VertexData::~VertexData() -{ - ll_aligned_free_16(mData); - mData = NULL; -} - -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 -{ - const F32* lp = this->getPosition().getF32ptr(); - const F32* rp = rhs.getPosition().getF32ptr(); - - if (lp[0] != rp[0]) - { - return lp[0] < rp[0]; - } - - if (rp[1] != lp[1]) - { - return lp[1] < rp[1]; - } - - if (rp[2] != lp[2]) - { - return lp[2] < rp[2]; - } - - lp = getNormal().getF32ptr(); - rp = rhs.getNormal().getF32ptr(); - - if (lp[0] != rp[0]) - { - return lp[0] < rp[0]; - } - - if (rp[1] != lp[1]) - { - return lp[1] < rp[1]; - } - - if (rp[2] != lp[2]) - { - return lp[2] < rp[2]; - } - - if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) - { - return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; - } - - return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; -} - -bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const -{ - return mData[POSITION].equals3(rhs.getPosition()) && - mData[NORMAL].equals3(rhs.getNormal()) && - mTexCoord == rhs.mTexCoord; -} - -bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const -{ - bool retval = false; - - const F32 epsilon = 0.00001f; - - if (rhs.mData[POSITION].equals3(mData[POSITION], epsilon) && - fabs(rhs.mTexCoord[0]-mTexCoord[0]) < epsilon && - fabs(rhs.mTexCoord[1]-mTexCoord[1]) < epsilon) - { - if (angle_cutoff > 1.f) - { - retval = (mData[NORMAL].equals3(rhs.mData[NORMAL], epsilon)); - } - else - { - F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); - retval = cur_angle > angle_cutoff; - } - } - - return retval; -} - -bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - //input stream is now pointing at a zlib compressed block of LLSD - //decompress block - LLSD mdl; - U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size); - if (uzip_result != LLUZipHelper::ZR_OK) - { - LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL; - return false; - } - return unpackVolumeFacesInternal(mdl); -} - -bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size) -{ - //input data is now pointing at a zlib compressed block of LLSD - //decompress block - LLSD mdl; - U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size); - if (uzip_result != LLUZipHelper::ZR_OK) - { - LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL; - return false; - } - return unpackVolumeFacesInternal(mdl); -} - -bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) -{ - { - U32 face_count = mdl.size(); - - if (face_count == 0) - { //no faces unpacked, treat as failed decode - LL_WARNS() << "found no faces!" << LL_ENDL; - return false; - } - - mVolumeFaces.resize(face_count); - - for (size_t i = 0; i < face_count; ++i) - { - LLVolumeFace& face = mVolumeFaces[i]; - - if (mdl[i].has("NoGeometry")) - { //face has no geometry, continue - face.resizeIndices(3); - face.resizeVertices(1); - face.mPositions->clear(); - face.mNormals->clear(); - face.mTexCoords->setZero(); - memset(face.mIndices, 0, sizeof(U16)*3); - continue; - } - - LLSD::Binary pos = mdl[i]["Position"]; - LLSD::Binary norm = mdl[i]["Normal"]; - LLSD::Binary tangent = mdl[i]["Tangent"]; - LLSD::Binary tc = mdl[i]["TexCoord0"]; - LLSD::Binary idx = mdl[i]["TriangleList"]; - - //copy out indices - S32 num_indices = idx.size() / 2; - const S32 indices_to_discard = num_indices % 3; - if (indices_to_discard > 0) - { - // Invalid number of triangle indices - LL_WARNS() << "Incomplete triangle discarded from face! Indices count " << num_indices << " was not divisible by 3. face index: " << i << " Total: " << face_count << LL_ENDL; - num_indices -= indices_to_discard; - } - face.resizeIndices(num_indices); - - if (num_indices > 2 && !face.mIndices) - { - LL_WARNS() << "Failed to allocate " << num_indices << " indices for face index: " << i << " Total: " << face_count << LL_ENDL; - continue; - } - - if (idx.empty() || face.mNumIndices < 3) - { //why is there an empty index list? - LL_WARNS() << "Empty face present! Face index: " << i << " Total: " << face_count << LL_ENDL; - continue; - } - - U16* indices = (U16*) &(idx[0]); - for (U32 j = 0; j < num_indices; ++j) - { - face.mIndices[j] = indices[j]; - } - - //copy out vertices - U32 num_verts = pos.size()/(3*2); - face.resizeVertices(num_verts); - - if (num_verts > 0 && !face.mPositions) - { - LL_WARNS() << "Failed to allocate " << num_verts << " vertices for face index: " << i << " Total: " << face_count << LL_ENDL; - face.resizeIndices(0); - continue; - } - - 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"]); - - //unpack normalized scale/translation - if (mdl[i].has("NormalizedScale")) - { - face.mNormalizedScale.setValue(mdl[i]["NormalizedScale"]); - } - else - { - face.mNormalizedScale.set(1, 1, 1); - } - - LLVector4a pos_range; - pos_range.setSub(max_pos, min_pos); - LLVector2 tc_range2 = max_tc - min_tc; - - LLVector4a tc_range; - tc_range.set(tc_range2[0], tc_range2[1], tc_range2[0], tc_range2[1]); - LLVector4a min_tc4(min_tc[0], min_tc[1], min_tc[0], min_tc[1]); - - LLVector4a* pos_out = face.mPositions; - LLVector4a* norm_out = face.mNormals; - LLVector4a* tc_out = (LLVector4a*) face.mTexCoords; - - { - U16* v = (U16*) &(pos[0]); - for (U32 j = 0; j < num_verts; ++j) - { - 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); - pos_out++; - v += 3; - } - - } - - { - if (!norm.empty()) - { - U16* n = (U16*) &(norm[0]); - for (U32 j = 0; j < num_verts; ++j) - { - 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++; - n += 3; - } - } - else - { - for (U32 j = 0; j < num_verts; ++j) - { - norm_out->clear(); - norm_out++; // or just norm_out[j].clear(); - } - } - } - -#if 0 // keep this code for now in case we decide to add support for on-the-wire tangents - { - if (!tangent.empty()) - { - face.allocateTangents(face.mNumVertices); - U16* t = (U16*)&(tangent[0]); - - // NOTE: tangents coming from the asset may not be mikkt space, but they should always be used by the GLTF shaders to - // maintain compliance with the GLTF spec - LLVector4a* t_out = face.mTangents; - - for (U32 j = 0; j < num_verts; ++j) - { - t_out->set((F32)t[0], (F32)t[1], (F32)t[2], (F32) t[3]); - t_out->div(65535.f); - t_out->mul(2.f); - t_out->sub(1.f); - - F32* tp = t_out->getF32ptr(); - tp[3] = tp[3] < 0.f ? -1.f : 1.f; - - t_out++; - t += 4; - } - } - } -#endif - - { - if (!tc.empty()) - { - U16* t = (U16*) &(tc[0]); - for (U32 j = 0; j < num_verts; j+=2) - { - if (j < num_verts-1) - { - tc_out->set((F32) t[0], (F32) t[1], (F32) t[2], (F32) t[3]); - } - else - { - tc_out->set((F32) t[0], (F32) t[1], 0.f, 0.f); - } - - t += 4; - - tc_out->div(65535.f); - tc_out->mul(tc_range); - tc_out->add(min_tc4); - - tc_out++; - } - } - else - { - for (U32 j = 0; j < num_verts; j += 2) - { - tc_out->clear(); - tc_out++; - } - } - } - - if (mdl[i].has("Weights")) - { - face.allocateWeights(num_verts); - if (!face.mWeights && num_verts) - { - LL_WARNS() << "Failed to allocate " << num_verts << " weights for face index: " << i << " Total: " << face_count << LL_ENDL; - face.resizeIndices(0); - face.resizeVertices(0); - continue; - } - - 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); - U32 joints[4] = {0,0,0,0}; - LLVector4 joints_with_weights(0,0,0,0); - - while (joint != END_INFLUENCES && idx < weights.size()) - { - U16 influence = weights[idx++]; - influence |= ((U16) weights[idx++] << 8); - - F32 w = llclamp((F32) influence / 65535.f, 0.001f, 0.999f); - wght.mV[cur_influence] = w; - joints[cur_influence] = joint; - cur_influence++; - - if (cur_influence >= 4) - { - joint = END_INFLUENCES; - } - else - { - joint = weights[idx++]; - } - } - F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW]; - if (wsum <= 0.f) - { - wght = LLVector4(0.999f,0.f,0.f,0.f); - } - for (U32 k=0; k<4; k++) - { - F32 f_combined = (F32) joints[k] + wght[k]; - joints_with_weights[k] = f_combined; - // Any weights we added above should wind up non-zero and applied to a specific bone. - // A failure here would indicate a floating point precision error in the math. - llassert((k >= cur_influence) || (f_combined - S32(f_combined) > 0.0f)); - } - face.mWeights[cur_vertex].loadua(joints_with_weights.mV); - - cur_vertex++; - } - - if (cur_vertex != num_verts || idx != weights.size()) - { - LL_WARNS() << "Vertex weight count does not match vertex count!" << LL_ENDL; - } - - } - - // 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; - } - } - - //calculate bounding box - // VFExtents change - LLVector4a& min = face.mExtents[0]; - LLVector4a& max = face.mExtents[1]; - - if (face.mNumVertices < 3) - { //empty face, use a dummy 1cm (at 1m scale) bounding box - min.splat(-0.005f); - max.splat(0.005f); - } - else - { - min = max = face.mPositions[0]; - - for (S32 i = 1; i < face.mNumVertices; ++i) - { - min.setMin(min, face.mPositions[i]); - max.setMax(max, face.mPositions[i]); - } - - if (face.mTexCoords) - { - LLVector2& min_tc = face.mTexCoordExtents[0]; - LLVector2& max_tc = face.mTexCoordExtents[1]; - - min_tc = face.mTexCoords[0]; - max_tc = face.mTexCoords[0]; - - for (U32 j = 1; j < face.mNumVertices; ++j) - { - update_min_max(min_tc, max_tc, face.mTexCoords[j]); - } - } - else - { - face.mTexCoordExtents[0].set(0,0); - face.mTexCoordExtents[1].set(1,1); - } - } - } - } - - if (!cacheOptimize(true)) - { - // Out of memory? - LL_WARNS() << "Failed to optimize!" << LL_ENDL; - mVolumeFaces.clear(); - return false; - } - - mSculptLevel = 0; // success! - - return true; -} - - -bool LLVolume::isMeshAssetLoaded() -{ - return mIsMeshAssetLoaded; -} - -void LLVolume::setMeshAssetLoaded(bool loaded) -{ - mIsMeshAssetLoaded = loaded; - if (loaded) - { - mIsMeshAssetUnavaliable = false; - } -} - -void LLVolume::setMeshAssetUnavaliable(bool unavaliable) -{ - // Don't set it if at least one lod loaded - if (!mIsMeshAssetLoaded) - { - mIsMeshAssetUnavaliable = unavaliable; - } -} - -bool LLVolume::isMeshAssetUnavaliable() -{ - return mIsMeshAssetUnavaliable; -} - -void LLVolume::copyFacesTo(std::vector &faces) const -{ - faces = mVolumeFaces; -} - -void LLVolume::copyFacesFrom(const std::vector &faces) -{ - mVolumeFaces = faces; - mSculptLevel = 0; -} - -void LLVolume::copyVolumeFaces(const LLVolume* volume) -{ - mVolumeFaces = volume->mVolumeFaces; - mSculptLevel = 0; -} - -bool LLVolume::cacheOptimize(bool gen_tangents) -{ - for (S32 i = 0; i < mVolumeFaces.size(); ++i) - { - if (!mVolumeFaces[i].cacheOptimize(gen_tangents)) - { - return false; - } - } - return true; -} - - -S32 LLVolume::getNumFaces() const -{ - return mIsMeshAssetLoaded ? getNumVolumeFaces() : (S32)mProfilep->mFaces.size(); -} - - -void LLVolume::createVolumeFaces() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - if (mGenerateSingleFace) - { - // do nothing - } - else - { - S32 num_faces = getNumFaces(); - bool partial_build = true; - if (num_faces != mVolumeFaces.size()) - { - partial_build = false; - mVolumeFaces.resize(num_faces); - } - // Initialize volume faces with parameter data - for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) - { - LLVolumeFace& vf = mVolumeFaces[i]; - LLProfile::Face& face = mProfilep->mFaces[i]; - vf.mBeginS = face.mIndex; - vf.mNumS = face.mCount; - if (vf.mNumS < 0) - { - LL_ERRS() << "Volume face corruption detected." << LL_ENDL; - } - - vf.mBeginT = 0; - vf.mNumT= getPath().mPath.size(); - vf.mID = i; - - // Set the type mask bits correctly - if (mParams.getProfileParams().getHollow() > 0) - { - vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; - } - if (mProfilep->isOpen()) - { - vf.mTypeMask |= LLVolumeFace::OPEN_MASK; - } - if (face.mCap) - { - vf.mTypeMask |= LLVolumeFace::CAP_MASK; - if (face.mFaceID == LL_FACE_PATH_BEGIN) - { - vf.mTypeMask |= LLVolumeFace::TOP_MASK; - } - else - { - llassert(face.mFaceID == LL_FACE_PATH_END); - vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; - } - } - else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; - } - else - { - vf.mTypeMask |= LLVolumeFace::SIDE_MASK; - if (face.mFlat) - { - vf.mTypeMask |= LLVolumeFace::FLAT_MASK; - } - if (face.mFaceID & LL_FACE_INNER_SIDE) - { - vf.mTypeMask |= LLVolumeFace::INNER_MASK; - if (face.mFlat && vf.mNumS > 2) - { //flat inner faces have to copy vert normals - vf.mNumS = vf.mNumS*2; - if (vf.mNumS < 0) - { - LL_ERRS() << "Volume face corruption detected." << LL_ENDL; - } - } - } - else - { - vf.mTypeMask |= LLVolumeFace::OUTER_MASK; - } - } - } - - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - (*iter).create(this, partial_build); - } - } -} - - -inline LLVector4a sculpt_rgb_to_vector(U8 r, U8 g, U8 b) -{ - // maps RGB values to vector values [0..255] -> [-0.5..0.5] - LLVector4a value; - LLVector4a sub(0.5f, 0.5f, 0.5f); - - value.set(r,g,b); - value.mul(1.f/255.f); - value.sub(sub); - - return value; -} - -inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) -{ - U32 index = (x + y * sculpt_width) * sculpt_components; - return index; -} - - -inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) -{ - U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width); - U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height); - - return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); -} - - -inline LLVector4a sculpt_index_to_vector(U32 index, const U8* sculpt_data) -{ - LLVector4a v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); - - return v; -} - -inline LLVector4a sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) -{ - U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); -} - -inline LLVector4a sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) -{ - U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); - - return sculpt_index_to_vector(index, sculpt_data); -} - - -F32 LLVolume::sculptGetSurfaceArea() -{ - // test to see if image has enough variation to create non-degenerate geometry - - F32 area = 0; - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - for (S32 s = 0; s < sizeS-1; s++) - { - for (S32 t = 0; t < sizeT-1; t++) - { - // get four corners of quad - LLVector4a& p1 = mMesh[(s )*sizeT + (t )]; - LLVector4a& p2 = mMesh[(s+1)*sizeT + (t )]; - LLVector4a& p3 = mMesh[(s )*sizeT + (t+1)]; - LLVector4a& p4 = mMesh[(s+1)*sizeT + (t+1)]; - - // compute the area of the quad by taking the length of the cross product of the two triangles - LLVector4a v0,v1,v2,v3; - v0.setSub(p1,p2); - v1.setSub(p1,p3); - v2.setSub(p4,p2); - v3.setSub(p4,p3); - - LLVector4a cross1, cross2; - cross1.setCross3(v0,v1); - cross2.setCross3(v2,v3); - - //LLVector3 cross1 = (p1 - p2) % (p1 - p3); - //LLVector3 cross2 = (p4 - p2) % (p4 - p3); - - area += (cross1.getLength3() + cross2.getLength3()).getF32() / 2.f; - } - } - - return area; -} - -// create empty placeholder shape -void LLVolume::sculptGenerateEmptyPlaceholder() -{ - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - - for (S32 s = 0; s < sizeS; s++) - { - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - LLVector4a& pt = mMesh[i]; - - F32* p = pt.getF32ptr(); - - p[0] = 0; - p[1] = 0; - p[2] = 0; - - llassert(pt.isFinite3()); - } - line += sizeT; - } -} - -// create sphere placeholder shape -void LLVolume::sculptGenerateSpherePlaceholder() -{ - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - - for (S32 s = 0; s < sizeS; s++) - { - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - LLVector4a& pt = mMesh[i]; - - - F32 u = (F32)s / (sizeS - 1); - F32 v = (F32)t / (sizeT - 1); - - const F32 RADIUS = (F32) 0.3; - - F32* p = pt.getF32ptr(); - - p[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); - p[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); - p[2] = (F32)(cos(F_PI * v) * RADIUS); - - llassert(pt.isFinite3()); - } - line += sizeT; - } -} - -// create the vertices from the map -void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) -{ - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - bool sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - bool sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - bool reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - S32 sizeS = mPathp->mPath.size(); - S32 sizeT = mProfilep->mProfile.size(); - - S32 line = 0; - for (S32 s = 0; s < sizeS; s++) - { - // Run along the profile. - for (S32 t = 0; t < sizeT; t++) - { - S32 i = t + line; - LLVector4a& pt = mMesh[i]; - - S32 reversed_t = t; - - if (reverse_horizontal) - { - reversed_t = sizeT - t - 1; - } - - U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); - U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); - - - if (y == 0) // top row stitching - { - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } - } - - if (y == sculpt_height) // bottom row stitching - { - // wrap? - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - { - y = 0; - } - else - { - y = sculpt_height - 1; - } - - // pinch? - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - { - x = sculpt_width / 2; - } - } - - if (x == sculpt_width) // side stitching - { - // wrap? - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - { - x = 0; - } - - else - { - x = sculpt_width - 1; - } - } - - pt = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); - - if (sculpt_mirror) - { - LLVector4a scale(-1.f,1,1,1); - pt.mul(scale); - } - - llassert(pt.isFinite3()); - } - - line += sizeT; - } -} - - -constexpr S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square -constexpr S32 SCULPT_REZ_2 = 8; -constexpr S32 SCULPT_REZ_3 = 16; -constexpr S32 SCULPT_REZ_4 = 32; - -S32 sculpt_sides(F32 detail) -{ - // detail is usually one of: 1, 1.5, 2.5, 4.0. - - if (detail <= 1.0) - { - return SCULPT_REZ_1; - } - if (detail <= 2.0) - { - return SCULPT_REZ_2; - } - if (detail <= 3.0) - { - return SCULPT_REZ_3; - } - else - { - return SCULPT_REZ_4; - } -} - - - -// determine the number of vertices in both s and t direction for this sculpt -void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) -{ - // this code has the following properties: - // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map - // while still using all available verts - // 2) the mesh cannot have more verts than is allowed by LOD - // 3) the mesh cannot have more verts than is allowed by the map - - S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); - S32 max_vertices_map = width * height / 4; - - S32 vertices; - if (max_vertices_map > 0) - vertices = llmin(max_vertices_lod, max_vertices_map); - else - vertices = max_vertices_lod; - - - F32 ratio; - if ((width == 0) || (height == 0)) - ratio = 1.f; - else - ratio = (F32) width / (F32) height; - - - s = (S32)(F32) sqrt(((F32)vertices / ratio)); - - s = llmax(s, 4); // no degenerate sizes, please - t = vertices / s; - - t = llmax(t, 4); // no degenerate sizes, please - s = vertices / t; -} - -// sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder) -{ - U8 sculpt_type = mParams.getSculptType(); - - bool data_is_empty = false; - - if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) - { - sculpt_level = -1; - data_is_empty = true; - } - - S32 requested_sizeS = 0; - S32 requested_sizeT = 0; - - sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); - - mPathp->generate(mParams.getPathParams(), mDetail, 0, true, requested_sizeS); - mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, true, requested_sizeT); - - S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got - S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got - - // weird crash bug - DEV-11158 - trying to collect more data: - if ((sizeS == 0) || (sizeT == 0)) - { - LL_WARNS() << "sculpt bad mesh size " << sizeS << " " << sizeT << LL_ENDL; - } - - sNumMeshPoints -= mMesh.size(); - mMesh.resize(sizeS * sizeT); - sNumMeshPoints += mMesh.size(); - - //generate vertex positions - if (!data_is_empty) - { - sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); - - // don't test lowest LOD to support legacy content DEV-33670 - if (mDetail > SCULPT_MIN_AREA_DETAIL) - { - F32 area = sculptGetSurfaceArea(); - - mSurfaceArea = area; - - const F32 SCULPT_MAX_AREA = 384.f; - - if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA) - { - data_is_empty = true; - visible_placeholder = true; - } - } - } - - if (data_is_empty) - { - if (visible_placeholder) - { - // Object should be visible since there will be nothing else to display - sculptGenerateSpherePlaceholder(); - } - else - { - sculptGenerateEmptyPlaceholder(); - } - } - - for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) - { - mFaceMask |= mProfilep->mFaces[i].mFaceID; - } - - mSculptLevel = sculpt_level; - - // Delete any existing faces so that they get regenerated - mVolumeFaces.clear(); - - createVolumeFaces(); -} - - - - -bool LLVolume::isCap(S32 face) -{ - return mProfilep->mFaces[face].mCap; -} - -bool LLVolume::isFlat(S32 face) -{ - return mProfilep->mFaces[face].mFlat; -} - - -bool LLVolumeParams::isSculpt() const -{ - return (mSculptType & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_NONE; -} - -bool LLVolumeParams::isMeshSculpt() const -{ - return (mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH; -} - -bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const -{ - return ( (getPathParams() == params.getPathParams()) && - (getProfileParams() == params.getProfileParams()) && - (mSculptID == params.mSculptID) && - (mSculptType == params.mSculptType) ); -} - -bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const -{ - return ( (getPathParams() != params.getPathParams()) || - (getProfileParams() != params.getProfileParams()) || - (mSculptID != params.mSculptID) || - (mSculptType != params.mSculptType) ); -} - -bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const -{ - if( getPathParams() != params.getPathParams() ) - { - return getPathParams() < params.getPathParams(); - } - - if (getProfileParams() != params.getProfileParams()) - { - return getProfileParams() < params.getProfileParams(); - } - - if (mSculptID != params.mSculptID) - { - return mSculptID < params.mSculptID; - } - - return mSculptType < params.mSculptType; - - -} - -void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) -{ - mProfileParams.copyParams(params.mProfileParams); - mPathParams.copyParams(params.mPathParams); - mSculptID = params.getSculptID(); - mSculptType = params.getSculptType(); -} - -// Less restricitve approx 0 for volumes -constexpr F32 APPROXIMATELY_ZERO = 0.001f; -bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) -{ - return (f >= -tolerance) && (f <= tolerance); -} - -// return true if in range (or nearly so) -static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) -{ - F32 min_delta = v - min; - if (min_delta < 0.f) - { - v = min; - if (!approx_zero(min_delta, tolerance)) - return false; - } - F32 max_delta = max - v; - if (max_delta < 0.f) - { - v = max; - if (!approx_zero(max_delta, tolerance)) - return false; - } - return true; -} - -bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); - - // Now set them. - mProfileParams.setBegin(begin); - mProfileParams.setEnd(end); - - return valid; -} - -bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) -{ - bool valid = true; - - // First, clamp to valid ranges. - F32 begin = b; - valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); - - F32 end = e; - valid &= limit_range(end, MIN_CUT_DELTA, 1.f); - - valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); - - // Now set them. - mPathParams.setBegin(begin); - mPathParams.setEnd(end); - - return valid; -} - -bool LLVolumeParams::setHollow(const F32 h) -{ - // Validate the hollow based on path and profile. - U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; - - F32 max_hollow = HOLLOW_MAX; - - // Only square holes have trouble. - if (LL_PCODE_HOLE_SQUARE == hole_type) - { - switch(profile) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - case LL_PCODE_PROFILE_EQUALTRI: - max_hollow = HOLLOW_MAX_SQUARE; - } - } - - F32 hollow = h; - bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); - mProfileParams.setHollow(hollow); - - return valid; -} - -bool LLVolumeParams::setTwistBegin(const F32 b) -{ - F32 twist_begin = b; - bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistBegin(twist_begin); - return valid; -} - -bool LLVolumeParams::setTwistEnd(const F32 e) -{ - F32 twist_end = e; - bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); - mPathParams.setTwistEnd(twist_end); - return valid; -} - -bool LLVolumeParams::setRatio(const F32 x, const F32 y) -{ - F32 min_x = RATIO_MIN; - F32 max_x = RATIO_MAX; - F32 min_y = RATIO_MIN; - F32 max_y = RATIO_MAX; - // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PATH_CIRCLE == path_type && - LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) - { - // Holes are more restricted... - min_x = HOLE_X_MIN; - max_x = HOLE_X_MAX; - min_y = HOLE_Y_MIN; - max_y = HOLE_Y_MAX; - } - - F32 ratio_x = x; - bool valid = limit_range(ratio_x, min_x, max_x); - F32 ratio_y = y; - valid &= limit_range(ratio_y, min_y, max_y); - - mPathParams.setScale(ratio_x, ratio_y); - - return valid; -} - -bool LLVolumeParams::setShear(const F32 x, const F32 y) -{ - F32 shear_x = x; - bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); - F32 shear_y = y; - valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); - mPathParams.setShear(shear_x, shear_y); - return valid; -} - -bool LLVolumeParams::setTaperX(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperX(taper); - return valid; -} - -bool LLVolumeParams::setTaperY(const F32 v) -{ - F32 taper = v; - bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); - mPathParams.setTaperY(taper); - return valid; -} - -bool LLVolumeParams::setRevolutions(const F32 r) -{ - F32 revolutions = r; - bool valid = limit_range(revolutions, REV_MIN, REV_MAX); - mPathParams.setRevolutions(revolutions); - return valid; -} - -bool LLVolumeParams::setRadiusOffset(const F32 offset) -{ - bool valid = true; - - // If this is a sphere, just set it to 0 and get out. - U8 path_type = mPathParams.getCurveType(); - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || - LL_PCODE_PATH_CIRCLE != path_type ) - { - mPathParams.setRadiusOffset(0.f); - return true; - } - - // Limit radius offset, based on taper and hole size y. - F32 radius_offset = offset; - F32 taper_y = getTaperY(); - F32 radius_mag = fabs(radius_offset); - F32 hole_y_mag = fabs(getRatioY()); - F32 taper_y_mag = fabs(taper_y); - // Check to see if the taper effects us. - if ( (radius_offset > 0.f && taper_y < 0.f) || - (radius_offset < 0.f && taper_y > 0.f) ) - { - // The taper does not help increase the radius offset range. - taper_y_mag = 0.f; - } - F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); - - // Enforce the maximum magnitude. - F32 delta = max_radius_mag - radius_mag; - if (delta < 0.f) - { - // Check radius offset sign. - if (radius_offset < 0.f) - { - radius_offset = -max_radius_mag; - } - else - { - radius_offset = max_radius_mag; - } - valid = approx_zero(delta, .1f); - } - - mPathParams.setRadiusOffset(radius_offset); - return valid; -} - -bool LLVolumeParams::setSkew(const F32 skew_value) -{ - bool valid = true; - - // Check the skew value against the revolutions. - F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); - F32 skew_mag = fabs(skew); - F32 revolutions = getRevolutions(); - F32 scale_x = getRatioX(); - F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); - // Discontinuity; A revolution of 1 allows skews below 0.5. - if ( fabs(revolutions - 1.0f) < 0.001) - min_skew_mag = 0.0f; - - // Clip skew. - F32 delta = skew_mag - min_skew_mag; - if (delta < 0.f) - { - // Check skew sign. - if (skew < 0.0f) - { - skew = -min_skew_mag; - } - else - { - skew = min_skew_mag; - } - valid = approx_zero(delta, .01f); - } - - mPathParams.setSkew(skew); - return valid; -} - -bool LLVolumeParams::setSculptID(const LLUUID& sculpt_id, U8 sculpt_type) -{ - mSculptID = sculpt_id; - mSculptType = sculpt_type; - return true; -} - -bool LLVolumeParams::setType(U8 profile, U8 path) -{ - bool result = true; - // First, check profile and path for validity. - U8 profile_type = profile & LL_PCODE_PROFILE_MASK; - U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; - U8 path_type = path >> 4; - - if (profile_type > LL_PCODE_PROFILE_MAX) - { - // Bad profile. Make it square. - profile = LL_PCODE_PROFILE_SQUARE; - result = false; - LL_WARNS() << "LLVolumeParams::setType changing bad profile type (" << profile_type - << ") to be LL_PCODE_PROFILE_SQUARE" << LL_ENDL; - } - else if (hole_type > LL_PCODE_HOLE_MAX) - { - // Bad hole. Make it the same. - profile = profile_type; - result = false; - LL_WARNS() << "LLVolumeParams::setType changing bad hole type (" << hole_type - << ") to be LL_PCODE_HOLE_SAME" << LL_ENDL; - } - - if (path_type < LL_PCODE_PATH_MIN || - path_type > LL_PCODE_PATH_MAX) - { - // Bad path. Make it linear. - result = false; - LL_WARNS() << "LLVolumeParams::setType changing bad path (" << path - << ") to be LL_PCODE_PATH_LINE" << LL_ENDL; - path = LL_PCODE_PATH_LINE; - } - - mProfileParams.setCurveType(profile); - mPathParams.setCurveType(path); - return result; -} - -// static -bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, - U8 path_curve, F32 path_begin, F32 path_end, - F32 scx, F32 scy, F32 shx, F32 shy, - F32 twistend, F32 twistbegin, F32 radiusoffset, - F32 tx, F32 ty, F32 revolutions, F32 skew) -{ - LLVolumeParams test_params; - if (!test_params.setType (prof_curve, path_curve)) - { - return false; - } - if (!test_params.setBeginAndEndS (prof_begin, prof_end)) - { - return false; - } - if (!test_params.setBeginAndEndT (path_begin, path_end)) - { - return false; - } - if (!test_params.setHollow (hollow)) - { - return false; - } - if (!test_params.setTwistBegin (twistbegin)) - { - return false; - } - if (!test_params.setTwistEnd (twistend)) - { - return false; - } - if (!test_params.setRatio (scx, scy)) - { - return false; - } - if (!test_params.setShear (shx, shy)) - { - return false; - } - if (!test_params.setTaper (tx, ty)) - { - return false; - } - if (!test_params.setRevolutions (revolutions)) - { - return false; - } - if (!test_params.setRadiusOffset (radiusoffset)) - { - return false; - } - if (!test_params.setSkew (skew)) - { - return false; - } - return true; -} - -void LLVolume::getLoDTriangleCounts(const LLVolumeParams& params, S32* counts) -{ //attempt to approximate the number of triangles that will result from generating a volume LoD set for the - //supplied LLVolumeParams -- inaccurate, but a close enough approximation for determining streaming cost - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - F32 detail[] = {1.f, 1.5f, 2.5f, 4.f}; - for (S32 i = 0; i < 4; i++) - { - S32 count = 0; - S32 path_points = LLPath::getNumPoints(params.getPathParams(), detail[i]); - S32 profile_points = LLProfile::getNumPoints(params.getProfileParams(), false, detail[i]); - - count = (profile_points-1)*2*(path_points-1); - count += profile_points*2; - - counts[i] = count; - } -} - - -S32 LLVolume::getNumTriangles(S32* vcount) const -{ - U32 triangle_count = 0; - U32 vertex_count = 0; - - for (S32 i = 0; i < getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = getVolumeFace(i); - triangle_count += face.mNumIndices/3; - - vertex_count += face.mNumVertices; - } - - - if (vcount) - { - *vcount = vertex_count; - } - - return triangle_count; -} - - -//----------------------------------------------------------------------------- -// generateSilhouetteVertices() -//----------------------------------------------------------------------------- -void LLVolume::generateSilhouetteVertices(std::vector &vertices, - std::vector &normals, - const LLVector3& obj_cam_vec_in, - const LLMatrix4& mat_in, - const LLMatrix3& norm_mat_in, - S32 face_mask) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_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(); - - if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - { - return; - } - - S32 cur_index = 0; - //for each face - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - LLVolumeFace& face = *iter; - - if (!(face_mask & (0x1 << cur_index++)) || - face.mNumIndices == 0 || face.mEdge.empty()) - { - continue; - } - - if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) - { - LLVector4a* v = (LLVector4a*)face.mPositions; - LLVector4a* n = (LLVector4a*)face.mNormals; - - for (U32 j = 0; j < face.mNumIndices / 3; j++) - { - for (S32 k = 0; k < 3; k++) - { - S32 index = face.mEdge[j * 3 + k]; - - if (index == -1) - { - // silhouette edge, currently only cubes, so no other conditions - - S32 v1 = face.mIndices[j * 3 + k]; - S32 v2 = face.mIndices[j * 3 + ((k + 1) % 3)]; - - LLVector4a t; - mat.affineTransform(v[v1], t); - vertices.push_back(LLVector3(t[0], t[1], t[2])); - - 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])); - } - } - } - - } - else - { - //============================================== - //DEBUG draw edge map instead of silhouette edge - //============================================== - -#if DEBUG_SILHOUETTE_EDGE_MAP - - //for each triangle - U32 tri_count = face.mNumIndices / 3; - for (U32 j = 0; j < tri_count; j++) { - //get vertices - S32 v1 = face.mIndices[j*3+0]; - S32 v2 = face.mIndices[j*3+1]; - S32 v3 = face.mIndices[j*3+2]; - - //get current face center - 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++) { - S32 nIndex = face.mEdge[j*3+k]; - if (nIndex <= -1) { - continue; - } - - if (nIndex >= (S32)tri_count) { - continue; - } - //get neighbor vertices - v1 = face.mIndices[nIndex*3+0]; - v2 = face.mIndices[nIndex*3+1]; - v3 = face.mIndices[nIndex*3+2]; - - //get neighbor face center - LLVector3 nCenter = (face.mVertices[v1].getPosition() + - face.mVertices[v2].getPosition() + - face.mVertices[v3].getPosition()) / 3.0f; - - //draw line - vertices.push_back(cCenter); - vertices.push_back(nCenter); - normals.push_back(LLVector3(1,1,1)); - normals.push_back(LLVector3(1,1,1)); - segments.push_back(vertices.size()); - } - } - - continue; - - //============================================== - //DEBUG - //============================================== - - //============================================== - //DEBUG draw normals instead of silhouette edge - //============================================== -#elif DEBUG_SILHOUETTE_NORMALS - - //for each vertex - 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].getPosition()); - vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mTangent*0.1f); - normals.push_back(LLVector3(0,0,1)); - normals.push_back(LLVector3(0,0,1)); - segments.push_back(vertices.size()); -#endif - } - - continue; -#else - //============================================== - //DEBUG - //============================================== - - constexpr U8 AWAY = 0x01, - TOWARDS = 0x02; - - //for each triangle - std::vector fFacing; - 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]; - - 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 - LLVector4a view; - view.setSub(obj_cam_vec, v[v1]); - bool away = view.dot3(norm) > 0.0f; - if (away) - { - fFacing[j] = AWAY; - } - else - { - fFacing[j] = TOWARDS; - } - } - } - - //for each triangle - for (U32 j = 0; j < face.mNumIndices/3; j++) - { - if (fFacing[j] == (AWAY | TOWARDS)) - { //this is a degenerate triangle - //take neighbor facing (degenerate faces get facing of one of their neighbors) - // *FIX IF NEEDED: this does not deal with neighboring degenerate faces - for (S32 k = 0; k < 3; k++) - { - S32 index = face.mEdge[j*3+k]; - if (index != -1) - { - fFacing[j] = fFacing[index]; - break; - } - } - continue; //skip degenerate face - } - - //for each edge - for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j*3+k]; - if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { - //our neighbor is degenerate, make him face our direction - fFacing[face.mEdge[j*3+k]] = fFacing[j]; - continue; - } - - if (index == -1 || //edge has no neighbor, MUST be a silhouette edge - (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge - - S32 v1 = face.mIndices[j*3+k]; - S32 v2 = face.mIndices[j*3+((k+1)%3)]; - - LLVector4a t; - mat.affineTransform(v[v1], t); - vertices.push_back(LLVector3(t[0], t[1], t[2])); - - 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])); - } - } - } -#endif - } - } -} - -S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face, - LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out) -{ - S32 hit_face = -1; - - S32 start_face; - S32 end_face; - - if (face == -1) // ALL_SIDES - { - start_face = 0; - end_face = getNumVolumeFaces() - 1; - } - else - { - start_face = face; - end_face = face; - } - - 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++) - { - LLVolumeFace &face = mVolumeFaces[i]; - - LLVector4a box_center; - box_center.setAdd(face.mExtents[0], face.mExtents[1]); - box_center.mul(0.5f); - - LLVector4a box_size; - box_size.setSub(face.mExtents[1], face.mExtents[0]); - - if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) - { - if (tangent_out != NULL) // if the caller wants tangents, we may need to generate them - { - genTangents(i); - } - - if (isUnique()) - { //don't bother with an octree for flexi volumes - U32 tri_count = face.mNumIndices/3; - - for (U32 j = 0; j < tri_count; ++j) - { - U16 idx0 = face.mIndices[j*3+0]; - U16 idx1 = face.mIndices[j*3+1]; - U16 idx2 = face.mIndices[j*3+2]; - - const LLVector4a& v0 = face.mPositions[idx0]; - const LLVector4a& v1 = face.mPositions[idx1]; - const LLVector4a& v2 = face.mPositions[idx2]; - - F32 a,b,t; - - if (LLTriangleRayIntersect(v0, v1, v2, - start, dir, a, b, t)) - { - 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; - - if (intersection != NULL) - { - LLVector4a intersect = dir; - intersect.mul(closest_t); - intersect.add(start); - *intersection = intersect; - } - - - if (tex_coord != NULL) - { - LLVector2* tc = (LLVector2*) face.mTexCoords; - *tex_coord = ((1.f - a - b) * tc[idx0] + - a * tc[idx1] + - b * tc[idx2]); - - } - - if (normal!= NULL) - { - LLVector4a* norm = face.mNormals; - - LLVector4a n1,n2,n3; - n1 = norm[idx0]; - n1.mul(1.f-a-b); - - n2 = norm[idx1]; - n2.mul(a); - - n3 = norm[idx2]; - n3.mul(b); - - n1.add(n2); - n1.add(n3); - - *normal = n1; - } - - if (tangent_out != NULL) - { - LLVector4a* tangents = face.mTangents; - - LLVector4a t1,t2,t3; - t1 = tangents[idx0]; - t1.mul(1.f-a-b); - - t2 = tangents[idx1]; - t2.mul(a); - - t3 = tangents[idx2]; - t3.mul(b); - - t1.add(t2); - t1.add(t3); - - *tangent_out = t1; - } - } - } - } - } - else - { - if (!face.getOctree()) - { - face.createOctree(); - } - - LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out); - intersect.traverse(face.getOctree()); - if (intersect.mHitFace) - { - hit_face = i; - } - } - } - } - - - return hit_face; -} - -class LLVertexIndexPair -{ -public: - LLVertexIndexPair(const LLVector3 &vertex, const S32 index); - - LLVector3 mVertex; - S32 mIndex; -}; - -LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) -{ - mVertex = vertex; - mIndex = index; -} - -constexpr F32 VERTEX_SLOP = 0.00001f; - -struct lessVertex -{ - bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) - { - const F32 slop = VERTEX_SLOP; - - if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) - { - return true; - } - else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) - { - return false; - } - - if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) - { - return true; - } - else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) - { - return false; - } - - if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) - { - return true; - } - else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) - { - return false; - } - - return false; - } -}; - -struct lessTriangle -{ - bool operator()(const S32 *a, const S32 *b) - { - if (*a < *b) - { - return true; - } - else if (*a > *b) - { - return false; - } - - if (*(a+1) < *(b+1)) - { - return true; - } - else if (*(a+1) > *(b+1)) - { - return false; - } - - if (*(a+2) < *(b+2)) - { - return true; - } - else if (*(a+2) > *(b+2)) - { - return false; - } - - return false; - } -}; - -bool equalTriangle(const S32 *a, const S32 *b) -{ - if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) - { - return true; - } - return false; -} - -bool LLVolumeParams::importFile(LLFILE *fp) -{ - //LL_INFOS() << "importing volume" << LL_ENDL; - const S32 BUFSIZE = 16384; - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - - while (!feof(fp)) - { - if (fgets(buffer, BUFSIZE, fp) == NULL) - { - buffer[0] = '\0'; - } - - sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */ - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importFile(fp); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importFile(fp); - } - else - { - LL_WARNS() << "unknown keyword " << keyword << " in volume import" << LL_ENDL; - } - } - - return true; -} - -bool LLVolumeParams::exportFile(LLFILE *fp) const -{ - fprintf(fp,"\tshape 0\n"); - fprintf(fp,"\t{\n"); - mPathParams.exportFile(fp); - mProfileParams.exportFile(fp); - fprintf(fp, "\t}\n"); - return true; -} - - -bool LLVolumeParams::importLegacyStream(std::istream& input_stream) -{ - //LL_INFOS() << "importing volume" << LL_ENDL; - const S32 BUFSIZE = 16384; - // *NOTE: changing the size or type of this buffer will require - // changing the sscanf below. - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - char keyword[256]; /* Flawfinder: ignore */ - keyword[0] = 0; - - while (input_stream.good()) - { - input_stream.getline(buffer, BUFSIZE); - sscanf(buffer, " %255s", keyword); - if (!strcmp("{", keyword)) - { - continue; - } - if (!strcmp("}",keyword)) - { - break; - } - else if (!strcmp("profile", keyword)) - { - mProfileParams.importLegacyStream(input_stream); - } - else if (!strcmp("path",keyword)) - { - mPathParams.importLegacyStream(input_stream); - } - else - { - LL_WARNS() << "unknown keyword " << keyword << " in volume import" << LL_ENDL; - } - } - - return true; -} - -bool LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const -{ - output_stream <<"\tshape 0\n"; - output_stream <<"\t{\n"; - mPathParams.exportLegacyStream(output_stream); - mProfileParams.exportLegacyStream(output_stream); - output_stream << "\t}\n"; - 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; -} - -bool LLVolumeParams::fromLLSD(LLSD& sd) -{ - mPathParams.fromLLSD(sd["path"]); - mProfileParams.fromLLSD(sd["profile"]); - sculptFromLLSD(sd["sculpt"]); - - return true; -} - -void LLVolumeParams::reduceS(F32 begin, F32 end) -{ - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) - { - F32 temp = begin; - begin = end; - end = temp; - } - F32 a = mProfileParams.getBegin(); - F32 b = mProfileParams.getEnd(); - mProfileParams.setBegin(a + begin * (b - a)); - mProfileParams.setEnd(a + end * (b - a)); -} - -void LLVolumeParams::reduceT(F32 begin, F32 end) -{ - begin = llclampf(begin); - end = llclampf(end); - if (begin > end) - { - F32 temp = begin; - begin = end; - end = temp; - } - F32 a = mPathParams.getBegin(); - F32 b = mPathParams.getEnd(); - mPathParams.setBegin(a + begin * (b - a)); - mPathParams.setEnd(a + end * (b - a)); -} - -const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity -const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity - -// returns true if the shape can be approximated with a convex shape -// 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(); - - U8 path_type = mPathParams.getCurveType(); - if ( path_length > MIN_CONCAVE_PATH_WEDGE - && ( mPathParams.getTwist() != mPathParams.getTwistBegin() - || (hollow > 0.f - && LL_PCODE_PATH_LINE != path_type) ) ) - { - // twist along a "not too short" path is concave - return false; - } - - F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); - bool same_hole = hollow == 0.f - || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; - - F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; - U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) - { - // it is a sphere and spheres get twice the minimum profile wedge - min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; - } - - bool convex_profile = ( ( profile_length == 1.f - || profile_length <= 0.5f ) - && hollow == 0.f ) // trivially convex - || ( profile_length <= min_profile_wedge - && same_hole ); // effectvely convex (even when hollow) - - if (!convex_profile) - { - // profile is concave - return false; - } - - if ( LL_PCODE_PATH_LINE == path_type ) - { - // straight paths with convex profile - return true; - } - - bool concave_path = (path_length < 1.0f) && (path_length > 0.5f); - if (concave_path) - { - return false; - } - - // we're left with spheres, toroids and tubes - if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) - { - // at this stage all spheres must be convex - return true; - } - - // it's a toroid or tube - if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) - { - // effectively convex - return true; - } - - return false; -} - -// debug -void LLVolumeParams::setCube() -{ - mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); - mProfileParams.setBegin(0.f); - mProfileParams.setEnd(1.f); - mProfileParams.setHollow(0.f); - - mPathParams.setBegin(0.f); - mPathParams.setEnd(1.f); - mPathParams.setScale(1.f, 1.f); - mPathParams.setShear(0.f, 0.f); - mPathParams.setCurveType(LL_PCODE_PATH_LINE); - mPathParams.setTwistBegin(0.f); - mPathParams.setTwistEnd(0.f); - mPathParams.setRadiusOffset(0.f); - mPathParams.setTaper(0.f, 0.f); - mPathParams.setRevolutions(0.f); - mPathParams.setSkew(0.f); -} - -LLFaceID LLVolume::generateFaceMask() -{ - LLFaceID new_mask = 0x0000; - - switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) - { - case LL_PCODE_PROFILE_CIRCLE: - case LL_PCODE_PROFILE_CIRCLE_HALF: - new_mask |= LL_FACE_OUTER_SIDE_0; - break; - case LL_PCODE_PROFILE_SQUARE: - { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } - } - break; - case LL_PCODE_PROFILE_ISOTRI: - case LL_PCODE_PROFILE_EQUALTRI: - case LL_PCODE_PROFILE_RIGHTTRI: - { - for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) - { - new_mask |= LL_FACE_OUTER_SIDE_0 << side; - } - } - break; - default: - LL_ERRS() << "Unknown profile!" << LL_ENDL; - break; - } - - // handle hollow objects - if (mParams.getProfileParams().getHollow() > 0) - { - new_mask |= LL_FACE_INNER_SIDE; - } - - // handle open profile curves - if (mProfilep->isOpen()) - { - new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; - } - - // handle open path curves - if (mPathp->isOpen()) - { - new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; - } - - return new_mask; -} - -bool LLVolume::isFaceMaskValid(LLFaceID face_mask) -{ - LLFaceID test_mask = 0; - for(S32 i = 0; i < getNumFaces(); i++) - { - test_mask |= mProfilep->mFaces[i].mFaceID; - } - - return test_mask == face_mask; -} - -bool LLVolume::isConvex() const -{ - // mParams.isConvex() may return false even though the final - // geometry is actually convex due to LOD approximations. - // TODO -- provide LLPath and LLProfile with isConvex() methods - // that correctly determine convexity. -- Leviathan - return mParams.isConvex(); -} - - -std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) -{ - s << "{type=" << (U32) profile_params.mCurveType; - s << ", begin=" << profile_params.mBegin; - s << ", end=" << profile_params.mEnd; - s << ", hollow=" << profile_params.mHollow; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) -{ - s << "{type=" << (U32) path_params.mCurveType; - s << ", begin=" << path_params.mBegin; - s << ", end=" << path_params.mEnd; - s << ", twist=" << path_params.mTwistEnd; - s << ", scale=" << path_params.mScale; - s << ", shear=" << path_params.mShear; - s << ", twist_begin=" << path_params.mTwistBegin; - s << ", radius_offset=" << path_params.mRadiusOffset; - s << ", taper=" << path_params.mTaper; - s << ", revolutions=" << path_params.mRevolutions; - s << ", skew=" << path_params.mSkew; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) -{ - s << "{profileparams = " << volume_params.mProfileParams; - s << ", pathparams = " << volume_params.mPathParams; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLProfile &profile) -{ - s << " {open=" << (U32) profile.mOpen; - s << ", dirty=" << profile.mDirty; - s << ", totalout=" << profile.mTotalOut; - s << ", total=" << profile.mTotal; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLPath &path) -{ - s << "{open=" << (U32) path.mOpen; - s << ", dirty=" << path.mDirty; - s << ", step=" << path.mStep; - s << ", total=" << path.mTotal; - s << "}"; - return s; -} - -std::ostream& operator<<(std::ostream &s, const LLVolume &volume) -{ - s << "{params = " << volume.getParams(); - s << ", path = " << *volume.mPathp; - s << ", profile = " << *volume.mProfilep; - s << "}"; - return s; -} - - -std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) -{ - s << "{params = " << volumep->getParams(); - s << ", path = " << *(volumep->mPathp); - s << ", profile = " << *(volumep->mProfilep); - s << "}"; - return s; -} - -LLVolumeFace::LLVolumeFace() : - mID(0), - mTypeMask(0), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0), - mNumVertices(0), - mNumAllocatedVertices(0), - mNumIndices(0), - mPositions(NULL), - mNormals(NULL), - mTangents(NULL), - mTexCoords(NULL), - mIndices(NULL), - mWeights(NULL), -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - mJustWeights(NULL), - mJointIndices(NULL), -#endif - mWeightsScrubbed(false), - mOctree(NULL), - mOctreeTriangles(NULL), - mOptimized(false) -{ - mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); - mExtents[0].splat(-0.5f); - mExtents[1].splat(0.5f); - mCenter = mExtents+2; -} - -LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) -: mID(0), - mTypeMask(0), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0), - mNumVertices(0), - mNumAllocatedVertices(0), - mNumIndices(0), - mPositions(NULL), - mNormals(NULL), - mTangents(NULL), - mTexCoords(NULL), - mIndices(NULL), - mWeights(NULL), -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - mJustWeights(NULL), - mJointIndices(NULL), -#endif - mWeightsScrubbed(false), - mOctree(NULL), - mOctreeTriangles(NULL) -{ - mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); - 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(); - - resizeVertices(src.mNumVertices); - resizeIndices(src.mNumIndices); - - if (mNumVertices) - { - S32 vert_size = mNumVertices*sizeof(LLVector4a); - S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; - - LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size); - - if (src.mNormals) - { - LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); - } - - if(src.mTexCoords) - { - LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); - } - - if (src.mTangents) - { - allocateTangents(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mTangents, (F32*) src.mTangents, vert_size); - } - else - { - ll_aligned_free_16(mTangents); - mTangents = NULL; - } - - if (src.mWeights) - { - llassert(!mWeights); // don't orphan an old alloc here accidentally - allocateWeights(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); - mWeightsScrubbed = src.mWeightsScrubbed; - } - else - { - ll_aligned_free_16(mWeights); - mWeights = NULL; - mWeightsScrubbed = false; - } - - #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - if (src.mJointIndices) - { - llassert(!mJointIndices); // don't orphan an old alloc here accidentally - allocateJointIndices(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mJointIndices, (F32*) src.mJointIndices, src.mNumVertices * sizeof(U8) * 4); - } - else*/ - { - ll_aligned_free_16(mJointIndices); - mJointIndices = NULL; - } - #endif - - } - - if (mNumIndices) - { - S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; - - LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); - } - else - { - ll_aligned_free_16(mIndices); - mIndices = NULL; - } - - mOptimized = src.mOptimized; - mNormalizedScale = src.mNormalizedScale; - - //delete - return *this; -} - -LLVolumeFace::~LLVolumeFace() -{ - ll_aligned_free_16(mExtents); - mExtents = NULL; - mCenter = NULL; - - freeData(); -} - -void LLVolumeFace::freeData() -{ - ll_aligned_free<64>(mPositions); - mPositions = NULL; - - //normals and texture coordinates are part of the same buffer as mPositions, do not free them separately - mNormals = NULL; - mTexCoords = NULL; - - ll_aligned_free_16(mIndices); - mIndices = NULL; - ll_aligned_free_16(mTangents); - mTangents = NULL; - ll_aligned_free_16(mWeights); - mWeights = NULL; - -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - ll_aligned_free_16(mJointIndices); - mJointIndices = NULL; - ll_aligned_free_16(mJustWeights); - mJustWeights = NULL; -#endif - - destroyOctree(); -} - -bool LLVolumeFace::create(LLVolume* volume, bool partial_build) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - //tree for this face is no longer valid - destroyOctree(); - - LL_CHECK_MEMORY - bool ret = false ; - if (mTypeMask & CAP_MASK) - { - ret = createCap(volume, partial_build); - LL_CHECK_MEMORY - } - else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) - { - ret = createSide(volume, partial_build); - LL_CHECK_MEMORY - } - else - { - LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL; - } - - return ret ; -} - -void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) -{ - cv.setPosition(mPositions[index]); - if (mNormals) - { - cv.setNormal(mNormals[index]); - } - else - { - cv.getNormal().clear(); - } - - if (mTexCoords) - { - cv.mTexCoord = mTexCoords[index]; - } - else - { - cv.mTexCoord.clear(); - } -} - -bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const -{ - return getPosition().equals3(rhs.getPosition()) && - mTexCoord == rhs.mTexCoord && - getNormal().equals3(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::remap() -{ - // Generate a remap buffer - std::vector remap(mNumVertices); - S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0], - mIndices, - mNumIndices, - mPositions, - mNormals, - mTexCoords, - mNumVertices); - - // Allocate new buffers - S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF; - U16* remap_indices = (U16*)ll_aligned_malloc_16(size); - - S32 tc_bytes_size = ((remap_vertices_count * sizeof(LLVector2)) + 0xF) & ~0xF; - LLVector4a* remap_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * remap_vertices_count + tc_bytes_size); - LLVector4a* remap_normals = remap_positions + remap_vertices_count; - LLVector2* remap_tex_coords = (LLVector2*)(remap_normals + remap_vertices_count); - - // Fill the buffers - LLMeshOptimizer::remapIndexBufferU16(remap_indices, mIndices, mNumIndices, &remap[0]); - LLMeshOptimizer::remapPositionsBuffer(remap_positions, mPositions, mNumVertices, &remap[0]); - LLMeshOptimizer::remapNormalsBuffer(remap_normals, mNormals, mNumVertices, &remap[0]); - LLMeshOptimizer::remapUVBuffer(remap_tex_coords, mTexCoords, mNumVertices, &remap[0]); - - // Free unused buffers - ll_aligned_free_16(mIndices); - ll_aligned_free<64>(mPositions); - - // Tangets are now invalid - ll_aligned_free_16(mTangents); - mTangents = NULL; - - // Assign new values - mIndices = remap_indices; - mPositions = remap_positions; - mNormals = remap_normals; - mTexCoords = remap_tex_coords; - mNumVertices = remap_vertices_count; - mNumAllocatedVertices = remap_vertices_count; -} - -void LLVolumeFace::optimize(F32 angle_cutoff) -{ - LLVolumeFace new_face; - - //map of points to vector of vertices at that point - std::map > point_map; - - LLVector4a range; - range.setSub(mExtents[1],mExtents[0]); - - //remove redundant vertices - for (U32 i = 0; i < mNumIndices; ++i) - { - U16 index = mIndices[i]; - - if (index >= mNumVertices) - { - // invalid index - // replace with a valid index to avoid crashes - index = mNumVertices - 1; - mIndices[i] = index; - - // Needs better logging - LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL; - } - - LLVolumeFace::VertexData cv; - getVertexData(index, cv); - - bool found = false; - - LLVector4a pos; - pos.setSub(mPositions[index], mExtents[0]); - pos.div(range); - - U64 pos64 = 0; - - pos64 = (U16) (pos[0]*65535); - pos64 = pos64 | (((U64) (pos[1]*65535)) << 16); - pos64 = pos64 | (((U64) (pos[2]*65535)) << 32); - - std::map >::iterator point_iter = point_map.find(pos64); - - 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[pos64].push_back(d); - } - } - } - - - if (angle_cutoff > 1.f && !mNormals) - { - // Now alloc'd with positions - //ll_aligned_free_16(new_face.mNormals); - new_face.mNormals = NULL; - } - - if (!mTexCoords) - { - // Now alloc'd with positions - //ll_aligned_free_16(new_face.mTexCoords); - new_face.mTexCoords = NULL; - } - - // Only swap data if we've actually optimized the mesh - // - if (new_face.mNumVertices <= mNumVertices) - { - llassert(new_face.mNumIndices == mNumIndices); - swapData(new_face); - } - -} - -class LLVCacheTriangleData; - -class LLVCacheVertexData -{ -public: - S32 mIdx; - S32 mCacheTag; - F64 mScore; - U32 mActiveTriangles; - std::vector mTriangles; - - LLVCacheVertexData() - { - mCacheTag = -1; - mScore = 0.0; - mActiveTriangles = 0; - mIdx = -1; - } -}; - -class LLVCacheTriangleData -{ -public: - bool mActive; - F64 mScore; - LLVCacheVertexData* mVertex[3]; - - LLVCacheTriangleData() - { - mActive = true; - mScore = 0.0; - mVertex[0] = mVertex[1] = mVertex[2] = NULL; - } - - void complete() - { - mActive = false; - for (S32 i = 0; i < 3; ++i) - { - if (mVertex[i]) - { - llassert(mVertex[i]->mActiveTriangles > 0); - mVertex[i]->mActiveTriangles--; - } - } - } - - bool operator<(const LLVCacheTriangleData& rhs) const - { //highest score first - return rhs.mScore < mScore; - } -}; - -constexpr F64 FindVertexScore_CacheDecayPower = 1.5; -constexpr F64 FindVertexScore_LastTriScore = 0.75; -constexpr F64 FindVertexScore_ValenceBoostScale = 2.0; -constexpr F64 FindVertexScore_ValenceBoostPower = 0.5; -constexpr U32 MaxSizeVertexCache = 32; -constexpr F64 FindVertexScore_Scaler = 1.0/(MaxSizeVertexCache-3); - -F64 find_vertex_score(LLVCacheVertexData& data) -{ - F64 score = -1.0; - - score = 0.0; - - S32 cache_idx = data.mCacheTag; - - if (cache_idx < 0) - { - //not in cache - } - else - { - if (cache_idx < 3) - { //vertex was in the last triangle - score = FindVertexScore_LastTriScore; - } - else - { //more points for being higher in the cache - score = 1.0-((cache_idx-3)*FindVertexScore_Scaler); - score = pow(score, FindVertexScore_CacheDecayPower); - } - } - - //bonus points for having low valence - F64 valence_boost = pow((F64)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); - score += FindVertexScore_ValenceBoostScale * valence_boost; - - return score; -} - -class LLVCacheFIFO -{ -public: - LLVCacheVertexData* mCache[MaxSizeVertexCache]; - U32 mMisses; - - LLVCacheFIFO() - { - mMisses = 0; - for (U32 i = 0; i < MaxSizeVertexCache; ++i) - { - mCache[i] = NULL; - } - } - - void addVertex(LLVCacheVertexData* data) - { - if (data->mCacheTag == -1) - { - mMisses++; - - S32 end = MaxSizeVertexCache-1; - - if (mCache[end]) - { - mCache[end]->mCacheTag = -1; - } - - for (S32 i = end; i > 0; --i) - { - mCache[i] = mCache[i-1]; - if (mCache[i]) - { - mCache[i]->mCacheTag = i; - } - } - - mCache[0] = data; - data->mCacheTag = 0; - } - } -}; - -class LLVCacheLRU -{ -public: - LLVCacheVertexData* mCache[MaxSizeVertexCache+3]; - - LLVCacheTriangleData* mBestTriangle; - - U32 mMisses; - - LLVCacheLRU() - { - for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) - { - mCache[i] = NULL; - } - - mBestTriangle = NULL; - mMisses = 0; - } - - void addVertex(LLVCacheVertexData* data) - { - S32 end = MaxSizeVertexCache+2; - if (data->mCacheTag != -1) - { //just moving a vertex to the front of the cache - end = data->mCacheTag; - } - else - { - mMisses++; - if (mCache[end]) - { //adding a new vertex, vertex at end of cache falls off - mCache[end]->mCacheTag = -1; - } - } - - for (S32 i = end; i > 0; --i) - { //adjust cache pointers and tags - mCache[i] = mCache[i-1]; - - if (mCache[i]) - { - mCache[i]->mCacheTag = i; - } - } - - mCache[0] = data; - mCache[0]->mCacheTag = 0; - } - - void addTriangle(LLVCacheTriangleData* data) - { - addVertex(data->mVertex[0]); - addVertex(data->mVertex[1]); - addVertex(data->mVertex[2]); - } - - void updateScores() - { - LLVCacheVertexData** data_iter = mCache+MaxSizeVertexCache; - LLVCacheVertexData** end_data = mCache+MaxSizeVertexCache+3; - - while(data_iter != end_data) - { - LLVCacheVertexData* data = *data_iter++; - //trailing 3 vertices aren't actually in the cache for scoring purposes - if (data) - { - data->mCacheTag = -1; - } - } - - data_iter = mCache; - end_data = mCache+MaxSizeVertexCache; - - while (data_iter != end_data) - { //update scores of vertices in cache - LLVCacheVertexData* data = *data_iter++; - if (data) - { - data->mScore = find_vertex_score(*data); - } - } - - mBestTriangle = NULL; - //update triangle scores - data_iter = mCache; - end_data = mCache+MaxSizeVertexCache+3; - - while (data_iter != end_data) - { - LLVCacheVertexData* data = *data_iter++; - if (data) - { - for (std::vector::iterator iter = data->mTriangles.begin(), end_iter = data->mTriangles.end(); iter != end_iter; ++iter) - { - LLVCacheTriangleData* tri = *iter; - if (tri->mActive) - { - tri->mScore = tri->mVertex[0] ? tri->mVertex[0]->mScore : 0; - tri->mScore += tri->mVertex[1] ? tri->mVertex[1]->mScore : 0; - tri->mScore += tri->mVertex[2] ? tri->mVertex[2]->mScore : 0; - - if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) - { - mBestTriangle = tri; - } - } - } - } - } - - //knock trailing 3 vertices off the cache - data_iter = mCache+MaxSizeVertexCache; - end_data = mCache+MaxSizeVertexCache+3; - while (data_iter != end_data) - { - LLVCacheVertexData* data = *data_iter; - if (data) - { - llassert(data->mCacheTag == -1); - *data_iter = NULL; - } - ++data_iter; - } - } -}; - -// data structures for tangent generation - -struct MikktData -{ - LLVolumeFace* face; - std::vector p; - std::vector n; - std::vector tc; - std::vector w; - std::vector t; - - MikktData(LLVolumeFace* f) - : face(f) - { - U32 count = face->mNumIndices; - - p.resize(count); - n.resize(count); - tc.resize(count); - t.resize(count); - - if (face->mWeights) - { - w.resize(count); - } - - - LLVector3 inv_scale(1.f / face->mNormalizedScale.mV[0], 1.f / face->mNormalizedScale.mV[1], 1.f / face->mNormalizedScale.mV[2]); - - - for (int i = 0; i < face->mNumIndices; ++i) - { - U32 idx = face->mIndices[i]; - - p[i].set(face->mPositions[idx].getF32ptr()); - p[i].scaleVec(face->mNormalizedScale); //put mesh in original coordinate frame when reconstructing tangents - n[i].set(face->mNormals[idx].getF32ptr()); - n[i].scaleVec(inv_scale); - n[i].normalize(); - tc[i].set(face->mTexCoords[idx]); - - if (idx >= face->mNumVertices) - { - // invalid index - // replace with a valid index to avoid crashes - idx = face->mNumVertices - 1; - face->mIndices[i] = idx; - - // Needs better logging - LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL; - } - - if (face->mWeights) - { - w[i].set(face->mWeights[idx].getF32ptr()); - } - } - } -}; - - -bool LLVolumeFace::cacheOptimize(bool gen_tangents) -{ //optimize for vertex cache according to Forsyth method: - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - llassert(!mOptimized); - mOptimized = true; - - if (gen_tangents && mNormals && mTexCoords) - { // generate mikkt space tangents before cache optimizing since the index buffer may change - // a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh - // and is executed on a background thread - SMikkTSpaceInterface ms; - - ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - LLVolumeFace* face = data->face; - return face->mNumIndices / 3; - }; - - ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace) - { - return 3; - }; - - ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* v = data->p[iFace * 3 + iVert].mV; - fvPosOut[0] = v[0]; - fvPosOut[1] = v[1]; - fvPosOut[2] = v[2]; - }; - - ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* n = data->n[iFace * 3 + iVert].mV; - fvNormOut[0] = n[0]; - fvNormOut[1] = n[1]; - fvNormOut[2] = n[2]; - }; - - ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* tc = data->tc[iFace * 3 + iVert].mV; - fvTexcOut[0] = tc[0]; - fvTexcOut[1] = tc[1]; - }; - - ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - S32 i = iFace * 3 + iVert; - - data->t[i].set(fvTangent); - data->t[i].mV[3] = fSign; - }; - - ms.m_setTSpace = nullptr; - - MikktData data(this); - - SMikkTSpaceContext ctx = { &ms, &data }; - - genTangSpaceDefault(&ctx); - - //re-weld - meshopt_Stream mos[] = - { - { &data.p[0], sizeof(LLVector3), sizeof(LLVector3) }, - { &data.n[0], sizeof(LLVector3), sizeof(LLVector3) }, - { &data.t[0], sizeof(LLVector4), sizeof(LLVector4) }, - { &data.tc[0], sizeof(LLVector2), sizeof(LLVector2) }, - { data.w.empty() ? nullptr : &data.w[0], sizeof(LLVector4), sizeof(LLVector4) } - }; - - std::vector remap; - remap.resize(data.p.size()); - - U32 stream_count = data.w.empty() ? 4 : 5; - - size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); - - if (vert_count < 65535 && vert_count != 0) - { - std::vector indices; - indices.resize(mNumIndices); - - //copy results back into volume - resizeVertices(vert_count); - - if (!data.w.empty()) - { - allocateWeights(vert_count); - } - - allocateTangents(mNumVertices); - - for (int i = 0; i < mNumIndices; ++i) - { - U32 src_idx = i; - U32 dst_idx = remap[i]; - if (dst_idx >= mNumVertices) - { - dst_idx = mNumVertices - 1; - // Shouldn't happen, figure out what gets returned in remap and why. - llassert(false); - LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL; - } - mIndices[i] = dst_idx; - - mPositions[dst_idx].load3(data.p[src_idx].mV); - mNormals[dst_idx].load3(data.n[src_idx].mV); - mTexCoords[dst_idx] = data.tc[src_idx]; - - mTangents[dst_idx].loadua(data.t[src_idx].mV); - - if (mWeights) - { - mWeights[dst_idx].loadua(data.w[src_idx].mV); - } - } - - // put back in normalized coordinate frame - LLVector4a inv_scale(1.f/mNormalizedScale.mV[0], 1.f / mNormalizedScale.mV[1], 1.f / mNormalizedScale.mV[2]); - LLVector4a scale; - scale.load3(mNormalizedScale.mV); - scale.getF32ptr()[3] = 1.f; - - for (int i = 0; i < mNumVertices; ++i) - { - mPositions[i].mul(inv_scale); - mNormals[i].mul(scale); - mNormals[i].normalize3(); - F32 w = mTangents[i].getF32ptr()[3]; - mTangents[i].mul(scale); - mTangents[i].normalize3(); - mTangents[i].getF32ptr()[3] = w; - } - } - else - { - if (vert_count == 0) - { - LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL; - } - // blew past the max vertex size limit, use legacy tangent generation which never adds verts - createTangents(); - } - } - - // cache optimize index buffer - - // meshopt needs scratch space, do some pointer shuffling to avoid an extra index buffer copy - U16* src_indices = mIndices; - mIndices = nullptr; - resizeIndices(mNumIndices); - - meshopt_optimizeVertexCache(mIndices, src_indices, mNumIndices, mNumVertices); - - ll_aligned_free_16(src_indices); - - return true; -} - -void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - if (getOctree()) - { - return; - } - - llassert(mNumIndices % 3 == 0); - - mOctree = new LLOctreeRoot(center, size, NULL); - new LLVolumeOctreeListener(mOctree); - const U32 num_triangles = mNumIndices / 3; - // Initialize all the triangles we need - mOctreeTriangles = new LLVolumeTriangle[num_triangles]; - - for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) - { //for each triangle - const U32 index = triangle_index * 3; - LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; - - const LLVector4a& v0 = mPositions[mIndices[index]]; - const LLVector4a& v1 = mPositions[mIndices[index + 1]]; - const LLVector4a& v2 = mPositions[mIndices[index + 2]]; - - //store pointers to vertex data - tri->mV[0] = &v0; - tri->mV[1] = &v1; - tri->mV[2] = &v2; - - //store indices - tri->mIndex[0] = mIndices[index]; - tri->mIndex[1] = mIndices[index + 1]; - tri->mIndex[2] = mIndices[index + 2]; - - //get minimum point - LLVector4a min = v0; - min.setMin(min, v1); - min.setMin(min, v2); - - //get maximum point - LLVector4a max = v0; - max.setMax(max, v1); - max.setMax(max, v2); - - //compute center - LLVector4a center; - center.setAdd(min, max); - center.mul(0.5f); - - tri->mPositionGroup = center; - - //compute "radius" - LLVector4a size; - size.setSub(max,min); - - tri->mRadius = size.getLength3().getF32() * scaler; - - //insert - mOctree->insert(tri); - } - - //remove unneeded octree layers - while (!mOctree->balance()) { } - - //calculate AABB for each node - LLVolumeOctreeRebound rebound(this); - rebound.traverse(mOctree); - - if (gDebugGL) - { - LLVolumeOctreeValidate validate; - validate.traverse(mOctree); - } -} - -void LLVolumeFace::destroyOctree() -{ - delete mOctree; - mOctree = NULL; - delete[] mOctreeTriangles; - mOctreeTriangles = NULL; -} - -const LLOctreeNode* LLVolumeFace::getOctree() const -{ - return mOctree; -} - - -void LLVolumeFace::swapData(LLVolumeFace& rhs) -{ - llswap(rhs.mPositions, mPositions); - llswap(rhs.mNormals, mNormals); - llswap(rhs.mTangents, mTangents); - 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, - LLVolumeFace::VertexData& vout, - F32 coef01, - F32 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.setNormal(v0.getNormal()); -} - -bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) -{ - LL_CHECK_MEMORY - - const LLAlignedArray& mesh = volume->getMesh(); - const LLAlignedArray& profile = volume->getProfile().mProfile; - S32 max_s = volume->getProfile().getTotal(); - S32 max_t = volume->getPath().mPath.size(); - - // S32 i; - S32 grid_size = (profile.size()-1)/4; - // VFExtents change - 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(S32 t = 0; t < 4; t++) - { - corners[t].getPosition().load4a(mesh[offset + (grid_size*t)].getF32ptr()); - corners[t].mTexCoord.mV[0] = profile[grid_size*t][0]+0.5f; - corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t][1]; - } - - { - 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(!(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; - } - - S32 size = (grid_size+1)*(grid_size+1); - resizeVertices(size); - - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - LLVector2* tc = (LLVector2*) mTexCoords; - - for(int gx = 0;gxsetAdd(min, max); - mCenter->mul(0.5f); - } - - if (!partial_build) - { - resizeIndices(grid_size*grid_size*6); - if (!volume->isMeshAssetLoaded()) - { - S32 size = grid_size * grid_size * 6; - try - { - mEdge.resize(size); - } - catch (std::bad_alloc&) - { - LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL; - return false; - } - } - - U16* out = mIndices; - - S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - - int cur_edge = 0; - - for(S32 gx = 0;gx=0;i--) - { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - - S32 edge_value = grid_size * 2 * gy + gx * 2; - - if (gx > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; // Mark face to higlight it - } - - if (gy < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; - - if (gx < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - if (gy > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; - } - else - { - for(S32 i=0;i<6;i++) - { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - - S32 edge_value = grid_size * 2 * gy + gx * 2; - - if (gy > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - if (gx < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; - - if (gy < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - if (gx > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; - } - } - } - } - - LL_CHECK_MEMORY - return true; -} - - -bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) -{ - if (!(mTypeMask & HOLLOW_MASK) && - !(mTypeMask & OPEN_MASK) && - ((volume->getParams().getPathParams().getBegin()==0.0f)&& - (volume->getParams().getPathParams().getEnd()==1.0f))&& - (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE && - volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE) - ){ - return createUnCutCubeCap(volume, partial_build); - } - - S32 num_vertices = 0, num_indices = 0; - - const LLAlignedArray& mesh = volume->getMesh(); - const LLAlignedArray& profile = volume->getProfile().mProfile; - - // All types of caps have the same number of vertices and indices - num_vertices = profile.size(); - num_indices = (profile.size() - 2)*3; - - if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) - { - resizeVertices(num_vertices+1); - - //if (!partial_build) - { - resizeIndices(num_indices+3); - } - } - else - { - resizeVertices(num_vertices); - //if (!partial_build) - { - resizeIndices(num_indices); - } - } - - LL_CHECK_MEMORY; - - S32 max_s = volume->getProfile().getTotal(); - S32 max_t = volume->getPath().mPath.size(); - - mCenter->clear(); - - S32 offset = 0; - if (mTypeMask & TOP_MASK) - { - offset = (max_t-1) * max_s; - } - else - { - offset = mBeginS; - } - - // Figure out the normal, assume all caps are flat faces. - // Cross product to get normals. - - LLVector2 cuv; - LLVector2 min_uv, max_uv; - // VFExtents change - LLVector4a& min = mExtents[0]; - LLVector4a& max = mExtents[1]; - - LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; - - // Copy the vertices into the array - - const LLVector4a* src = mesh.mArray+offset; - const LLVector4a* end = src+num_vertices; - - min = *src; - max = min; - - - const LLVector4a* p = profile.mArray; - - if (mTypeMask & TOP_MASK) - { - min_uv.set((*p)[0]+0.5f, - (*p)[1]+0.5f); - - max_uv = min_uv; - - while(src < end) - { - tc->mV[0] = (*p)[0]+0.5f; - tc->mV[1] = (*p)[1]+0.5f; - - llassert(src->isFinite3()); // MAINT-5660; don't know why this happens, does not affect Release builds - update_min_max(min,max,*src); - update_min_max(min_uv, max_uv, *tc); - - *pos = *src; - - llassert(pos->isFinite3()); - - ++p; - ++tc; - ++src; - ++pos; - } - } - else - { - - min_uv.set((*p)[0]+0.5f, - 0.5f - (*p)[1]); - max_uv = min_uv; - - while(src < end) - { - // Mirror for underside. - tc->mV[0] = (*p)[0]+0.5f; - tc->mV[1] = 0.5f - (*p)[1]; - - llassert(src->isFinite3()); - update_min_max(min,max,*src); - update_min_max(min_uv, max_uv, *tc); - - *pos = *src; - - llassert(pos->isFinite3()); - - ++p; - ++tc; - ++src; - ++pos; - } - } - - LL_CHECK_MEMORY - - mCenter->setAdd(min, max); - mCenter->mul(0.5f); - - cuv = (min_uv + max_uv)*0.5f; - - - VertexData vd; - vd.setPosition(*mCenter); - vd.mTexCoord = cuv; - - if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) - { - *pos++ = *mCenter; - *tc++ = cuv; - num_vertices++; - } - - LL_CHECK_MEMORY - - //if (partial_build) - //{ - // return true; - //} - - if (mTypeMask & HOLLOW_MASK) - { - if (mTypeMask & TOP_MASK) - { - // HOLLOW TOP - // Does it matter if it's open or closed? - djs - - S32 pt1 = 0, pt2 = num_vertices - 1; - S32 i = 0; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - const LLVector4a& p1 = profile[pt1]; - const LLVector4a& p2 = profile[pt2]; - const LLVector4a& pa = profile[pt1+1]; - const LLVector4a& pb = profile[pt2-1]; - - const F32* p1V = p1.getF32ptr(); - const F32* p2V = p2.getF32ptr(); - const F32* paV = pa.getF32ptr(); - const F32* pbV = pb.getF32ptr(); - - //p1.mV[VZ] = 0.f; - //p2.mV[VZ] = 0.f; - //pa.mV[VZ] = 0.f; - //pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1V[0]*paV[1] - paV[0]*p1V[1]) + - (paV[0]*p2V[1] - p2V[0]*paV[1]) + - (p2V[0]*p1V[1] - p1V[0]*p2V[1]); - - area_1ba = (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + - (pbV[0]*paV[1] - paV[0]*pbV[1]) + - (paV[0]*p1V[1] - p1V[0]*paV[1]); - - area_21b = (p2V[0]*p1V[1] - p1V[0]*p2V[1]) + - (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + - (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - - area_2ab = (p2V[0]*paV[1] - paV[0]*p2V[1]) + - (paV[0]*pbV[1] - pbV[0]*paV[1]) + - (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - - bool use_tri1a2 = true; - bool tri_1a2 = true; - bool tri_21b = true; - - if (area_1a2 < 0) - { - tri_1a2 = false; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = false; - } - if (area_21b < 0) - { - tri_21b = false; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = false; - } - - if (!tri_1a2) - { - use_tri1a2 = false; - } - else if (!tri_21b) - { - use_tri1a2 = true; - } - else - { - LLVector4a d1; - d1.setSub(p1, pa); - - LLVector4a d2; - d2.setSub(p2, pb); - - if (d1.dot3(d1) < d2.dot3(d2)) - { - use_tri1a2 = true; - } - else - { - use_tri1a2 = false; - } - } - - if (use_tri1a2) - { - mIndices[i++] = pt1; - mIndices[i++] = pt1 + 1; - mIndices[i++] = pt2; - pt1++; - } - else - { - mIndices[i++] = pt1; - mIndices[i++] = pt2 - 1; - mIndices[i++] = pt2; - pt2--; - } - } - } - else - { - // HOLLOW BOTTOM - // Does it matter if it's open or closed? - djs - - llassert(mTypeMask & BOTTOM_MASK); - S32 pt1 = 0, pt2 = num_vertices - 1; - - S32 i = 0; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - const LLVector4a& p1 = profile[pt1]; - const LLVector4a& p2 = profile[pt2]; - const LLVector4a& pa = profile[pt1+1]; - const LLVector4a& pb = profile[pt2-1]; - - const F32* p1V = p1.getF32ptr(); - const F32* p2V = p2.getF32ptr(); - const F32* paV = pa.getF32ptr(); - const F32* pbV = pb.getF32ptr(); - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1V[0]*paV[1] - paV[0]*p1V[1]) + - (paV[0]*p2V[1] - p2V[0]*paV[1]) + - (p2V[0]*p1V[1] - p1V[0]*p2V[1]); - - area_1ba = (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + - (pbV[0]*paV[1] - paV[0]*pbV[1]) + - (paV[0]*p1V[1] - p1V[0]*paV[1]); - - area_21b = (p2V[0]*p1V[1] - p1V[0]*p2V[1]) + - (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + - (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - - area_2ab = (p2V[0]*paV[1] - paV[0]*p2V[1]) + - (paV[0]*pbV[1] - pbV[0]*paV[1]) + - (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - - bool use_tri1a2 = true; - bool tri_1a2 = true; - bool tri_21b = true; - - if (area_1a2 < 0) - { - tri_1a2 = false; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = false; - } - if (area_21b < 0) - { - tri_21b = false; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = false; - } - - if (!tri_1a2) - { - use_tri1a2 = false; - } - else if (!tri_21b) - { - use_tri1a2 = true; - } - else - { - LLVector4a d1; - d1.setSub(p1,pa); - LLVector4a d2; - d2.setSub(p2,pb); - - if (d1.dot3(d1) < d2.dot3(d2)) - { - use_tri1a2 = true; - } - else - { - use_tri1a2 = false; - } - } - - // Flipped backfacing from top - if (use_tri1a2) - { - mIndices[i++] = pt1; - mIndices[i++] = pt2; - mIndices[i++] = pt1 + 1; - pt1++; - } - else - { - mIndices[i++] = pt1; - mIndices[i++] = pt2; - mIndices[i++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Not hollow, generate the triangle fan. - U16 v1 = 2; - U16 v2 = 1; - - if (mTypeMask & TOP_MASK) - { - v1 = 1; - v2 = 2; - } - - for (S32 i = 0; i < (num_vertices - 2); i++) - { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+v1] = i; - mIndices[3*i+v2] = i + 1; - } - - - } - - LLVector4a d0,d1; - LL_CHECK_MEMORY - - - 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 - if(normal.getF32ptr()[2] >= 0) - normal.set(0.f,0.f,1.f); - else - normal.set(0.f,0.f,-1.f); - } - - 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; -} - -void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, - const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent); - -void LLVolumeFace::createTangents() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - - if (!mTangents) - { - allocateTangents(mNumVertices); - - //generate tangents - LLVector4a* ptr = (LLVector4a*)mTangents; - - LLVector4a* end = mTangents + mNumVertices; - while (ptr < end) - { - (*ptr++).clear(); - } - - CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents); - - //normalize normals - for (U32 i = 0; i < mNumVertices; i++) - { - //bump map/planar projection code requires normals to be normalized - mNormals[i].normalize3fast(); - } - } - -} - -void LLVolumeFace::resizeVertices(S32 num_verts) -{ - ll_aligned_free<64>(mPositions); - //DO NOT free mNormals and mTexCoords as they are part of mPositions buffer - ll_aligned_free_16(mTangents); - - mTangents = NULL; - - if (num_verts) - { - //pad texture coordinate block end to allow for QWORD reads - S32 tc_size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - - mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+tc_size); - mNormals = mPositions+num_verts; - mTexCoords = (LLVector2*) (mNormals+num_verts); - - ll_assert_aligned(mPositions, 64); - } - else - { - mPositions = NULL; - mNormals = NULL; - mTexCoords = NULL; - } - - - if (mPositions) - { - mNumVertices = num_verts; - mNumAllocatedVertices = num_verts; - } - else - { - // Either num_verts is zero or allocation failure - mNumVertices = 0; - mNumAllocatedVertices = 0; - } - - // Force update - mJointRiggingInfoTab.clear(); -} - -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; - - if (new_verts > mNumAllocatedVertices) - { - // double buffer size on expansion - new_verts *= 2; - - S32 new_tc_size = ((new_verts*8)+0xF) & ~0xF; - S32 old_tc_size = ((mNumVertices*8)+0xF) & ~0xF; - - S32 old_vsize = mNumVertices*16; - - S32 new_size = new_verts*16*2+new_tc_size; - - LLVector4a* old_buf = mPositions; - - mPositions = (LLVector4a*) ll_aligned_malloc<64>(new_size); - mNormals = mPositions+new_verts; - mTexCoords = (LLVector2*) (mNormals+new_verts); - - if (old_buf != NULL) - { - // copy old positions into new buffer - LLVector4a::memcpyNonAliased16((F32*)mPositions, (F32*)old_buf, old_vsize); - - // normals - LLVector4a::memcpyNonAliased16((F32*)mNormals, (F32*)(old_buf + mNumVertices), old_vsize); - - // tex coords - LLVector4a::memcpyNonAliased16((F32*)mTexCoords, (F32*)(old_buf + mNumVertices * 2), old_tc_size); - } - - // just clear tangents - ll_aligned_free_16(mTangents); - mTangents = NULL; - ll_aligned_free<64>(old_buf); - - mNumAllocatedVertices = new_verts; - - } - - mPositions[mNumVertices] = pos; - mNormals[mNumVertices] = norm; - mTexCoords[mNumVertices] = tc; - - mNumVertices++; -} - -void LLVolumeFace::allocateTangents(S32 num_verts) -{ - ll_aligned_free_16(mTangents); - mTangents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); -} - -void LLVolumeFace::allocateWeights(S32 num_verts) -{ - ll_aligned_free_16(mWeights); - mWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); - -} - -void LLVolumeFace::allocateJointIndices(S32 num_verts) -{ -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - ll_aligned_free_16(mJointIndices); - ll_aligned_free_16(mJustWeights); - - mJointIndices = (U8*)ll_aligned_malloc_16(sizeof(U8) * 4 * num_verts); - mJustWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * num_verts); -#endif -} - -void LLVolumeFace::resizeIndices(S32 num_indices) -{ - ll_aligned_free_16(mIndices); - llassert(num_indices % 3 == 0); - - if (num_indices) - { - //pad index block end to allow for QWORD reads - S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; - - mIndices = (U16*) ll_aligned_malloc_16(size); - } - else - { - mIndices = NULL; - } - - if (mIndices) - { - mNumIndices = num_indices; - } - else - { - // Either num_indices is zero or allocation failure - mNumIndices = 0; - } -} - -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) - { - mIndices = (U16*) ll_aligned_realloc_16(mIndices, new_size, old_size); - ll_assert_aligned(mIndices,16); - } - - mIndices[mNumIndices++] = idx; -} - -void LLVolumeFace::fillFromLegacyData(std::vector& v, std::vector& idx) -{ - resizeVertices(v.size()); - resizeIndices(idx.size()); - - for (U32 i = 0; i < v.size(); ++i) - { - 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]; - } -} - -bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - LL_CHECK_MEMORY - bool flat = mTypeMask & FLAT_MASK; - - U8 sculpt_type = volume->getParams().getSculptType(); - U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; - bool sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; - bool sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; - bool sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR - - S32 num_vertices, num_indices; - - const LLAlignedArray& mesh = volume->getMesh(); - const LLAlignedArray& profile = volume->getProfile().mProfile; - const LLAlignedArray& path_data = volume->getPath().mPath; - - S32 max_s = volume->getProfile().getTotal(); - - S32 s, t, i; - F32 ss, tt; - - num_vertices = mNumS*mNumT; - num_indices = (mNumS-1)*(mNumT-1)*6; - - partial_build = (num_vertices > mNumVertices || num_indices > mNumIndices) ? false : partial_build; - - if (!partial_build) - { - resizeVertices(num_vertices); - resizeIndices(num_indices); - - if (!volume->isMeshAssetLoaded()) - { - try - { - mEdge.resize(num_indices); - } - catch (std::bad_alloc&) - { - LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL; - return false; - } - } - } - - LL_CHECK_MEMORY - - LLVector4a* pos = (LLVector4a*) mPositions; - LLVector2* tc = (LLVector2*) mTexCoords; - F32 begin_stex = floorf(profile[mBeginS][2]); - S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; - - S32 cur_vertex = 0; - S32 end_t = mBeginT+mNumT; - bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2; - - // Copy the vertices into the array - for (t = mBeginT; t < end_t; t++) - { - tt = path_data[t].mTexT; - for (s = 0; s < num_s; s++) - { - if (mTypeMask & END_MASK) - { - if (s) - { - ss = 1.f; - } - else - { - ss = 0.f; - } - } - else - { - // Get s value for tex-coord. - S32 index = mBeginS + s; - if (index >= profile.size()) - { - // edge? - ss = flat ? 1.f - begin_stex : 1.f; - } - else if (!flat) - { - ss = profile[index][2]; - } - else - { - ss = profile[index][2] - begin_stex; - } - } - - if (sculpt_reverse_horizontal) - { - ss = 1.f - ss; - } - - // Check to see if this triangle wraps around the array. - if (mBeginS + s >= max_s) - { - // We're wrapping - i = mBeginS + s + max_s*(t-1); - } - else - { - i = mBeginS + s + max_s*t; - } - - mesh[i].store4a((F32*)(pos+cur_vertex)); - tc[cur_vertex].set(ss,tt); - - cur_vertex++; - - if (test && s > 0) - { - mesh[i].store4a((F32*)(pos+cur_vertex)); - tc[cur_vertex].set(ss,tt); - cur_vertex++; - } - } - - if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) - { - if (mTypeMask & OPEN_MASK) - { - s = num_s-1; - } - else - { - s = 0; - } - - i = mBeginS + s + max_s*t; - ss = profile[mBeginS + s][2] - begin_stex; - - mesh[i].store4a((F32*)(pos+cur_vertex)); - tc[cur_vertex].set(ss,tt); - - cur_vertex++; - } - } - LL_CHECK_MEMORY - - mCenter->clear(); - - LLVector4a* cur_pos = pos; - LLVector4a* end_pos = pos + mNumVertices; - - //get bounding box for this side - LLVector4a face_min; - LLVector4a face_max; - - face_min = face_max = *cur_pos++; - - while (cur_pos < end_pos) - { - update_min_max(face_min, face_max, *cur_pos++); - } - // VFExtents change - mExtents[0] = face_min; - mExtents[1] = face_max; - - U32 tc_count = mNumVertices; - if (tc_count%2 == 1) - { //odd number of texture coordinates, duplicate last entry to padded end of array - tc_count++; - mTexCoords[mNumVertices] = mTexCoords[mNumVertices-1]; - } - - LLVector4a* cur_tc = (LLVector4a*) mTexCoords; - LLVector4a* end_tc = (LLVector4a*) (mTexCoords+tc_count); - - LLVector4a tc_min; - LLVector4a tc_max; - - tc_min = tc_max = *cur_tc++; - - while (cur_tc < end_tc) - { - update_min_max(tc_min, tc_max, *cur_tc++); - } - - F32* minp = tc_min.getF32ptr(); - F32* maxp = tc_max.getF32ptr(); - - mTexCoordExtents[0].mV[0] = llmin(minp[0], minp[2]); - mTexCoordExtents[0].mV[1] = llmin(minp[1], minp[3]); - mTexCoordExtents[1].mV[0] = llmax(maxp[0], maxp[2]); - mTexCoordExtents[1].mV[1] = llmax(maxp[1], maxp[3]); - - mCenter->setAdd(face_min, face_max); - mCenter->mul(0.5f); - - S32 cur_index = 0; - S32 cur_edge = 0; - bool flat_face = mTypeMask & FLAT_MASK; - - if (!partial_build) - { - // Now we generate the indices. - for (t = 0; t < (mNumT-1); t++) - { - for (s = 0; s < (mNumS-1); s++) - { - mIndices[cur_index++] = s + mNumS*t; //bottom left - mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - mIndices[cur_index++] = s + mNumS*(t+1); //top left - mIndices[cur_index++] = s + mNumS*t; //bottom left - mIndices[cur_index++] = s+1 + mNumS*t; //bottom right - mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - - // bottom left/top right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; - - if (t < mNumT-2) - { // top right/top left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; - } - else if (mNumT <= 3 || volume->getPath().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on T - mEdge[cur_edge++] = s*2+1; - } - - if (s > 0) - { // top left/bottom left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; - } - else if (flat_face || volume->getProfile().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; - } - - if (t > 0) - { // bottom left/bottom right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; - } - else if (mNumT <= 3 || volume->getPath().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on T - mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; - } - - if (s < mNumS-2) - { // bottom right/top right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; - } - else if (flat_face || volume->getProfile().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t; - } - - // top right/bottom left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; - } - } - } - - LL_CHECK_MEMORY - - //clear normals - F32* dst = (F32*) mNormals; - F32* end = (F32*) (mNormals+mNumVertices); - LLVector4a zero = LLVector4a::getZero(); - - while (dst < end) - { - zero.store4a(dst); - dst += 4; - } - - LL_CHECK_MEMORY - - //generate normals - U32 count = mNumIndices/3; - - LLVector4a* norm = mNormals; - - static thread_local LLAlignedArray triangle_normals; - try - { - triangle_normals.resize(count); - } - catch (std::bad_alloc&) - { - LL_WARNS("LLVOLUME") << "Resize of triangle_normals to " << count << " failed" << LL_ENDL; - return false; - } - LLVector4a* output = triangle_normals.mArray; - LLVector4a* end_output = output+count; - - U16* idx = mIndices; - - while (output < end_output) - { - LLVector4a b,v1,v2; - b.load4a((F32*) (pos+idx[0])); - v1.load4a((F32*) (pos+idx[1])); - v2.load4a((F32*) (pos+idx[2])); - - //calculate triangle normal - LLVector4a a; - - a.setSub(b, v1); - b.sub(v2); - - - LLQuad& vector1 = *((LLQuad*) &v1); - LLQuad& vector2 = *((LLQuad*) &v2); - - LLQuad& amQ = *((LLQuad*) &a); - LLQuad& bmQ = *((LLQuad*) &b); - - //v1.setCross3(t,v0); - //setCross3(const LLVector4a& a, const LLVector4a& b) - // Vectors are stored in memory in w, z, y, x order from high to low - // Set vector1 = { a[W], a[X], a[Z], a[Y] } - vector1 = _mm_shuffle_ps( amQ, amQ, _MM_SHUFFLE( 3, 0, 2, 1 )); - // Set vector2 = { b[W], b[Y], b[X], b[Z] } - vector2 = _mm_shuffle_ps( bmQ, bmQ, _MM_SHUFFLE( 3, 1, 0, 2 )); - // mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] } - vector2 = _mm_mul_ps( vector1, vector2 ); - // vector3 = { a[W], a[Y], a[X], a[Z] } - amQ = _mm_shuffle_ps( amQ, amQ, _MM_SHUFFLE( 3, 1, 0, 2 )); - // vector4 = { b[W], b[X], b[Z], b[Y] } - bmQ = _mm_shuffle_ps( bmQ, bmQ, _MM_SHUFFLE( 3, 0, 2, 1 )); - // mQ = { 0, a[X]*b[Y] - a[Y]*b[X], a[Z]*b[X] - a[X]*b[Z], a[Y]*b[Z] - a[Z]*b[Y] } - vector1 = _mm_sub_ps( vector2, _mm_mul_ps( amQ, bmQ )); - - llassert(v1.isFinite3()); - - v1.store4a((F32*) output); - - - output++; - idx += 3; - } - - idx = mIndices; - - LLVector4a* src = triangle_normals.mArray; - - for (U32 i = 0; i < count; i++) //for each triangle - { - LLVector4a c; - c.load4a((F32*) (src++)); - - LLVector4a* n0p = norm+idx[0]; - LLVector4a* n1p = norm+idx[1]; - LLVector4a* n2p = norm+idx[2]; - - idx += 3; - - LLVector4a n0,n1,n2; - n0.load4a((F32*) n0p); - n1.load4a((F32*) n1p); - n2.load4a((F32*) n2p); - - n0.add(c); - n1.add(c); - n2.add(c); - - llassert(c.isFinite3()); - - //even out quad contributions - switch (i%2+1) - { - case 0: n0.add(c); break; - case 1: n1.add(c); break; - case 2: n2.add(c); break; - }; - - n0.store4a((F32*) n0p); - n1.store4a((F32*) n1p); - n2.store4a((F32*) n2p); - } - - LL_CHECK_MEMORY - - // adjust normals based on wrapping and stitching - - 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()) - { //wrap normals on T - for (S32 i = 0; i < mNumS; i++) - { - LLVector4a n; - n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); - norm[i] = n; - norm[mNumS*(mNumT-1)+i] = n; - } - } - - if (!volume->getProfile().isOpen() && !s_bottom_converges) - { //wrap normals on S - for (S32 i = 0; i < mNumT; i++) - { - LLVector4a n; - n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); - norm[mNumS * i] = n; - norm[mNumS * i+mNumS-1] = n; - } - } - - if (volume->getPathType() == LL_PCODE_PATH_CIRCLE && - ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) - { - if (s_bottom_converges) - { //all lower S have same normal - for (S32 i = 0; i < mNumT; i++) - { - norm[mNumS*i].set(1,0,0); - } - } - - if (s_top_converges) - { //all upper S have same normal - for (S32 i = 0; i < mNumT; i++) - { - norm[mNumS*i+mNumS-1].set(-1,0,0); - } - } - } - } - else // logic for sculpt volumes - { - bool average_poles = false; - bool wrap_s = false; - bool wrap_t = false; - - if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) - average_poles = true; - - if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || - (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || - (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) - wrap_s = true; - - if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) - wrap_t = true; - - - if (average_poles) - { - // average normals for north pole - - LLVector4a average; - average.clear(); - - for (S32 i = 0; i < mNumS; i++) - { - average.add(norm[i]); - } - - // set average - for (S32 i = 0; i < mNumS; i++) - { - norm[i] = average; - } - - // average normals for south pole - - average.clear(); - - for (S32 i = 0; i < mNumS; i++) - { - average.add(norm[i + mNumS * (mNumT - 1)]); - } - - // set average - for (S32 i = 0; i < mNumS; i++) - { - norm[i + mNumS * (mNumT - 1)] = average; - } - - } - - - if (wrap_s) - { - for (S32 i = 0; i < mNumT; i++) - { - 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++) - { - LLVector4a n; - n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); - norm[i] = n; - norm[mNumS*(mNumT-1)+i] = n; - } - } - - } - - LL_CHECK_MEMORY - - return true; -} - -//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) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME - - //LLVector4a *tan1 = new LLVector4a[vertexCount * 2]; - LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a)); - // new(tan1) LLVector4a; - - LLVector4a* tan2 = tan1 + vertexCount; - - U32 count = vertexCount * 2; - for (U32 i = 0; i < count; i++) - { - tan1[i].clear(); - } - - for (U32 a = 0; a < triangleCount; a++) - { - U32 i1 = *index_array++; - U32 i2 = *index_array++; - U32 i3 = *index_array++; - - const LLVector4a& v1 = vertex[i1]; - const LLVector4a& v2 = vertex[i2]; - const LLVector4a& v3 = vertex[i3]; - - const LLVector2& w1 = texcoord[i1]; - const LLVector2& w2 = texcoord[i2]; - const LLVector2& w3 = texcoord[i3]; - - 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) - : ((rd > 0.0f) ? 1024.f : -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); - - tan1[i1].add(sdir); - tan1[i2].add(sdir); - tan1[i3].add(sdir); - - tan2[i1].add(tdir); - tan2[i2].add(tdir); - tan2[i3].add(tdir); - } - - for (U32 a = 0; a < vertexCount; a++) - { - LLVector4a n = normal[a]; - - const LLVector4a& t = tan1[a]; - - 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(); - - // Calculate handedness - F32 handedness = ncrosst.dot3(tan2[a]).getF32() < 0.f ? -1.f : 1.f; - - tsubn.getF32ptr()[3] = handedness; - - tangent[a] = tsubn; - } - else - { //degenerate, make up a value - tangent[a].set(0,0,1,1); - } - } - - ll_aligned_free_16(tan1); -} - - +/** + * @file llvolume.cpp + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llmemory.h" +#include "llmath.h" + +#include +#if !LL_WINDOWS +#include +#endif +#include +#include + +#include "llerror.h" + +#include "llvolumemgr.h" +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llmatrix3a.h" +#include "lloctree.h" +#include "llvolume.h" +#include "llvolumeoctree.h" +#include "llstl.h" +#include "llsdserialize.h" +#include "llvector4a.h" +#include "llmatrix4a.h" +#include "llmeshoptimizer.h" +#include "lltimer.h" + +#include "mikktspace/mikktspace.h" +#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file + +#include "meshoptimizer/meshoptimizer.h" + +#define DEBUG_SILHOUETTE_BINORMALS 0 +#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette +#define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette + +constexpr F32 MIN_CUT_DELTA = 0.02f; + +constexpr F32 HOLLOW_MIN = 0.f; +constexpr F32 HOLLOW_MAX = 0.95f; +constexpr F32 HOLLOW_MAX_SQUARE = 0.7f; + +constexpr F32 TWIST_MIN = -1.f; +constexpr F32 TWIST_MAX = 1.f; + +constexpr F32 RATIO_MIN = 0.f; +constexpr F32 RATIO_MAX = 2.f; // Tom Y: Inverted sense here: 0 = top taper, 2 = bottom taper + +constexpr F32 HOLE_X_MIN= 0.05f; +constexpr F32 HOLE_X_MAX= 1.0f; + +constexpr F32 HOLE_Y_MIN= 0.05f; +constexpr F32 HOLE_Y_MAX= 0.5f; + +constexpr F32 SHEAR_MIN = -0.5f; +constexpr F32 SHEAR_MAX = 0.5f; + +constexpr F32 REV_MIN = 1.f; +constexpr F32 REV_MAX = 4.f; + +constexpr F32 TAPER_MIN = -1.f; +constexpr F32 TAPER_MAX = 1.f; + +constexpr F32 SKEW_MIN = -0.95f; +constexpr F32 SKEW_MAX = 0.95f; + +constexpr F32 SCULPT_MIN_AREA = 0.002f; +constexpr S32 SCULPT_MIN_AREA_DETAIL = 1; + +bool gDebugGL = false; // See settings.xml "RenderDebugGL" + +bool check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) +{ + LLVector3 test = (pt2-pt1)%(pt3-pt2); + + //answer + if(test * norm < 0) + { + return false; + } + else + { + return true; + } +} + +bool LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) +{ + 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[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[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; +} + +// 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) + : ((rd > 0.0f) ? 1024.f : -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. +// 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 LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_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); + + /* if determinant is near zero, ray lies in plane of triangle */ + LLVector4a det; + det.setAllDot3(edge1, pvec); + + if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7) + { + /* calculate distance from vert0 to ray origin */ + LLVector4a tvec; + tvec.setSub(orig, vert0); + + /* calculate U parameter and test bounds */ + LLVector4a u; + u.setAllDot3(tvec,pvec); + + if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) && + (u.lessEqual(det).getGatheredBits() & 0x7)) + { + /* 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.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7; + S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 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; + } + } + } + + 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); + + /* if determinant is near zero, ray lies in plane of triangle */ + F32 det = edge1.dot3(pvec).getF32(); + + + 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); + + /* calculate U parameter and test bounds */ + u = (tvec.dot3(pvec).getF32()) * inv_det; + if (u < 0.f || u > 1.f) + { + return false; + } + + /* prepare to test V parameter */ + tvec.sub(edge1); + + /* calculate V parameter and test bounds */ + v = (dir.dot3(tvec).getF32()) * inv_det; + + if (v < 0.f || u + v > 1.f) + { + return false; + } + + /* calculate t, ray intersects triangle */ + t = (edge2.dot3(tvec).getF32()) * inv_det; + + intersection_a = u; + intersection_b = v; + intersection_t = t; + + + return true; +} + +class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst +{ +public: + const LLVolumeFace* mFace; + + LLVolumeOctreeRebound(const LLVolumeFace* face) + { + mFace = face; + } + + virtual void visit(const LLOctreeNode* branch) + { //this is a depth first traversal, so it's safe to assum all children have complete + //bounding data + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); + + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + if (!branch->isEmpty()) + { //node has data, find AABB that binds data set + const LLVolumeTriangle* tri = *(branch->getDataBegin()); + + //initialize min/max to first available vertex + min = *(tri->mV[0]); + max = *(tri->mV[0]); + + for (LLOctreeNode::const_element_iter iter = branch->getDataBegin(); iter != branch->getDataEnd(); ++iter) + { //for each triangle in node + + //stretch by triangles in node + tri = *iter; + + min.setMin(min, *tri->mV[0]); + min.setMin(min, *tri->mV[1]); + min.setMin(min, *tri->mV[2]); + + max.setMax(max, *tri->mV[0]); + max.setMax(max, *tri->mV[1]); + max.setMax(max, *tri->mV[2]); + } + } + else if (branch->getChildCount() > 0) + { //no data, but child nodes exist + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); + + //initialize min/max to extents of first child + min = child->mExtents[0]; + max = child->mExtents[1]; + } + else + { + llassert(!branch->isLeaf()); // Empty leaf + } + + for (S32 i = 0; i < branch->getChildCount(); ++i) + { //stretch by child extents + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + min.setMin(min, child->mExtents[0]); + max.setMax(max, child->mExtents[1]); + } + + node->mBounds[0].setAdd(min, max); + node->mBounds[0].mul(0.5f); + + node->mBounds[1].setSub(max,min); + node->mBounds[1].mul(0.5f); + } +}; + +//------------------------------------------------------------------- +// statics +//------------------------------------------------------------------- + + +//---------------------------------------------------- + +LLProfile::Face* LLProfile::addCap(S16 faceID) +{ + Face *face = vector_append(mFaces, 1); + + face->mIndex = 0; + face->mCount = mTotal; + face->mScaleU= 1.0f; + face->mCap = true; + face->mFaceID = faceID; + return face; +} + +LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, bool flat) +{ + Face *face = vector_append(mFaces, 1); + + face->mIndex = i; + face->mCount = count; + face->mScaleU= scaleU; + + face->mFlat = flat; + face->mCap = false; + face->mFaceID = faceID; + return face; +} + +//static +S32 LLProfile::getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) +{ // this is basically LLProfile::genNGon stripped down to only the operations that influence the number of points + S32 np = 0; + + // Generate an n-sided "circular" path. + // 0 is (1,0), and we go counter-clockwise along a circular path from there. + F32 t, t_step, t_first, t_fraction; + + F32 begin = params.getBegin(); + F32 end = params.getEnd(); + + t_step = 1.0f / sides; + + t_first = floor(begin * sides) / (F32)sides; + + // pt1 is the first point on the fractional face. + // Starting t and ang values for the first face + t = t_first; + + // Increment to the next point. + // pt2 is the end point on the fractional face + t += t_step; + + t_fraction = (begin - t_first)*sides; + + // Only use if it's not almost exactly on an edge. + if (t_fraction < 0.9999f) + { + np++; + } + + // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 + while (t < end) + { + // Iterate through all the integer steps of t. + np++; + + t += t_step; + } + + t_fraction = (end - (t - t_step))*sides; + + // Find the fraction that we need to add to the end point. + t_fraction = (end - (t - t_step))*sides; + if (t_fraction > 0.0001f) + { + np++; + } + + // If we're sliced, the profile is open. + if ((end - begin)*ang_scale < 0.99f) + { + if (params.getHollow() <= 0) + { + // put center point if not hollow. + np++; + } + } + + return np; +} + +// What is the bevel parameter used for? - DJS 04/05/02 +// Bevel parameter is currently unused but presumedly would support +// filleted and chamfered corners +void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split) +{ + // Generate an n-sided "circular" path. + // 0 is (1,0), and we go counter-clockwise along a circular path from there. + constexpr F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + F32 scale = 0.5f; + F32 t, t_step, t_first, t_fraction, ang, ang_step; + LLVector4a pt1,pt2; + + F32 begin = params.getBegin(); + F32 end = params.getEnd(); + + t_step = 1.0f / sides; + ang_step = 2.0f*F_PI*t_step*ang_scale; + + // Scale to have size "match" scale. Compensates to get object to generally fill bounding box. + + S32 total_sides = ll_round(sides / ang_scale); // Total number of sides all around + + if (total_sides < 8) + { + scale = tableScale[total_sides]; + } + + t_first = floor(begin * sides) / (F32)sides; + + // pt1 is the first point on the fractional face. + // Starting t and ang values for the first face + t = t_first; + ang = 2.0f*F_PI*(t*ang_scale + offset); + pt1.set(cos(ang)*scale,sin(ang)*scale, t); + + // Increment to the next point. + // pt2 is the end point on the fractional face + t += t_step; + ang += ang_step; + pt2.set(cos(ang)*scale,sin(ang)*scale,t); + + t_fraction = (begin - t_first)*sides; + + // Only use if it's not almost exactly on an edge. + if (t_fraction < 0.9999f) + { + LLVector4a new_pt; + new_pt.setLerp(pt1, pt2, t_fraction); + mProfile.push_back(new_pt); + } + + // There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02 + while (t < end) + { + // Iterate through all the integer steps of t. + pt1.set(cos(ang)*scale,sin(ang)*scale,t); + + if (mProfile.size() > 0) { + LLVector4a p = mProfile[mProfile.size()-1]; + for (S32 i = 0; i < split && mProfile.size() > 0; i++) { + //mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); + LLVector4a new_pt; + new_pt.setSub(pt1, p); + new_pt.mul(1.0f/(float)(split+1) * (float)(i+1)); + new_pt.add(p); + mProfile.push_back(new_pt); + } + } + mProfile.push_back(pt1); + + t += t_step; + ang += ang_step; + } + + t_fraction = (end - (t - t_step))*sides; + + // pt1 is the first point on the fractional face + // pt2 is the end point on the fractional face + pt2.set(cos(ang)*scale,sin(ang)*scale,t); + + // Find the fraction that we need to add to the end point. + t_fraction = (end - (t - t_step))*sides; + if (t_fraction > 0.0001f) + { + LLVector4a new_pt; + new_pt.setLerp(pt1, pt2, t_fraction); + + if (mProfile.size() > 0) { + LLVector4a p = mProfile[mProfile.size()-1]; + for (S32 i = 0; i < split && mProfile.size() > 0; i++) { + //mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); + + LLVector4a pt1; + pt1.setSub(new_pt, p); + pt1.mul(1.0f/(float)(split+1) * (float)(i+1)); + pt1.add(p); + mProfile.push_back(pt1); + } + } + mProfile.push_back(new_pt); + } + + // If we're sliced, the profile is open. + if ((end - begin)*ang_scale < 0.99f) + { + if ((end - begin)*ang_scale > 0.5f) + { + mConcave = true; + } + else + { + mConcave = false; + } + mOpen = true; + if (params.getHollow() <= 0) + { + // put center point if not hollow. + mProfile.push_back(LLVector4a(0,0,0)); + } + } + else + { + // The profile isn't open. + mOpen = false; + mConcave = false; + } + + mTotal = mProfile.size(); +} + +// Hollow is percent of the original bounding box, not of this particular +// profile's geometry. Thus, a swept triangle needs lower hollow values than +// a swept square. +LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, bool flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split) +{ + // Note that addHole will NOT work for non-"circular" profiles, if we ever decide to use them. + + // Total add has number of vertices on outside. + mTotalOut = mTotal; + + // Why is the "bevel" parameter -1? DJS 04/05/02 + genNGon(params, llfloor(sides),offset,-1, ang_scale, split); + + Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); + + static thread_local LLAlignedArray pt; + pt.resize(mTotal) ; + + for (S32 i=mTotalOut;i end - 0.01f) + { + LL_WARNS() << "LLProfile::generate() assertion failed (begin >= end)" << LL_ENDL; + return false; + } + + S32 face_num = 0; + + switch (params.getCurveType() & LL_PCODE_PROFILE_MASK) + { + case LL_PCODE_PROFILE_SQUARE: + { + genNGon(params, 4,-0.375, 0, 1, split); + if (path_open) + { + addCap (LL_FACE_PATH_BEGIN); + } + + for (i = llfloor(begin * 4.f); i < llfloor(end * 4.f + .999f); i++) + { + addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, true); + } + + LLVector4a scale(1,1,4,1); + + for (i = 0; i <(S32) mProfile.size(); i++) + { + // Scale by 4 to generate proper tex coords. + mProfile[i].mul(scale); + llassert(mProfile[i].isFinite3()); + } + + if (hollow) + { + switch (params.getCurveType() & LL_PCODE_HOLE_MASK) + { + case LL_PCODE_HOLE_TRIANGLE: + // This offset is not correct, but we can't change it now... DK 11/17/04 + addHole(params, true, 3, -0.375f, hollow, 1.f, split); + break; + case LL_PCODE_HOLE_CIRCLE: + // TODO: Compute actual detail levels for cubes + addHole(params, false, MIN_DETAIL_FACES * detail, -0.375f, hollow, 1.f); + break; + case LL_PCODE_HOLE_SAME: + case LL_PCODE_HOLE_SQUARE: + default: + addHole(params, true, 4, -0.375f, hollow, 1.f, split); + break; + } + } + + if (path_open) { + mFaces[0].mCount = mTotal; + } + } + break; + case LL_PCODE_PROFILE_ISOTRI: + case LL_PCODE_PROFILE_RIGHTTRI: + case LL_PCODE_PROFILE_EQUALTRI: + { + genNGon(params, 3,0, 0, 1, split); + LLVector4a scale(1,1,3,1); + for (i = 0; i <(S32) mProfile.size(); i++) + { + // Scale by 3 to generate proper tex coords. + mProfile[i].mul(scale); + llassert(mProfile[i].isFinite3()); + } + + if (path_open) + { + addCap(LL_FACE_PATH_BEGIN); + } + + for (i = llfloor(begin * 3.f); i < llfloor(end * 3.f + .999f); i++) + { + addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, true); + } + if (hollow) + { + // Swept triangles need smaller hollowness values, + // because the triangle doesn't fill the bounding box. + F32 triangle_hollow = hollow / 2.f; + + switch (params.getCurveType() & LL_PCODE_HOLE_MASK) + { + case LL_PCODE_HOLE_CIRCLE: + // TODO: Actually generate level of detail for triangles + addHole(params, false, MIN_DETAIL_FACES * detail, 0, triangle_hollow, 1.f); + break; + case LL_PCODE_HOLE_SQUARE: + addHole(params, true, 4, 0, triangle_hollow, 1.f, split); + break; + case LL_PCODE_HOLE_SAME: + case LL_PCODE_HOLE_TRIANGLE: + default: + addHole(params, true, 3, 0, triangle_hollow, 1.f, split); + break; + } + } + } + break; + case LL_PCODE_PROFILE_CIRCLE: + { + // If this has a square hollow, we should adjust the + // number of faces a bit so that the geometry lines up. + U8 hole_type=0; + F32 circle_detail = MIN_DETAIL_FACES * detail; + if (hollow) + { + hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; + if (hole_type == LL_PCODE_HOLE_SQUARE) + { + // Snap to the next multiple of four sides, + // so that corners line up. + circle_detail = llceil(circle_detail / 4.0f) * 4.0f; + } + } + + S32 sides = (S32)circle_detail; + + if (is_sculpted) + sides = sculpt_size; + + genNGon(params, sides); + + if (path_open) + { + addCap (LL_FACE_PATH_BEGIN); + } + + if (mOpen && !hollow) + { + addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, false); + } + else + { + addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, false); + } + + if (hollow) + { + switch (hole_type) + { + case LL_PCODE_HOLE_SQUARE: + addHole(params, true, 4, 0, hollow, 1.f, split); + break; + case LL_PCODE_HOLE_TRIANGLE: + addHole(params, true, 3, 0, hollow, 1.f, split); + break; + case LL_PCODE_HOLE_CIRCLE: + case LL_PCODE_HOLE_SAME: + default: + addHole(params, true, circle_detail, 0, hollow, 1.f); + break; + } + } + } + break; + case LL_PCODE_PROFILE_CIRCLE_HALF: + { + // If this has a square hollow, we should adjust the + // number of faces a bit so that the geometry lines up. + U8 hole_type=0; + // Number of faces is cut in half because it's only a half-circle. + F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f; + if (hollow) + { + hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK; + if (hole_type == LL_PCODE_HOLE_SQUARE) + { + // Snap to the next multiple of four sides (div 2), + // so that corners line up. + circle_detail = llceil(circle_detail / 2.0f) * 2.0f; + } + } + genNGon(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f); + if (path_open) + { + addCap(LL_FACE_PATH_BEGIN); + } + if (mOpen && !params.getHollow()) + { + addFace(0,mTotal-1,0,LL_FACE_OUTER_SIDE_0, false); + } + else + { + addFace(0,mTotal,0,LL_FACE_OUTER_SIDE_0, false); + } + + if (hollow) + { + switch (hole_type) + { + case LL_PCODE_HOLE_SQUARE: + addHole(params, true, 2, 0.5f, hollow, 0.5f, split); + break; + case LL_PCODE_HOLE_TRIANGLE: + addHole(params, true, 3, 0.5f, hollow, 0.5f, split); + break; + case LL_PCODE_HOLE_CIRCLE: + case LL_PCODE_HOLE_SAME: + default: + addHole(params, false, circle_detail, 0.5f, hollow, 0.5f); + break; + } + } + + // Special case for openness of sphere + if ((params.getEnd() - params.getBegin()) < 1.f) + { + mOpen = true; + } + else if (!hollow) + { + mOpen = false; + mProfile.push_back(mProfile[0]); + mTotal++; + } + } + break; + default: + LL_ERRS() << "Unknown profile: getCurveType()=" << params.getCurveType() << LL_ENDL; + break; + }; + + if (path_open) + { + addCap(LL_FACE_PATH_END); // bottom + } + + if ( mOpen) // interior edge caps + { + addFace(mTotal-1, 2,0.5,LL_FACE_PROFILE_BEGIN, true); + + if (hollow) + { + addFace(mTotalOut-1, 2,0.5,LL_FACE_PROFILE_END, true); + } + else + { + addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, true); + } + } + + return true; +} + + + +bool LLProfileParams::importFile(LLFILE *fp) +{ + const S32 BUFSIZE = 16384; + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + // *NOTE: changing the size or type of these buffers will require + // changing the sscanf below. + char keyword[256]; /* Flawfinder: ignore */ + char valuestr[256]; /* Flawfinder: ignore */ + keyword[0] = 0; + valuestr[0] = 0; + F32 tempF32; + U32 tempU32; + + while (!feof(fp)) + { + if (fgets(buffer, BUFSIZE, fp) == NULL) + { + buffer[0] = '\0'; + } + + sscanf( /* Flawfinder: ignore */ + buffer, + " %255s %255s", + keyword, valuestr); + if (!strcmp("{", keyword)) + { + continue; + } + if (!strcmp("}",keyword)) + { + break; + } + else if (!strcmp("curve", keyword)) + { + sscanf(valuestr,"%d",&tempU32); + setCurveType((U8) tempU32); + } + else if (!strcmp("begin",keyword)) + { + sscanf(valuestr,"%g",&tempF32); + setBegin(tempF32); + } + else if (!strcmp("end",keyword)) + { + sscanf(valuestr,"%g",&tempF32); + setEnd(tempF32); + } + else if (!strcmp("hollow",keyword)) + { + sscanf(valuestr,"%g",&tempF32); + setHollow(tempF32); + } + else + { + LL_WARNS() << "unknown keyword " << keyword << " in profile import" << LL_ENDL; + } + } + + return true; +} + + +bool LLProfileParams::exportFile(LLFILE *fp) const +{ + fprintf(fp,"\t\tprofile 0\n"); + fprintf(fp,"\t\t{\n"); + fprintf(fp,"\t\t\tcurve\t%d\n", getCurveType()); + fprintf(fp,"\t\t\tbegin\t%g\n", getBegin()); + fprintf(fp,"\t\t\tend\t%g\n", getEnd()); + fprintf(fp,"\t\t\thollow\t%g\n", getHollow()); + fprintf(fp, "\t\t}\n"); + return true; +} + + +bool LLProfileParams::importLegacyStream(std::istream& input_stream) +{ + const S32 BUFSIZE = 16384; + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + // *NOTE: changing the size or type of these buffers will require + // changing the sscanf below. + char keyword[256]; /* Flawfinder: ignore */ + char valuestr[256]; /* Flawfinder: ignore */ + keyword[0] = 0; + valuestr[0] = 0; + F32 tempF32; + U32 tempU32; + + while (input_stream.good()) + { + input_stream.getline(buffer, BUFSIZE); + sscanf( /* Flawfinder: ignore */ + buffer, + " %255s %255s", + keyword, + valuestr); + if (!strcmp("{", keyword)) + { + continue; + } + if (!strcmp("}",keyword)) + { + break; + } + else if (!strcmp("curve", keyword)) + { + sscanf(valuestr,"%d",&tempU32); + setCurveType((U8) tempU32); + } + else if (!strcmp("begin",keyword)) + { + sscanf(valuestr,"%g",&tempF32); + setBegin(tempF32); + } + else if (!strcmp("end",keyword)) + { + sscanf(valuestr,"%g",&tempF32); + setEnd(tempF32); + } + else if (!strcmp("hollow",keyword)) + { + sscanf(valuestr,"%g",&tempF32); + setHollow(tempF32); + } + else + { + LL_WARNS() << "unknown keyword " << keyword << " in profile import" << LL_ENDL; + } + } + + return true; +} + + +bool LLProfileParams::exportLegacyStream(std::ostream& output_stream) const +{ + output_stream <<"\t\tprofile 0\n"; + output_stream <<"\t\t{\n"; + output_stream <<"\t\t\tcurve\t" << (S32) getCurveType() << "\n"; + output_stream <<"\t\t\tbegin\t" << getBegin() << "\n"; + output_stream <<"\t\t\tend\t" << getEnd() << "\n"; + output_stream <<"\t\t\thollow\t" << getHollow() << "\n"; + output_stream << "\t\t}\n"; + return true; +} + +LLSD LLProfileParams::asLLSD() const +{ + LLSD sd; + + sd["curve"] = getCurveType(); + sd["begin"] = getBegin(); + sd["end"] = getEnd(); + sd["hollow"] = getHollow(); + return sd; +} + +bool LLProfileParams::fromLLSD(LLSD& sd) +{ + setCurveType(sd["curve"].asInteger()); + setBegin((F32)sd["begin"].asReal()); + setEnd((F32)sd["end"].asReal()); + setHollow((F32)sd["hollow"].asReal()); + return true; +} + +void LLProfileParams::copyParams(const LLProfileParams ¶ms) +{ + setCurveType(params.getCurveType()); + setBegin(params.getBegin()); + setEnd(params.getEnd()); + setHollow(params.getHollow()); +} + + +LLPath::~LLPath() +{ +} + +S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) +{ //this is basically LLPath::genNGon stripped down to only operations that influence the number of points added + S32 ret = 0; + + F32 step= 1.0f / sides; + F32 t = params.getBegin(); + ret = 1; + + t+=step; + + // Snap to a quantized parameter, so that cut does not + // affect most sample points. + t = ((S32)(t * sides)) / (F32)sides; + + // Run through the non-cut dependent points. + while (t < params.getEnd()) + { + ret++; + t+=step; + } + + ret++; + + return ret; +} + +void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. + constexpr F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + + F32 revolutions = params.getRevolutions(); + F32 skew = params.getSkew(); + F32 skew_mag = fabs(skew); + F32 hole_x = params.getScaleX() * (1.0f - skew_mag); + F32 hole_y = params.getScaleY(); + + // Calculate taper begin/end for x,y (Negative means taper the beginning) + F32 taper_x_begin = 1.0f; + F32 taper_x_end = 1.0f - params.getTaperX(); + F32 taper_y_begin = 1.0f; + F32 taper_y_end = 1.0f - params.getTaperY(); + + if ( taper_x_end > 1.0f ) + { + // Flip tapering. + taper_x_begin = 2.0f - taper_x_end; + taper_x_end = 1.0f; + } + if ( taper_y_end > 1.0f ) + { + // Flip tapering. + taper_y_begin = 2.0f - taper_y_end; + taper_y_end = 1.0f; + } + + // For spheres, the radius is usually zero. + F32 radius_start = 0.5f; + if (sides < 8) + { + radius_start = tableScale[sides]; + } + + // Scale the radius to take the hole size into account. + radius_start *= 1.0f - hole_y; + + // Now check the radius offset to calculate the start,end radius. (Negative means + // decrease the start radius instead). + F32 radius_end = radius_start; + F32 radius_offset = params.getRadiusOffset(); + if (radius_offset < 0.f) + { + radius_start *= 1.f + radius_offset; + } + else + { + radius_end *= 1.f - radius_offset; + } + + // Is the path NOT a closed loop? + mOpen = ( (params.getEnd()*end_scale - params.getBegin() < 1.0f) || + (skew_mag > 0.001f) || + (fabs(taper_x_end - taper_x_begin) > 0.001f) || + (fabs(taper_y_end - taper_y_begin) > 0.001f) || + (fabs(radius_end - radius_start) > 0.001f) ); + + F32 ang, c, s; + LLQuaternion twist, qang; + PathPt *pt; + LLVector3 path_axis (1.f, 0.f, 0.f); + //LLVector3 twist_axis(0.f, 0.f, 1.f); + F32 twist_begin = params.getTwistBegin() * twist_scale; + F32 twist_end = params.getTwist() * twist_scale; + + // We run through this once before the main loop, to make sure + // the path begins at the correct cut. + F32 step= 1.0f / sides; + F32 t = params.getBegin(); + pt = mPath.append(1); + ang = 2.0f*F_PI*revolutions * t; + s = sin(ang)*lerp(radius_start, radius_end, t); + c = cos(ang)*lerp(radius_start, radius_end, t); + + + pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) + + lerp(-skew ,skew, t) * 0.5f, + c + lerp(0,params.getShear().mV[1],s), + s); + pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), + hole_y * lerp(taper_y_begin, taper_y_end, t), + 0,1); + pt->mTexT = t; + + // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 + twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); + // Rotate the point around the circle's center. + qang.setQuat (ang,path_axis); + + LLMatrix3 rot(twist * qang); + + pt->mRot.loadu(rot); + + t+=step; + + // Snap to a quantized parameter, so that cut does not + // affect most sample points. + t = ((S32)(t * sides)) / (F32)sides; + + // Run through the non-cut dependent points. + while (t < params.getEnd()) + { + pt = mPath.append(1); + + ang = 2.0f*F_PI*revolutions * t; + c = cos(ang)*lerp(radius_start, radius_end, t); + s = sin(ang)*lerp(radius_start, radius_end, t); + + pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) + + lerp(-skew ,skew, t) * 0.5f, + c + lerp(0,params.getShear().mV[1],s), + s); + + pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), + hole_y * lerp(taper_y_begin, taper_y_end, t), + 0,1); + pt->mTexT = t; + + // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 + twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); + // Rotate the point around the circle's center. + qang.setQuat (ang,path_axis); + LLMatrix3 tmp(twist*qang); + pt->mRot.loadu(tmp); + + t+=step; + } + + // Make one final pass for the end cut. + t = params.getEnd(); + pt = mPath.append(1); + ang = 2.0f*F_PI*revolutions * t; + c = cos(ang)*lerp(radius_start, radius_end, t); + s = sin(ang)*lerp(radius_start, radius_end, t); + + pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) + + lerp(-skew ,skew, t) * 0.5f, + c + lerp(0,params.getShear().mV[1],s), + s); + pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), + hole_y * lerp(taper_y_begin, taper_y_end, t), + 0,1); + pt->mTexT = t; + + // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 + twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); + // Rotate the point around the circle's center. + qang.setQuat (ang,path_axis); + LLMatrix3 tmp(twist*qang); + pt->mRot.loadu(tmp); + + mTotal = mPath.size(); +} + +const LLVector2 LLPathParams::getBeginScale() const +{ + LLVector2 begin_scale(1.f, 1.f); + if (getScaleX() > 1) + { + begin_scale.mV[0] = 2-getScaleX(); + } + if (getScaleY() > 1) + { + begin_scale.mV[1] = 2-getScaleY(); + } + return begin_scale; +} + +const LLVector2 LLPathParams::getEndScale() const +{ + LLVector2 end_scale(1.f, 1.f); + if (getScaleX() < 1) + { + end_scale.mV[0] = getScaleX(); + } + if (getScaleY() < 1) + { + end_scale.mV[1] = getScaleY(); + } + return end_scale; +} + +S32 LLPath::getNumPoints(const LLPathParams& params, F32 detail) +{ // this is basically LLPath::generate stripped down to only the operations that influence the number of points + if (detail < MIN_LOD) + { + detail = MIN_LOD; + } + + S32 np = 2; // hardcode for line + + // Is this 0xf0 mask really necessary? DK 03/02/05 + + switch (params.getCurveType() & 0xf0) + { + default: + case LL_PCODE_PATH_LINE: + { + // Take the begin/end twist into account for detail. + np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; + } + break; + + case LL_PCODE_PATH_CIRCLE: + { + // Increase the detail as the revolutions and twist increase. + F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist()); + + S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions()); + + np = sides; + } + break; + + case LL_PCODE_PATH_CIRCLE2: + { + //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); + np = getNumNGonPoints(params, llfloor(MIN_DETAIL_FACES * detail)); + } + break; + + case LL_PCODE_PATH_TEST: + + np = 5; + break; + }; + + return np; +} + +bool LLPath::generate(const LLPathParams& params, F32 detail, S32 split, + bool is_sculpted, S32 sculpt_size) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + if ((!mDirty) && (!is_sculpted)) + { + return false; + } + + if (detail < MIN_LOD) + { + LL_INFOS() << "Generating path with LOD < MIN! Clamping to 1" << LL_ENDL; + detail = MIN_LOD; + } + + mDirty = false; + S32 np = 2; // hardcode for line + + mPath.resize(0); + mOpen = true; + + // Is this 0xf0 mask really necessary? DK 03/02/05 + switch (params.getCurveType() & 0xf0) + { + default: + case LL_PCODE_PATH_LINE: + { + // Take the begin/end twist into account for detail. + np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2; + if (np < split+2) + { + np = split+2; + } + + mStep = 1.0f / (np-1); + + mPath.resize(np); + + LLVector2 start_scale = params.getBeginScale(); + LLVector2 end_scale = params.getEndScale(); + + for (S32 i=0;i= 0.99f && + params.getScaleX() >= .99f) + { + mOpen = false; + } + + //genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f); + genNGon(params, llfloor(MIN_DETAIL_FACES * detail)); + + F32 toggle = 0.5f; + for (S32 i=0;i<(S32)mPath.size();i++) + { + mPath[i].mPos.getF32ptr()[0] = toggle; + if (toggle == 0.5f) + toggle = -0.5f; + else + toggle = 0.5f; + } + } + + break; + + case LL_PCODE_PATH_TEST: + + np = 5; + mStep = 1.0f / (np-1); + + mPath.resize(np); + + for (S32 i=0;iresizePath(length); + mVolumeFaces.clear(); + setDirty(); +} + +void LLVolume::regen() +{ + generate(); + createVolumeFaces(); +} + +void LLVolume::genTangents(S32 face) +{ + // generate legacy tangents for the specified face + llassert(!isMeshAssetLoaded() || mVolumeFaces[face].mTangents != nullptr); // if this is a complete mesh asset, we should already have tangents + mVolumeFaces[face].createTangents(); +} + +LLVolume::~LLVolume() +{ + sNumMeshPoints -= mMesh.size(); + delete mPathp; + + delete mProfilep; + + mPathp = NULL; + mProfilep = NULL; + mVolumeFaces.clear(); + + ll_aligned_free_16(mHullPoints); + mHullPoints = NULL; + ll_aligned_free_16(mHullIndices); + mHullIndices = NULL; +} + +bool LLVolume::generate() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + LL_CHECK_MEMORY + llassert_always(mProfilep); + + //Added 10.03.05 Dave Parks + // Split is a parameter to LLProfile::generate that tesselates edges on the profile + // to prevent lighting and texture interpolation errors on triangles that are + // stretched due to twisting or scaling on the path. + S32 split = (S32) ((mDetail)*0.66f); + + if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_LINE && + (mParams.getPathParams().getScale().mV[0] != 1.0f || + mParams.getPathParams().getScale().mV[1] != 1.0f) && + (mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_SQUARE || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_ISOTRI || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_EQUALTRI || + mParams.getProfileParams().getCurveType() == LL_PCODE_PROFILE_RIGHTTRI)) + { + split = 0; + } + + mLODScaleBias.setVec(0.5f, 0.5f, 0.5f); + + F32 profile_detail = mDetail; + F32 path_detail = mDetail; + + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + U8 path_type = mParams.getPathParams().getCurveType(); + U8 profile_type = mParams.getProfileParams().getCurveType(); + if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) + { + //cylinders don't care about Z-Axis + mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); + } + else if (path_type == LL_PCODE_PATH_CIRCLE) + { + mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + } + } + + bool regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); + bool regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); + + if (regenPath || regenProf ) + { + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + sNumMeshPoints -= mMesh.size(); + mMesh.resize(sizeT * sizeS); + sNumMeshPoints += mMesh.size(); + + //generate vertex positions + + // Run along the path. + LLVector4a* dst = mMesh.mArray; + + for (S32 s = 0; s < sizeS; ++s) + { + F32* scale = mPathp->mPath[s].mScale.getF32ptr(); + + F32 sc [] = + { scale[0], 0, 0, 0, + 0, scale[1], 0, 0, + 0, 0, scale[2], 0, + 0, 0, 0, 1 }; + + LLMatrix4 rot((F32*) mPathp->mPath[s].mRot.mMatrix); + LLMatrix4 scale_mat(sc); + + scale_mat *= rot; + + LLMatrix4a rot_mat; + rot_mat.loadu(scale_mat); + + LLVector4a* profile = mProfilep->mProfile.mArray; + LLVector4a* end_profile = profile+sizeT; + LLVector4a offset = mPathp->mPath[s].mPos; + + // hack to work around MAINT-5660 for debug until we can suss out + // what is wrong with the path generated that inserts NaNs... + if (!offset.isFinite3()) + { + offset.clear(); + } + + LLVector4a tmp; + + // Run along the profile. + while (profile < end_profile) + { + rot_mat.rotate(*profile++, tmp); + dst->setAdd(tmp,offset); + ++dst; + } + } + + for (std::vector::iterator iter = mProfilep->mFaces.begin(); + iter != mProfilep->mFaces.end(); ++iter) + { + LLFaceID id = iter->mFaceID; + mFaceMask |= id; + } + LL_CHECK_MEMORY + return true; + } + + LL_CHECK_MEMORY + return false; +} + +void LLVolumeFace::VertexData::init() +{ + if (!mData) + { + mData = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2); + } +} + +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, 2*sizeof(LLVector4a)); + mTexCoord = rhs.mTexCoord; + } + return *this; +} + +LLVolumeFace::VertexData::~VertexData() +{ + ll_aligned_free_16(mData); + mData = NULL; +} + +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 +{ + const F32* lp = this->getPosition().getF32ptr(); + const F32* rp = rhs.getPosition().getF32ptr(); + + if (lp[0] != rp[0]) + { + return lp[0] < rp[0]; + } + + if (rp[1] != lp[1]) + { + return lp[1] < rp[1]; + } + + if (rp[2] != lp[2]) + { + return lp[2] < rp[2]; + } + + lp = getNormal().getF32ptr(); + rp = rhs.getNormal().getF32ptr(); + + if (lp[0] != rp[0]) + { + return lp[0] < rp[0]; + } + + if (rp[1] != lp[1]) + { + return lp[1] < rp[1]; + } + + if (rp[2] != lp[2]) + { + return lp[2] < rp[2]; + } + + if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0]) + { + return mTexCoord.mV[0] < rhs.mTexCoord.mV[0]; + } + + return mTexCoord.mV[1] < rhs.mTexCoord.mV[1]; +} + +bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const +{ + return mData[POSITION].equals3(rhs.getPosition()) && + mData[NORMAL].equals3(rhs.getNormal()) && + mTexCoord == rhs.mTexCoord; +} + +bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const +{ + bool retval = false; + + const F32 epsilon = 0.00001f; + + if (rhs.mData[POSITION].equals3(mData[POSITION], epsilon) && + fabs(rhs.mTexCoord[0]-mTexCoord[0]) < epsilon && + fabs(rhs.mTexCoord[1]-mTexCoord[1]) < epsilon) + { + if (angle_cutoff > 1.f) + { + retval = (mData[NORMAL].equals3(rhs.mData[NORMAL], epsilon)); + } + else + { + F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32(); + retval = cur_angle > angle_cutoff; + } + } + + return retval; +} + +bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + //input stream is now pointing at a zlib compressed block of LLSD + //decompress block + LLSD mdl; + U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size); + if (uzip_result != LLUZipHelper::ZR_OK) + { + LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL; + return false; + } + return unpackVolumeFacesInternal(mdl); +} + +bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size) +{ + //input data is now pointing at a zlib compressed block of LLSD + //decompress block + LLSD mdl; + U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size); + if (uzip_result != LLUZipHelper::ZR_OK) + { + LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL; + return false; + } + return unpackVolumeFacesInternal(mdl); +} + +bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) +{ + { + U32 face_count = mdl.size(); + + if (face_count == 0) + { //no faces unpacked, treat as failed decode + LL_WARNS() << "found no faces!" << LL_ENDL; + return false; + } + + mVolumeFaces.resize(face_count); + + for (size_t i = 0; i < face_count; ++i) + { + LLVolumeFace& face = mVolumeFaces[i]; + + if (mdl[i].has("NoGeometry")) + { //face has no geometry, continue + face.resizeIndices(3); + face.resizeVertices(1); + face.mPositions->clear(); + face.mNormals->clear(); + face.mTexCoords->setZero(); + memset(face.mIndices, 0, sizeof(U16)*3); + continue; + } + + LLSD::Binary pos = mdl[i]["Position"]; + LLSD::Binary norm = mdl[i]["Normal"]; + LLSD::Binary tangent = mdl[i]["Tangent"]; + LLSD::Binary tc = mdl[i]["TexCoord0"]; + LLSD::Binary idx = mdl[i]["TriangleList"]; + + //copy out indices + S32 num_indices = idx.size() / 2; + const S32 indices_to_discard = num_indices % 3; + if (indices_to_discard > 0) + { + // Invalid number of triangle indices + LL_WARNS() << "Incomplete triangle discarded from face! Indices count " << num_indices << " was not divisible by 3. face index: " << i << " Total: " << face_count << LL_ENDL; + num_indices -= indices_to_discard; + } + face.resizeIndices(num_indices); + + if (num_indices > 2 && !face.mIndices) + { + LL_WARNS() << "Failed to allocate " << num_indices << " indices for face index: " << i << " Total: " << face_count << LL_ENDL; + continue; + } + + if (idx.empty() || face.mNumIndices < 3) + { //why is there an empty index list? + LL_WARNS() << "Empty face present! Face index: " << i << " Total: " << face_count << LL_ENDL; + continue; + } + + U16* indices = (U16*) &(idx[0]); + for (U32 j = 0; j < num_indices; ++j) + { + face.mIndices[j] = indices[j]; + } + + //copy out vertices + U32 num_verts = pos.size()/(3*2); + face.resizeVertices(num_verts); + + if (num_verts > 0 && !face.mPositions) + { + LL_WARNS() << "Failed to allocate " << num_verts << " vertices for face index: " << i << " Total: " << face_count << LL_ENDL; + face.resizeIndices(0); + continue; + } + + 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"]); + + //unpack normalized scale/translation + if (mdl[i].has("NormalizedScale")) + { + face.mNormalizedScale.setValue(mdl[i]["NormalizedScale"]); + } + else + { + face.mNormalizedScale.set(1, 1, 1); + } + + LLVector4a pos_range; + pos_range.setSub(max_pos, min_pos); + LLVector2 tc_range2 = max_tc - min_tc; + + LLVector4a tc_range; + tc_range.set(tc_range2[0], tc_range2[1], tc_range2[0], tc_range2[1]); + LLVector4a min_tc4(min_tc[0], min_tc[1], min_tc[0], min_tc[1]); + + LLVector4a* pos_out = face.mPositions; + LLVector4a* norm_out = face.mNormals; + LLVector4a* tc_out = (LLVector4a*) face.mTexCoords; + + { + U16* v = (U16*) &(pos[0]); + for (U32 j = 0; j < num_verts; ++j) + { + 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); + pos_out++; + v += 3; + } + + } + + { + if (!norm.empty()) + { + U16* n = (U16*) &(norm[0]); + for (U32 j = 0; j < num_verts; ++j) + { + 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++; + n += 3; + } + } + else + { + for (U32 j = 0; j < num_verts; ++j) + { + norm_out->clear(); + norm_out++; // or just norm_out[j].clear(); + } + } + } + +#if 0 // keep this code for now in case we decide to add support for on-the-wire tangents + { + if (!tangent.empty()) + { + face.allocateTangents(face.mNumVertices); + U16* t = (U16*)&(tangent[0]); + + // NOTE: tangents coming from the asset may not be mikkt space, but they should always be used by the GLTF shaders to + // maintain compliance with the GLTF spec + LLVector4a* t_out = face.mTangents; + + for (U32 j = 0; j < num_verts; ++j) + { + t_out->set((F32)t[0], (F32)t[1], (F32)t[2], (F32) t[3]); + t_out->div(65535.f); + t_out->mul(2.f); + t_out->sub(1.f); + + F32* tp = t_out->getF32ptr(); + tp[3] = tp[3] < 0.f ? -1.f : 1.f; + + t_out++; + t += 4; + } + } + } +#endif + + { + if (!tc.empty()) + { + U16* t = (U16*) &(tc[0]); + for (U32 j = 0; j < num_verts; j+=2) + { + if (j < num_verts-1) + { + tc_out->set((F32) t[0], (F32) t[1], (F32) t[2], (F32) t[3]); + } + else + { + tc_out->set((F32) t[0], (F32) t[1], 0.f, 0.f); + } + + t += 4; + + tc_out->div(65535.f); + tc_out->mul(tc_range); + tc_out->add(min_tc4); + + tc_out++; + } + } + else + { + for (U32 j = 0; j < num_verts; j += 2) + { + tc_out->clear(); + tc_out++; + } + } + } + + if (mdl[i].has("Weights")) + { + face.allocateWeights(num_verts); + if (!face.mWeights && num_verts) + { + LL_WARNS() << "Failed to allocate " << num_verts << " weights for face index: " << i << " Total: " << face_count << LL_ENDL; + face.resizeIndices(0); + face.resizeVertices(0); + continue; + } + + 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); + U32 joints[4] = {0,0,0,0}; + LLVector4 joints_with_weights(0,0,0,0); + + while (joint != END_INFLUENCES && idx < weights.size()) + { + U16 influence = weights[idx++]; + influence |= ((U16) weights[idx++] << 8); + + F32 w = llclamp((F32) influence / 65535.f, 0.001f, 0.999f); + wght.mV[cur_influence] = w; + joints[cur_influence] = joint; + cur_influence++; + + if (cur_influence >= 4) + { + joint = END_INFLUENCES; + } + else + { + joint = weights[idx++]; + } + } + F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW]; + if (wsum <= 0.f) + { + wght = LLVector4(0.999f,0.f,0.f,0.f); + } + for (U32 k=0; k<4; k++) + { + F32 f_combined = (F32) joints[k] + wght[k]; + joints_with_weights[k] = f_combined; + // Any weights we added above should wind up non-zero and applied to a specific bone. + // A failure here would indicate a floating point precision error in the math. + llassert((k >= cur_influence) || (f_combined - S32(f_combined) > 0.0f)); + } + face.mWeights[cur_vertex].loadua(joints_with_weights.mV); + + cur_vertex++; + } + + if (cur_vertex != num_verts || idx != weights.size()) + { + LL_WARNS() << "Vertex weight count does not match vertex count!" << LL_ENDL; + } + + } + + // 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; + } + } + + //calculate bounding box + // VFExtents change + LLVector4a& min = face.mExtents[0]; + LLVector4a& max = face.mExtents[1]; + + if (face.mNumVertices < 3) + { //empty face, use a dummy 1cm (at 1m scale) bounding box + min.splat(-0.005f); + max.splat(0.005f); + } + else + { + min = max = face.mPositions[0]; + + for (S32 i = 1; i < face.mNumVertices; ++i) + { + min.setMin(min, face.mPositions[i]); + max.setMax(max, face.mPositions[i]); + } + + if (face.mTexCoords) + { + LLVector2& min_tc = face.mTexCoordExtents[0]; + LLVector2& max_tc = face.mTexCoordExtents[1]; + + min_tc = face.mTexCoords[0]; + max_tc = face.mTexCoords[0]; + + for (U32 j = 1; j < face.mNumVertices; ++j) + { + update_min_max(min_tc, max_tc, face.mTexCoords[j]); + } + } + else + { + face.mTexCoordExtents[0].set(0,0); + face.mTexCoordExtents[1].set(1,1); + } + } + } + } + + if (!cacheOptimize(true)) + { + // Out of memory? + LL_WARNS() << "Failed to optimize!" << LL_ENDL; + mVolumeFaces.clear(); + return false; + } + + mSculptLevel = 0; // success! + + return true; +} + + +bool LLVolume::isMeshAssetLoaded() +{ + return mIsMeshAssetLoaded; +} + +void LLVolume::setMeshAssetLoaded(bool loaded) +{ + mIsMeshAssetLoaded = loaded; + if (loaded) + { + mIsMeshAssetUnavaliable = false; + } +} + +void LLVolume::setMeshAssetUnavaliable(bool unavaliable) +{ + // Don't set it if at least one lod loaded + if (!mIsMeshAssetLoaded) + { + mIsMeshAssetUnavaliable = unavaliable; + } +} + +bool LLVolume::isMeshAssetUnavaliable() +{ + return mIsMeshAssetUnavaliable; +} + +void LLVolume::copyFacesTo(std::vector &faces) const +{ + faces = mVolumeFaces; +} + +void LLVolume::copyFacesFrom(const std::vector &faces) +{ + mVolumeFaces = faces; + mSculptLevel = 0; +} + +void LLVolume::copyVolumeFaces(const LLVolume* volume) +{ + mVolumeFaces = volume->mVolumeFaces; + mSculptLevel = 0; +} + +bool LLVolume::cacheOptimize(bool gen_tangents) +{ + for (S32 i = 0; i < mVolumeFaces.size(); ++i) + { + if (!mVolumeFaces[i].cacheOptimize(gen_tangents)) + { + return false; + } + } + return true; +} + + +S32 LLVolume::getNumFaces() const +{ + return mIsMeshAssetLoaded ? getNumVolumeFaces() : (S32)mProfilep->mFaces.size(); +} + + +void LLVolume::createVolumeFaces() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + if (mGenerateSingleFace) + { + // do nothing + } + else + { + S32 num_faces = getNumFaces(); + bool partial_build = true; + if (num_faces != mVolumeFaces.size()) + { + partial_build = false; + mVolumeFaces.resize(num_faces); + } + // Initialize volume faces with parameter data + for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++) + { + LLVolumeFace& vf = mVolumeFaces[i]; + LLProfile::Face& face = mProfilep->mFaces[i]; + vf.mBeginS = face.mIndex; + vf.mNumS = face.mCount; + if (vf.mNumS < 0) + { + LL_ERRS() << "Volume face corruption detected." << LL_ENDL; + } + + vf.mBeginT = 0; + vf.mNumT= getPath().mPath.size(); + vf.mID = i; + + // Set the type mask bits correctly + if (mParams.getProfileParams().getHollow() > 0) + { + vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK; + } + if (mProfilep->isOpen()) + { + vf.mTypeMask |= LLVolumeFace::OPEN_MASK; + } + if (face.mCap) + { + vf.mTypeMask |= LLVolumeFace::CAP_MASK; + if (face.mFaceID == LL_FACE_PATH_BEGIN) + { + vf.mTypeMask |= LLVolumeFace::TOP_MASK; + } + else + { + llassert(face.mFaceID == LL_FACE_PATH_END); + vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK; + } + } + else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END)) + { + vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK; + } + else + { + vf.mTypeMask |= LLVolumeFace::SIDE_MASK; + if (face.mFlat) + { + vf.mTypeMask |= LLVolumeFace::FLAT_MASK; + } + if (face.mFaceID & LL_FACE_INNER_SIDE) + { + vf.mTypeMask |= LLVolumeFace::INNER_MASK; + if (face.mFlat && vf.mNumS > 2) + { //flat inner faces have to copy vert normals + vf.mNumS = vf.mNumS*2; + if (vf.mNumS < 0) + { + LL_ERRS() << "Volume face corruption detected." << LL_ENDL; + } + } + } + else + { + vf.mTypeMask |= LLVolumeFace::OUTER_MASK; + } + } + } + + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + (*iter).create(this, partial_build); + } + } +} + + +inline LLVector4a sculpt_rgb_to_vector(U8 r, U8 g, U8 b) +{ + // maps RGB values to vector values [0..255] -> [-0.5..0.5] + LLVector4a value; + LLVector4a sub(0.5f, 0.5f, 0.5f); + + value.set(r,g,b); + value.mul(1.f/255.f); + value.sub(sub); + + return value; +} + +inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) +{ + U32 index = (x + y * sculpt_width) * sculpt_components; + return index; +} + + +inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components) +{ + U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width); + U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height); + + return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); +} + + +inline LLVector4a sculpt_index_to_vector(U32 index, const U8* sculpt_data) +{ + LLVector4a v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); + + return v; +} + +inline LLVector4a sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +{ + U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); + + return sculpt_index_to_vector(index, sculpt_data); +} + +inline LLVector4a sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +{ + U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); + + return sculpt_index_to_vector(index, sculpt_data); +} + + +F32 LLVolume::sculptGetSurfaceArea() +{ + // test to see if image has enough variation to create non-degenerate geometry + + F32 area = 0; + + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + for (S32 s = 0; s < sizeS-1; s++) + { + for (S32 t = 0; t < sizeT-1; t++) + { + // get four corners of quad + LLVector4a& p1 = mMesh[(s )*sizeT + (t )]; + LLVector4a& p2 = mMesh[(s+1)*sizeT + (t )]; + LLVector4a& p3 = mMesh[(s )*sizeT + (t+1)]; + LLVector4a& p4 = mMesh[(s+1)*sizeT + (t+1)]; + + // compute the area of the quad by taking the length of the cross product of the two triangles + LLVector4a v0,v1,v2,v3; + v0.setSub(p1,p2); + v1.setSub(p1,p3); + v2.setSub(p4,p2); + v3.setSub(p4,p3); + + LLVector4a cross1, cross2; + cross1.setCross3(v0,v1); + cross2.setCross3(v2,v3); + + //LLVector3 cross1 = (p1 - p2) % (p1 - p3); + //LLVector3 cross2 = (p4 - p2) % (p4 - p3); + + area += (cross1.getLength3() + cross2.getLength3()).getF32() / 2.f; + } + } + + return area; +} + +// create empty placeholder shape +void LLVolume::sculptGenerateEmptyPlaceholder() +{ + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + S32 line = 0; + + for (S32 s = 0; s < sizeS; s++) + { + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + LLVector4a& pt = mMesh[i]; + + F32* p = pt.getF32ptr(); + + p[0] = 0; + p[1] = 0; + p[2] = 0; + + llassert(pt.isFinite3()); + } + line += sizeT; + } +} + +// create sphere placeholder shape +void LLVolume::sculptGenerateSpherePlaceholder() +{ + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + S32 line = 0; + + for (S32 s = 0; s < sizeS; s++) + { + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + LLVector4a& pt = mMesh[i]; + + + F32 u = (F32)s / (sizeS - 1); + F32 v = (F32)t / (sizeT - 1); + + const F32 RADIUS = (F32) 0.3; + + F32* p = pt.getF32ptr(); + + p[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); + p[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); + p[2] = (F32)(cos(F_PI * v) * RADIUS); + + llassert(pt.isFinite3()); + } + line += sizeT; + } +} + +// create the vertices from the map +void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type) +{ + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + bool sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + bool sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + bool reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + + S32 line = 0; + for (S32 s = 0; s < sizeS; s++) + { + // Run along the profile. + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + LLVector4a& pt = mMesh[i]; + + S32 reversed_t = t; + + if (reverse_horizontal) + { + reversed_t = sizeT - t - 1; + } + + U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width); + U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height); + + + if (y == 0) // top row stitching + { + // pinch? + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) + { + x = sculpt_width / 2; + } + } + + if (y == sculpt_height) // bottom row stitching + { + // wrap? + if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) + { + y = 0; + } + else + { + y = sculpt_height - 1; + } + + // pinch? + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) + { + x = sculpt_width / 2; + } + } + + if (x == sculpt_width) // side stitching + { + // wrap? + if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || + (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || + (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) + { + x = 0; + } + + else + { + x = sculpt_width - 1; + } + } + + pt = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); + + if (sculpt_mirror) + { + LLVector4a scale(-1.f,1,1,1); + pt.mul(scale); + } + + llassert(pt.isFinite3()); + } + + line += sizeT; + } +} + + +constexpr S32 SCULPT_REZ_1 = 6; // changed from 4 to 6 - 6 looks round whereas 4 looks square +constexpr S32 SCULPT_REZ_2 = 8; +constexpr S32 SCULPT_REZ_3 = 16; +constexpr S32 SCULPT_REZ_4 = 32; + +S32 sculpt_sides(F32 detail) +{ + // detail is usually one of: 1, 1.5, 2.5, 4.0. + + if (detail <= 1.0) + { + return SCULPT_REZ_1; + } + if (detail <= 2.0) + { + return SCULPT_REZ_2; + } + if (detail <= 3.0) + { + return SCULPT_REZ_3; + } + else + { + return SCULPT_REZ_4; + } +} + + + +// determine the number of vertices in both s and t direction for this sculpt +void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t) +{ + // this code has the following properties: + // 1) the aspect ratio of the mesh is as close as possible to the ratio of the map + // while still using all available verts + // 2) the mesh cannot have more verts than is allowed by LOD + // 3) the mesh cannot have more verts than is allowed by the map + + S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0); + S32 max_vertices_map = width * height / 4; + + S32 vertices; + if (max_vertices_map > 0) + vertices = llmin(max_vertices_lod, max_vertices_map); + else + vertices = max_vertices_lod; + + + F32 ratio; + if ((width == 0) || (height == 0)) + ratio = 1.f; + else + ratio = (F32) width / (F32) height; + + + s = (S32)(F32) sqrt(((F32)vertices / ratio)); + + s = llmax(s, 4); // no degenerate sizes, please + t = vertices / s; + + t = llmax(t, 4); // no degenerate sizes, please + s = vertices / t; +} + +// sculpt replaces generate() for sculpted surfaces +void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder) +{ + U8 sculpt_type = mParams.getSculptType(); + + bool data_is_empty = false; + + if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL) + { + sculpt_level = -1; + data_is_empty = true; + } + + S32 requested_sizeS = 0; + S32 requested_sizeT = 0; + + sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT); + + mPathp->generate(mParams.getPathParams(), mDetail, 0, true, requested_sizeS); + mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, true, requested_sizeT); + + S32 sizeS = mPathp->mPath.size(); // we requested a specific size, now see what we really got + S32 sizeT = mProfilep->mProfile.size(); // we requested a specific size, now see what we really got + + // weird crash bug - DEV-11158 - trying to collect more data: + if ((sizeS == 0) || (sizeT == 0)) + { + LL_WARNS() << "sculpt bad mesh size " << sizeS << " " << sizeT << LL_ENDL; + } + + sNumMeshPoints -= mMesh.size(); + mMesh.resize(sizeS * sizeT); + sNumMeshPoints += mMesh.size(); + + //generate vertex positions + if (!data_is_empty) + { + sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); + + // don't test lowest LOD to support legacy content DEV-33670 + if (mDetail > SCULPT_MIN_AREA_DETAIL) + { + F32 area = sculptGetSurfaceArea(); + + mSurfaceArea = area; + + const F32 SCULPT_MAX_AREA = 384.f; + + if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA) + { + data_is_empty = true; + visible_placeholder = true; + } + } + } + + if (data_is_empty) + { + if (visible_placeholder) + { + // Object should be visible since there will be nothing else to display + sculptGenerateSpherePlaceholder(); + } + else + { + sculptGenerateEmptyPlaceholder(); + } + } + + for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++) + { + mFaceMask |= mProfilep->mFaces[i].mFaceID; + } + + mSculptLevel = sculpt_level; + + // Delete any existing faces so that they get regenerated + mVolumeFaces.clear(); + + createVolumeFaces(); +} + + + + +bool LLVolume::isCap(S32 face) +{ + return mProfilep->mFaces[face].mCap; +} + +bool LLVolume::isFlat(S32 face) +{ + return mProfilep->mFaces[face].mFlat; +} + + +bool LLVolumeParams::isSculpt() const +{ + return (mSculptType & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_NONE; +} + +bool LLVolumeParams::isMeshSculpt() const +{ + return (mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH; +} + +bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const +{ + return ( (getPathParams() == params.getPathParams()) && + (getProfileParams() == params.getProfileParams()) && + (mSculptID == params.mSculptID) && + (mSculptType == params.mSculptType) ); +} + +bool LLVolumeParams::operator!=(const LLVolumeParams ¶ms) const +{ + return ( (getPathParams() != params.getPathParams()) || + (getProfileParams() != params.getProfileParams()) || + (mSculptID != params.mSculptID) || + (mSculptType != params.mSculptType) ); +} + +bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const +{ + if( getPathParams() != params.getPathParams() ) + { + return getPathParams() < params.getPathParams(); + } + + if (getProfileParams() != params.getProfileParams()) + { + return getProfileParams() < params.getProfileParams(); + } + + if (mSculptID != params.mSculptID) + { + return mSculptID < params.mSculptID; + } + + return mSculptType < params.mSculptType; + + +} + +void LLVolumeParams::copyParams(const LLVolumeParams ¶ms) +{ + mProfileParams.copyParams(params.mProfileParams); + mPathParams.copyParams(params.mPathParams); + mSculptID = params.getSculptID(); + mSculptType = params.getSculptType(); +} + +// Less restricitve approx 0 for volumes +constexpr F32 APPROXIMATELY_ZERO = 0.001f; +bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO) +{ + return (f >= -tolerance) && (f <= tolerance); +} + +// return true if in range (or nearly so) +static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO) +{ + F32 min_delta = v - min; + if (min_delta < 0.f) + { + v = min; + if (!approx_zero(min_delta, tolerance)) + return false; + } + F32 max_delta = max - v; + if (max_delta < 0.f) + { + v = max; + if (!approx_zero(max_delta, tolerance)) + return false; + } + return true; +} + +bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e) +{ + bool valid = true; + + // First, clamp to valid ranges. + F32 begin = b; + valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); + + F32 end = e; + if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error + valid &= limit_range(end, MIN_CUT_DELTA, 1.f); + + valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); + + // Now set them. + mProfileParams.setBegin(begin); + mProfileParams.setEnd(end); + + return valid; +} + +bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e) +{ + bool valid = true; + + // First, clamp to valid ranges. + F32 begin = b; + valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA); + + F32 end = e; + valid &= limit_range(end, MIN_CUT_DELTA, 1.f); + + valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f); + + // Now set them. + mPathParams.setBegin(begin); + mPathParams.setEnd(end); + + return valid; +} + +bool LLVolumeParams::setHollow(const F32 h) +{ + // Validate the hollow based on path and profile. + U8 profile = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + U8 hole_type = mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK; + + F32 max_hollow = HOLLOW_MAX; + + // Only square holes have trouble. + if (LL_PCODE_HOLE_SQUARE == hole_type) + { + switch(profile) + { + case LL_PCODE_PROFILE_CIRCLE: + case LL_PCODE_PROFILE_CIRCLE_HALF: + case LL_PCODE_PROFILE_EQUALTRI: + max_hollow = HOLLOW_MAX_SQUARE; + } + } + + F32 hollow = h; + bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow); + mProfileParams.setHollow(hollow); + + return valid; +} + +bool LLVolumeParams::setTwistBegin(const F32 b) +{ + F32 twist_begin = b; + bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX); + mPathParams.setTwistBegin(twist_begin); + return valid; +} + +bool LLVolumeParams::setTwistEnd(const F32 e) +{ + F32 twist_end = e; + bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX); + mPathParams.setTwistEnd(twist_end); + return valid; +} + +bool LLVolumeParams::setRatio(const F32 x, const F32 y) +{ + F32 min_x = RATIO_MIN; + F32 max_x = RATIO_MAX; + F32 min_y = RATIO_MIN; + F32 max_y = RATIO_MAX; + // If this is a circular path (and not a sphere) then 'ratio' is actually hole size. + U8 path_type = mPathParams.getCurveType(); + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PATH_CIRCLE == path_type && + LL_PCODE_PROFILE_CIRCLE_HALF != profile_type) + { + // Holes are more restricted... + min_x = HOLE_X_MIN; + max_x = HOLE_X_MAX; + min_y = HOLE_Y_MIN; + max_y = HOLE_Y_MAX; + } + + F32 ratio_x = x; + bool valid = limit_range(ratio_x, min_x, max_x); + F32 ratio_y = y; + valid &= limit_range(ratio_y, min_y, max_y); + + mPathParams.setScale(ratio_x, ratio_y); + + return valid; +} + +bool LLVolumeParams::setShear(const F32 x, const F32 y) +{ + F32 shear_x = x; + bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX); + F32 shear_y = y; + valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX); + mPathParams.setShear(shear_x, shear_y); + return valid; +} + +bool LLVolumeParams::setTaperX(const F32 v) +{ + F32 taper = v; + bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); + mPathParams.setTaperX(taper); + return valid; +} + +bool LLVolumeParams::setTaperY(const F32 v) +{ + F32 taper = v; + bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX); + mPathParams.setTaperY(taper); + return valid; +} + +bool LLVolumeParams::setRevolutions(const F32 r) +{ + F32 revolutions = r; + bool valid = limit_range(revolutions, REV_MIN, REV_MAX); + mPathParams.setRevolutions(revolutions); + return valid; +} + +bool LLVolumeParams::setRadiusOffset(const F32 offset) +{ + bool valid = true; + + // If this is a sphere, just set it to 0 and get out. + U8 path_type = mPathParams.getCurveType(); + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type || + LL_PCODE_PATH_CIRCLE != path_type ) + { + mPathParams.setRadiusOffset(0.f); + return true; + } + + // Limit radius offset, based on taper and hole size y. + F32 radius_offset = offset; + F32 taper_y = getTaperY(); + F32 radius_mag = fabs(radius_offset); + F32 hole_y_mag = fabs(getRatioY()); + F32 taper_y_mag = fabs(taper_y); + // Check to see if the taper effects us. + if ( (radius_offset > 0.f && taper_y < 0.f) || + (radius_offset < 0.f && taper_y > 0.f) ) + { + // The taper does not help increase the radius offset range. + taper_y_mag = 0.f; + } + F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + + // Enforce the maximum magnitude. + F32 delta = max_radius_mag - radius_mag; + if (delta < 0.f) + { + // Check radius offset sign. + if (radius_offset < 0.f) + { + radius_offset = -max_radius_mag; + } + else + { + radius_offset = max_radius_mag; + } + valid = approx_zero(delta, .1f); + } + + mPathParams.setRadiusOffset(radius_offset); + return valid; +} + +bool LLVolumeParams::setSkew(const F32 skew_value) +{ + bool valid = true; + + // Check the skew value against the revolutions. + F32 skew = llclamp(skew_value, SKEW_MIN, SKEW_MAX); + F32 skew_mag = fabs(skew); + F32 revolutions = getRevolutions(); + F32 scale_x = getRatioX(); + F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); + // Discontinuity; A revolution of 1 allows skews below 0.5. + if ( fabs(revolutions - 1.0f) < 0.001) + min_skew_mag = 0.0f; + + // Clip skew. + F32 delta = skew_mag - min_skew_mag; + if (delta < 0.f) + { + // Check skew sign. + if (skew < 0.0f) + { + skew = -min_skew_mag; + } + else + { + skew = min_skew_mag; + } + valid = approx_zero(delta, .01f); + } + + mPathParams.setSkew(skew); + return valid; +} + +bool LLVolumeParams::setSculptID(const LLUUID& sculpt_id, U8 sculpt_type) +{ + mSculptID = sculpt_id; + mSculptType = sculpt_type; + return true; +} + +bool LLVolumeParams::setType(U8 profile, U8 path) +{ + bool result = true; + // First, check profile and path for validity. + U8 profile_type = profile & LL_PCODE_PROFILE_MASK; + U8 hole_type = (profile & LL_PCODE_HOLE_MASK) >> 4; + U8 path_type = path >> 4; + + if (profile_type > LL_PCODE_PROFILE_MAX) + { + // Bad profile. Make it square. + profile = LL_PCODE_PROFILE_SQUARE; + result = false; + LL_WARNS() << "LLVolumeParams::setType changing bad profile type (" << profile_type + << ") to be LL_PCODE_PROFILE_SQUARE" << LL_ENDL; + } + else if (hole_type > LL_PCODE_HOLE_MAX) + { + // Bad hole. Make it the same. + profile = profile_type; + result = false; + LL_WARNS() << "LLVolumeParams::setType changing bad hole type (" << hole_type + << ") to be LL_PCODE_HOLE_SAME" << LL_ENDL; + } + + if (path_type < LL_PCODE_PATH_MIN || + path_type > LL_PCODE_PATH_MAX) + { + // Bad path. Make it linear. + result = false; + LL_WARNS() << "LLVolumeParams::setType changing bad path (" << path + << ") to be LL_PCODE_PATH_LINE" << LL_ENDL; + path = LL_PCODE_PATH_LINE; + } + + mProfileParams.setCurveType(profile); + mPathParams.setCurveType(path); + return result; +} + +// static +bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, + U8 path_curve, F32 path_begin, F32 path_end, + F32 scx, F32 scy, F32 shx, F32 shy, + F32 twistend, F32 twistbegin, F32 radiusoffset, + F32 tx, F32 ty, F32 revolutions, F32 skew) +{ + LLVolumeParams test_params; + if (!test_params.setType (prof_curve, path_curve)) + { + return false; + } + if (!test_params.setBeginAndEndS (prof_begin, prof_end)) + { + return false; + } + if (!test_params.setBeginAndEndT (path_begin, path_end)) + { + return false; + } + if (!test_params.setHollow (hollow)) + { + return false; + } + if (!test_params.setTwistBegin (twistbegin)) + { + return false; + } + if (!test_params.setTwistEnd (twistend)) + { + return false; + } + if (!test_params.setRatio (scx, scy)) + { + return false; + } + if (!test_params.setShear (shx, shy)) + { + return false; + } + if (!test_params.setTaper (tx, ty)) + { + return false; + } + if (!test_params.setRevolutions (revolutions)) + { + return false; + } + if (!test_params.setRadiusOffset (radiusoffset)) + { + return false; + } + if (!test_params.setSkew (skew)) + { + return false; + } + return true; +} + +void LLVolume::getLoDTriangleCounts(const LLVolumeParams& params, S32* counts) +{ //attempt to approximate the number of triangles that will result from generating a volume LoD set for the + //supplied LLVolumeParams -- inaccurate, but a close enough approximation for determining streaming cost + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + F32 detail[] = {1.f, 1.5f, 2.5f, 4.f}; + for (S32 i = 0; i < 4; i++) + { + S32 count = 0; + S32 path_points = LLPath::getNumPoints(params.getPathParams(), detail[i]); + S32 profile_points = LLProfile::getNumPoints(params.getProfileParams(), false, detail[i]); + + count = (profile_points-1)*2*(path_points-1); + count += profile_points*2; + + counts[i] = count; + } +} + + +S32 LLVolume::getNumTriangles(S32* vcount) const +{ + U32 triangle_count = 0; + U32 vertex_count = 0; + + for (S32 i = 0; i < getNumVolumeFaces(); ++i) + { + const LLVolumeFace& face = getVolumeFace(i); + triangle_count += face.mNumIndices/3; + + vertex_count += face.mNumVertices; + } + + + if (vcount) + { + *vcount = vertex_count; + } + + return triangle_count; +} + + +//----------------------------------------------------------------------------- +// generateSilhouetteVertices() +//----------------------------------------------------------------------------- +void LLVolume::generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + const LLVector3& obj_cam_vec_in, + const LLMatrix4& mat_in, + const LLMatrix3& norm_mat_in, + S32 face_mask) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_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(); + + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { + return; + } + + S32 cur_index = 0; + //for each face + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + LLVolumeFace& face = *iter; + + if (!(face_mask & (0x1 << cur_index++)) || + face.mNumIndices == 0 || face.mEdge.empty()) + { + continue; + } + + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) + { + LLVector4a* v = (LLVector4a*)face.mPositions; + LLVector4a* n = (LLVector4a*)face.mNormals; + + for (U32 j = 0; j < face.mNumIndices / 3; j++) + { + for (S32 k = 0; k < 3; k++) + { + S32 index = face.mEdge[j * 3 + k]; + + if (index == -1) + { + // silhouette edge, currently only cubes, so no other conditions + + S32 v1 = face.mIndices[j * 3 + k]; + S32 v2 = face.mIndices[j * 3 + ((k + 1) % 3)]; + + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + 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])); + } + } + } + + } + else + { + //============================================== + //DEBUG draw edge map instead of silhouette edge + //============================================== + +#if DEBUG_SILHOUETTE_EDGE_MAP + + //for each triangle + U32 tri_count = face.mNumIndices / 3; + for (U32 j = 0; j < tri_count; j++) { + //get vertices + S32 v1 = face.mIndices[j*3+0]; + S32 v2 = face.mIndices[j*3+1]; + S32 v3 = face.mIndices[j*3+2]; + + //get current face center + 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++) { + S32 nIndex = face.mEdge[j*3+k]; + if (nIndex <= -1) { + continue; + } + + if (nIndex >= (S32)tri_count) { + continue; + } + //get neighbor vertices + v1 = face.mIndices[nIndex*3+0]; + v2 = face.mIndices[nIndex*3+1]; + v3 = face.mIndices[nIndex*3+2]; + + //get neighbor face center + LLVector3 nCenter = (face.mVertices[v1].getPosition() + + face.mVertices[v2].getPosition() + + face.mVertices[v3].getPosition()) / 3.0f; + + //draw line + vertices.push_back(cCenter); + vertices.push_back(nCenter); + normals.push_back(LLVector3(1,1,1)); + normals.push_back(LLVector3(1,1,1)); + segments.push_back(vertices.size()); + } + } + + continue; + + //============================================== + //DEBUG + //============================================== + + //============================================== + //DEBUG draw normals instead of silhouette edge + //============================================== +#elif DEBUG_SILHOUETTE_NORMALS + + //for each vertex + 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].getPosition()); + vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mTangent*0.1f); + normals.push_back(LLVector3(0,0,1)); + normals.push_back(LLVector3(0,0,1)); + segments.push_back(vertices.size()); +#endif + } + + continue; +#else + //============================================== + //DEBUG + //============================================== + + constexpr U8 AWAY = 0x01, + TOWARDS = 0x02; + + //for each triangle + std::vector fFacing; + 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]; + + 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 + LLVector4a view; + view.setSub(obj_cam_vec, v[v1]); + bool away = view.dot3(norm) > 0.0f; + if (away) + { + fFacing[j] = AWAY; + } + else + { + fFacing[j] = TOWARDS; + } + } + } + + //for each triangle + for (U32 j = 0; j < face.mNumIndices/3; j++) + { + if (fFacing[j] == (AWAY | TOWARDS)) + { //this is a degenerate triangle + //take neighbor facing (degenerate faces get facing of one of their neighbors) + // *FIX IF NEEDED: this does not deal with neighboring degenerate faces + for (S32 k = 0; k < 3; k++) + { + S32 index = face.mEdge[j*3+k]; + if (index != -1) + { + fFacing[j] = fFacing[index]; + break; + } + } + continue; //skip degenerate face + } + + //for each edge + for (S32 k = 0; k < 3; k++) { + S32 index = face.mEdge[j*3+k]; + if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { + //our neighbor is degenerate, make him face our direction + fFacing[face.mEdge[j*3+k]] = fFacing[j]; + continue; + } + + if (index == -1 || //edge has no neighbor, MUST be a silhouette edge + (fFacing[index] & fFacing[j]) == 0) { //we found a silhouette edge + + S32 v1 = face.mIndices[j*3+k]; + S32 v2 = face.mIndices[j*3+((k+1)%3)]; + + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + 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])); + } + } + } +#endif + } + } +} + +S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face, + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out) +{ + S32 hit_face = -1; + + S32 start_face; + S32 end_face; + + if (face == -1) // ALL_SIDES + { + start_face = 0; + end_face = getNumVolumeFaces() - 1; + } + else + { + start_face = face; + end_face = face; + } + + 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++) + { + LLVolumeFace &face = mVolumeFaces[i]; + + LLVector4a box_center; + box_center.setAdd(face.mExtents[0], face.mExtents[1]); + box_center.mul(0.5f); + + LLVector4a box_size; + box_size.setSub(face.mExtents[1], face.mExtents[0]); + + if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) + { + if (tangent_out != NULL) // if the caller wants tangents, we may need to generate them + { + genTangents(i); + } + + if (isUnique()) + { //don't bother with an octree for flexi volumes + U32 tri_count = face.mNumIndices/3; + + for (U32 j = 0; j < tri_count; ++j) + { + U16 idx0 = face.mIndices[j*3+0]; + U16 idx1 = face.mIndices[j*3+1]; + U16 idx2 = face.mIndices[j*3+2]; + + const LLVector4a& v0 = face.mPositions[idx0]; + const LLVector4a& v1 = face.mPositions[idx1]; + const LLVector4a& v2 = face.mPositions[idx2]; + + F32 a,b,t; + + if (LLTriangleRayIntersect(v0, v1, v2, + start, dir, a, b, t)) + { + 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; + + if (intersection != NULL) + { + LLVector4a intersect = dir; + intersect.mul(closest_t); + intersect.add(start); + *intersection = intersect; + } + + + if (tex_coord != NULL) + { + LLVector2* tc = (LLVector2*) face.mTexCoords; + *tex_coord = ((1.f - a - b) * tc[idx0] + + a * tc[idx1] + + b * tc[idx2]); + + } + + if (normal!= NULL) + { + LLVector4a* norm = face.mNormals; + + LLVector4a n1,n2,n3; + n1 = norm[idx0]; + n1.mul(1.f-a-b); + + n2 = norm[idx1]; + n2.mul(a); + + n3 = norm[idx2]; + n3.mul(b); + + n1.add(n2); + n1.add(n3); + + *normal = n1; + } + + if (tangent_out != NULL) + { + LLVector4a* tangents = face.mTangents; + + LLVector4a t1,t2,t3; + t1 = tangents[idx0]; + t1.mul(1.f-a-b); + + t2 = tangents[idx1]; + t2.mul(a); + + t3 = tangents[idx2]; + t3.mul(b); + + t1.add(t2); + t1.add(t3); + + *tangent_out = t1; + } + } + } + } + } + else + { + if (!face.getOctree()) + { + face.createOctree(); + } + + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out); + intersect.traverse(face.getOctree()); + if (intersect.mHitFace) + { + hit_face = i; + } + } + } + } + + + return hit_face; +} + +class LLVertexIndexPair +{ +public: + LLVertexIndexPair(const LLVector3 &vertex, const S32 index); + + LLVector3 mVertex; + S32 mIndex; +}; + +LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index) +{ + mVertex = vertex; + mIndex = index; +} + +constexpr F32 VERTEX_SLOP = 0.00001f; + +struct lessVertex +{ + bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b) + { + const F32 slop = VERTEX_SLOP; + + if (a->mVertex.mV[0] + slop < b->mVertex.mV[0]) + { + return true; + } + else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0]) + { + return false; + } + + if (a->mVertex.mV[1] + slop < b->mVertex.mV[1]) + { + return true; + } + else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1]) + { + return false; + } + + if (a->mVertex.mV[2] + slop < b->mVertex.mV[2]) + { + return true; + } + else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2]) + { + return false; + } + + return false; + } +}; + +struct lessTriangle +{ + bool operator()(const S32 *a, const S32 *b) + { + if (*a < *b) + { + return true; + } + else if (*a > *b) + { + return false; + } + + if (*(a+1) < *(b+1)) + { + return true; + } + else if (*(a+1) > *(b+1)) + { + return false; + } + + if (*(a+2) < *(b+2)) + { + return true; + } + else if (*(a+2) > *(b+2)) + { + return false; + } + + return false; + } +}; + +bool equalTriangle(const S32 *a, const S32 *b) +{ + if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2))) + { + return true; + } + return false; +} + +bool LLVolumeParams::importFile(LLFILE *fp) +{ + //LL_INFOS() << "importing volume" << LL_ENDL; + const S32 BUFSIZE = 16384; + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + // *NOTE: changing the size or type of this buffer will require + // changing the sscanf below. + char keyword[256]; /* Flawfinder: ignore */ + keyword[0] = 0; + + while (!feof(fp)) + { + if (fgets(buffer, BUFSIZE, fp) == NULL) + { + buffer[0] = '\0'; + } + + sscanf(buffer, " %255s", keyword); /* Flawfinder: ignore */ + if (!strcmp("{", keyword)) + { + continue; + } + if (!strcmp("}",keyword)) + { + break; + } + else if (!strcmp("profile", keyword)) + { + mProfileParams.importFile(fp); + } + else if (!strcmp("path",keyword)) + { + mPathParams.importFile(fp); + } + else + { + LL_WARNS() << "unknown keyword " << keyword << " in volume import" << LL_ENDL; + } + } + + return true; +} + +bool LLVolumeParams::exportFile(LLFILE *fp) const +{ + fprintf(fp,"\tshape 0\n"); + fprintf(fp,"\t{\n"); + mPathParams.exportFile(fp); + mProfileParams.exportFile(fp); + fprintf(fp, "\t}\n"); + return true; +} + + +bool LLVolumeParams::importLegacyStream(std::istream& input_stream) +{ + //LL_INFOS() << "importing volume" << LL_ENDL; + const S32 BUFSIZE = 16384; + // *NOTE: changing the size or type of this buffer will require + // changing the sscanf below. + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + char keyword[256]; /* Flawfinder: ignore */ + keyword[0] = 0; + + while (input_stream.good()) + { + input_stream.getline(buffer, BUFSIZE); + sscanf(buffer, " %255s", keyword); + if (!strcmp("{", keyword)) + { + continue; + } + if (!strcmp("}",keyword)) + { + break; + } + else if (!strcmp("profile", keyword)) + { + mProfileParams.importLegacyStream(input_stream); + } + else if (!strcmp("path",keyword)) + { + mPathParams.importLegacyStream(input_stream); + } + else + { + LL_WARNS() << "unknown keyword " << keyword << " in volume import" << LL_ENDL; + } + } + + return true; +} + +bool LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const +{ + output_stream <<"\tshape 0\n"; + output_stream <<"\t{\n"; + mPathParams.exportLegacyStream(output_stream); + mProfileParams.exportLegacyStream(output_stream); + output_stream << "\t}\n"; + 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; +} + +bool LLVolumeParams::fromLLSD(LLSD& sd) +{ + mPathParams.fromLLSD(sd["path"]); + mProfileParams.fromLLSD(sd["profile"]); + sculptFromLLSD(sd["sculpt"]); + + return true; +} + +void LLVolumeParams::reduceS(F32 begin, F32 end) +{ + begin = llclampf(begin); + end = llclampf(end); + if (begin > end) + { + F32 temp = begin; + begin = end; + end = temp; + } + F32 a = mProfileParams.getBegin(); + F32 b = mProfileParams.getEnd(); + mProfileParams.setBegin(a + begin * (b - a)); + mProfileParams.setEnd(a + end * (b - a)); +} + +void LLVolumeParams::reduceT(F32 begin, F32 end) +{ + begin = llclampf(begin); + end = llclampf(end); + if (begin > end) + { + F32 temp = begin; + begin = end; + end = temp; + } + F32 a = mPathParams.getBegin(); + F32 b = mPathParams.getEnd(); + mPathParams.setBegin(a + begin * (b - a)); + mPathParams.setEnd(a + end * (b - a)); +} + +const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity +const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity + +// returns true if the shape can be approximated with a convex shape +// 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(); + + U8 path_type = mPathParams.getCurveType(); + if ( path_length > MIN_CONCAVE_PATH_WEDGE + && ( mPathParams.getTwist() != mPathParams.getTwistBegin() + || (hollow > 0.f + && LL_PCODE_PATH_LINE != path_type) ) ) + { + // twist along a "not too short" path is concave + return false; + } + + F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); + bool same_hole = hollow == 0.f + || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; + + F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; + U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) + { + // it is a sphere and spheres get twice the minimum profile wedge + min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; + } + + bool convex_profile = ( ( profile_length == 1.f + || profile_length <= 0.5f ) + && hollow == 0.f ) // trivially convex + || ( profile_length <= min_profile_wedge + && same_hole ); // effectvely convex (even when hollow) + + if (!convex_profile) + { + // profile is concave + return false; + } + + if ( LL_PCODE_PATH_LINE == path_type ) + { + // straight paths with convex profile + return true; + } + + bool concave_path = (path_length < 1.0f) && (path_length > 0.5f); + if (concave_path) + { + return false; + } + + // we're left with spheres, toroids and tubes + if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ) + { + // at this stage all spheres must be convex + return true; + } + + // it's a toroid or tube + if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) + { + // effectively convex + return true; + } + + return false; +} + +// debug +void LLVolumeParams::setCube() +{ + mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); + mProfileParams.setBegin(0.f); + mProfileParams.setEnd(1.f); + mProfileParams.setHollow(0.f); + + mPathParams.setBegin(0.f); + mPathParams.setEnd(1.f); + mPathParams.setScale(1.f, 1.f); + mPathParams.setShear(0.f, 0.f); + mPathParams.setCurveType(LL_PCODE_PATH_LINE); + mPathParams.setTwistBegin(0.f); + mPathParams.setTwistEnd(0.f); + mPathParams.setRadiusOffset(0.f); + mPathParams.setTaper(0.f, 0.f); + mPathParams.setRevolutions(0.f); + mPathParams.setSkew(0.f); +} + +LLFaceID LLVolume::generateFaceMask() +{ + LLFaceID new_mask = 0x0000; + + switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK) + { + case LL_PCODE_PROFILE_CIRCLE: + case LL_PCODE_PROFILE_CIRCLE_HALF: + new_mask |= LL_FACE_OUTER_SIDE_0; + break; + case LL_PCODE_PROFILE_SQUARE: + { + for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++) + { + new_mask |= LL_FACE_OUTER_SIDE_0 << side; + } + } + break; + case LL_PCODE_PROFILE_ISOTRI: + case LL_PCODE_PROFILE_EQUALTRI: + case LL_PCODE_PROFILE_RIGHTTRI: + { + for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++) + { + new_mask |= LL_FACE_OUTER_SIDE_0 << side; + } + } + break; + default: + LL_ERRS() << "Unknown profile!" << LL_ENDL; + break; + } + + // handle hollow objects + if (mParams.getProfileParams().getHollow() > 0) + { + new_mask |= LL_FACE_INNER_SIDE; + } + + // handle open profile curves + if (mProfilep->isOpen()) + { + new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END; + } + + // handle open path curves + if (mPathp->isOpen()) + { + new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END; + } + + return new_mask; +} + +bool LLVolume::isFaceMaskValid(LLFaceID face_mask) +{ + LLFaceID test_mask = 0; + for(S32 i = 0; i < getNumFaces(); i++) + { + test_mask |= mProfilep->mFaces[i].mFaceID; + } + + return test_mask == face_mask; +} + +bool LLVolume::isConvex() const +{ + // mParams.isConvex() may return false even though the final + // geometry is actually convex due to LOD approximations. + // TODO -- provide LLPath and LLProfile with isConvex() methods + // that correctly determine convexity. -- Leviathan + return mParams.isConvex(); +} + + +std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params) +{ + s << "{type=" << (U32) profile_params.mCurveType; + s << ", begin=" << profile_params.mBegin; + s << ", end=" << profile_params.mEnd; + s << ", hollow=" << profile_params.mHollow; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params) +{ + s << "{type=" << (U32) path_params.mCurveType; + s << ", begin=" << path_params.mBegin; + s << ", end=" << path_params.mEnd; + s << ", twist=" << path_params.mTwistEnd; + s << ", scale=" << path_params.mScale; + s << ", shear=" << path_params.mShear; + s << ", twist_begin=" << path_params.mTwistBegin; + s << ", radius_offset=" << path_params.mRadiusOffset; + s << ", taper=" << path_params.mTaper; + s << ", revolutions=" << path_params.mRevolutions; + s << ", skew=" << path_params.mSkew; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params) +{ + s << "{profileparams = " << volume_params.mProfileParams; + s << ", pathparams = " << volume_params.mPathParams; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLProfile &profile) +{ + s << " {open=" << (U32) profile.mOpen; + s << ", dirty=" << profile.mDirty; + s << ", totalout=" << profile.mTotalOut; + s << ", total=" << profile.mTotal; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLPath &path) +{ + s << "{open=" << (U32) path.mOpen; + s << ", dirty=" << path.mDirty; + s << ", step=" << path.mStep; + s << ", total=" << path.mTotal; + s << "}"; + return s; +} + +std::ostream& operator<<(std::ostream &s, const LLVolume &volume) +{ + s << "{params = " << volume.getParams(); + s << ", path = " << *volume.mPathp; + s << ", profile = " << *volume.mProfilep; + s << "}"; + return s; +} + + +std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) +{ + s << "{params = " << volumep->getParams(); + s << ", path = " << *(volumep->mPathp); + s << ", profile = " << *(volumep->mProfilep); + s << "}"; + return s; +} + +LLVolumeFace::LLVolumeFace() : + mID(0), + mTypeMask(0), + mBeginS(0), + mBeginT(0), + mNumS(0), + mNumT(0), + mNumVertices(0), + mNumAllocatedVertices(0), + mNumIndices(0), + mPositions(NULL), + mNormals(NULL), + mTangents(NULL), + mTexCoords(NULL), + mIndices(NULL), + mWeights(NULL), +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + mJustWeights(NULL), + mJointIndices(NULL), +#endif + mWeightsScrubbed(false), + mOctree(NULL), + mOctreeTriangles(NULL), + mOptimized(false) +{ + mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); + mExtents[0].splat(-0.5f); + mExtents[1].splat(0.5f); + mCenter = mExtents+2; +} + +LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) +: mID(0), + mTypeMask(0), + mBeginS(0), + mBeginT(0), + mNumS(0), + mNumT(0), + mNumVertices(0), + mNumAllocatedVertices(0), + mNumIndices(0), + mPositions(NULL), + mNormals(NULL), + mTangents(NULL), + mTexCoords(NULL), + mIndices(NULL), + mWeights(NULL), +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + mJustWeights(NULL), + mJointIndices(NULL), +#endif + mWeightsScrubbed(false), + mOctree(NULL), + mOctreeTriangles(NULL) +{ + mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); + 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(); + + resizeVertices(src.mNumVertices); + resizeIndices(src.mNumIndices); + + if (mNumVertices) + { + S32 vert_size = mNumVertices*sizeof(LLVector4a); + S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; + + LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size); + + if (src.mNormals) + { + LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); + } + + if(src.mTexCoords) + { + LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); + } + + if (src.mTangents) + { + allocateTangents(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mTangents, (F32*) src.mTangents, vert_size); + } + else + { + ll_aligned_free_16(mTangents); + mTangents = NULL; + } + + if (src.mWeights) + { + llassert(!mWeights); // don't orphan an old alloc here accidentally + allocateWeights(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); + mWeightsScrubbed = src.mWeightsScrubbed; + } + else + { + ll_aligned_free_16(mWeights); + mWeights = NULL; + mWeightsScrubbed = false; + } + + #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + if (src.mJointIndices) + { + llassert(!mJointIndices); // don't orphan an old alloc here accidentally + allocateJointIndices(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mJointIndices, (F32*) src.mJointIndices, src.mNumVertices * sizeof(U8) * 4); + } + else*/ + { + ll_aligned_free_16(mJointIndices); + mJointIndices = NULL; + } + #endif + + } + + if (mNumIndices) + { + S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; + + LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); + } + else + { + ll_aligned_free_16(mIndices); + mIndices = NULL; + } + + mOptimized = src.mOptimized; + mNormalizedScale = src.mNormalizedScale; + + //delete + return *this; +} + +LLVolumeFace::~LLVolumeFace() +{ + ll_aligned_free_16(mExtents); + mExtents = NULL; + mCenter = NULL; + + freeData(); +} + +void LLVolumeFace::freeData() +{ + ll_aligned_free<64>(mPositions); + mPositions = NULL; + + //normals and texture coordinates are part of the same buffer as mPositions, do not free them separately + mNormals = NULL; + mTexCoords = NULL; + + ll_aligned_free_16(mIndices); + mIndices = NULL; + ll_aligned_free_16(mTangents); + mTangents = NULL; + ll_aligned_free_16(mWeights); + mWeights = NULL; + +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + ll_aligned_free_16(mJointIndices); + mJointIndices = NULL; + ll_aligned_free_16(mJustWeights); + mJustWeights = NULL; +#endif + + destroyOctree(); +} + +bool LLVolumeFace::create(LLVolume* volume, bool partial_build) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + //tree for this face is no longer valid + destroyOctree(); + + LL_CHECK_MEMORY + bool ret = false ; + if (mTypeMask & CAP_MASK) + { + ret = createCap(volume, partial_build); + LL_CHECK_MEMORY + } + else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) + { + ret = createSide(volume, partial_build); + LL_CHECK_MEMORY + } + else + { + LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL; + } + + return ret ; +} + +void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) +{ + cv.setPosition(mPositions[index]); + if (mNormals) + { + cv.setNormal(mNormals[index]); + } + else + { + cv.getNormal().clear(); + } + + if (mTexCoords) + { + cv.mTexCoord = mTexCoords[index]; + } + else + { + cv.mTexCoord.clear(); + } +} + +bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const +{ + return getPosition().equals3(rhs.getPosition()) && + mTexCoord == rhs.mTexCoord && + getNormal().equals3(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::remap() +{ + // Generate a remap buffer + std::vector remap(mNumVertices); + S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0], + mIndices, + mNumIndices, + mPositions, + mNormals, + mTexCoords, + mNumVertices); + + // Allocate new buffers + S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF; + U16* remap_indices = (U16*)ll_aligned_malloc_16(size); + + S32 tc_bytes_size = ((remap_vertices_count * sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector4a* remap_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * remap_vertices_count + tc_bytes_size); + LLVector4a* remap_normals = remap_positions + remap_vertices_count; + LLVector2* remap_tex_coords = (LLVector2*)(remap_normals + remap_vertices_count); + + // Fill the buffers + LLMeshOptimizer::remapIndexBufferU16(remap_indices, mIndices, mNumIndices, &remap[0]); + LLMeshOptimizer::remapPositionsBuffer(remap_positions, mPositions, mNumVertices, &remap[0]); + LLMeshOptimizer::remapNormalsBuffer(remap_normals, mNormals, mNumVertices, &remap[0]); + LLMeshOptimizer::remapUVBuffer(remap_tex_coords, mTexCoords, mNumVertices, &remap[0]); + + // Free unused buffers + ll_aligned_free_16(mIndices); + ll_aligned_free<64>(mPositions); + + // Tangets are now invalid + ll_aligned_free_16(mTangents); + mTangents = NULL; + + // Assign new values + mIndices = remap_indices; + mPositions = remap_positions; + mNormals = remap_normals; + mTexCoords = remap_tex_coords; + mNumVertices = remap_vertices_count; + mNumAllocatedVertices = remap_vertices_count; +} + +void LLVolumeFace::optimize(F32 angle_cutoff) +{ + LLVolumeFace new_face; + + //map of points to vector of vertices at that point + std::map > point_map; + + LLVector4a range; + range.setSub(mExtents[1],mExtents[0]); + + //remove redundant vertices + for (U32 i = 0; i < mNumIndices; ++i) + { + U16 index = mIndices[i]; + + if (index >= mNumVertices) + { + // invalid index + // replace with a valid index to avoid crashes + index = mNumVertices - 1; + mIndices[i] = index; + + // Needs better logging + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL; + } + + LLVolumeFace::VertexData cv; + getVertexData(index, cv); + + bool found = false; + + LLVector4a pos; + pos.setSub(mPositions[index], mExtents[0]); + pos.div(range); + + U64 pos64 = 0; + + pos64 = (U16) (pos[0]*65535); + pos64 = pos64 | (((U64) (pos[1]*65535)) << 16); + pos64 = pos64 | (((U64) (pos[2]*65535)) << 32); + + std::map >::iterator point_iter = point_map.find(pos64); + + 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[pos64].push_back(d); + } + } + } + + + if (angle_cutoff > 1.f && !mNormals) + { + // Now alloc'd with positions + //ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!mTexCoords) + { + // Now alloc'd with positions + //ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + + // Only swap data if we've actually optimized the mesh + // + if (new_face.mNumVertices <= mNumVertices) + { + llassert(new_face.mNumIndices == mNumIndices); + swapData(new_face); + } + +} + +class LLVCacheTriangleData; + +class LLVCacheVertexData +{ +public: + S32 mIdx; + S32 mCacheTag; + F64 mScore; + U32 mActiveTriangles; + std::vector mTriangles; + + LLVCacheVertexData() + { + mCacheTag = -1; + mScore = 0.0; + mActiveTriangles = 0; + mIdx = -1; + } +}; + +class LLVCacheTriangleData +{ +public: + bool mActive; + F64 mScore; + LLVCacheVertexData* mVertex[3]; + + LLVCacheTriangleData() + { + mActive = true; + mScore = 0.0; + mVertex[0] = mVertex[1] = mVertex[2] = NULL; + } + + void complete() + { + mActive = false; + for (S32 i = 0; i < 3; ++i) + { + if (mVertex[i]) + { + llassert(mVertex[i]->mActiveTriangles > 0); + mVertex[i]->mActiveTriangles--; + } + } + } + + bool operator<(const LLVCacheTriangleData& rhs) const + { //highest score first + return rhs.mScore < mScore; + } +}; + +constexpr F64 FindVertexScore_CacheDecayPower = 1.5; +constexpr F64 FindVertexScore_LastTriScore = 0.75; +constexpr F64 FindVertexScore_ValenceBoostScale = 2.0; +constexpr F64 FindVertexScore_ValenceBoostPower = 0.5; +constexpr U32 MaxSizeVertexCache = 32; +constexpr F64 FindVertexScore_Scaler = 1.0/(MaxSizeVertexCache-3); + +F64 find_vertex_score(LLVCacheVertexData& data) +{ + F64 score = -1.0; + + score = 0.0; + + S32 cache_idx = data.mCacheTag; + + if (cache_idx < 0) + { + //not in cache + } + else + { + if (cache_idx < 3) + { //vertex was in the last triangle + score = FindVertexScore_LastTriScore; + } + else + { //more points for being higher in the cache + score = 1.0-((cache_idx-3)*FindVertexScore_Scaler); + score = pow(score, FindVertexScore_CacheDecayPower); + } + } + + //bonus points for having low valence + F64 valence_boost = pow((F64)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); + score += FindVertexScore_ValenceBoostScale * valence_boost; + + return score; +} + +class LLVCacheFIFO +{ +public: + LLVCacheVertexData* mCache[MaxSizeVertexCache]; + U32 mMisses; + + LLVCacheFIFO() + { + mMisses = 0; + for (U32 i = 0; i < MaxSizeVertexCache; ++i) + { + mCache[i] = NULL; + } + } + + void addVertex(LLVCacheVertexData* data) + { + if (data->mCacheTag == -1) + { + mMisses++; + + S32 end = MaxSizeVertexCache-1; + + if (mCache[end]) + { + mCache[end]->mCacheTag = -1; + } + + for (S32 i = end; i > 0; --i) + { + mCache[i] = mCache[i-1]; + if (mCache[i]) + { + mCache[i]->mCacheTag = i; + } + } + + mCache[0] = data; + data->mCacheTag = 0; + } + } +}; + +class LLVCacheLRU +{ +public: + LLVCacheVertexData* mCache[MaxSizeVertexCache+3]; + + LLVCacheTriangleData* mBestTriangle; + + U32 mMisses; + + LLVCacheLRU() + { + for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) + { + mCache[i] = NULL; + } + + mBestTriangle = NULL; + mMisses = 0; + } + + void addVertex(LLVCacheVertexData* data) + { + S32 end = MaxSizeVertexCache+2; + if (data->mCacheTag != -1) + { //just moving a vertex to the front of the cache + end = data->mCacheTag; + } + else + { + mMisses++; + if (mCache[end]) + { //adding a new vertex, vertex at end of cache falls off + mCache[end]->mCacheTag = -1; + } + } + + for (S32 i = end; i > 0; --i) + { //adjust cache pointers and tags + mCache[i] = mCache[i-1]; + + if (mCache[i]) + { + mCache[i]->mCacheTag = i; + } + } + + mCache[0] = data; + mCache[0]->mCacheTag = 0; + } + + void addTriangle(LLVCacheTriangleData* data) + { + addVertex(data->mVertex[0]); + addVertex(data->mVertex[1]); + addVertex(data->mVertex[2]); + } + + void updateScores() + { + LLVCacheVertexData** data_iter = mCache+MaxSizeVertexCache; + LLVCacheVertexData** end_data = mCache+MaxSizeVertexCache+3; + + while(data_iter != end_data) + { + LLVCacheVertexData* data = *data_iter++; + //trailing 3 vertices aren't actually in the cache for scoring purposes + if (data) + { + data->mCacheTag = -1; + } + } + + data_iter = mCache; + end_data = mCache+MaxSizeVertexCache; + + while (data_iter != end_data) + { //update scores of vertices in cache + LLVCacheVertexData* data = *data_iter++; + if (data) + { + data->mScore = find_vertex_score(*data); + } + } + + mBestTriangle = NULL; + //update triangle scores + data_iter = mCache; + end_data = mCache+MaxSizeVertexCache+3; + + while (data_iter != end_data) + { + LLVCacheVertexData* data = *data_iter++; + if (data) + { + for (std::vector::iterator iter = data->mTriangles.begin(), end_iter = data->mTriangles.end(); iter != end_iter; ++iter) + { + LLVCacheTriangleData* tri = *iter; + if (tri->mActive) + { + tri->mScore = tri->mVertex[0] ? tri->mVertex[0]->mScore : 0; + tri->mScore += tri->mVertex[1] ? tri->mVertex[1]->mScore : 0; + tri->mScore += tri->mVertex[2] ? tri->mVertex[2]->mScore : 0; + + if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) + { + mBestTriangle = tri; + } + } + } + } + } + + //knock trailing 3 vertices off the cache + data_iter = mCache+MaxSizeVertexCache; + end_data = mCache+MaxSizeVertexCache+3; + while (data_iter != end_data) + { + LLVCacheVertexData* data = *data_iter; + if (data) + { + llassert(data->mCacheTag == -1); + *data_iter = NULL; + } + ++data_iter; + } + } +}; + +// data structures for tangent generation + +struct MikktData +{ + LLVolumeFace* face; + std::vector p; + std::vector n; + std::vector tc; + std::vector w; + std::vector t; + + MikktData(LLVolumeFace* f) + : face(f) + { + U32 count = face->mNumIndices; + + p.resize(count); + n.resize(count); + tc.resize(count); + t.resize(count); + + if (face->mWeights) + { + w.resize(count); + } + + + LLVector3 inv_scale(1.f / face->mNormalizedScale.mV[0], 1.f / face->mNormalizedScale.mV[1], 1.f / face->mNormalizedScale.mV[2]); + + + for (int i = 0; i < face->mNumIndices; ++i) + { + U32 idx = face->mIndices[i]; + + p[i].set(face->mPositions[idx].getF32ptr()); + p[i].scaleVec(face->mNormalizedScale); //put mesh in original coordinate frame when reconstructing tangents + n[i].set(face->mNormals[idx].getF32ptr()); + n[i].scaleVec(inv_scale); + n[i].normalize(); + tc[i].set(face->mTexCoords[idx]); + + if (idx >= face->mNumVertices) + { + // invalid index + // replace with a valid index to avoid crashes + idx = face->mNumVertices - 1; + face->mIndices[i] = idx; + + // Needs better logging + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL; + } + + if (face->mWeights) + { + w[i].set(face->mWeights[idx].getF32ptr()); + } + } + } +}; + + +bool LLVolumeFace::cacheOptimize(bool gen_tangents) +{ //optimize for vertex cache according to Forsyth method: + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + llassert(!mOptimized); + mOptimized = true; + + if (gen_tangents && mNormals && mTexCoords) + { // generate mikkt space tangents before cache optimizing since the index buffer may change + // a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh + // and is executed on a background thread + SMikkTSpaceInterface ms; + + ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext) + { + MikktData* data = (MikktData*)pContext->m_pUserData; + LLVolumeFace* face = data->face; + return face->mNumIndices / 3; + }; + + ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace) + { + return 3; + }; + + ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) + { + MikktData* data = (MikktData*)pContext->m_pUserData; + F32* v = data->p[iFace * 3 + iVert].mV; + fvPosOut[0] = v[0]; + fvPosOut[1] = v[1]; + fvPosOut[2] = v[2]; + }; + + ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) + { + MikktData* data = (MikktData*)pContext->m_pUserData; + F32* n = data->n[iFace * 3 + iVert].mV; + fvNormOut[0] = n[0]; + fvNormOut[1] = n[1]; + fvNormOut[2] = n[2]; + }; + + ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) + { + MikktData* data = (MikktData*)pContext->m_pUserData; + F32* tc = data->tc[iFace * 3 + iVert].mV; + fvTexcOut[0] = tc[0]; + fvTexcOut[1] = tc[1]; + }; + + ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) + { + MikktData* data = (MikktData*)pContext->m_pUserData; + S32 i = iFace * 3 + iVert; + + data->t[i].set(fvTangent); + data->t[i].mV[3] = fSign; + }; + + ms.m_setTSpace = nullptr; + + MikktData data(this); + + SMikkTSpaceContext ctx = { &ms, &data }; + + genTangSpaceDefault(&ctx); + + //re-weld + meshopt_Stream mos[] = + { + { &data.p[0], sizeof(LLVector3), sizeof(LLVector3) }, + { &data.n[0], sizeof(LLVector3), sizeof(LLVector3) }, + { &data.t[0], sizeof(LLVector4), sizeof(LLVector4) }, + { &data.tc[0], sizeof(LLVector2), sizeof(LLVector2) }, + { data.w.empty() ? nullptr : &data.w[0], sizeof(LLVector4), sizeof(LLVector4) } + }; + + std::vector remap; + remap.resize(data.p.size()); + + U32 stream_count = data.w.empty() ? 4 : 5; + + size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); + + if (vert_count < 65535 && vert_count != 0) + { + std::vector indices; + indices.resize(mNumIndices); + + //copy results back into volume + resizeVertices(vert_count); + + if (!data.w.empty()) + { + allocateWeights(vert_count); + } + + allocateTangents(mNumVertices); + + for (int i = 0; i < mNumIndices; ++i) + { + U32 src_idx = i; + U32 dst_idx = remap[i]; + if (dst_idx >= mNumVertices) + { + dst_idx = mNumVertices - 1; + // Shouldn't happen, figure out what gets returned in remap and why. + llassert(false); + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL; + } + mIndices[i] = dst_idx; + + mPositions[dst_idx].load3(data.p[src_idx].mV); + mNormals[dst_idx].load3(data.n[src_idx].mV); + mTexCoords[dst_idx] = data.tc[src_idx]; + + mTangents[dst_idx].loadua(data.t[src_idx].mV); + + if (mWeights) + { + mWeights[dst_idx].loadua(data.w[src_idx].mV); + } + } + + // put back in normalized coordinate frame + LLVector4a inv_scale(1.f/mNormalizedScale.mV[0], 1.f / mNormalizedScale.mV[1], 1.f / mNormalizedScale.mV[2]); + LLVector4a scale; + scale.load3(mNormalizedScale.mV); + scale.getF32ptr()[3] = 1.f; + + for (int i = 0; i < mNumVertices; ++i) + { + mPositions[i].mul(inv_scale); + mNormals[i].mul(scale); + mNormals[i].normalize3(); + F32 w = mTangents[i].getF32ptr()[3]; + mTangents[i].mul(scale); + mTangents[i].normalize3(); + mTangents[i].getF32ptr()[3] = w; + } + } + else + { + if (vert_count == 0) + { + LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL; + } + // blew past the max vertex size limit, use legacy tangent generation which never adds verts + createTangents(); + } + } + + // cache optimize index buffer + + // meshopt needs scratch space, do some pointer shuffling to avoid an extra index buffer copy + U16* src_indices = mIndices; + mIndices = nullptr; + resizeIndices(mNumIndices); + + meshopt_optimizeVertexCache(mIndices, src_indices, mNumIndices, mNumVertices); + + ll_aligned_free_16(src_indices); + + return true; +} + +void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + if (getOctree()) + { + return; + } + + llassert(mNumIndices % 3 == 0); + + mOctree = new LLOctreeRoot(center, size, NULL); + new LLVolumeOctreeListener(mOctree); + const U32 num_triangles = mNumIndices / 3; + // Initialize all the triangles we need + mOctreeTriangles = new LLVolumeTriangle[num_triangles]; + + for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index) + { //for each triangle + const U32 index = triangle_index * 3; + LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; + + const LLVector4a& v0 = mPositions[mIndices[index]]; + const LLVector4a& v1 = mPositions[mIndices[index + 1]]; + const LLVector4a& v2 = mPositions[mIndices[index + 2]]; + + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = mIndices[index]; + tri->mIndex[1] = mIndices[index + 1]; + tri->mIndex[2] = mIndices[index + 2]; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max,min); + + tri->mRadius = size.getLength3().getF32() * scaler; + + //insert + mOctree->insert(tri); + } + + //remove unneeded octree layers + while (!mOctree->balance()) { } + + //calculate AABB for each node + LLVolumeOctreeRebound rebound(this); + rebound.traverse(mOctree); + + if (gDebugGL) + { + LLVolumeOctreeValidate validate; + validate.traverse(mOctree); + } +} + +void LLVolumeFace::destroyOctree() +{ + delete mOctree; + mOctree = NULL; + delete[] mOctreeTriangles; + mOctreeTriangles = NULL; +} + +const LLOctreeNode* LLVolumeFace::getOctree() const +{ + return mOctree; +} + + +void LLVolumeFace::swapData(LLVolumeFace& rhs) +{ + llswap(rhs.mPositions, mPositions); + llswap(rhs.mNormals, mNormals); + llswap(rhs.mTangents, mTangents); + 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, + LLVolumeFace::VertexData& vout, + F32 coef01, + F32 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.setNormal(v0.getNormal()); +} + +bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) +{ + LL_CHECK_MEMORY + + const LLAlignedArray& mesh = volume->getMesh(); + const LLAlignedArray& profile = volume->getProfile().mProfile; + S32 max_s = volume->getProfile().getTotal(); + S32 max_t = volume->getPath().mPath.size(); + + // S32 i; + S32 grid_size = (profile.size()-1)/4; + // VFExtents change + 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(S32 t = 0; t < 4; t++) + { + corners[t].getPosition().load4a(mesh[offset + (grid_size*t)].getF32ptr()); + corners[t].mTexCoord.mV[0] = profile[grid_size*t][0]+0.5f; + corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t][1]; + } + + { + 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(!(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; + } + + S32 size = (grid_size+1)*(grid_size+1); + resizeVertices(size); + + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + LLVector2* tc = (LLVector2*) mTexCoords; + + for(int gx = 0;gxsetAdd(min, max); + mCenter->mul(0.5f); + } + + if (!partial_build) + { + resizeIndices(grid_size*grid_size*6); + if (!volume->isMeshAssetLoaded()) + { + S32 size = grid_size * grid_size * 6; + try + { + mEdge.resize(size); + } + catch (std::bad_alloc&) + { + LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL; + return false; + } + } + + U16* out = mIndices; + + S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; + + int cur_edge = 0; + + for(S32 gx = 0;gx=0;i--) + { + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } + + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gx > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; // Mark face to higlight it + } + + if (gy < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + + if (gx < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gy > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + } + else + { + for(S32 i=0;i<6;i++) + { + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } + + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gy > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gx < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + + if (gy < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gx > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + } + } + } + } + + LL_CHECK_MEMORY + return true; +} + + +bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) +{ + if (!(mTypeMask & HOLLOW_MASK) && + !(mTypeMask & OPEN_MASK) && + ((volume->getParams().getPathParams().getBegin()==0.0f)&& + (volume->getParams().getPathParams().getEnd()==1.0f))&& + (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE && + volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE) + ){ + return createUnCutCubeCap(volume, partial_build); + } + + S32 num_vertices = 0, num_indices = 0; + + const LLAlignedArray& mesh = volume->getMesh(); + const LLAlignedArray& profile = volume->getProfile().mProfile; + + // All types of caps have the same number of vertices and indices + num_vertices = profile.size(); + num_indices = (profile.size() - 2)*3; + + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) + { + resizeVertices(num_vertices+1); + + //if (!partial_build) + { + resizeIndices(num_indices+3); + } + } + else + { + resizeVertices(num_vertices); + //if (!partial_build) + { + resizeIndices(num_indices); + } + } + + LL_CHECK_MEMORY; + + S32 max_s = volume->getProfile().getTotal(); + S32 max_t = volume->getPath().mPath.size(); + + mCenter->clear(); + + S32 offset = 0; + if (mTypeMask & TOP_MASK) + { + offset = (max_t-1) * max_s; + } + else + { + offset = mBeginS; + } + + // Figure out the normal, assume all caps are flat faces. + // Cross product to get normals. + + LLVector2 cuv; + LLVector2 min_uv, max_uv; + // VFExtents change + LLVector4a& min = mExtents[0]; + LLVector4a& max = mExtents[1]; + + LLVector2* tc = (LLVector2*) mTexCoords; + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + + // Copy the vertices into the array + + const LLVector4a* src = mesh.mArray+offset; + const LLVector4a* end = src+num_vertices; + + min = *src; + max = min; + + + const LLVector4a* p = profile.mArray; + + if (mTypeMask & TOP_MASK) + { + min_uv.set((*p)[0]+0.5f, + (*p)[1]+0.5f); + + max_uv = min_uv; + + while(src < end) + { + tc->mV[0] = (*p)[0]+0.5f; + tc->mV[1] = (*p)[1]+0.5f; + + llassert(src->isFinite3()); // MAINT-5660; don't know why this happens, does not affect Release builds + update_min_max(min,max,*src); + update_min_max(min_uv, max_uv, *tc); + + *pos = *src; + + llassert(pos->isFinite3()); + + ++p; + ++tc; + ++src; + ++pos; + } + } + else + { + + min_uv.set((*p)[0]+0.5f, + 0.5f - (*p)[1]); + max_uv = min_uv; + + while(src < end) + { + // Mirror for underside. + tc->mV[0] = (*p)[0]+0.5f; + tc->mV[1] = 0.5f - (*p)[1]; + + llassert(src->isFinite3()); + update_min_max(min,max,*src); + update_min_max(min_uv, max_uv, *tc); + + *pos = *src; + + llassert(pos->isFinite3()); + + ++p; + ++tc; + ++src; + ++pos; + } + } + + LL_CHECK_MEMORY + + mCenter->setAdd(min, max); + mCenter->mul(0.5f); + + cuv = (min_uv + max_uv)*0.5f; + + + VertexData vd; + vd.setPosition(*mCenter); + vd.mTexCoord = cuv; + + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) + { + *pos++ = *mCenter; + *tc++ = cuv; + num_vertices++; + } + + LL_CHECK_MEMORY + + //if (partial_build) + //{ + // return true; + //} + + if (mTypeMask & HOLLOW_MASK) + { + if (mTypeMask & TOP_MASK) + { + // HOLLOW TOP + // Does it matter if it's open or closed? - djs + + S32 pt1 = 0, pt2 = num_vertices - 1; + S32 i = 0; + while (pt2 - pt1 > 1) + { + // Use the profile points instead of the mesh, since you want + // the un-transformed profile distances. + const LLVector4a& p1 = profile[pt1]; + const LLVector4a& p2 = profile[pt2]; + const LLVector4a& pa = profile[pt1+1]; + const LLVector4a& pb = profile[pt2-1]; + + const F32* p1V = p1.getF32ptr(); + const F32* p2V = p2.getF32ptr(); + const F32* paV = pa.getF32ptr(); + const F32* pbV = pb.getF32ptr(); + + //p1.mV[VZ] = 0.f; + //p2.mV[VZ] = 0.f; + //pa.mV[VZ] = 0.f; + //pb.mV[VZ] = 0.f; + + // Use area of triangle to determine backfacing + F32 area_1a2, area_1ba, area_21b, area_2ab; + area_1a2 = (p1V[0]*paV[1] - paV[0]*p1V[1]) + + (paV[0]*p2V[1] - p2V[0]*paV[1]) + + (p2V[0]*p1V[1] - p1V[0]*p2V[1]); + + area_1ba = (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*paV[1] - paV[0]*pbV[1]) + + (paV[0]*p1V[1] - p1V[0]*paV[1]); + + area_21b = (p2V[0]*p1V[1] - p1V[0]*p2V[1]) + + (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); + + area_2ab = (p2V[0]*paV[1] - paV[0]*p2V[1]) + + (paV[0]*pbV[1] - pbV[0]*paV[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); + + bool use_tri1a2 = true; + bool tri_1a2 = true; + bool tri_21b = true; + + if (area_1a2 < 0) + { + tri_1a2 = false; + } + if (area_2ab < 0) + { + // Can't use, because it contains point b + tri_1a2 = false; + } + if (area_21b < 0) + { + tri_21b = false; + } + if (area_1ba < 0) + { + // Can't use, because it contains point b + tri_21b = false; + } + + if (!tri_1a2) + { + use_tri1a2 = false; + } + else if (!tri_21b) + { + use_tri1a2 = true; + } + else + { + LLVector4a d1; + d1.setSub(p1, pa); + + LLVector4a d2; + d2.setSub(p2, pb); + + if (d1.dot3(d1) < d2.dot3(d2)) + { + use_tri1a2 = true; + } + else + { + use_tri1a2 = false; + } + } + + if (use_tri1a2) + { + mIndices[i++] = pt1; + mIndices[i++] = pt1 + 1; + mIndices[i++] = pt2; + pt1++; + } + else + { + mIndices[i++] = pt1; + mIndices[i++] = pt2 - 1; + mIndices[i++] = pt2; + pt2--; + } + } + } + else + { + // HOLLOW BOTTOM + // Does it matter if it's open or closed? - djs + + llassert(mTypeMask & BOTTOM_MASK); + S32 pt1 = 0, pt2 = num_vertices - 1; + + S32 i = 0; + while (pt2 - pt1 > 1) + { + // Use the profile points instead of the mesh, since you want + // the un-transformed profile distances. + const LLVector4a& p1 = profile[pt1]; + const LLVector4a& p2 = profile[pt2]; + const LLVector4a& pa = profile[pt1+1]; + const LLVector4a& pb = profile[pt2-1]; + + const F32* p1V = p1.getF32ptr(); + const F32* p2V = p2.getF32ptr(); + const F32* paV = pa.getF32ptr(); + const F32* pbV = pb.getF32ptr(); + + // Use area of triangle to determine backfacing + F32 area_1a2, area_1ba, area_21b, area_2ab; + area_1a2 = (p1V[0]*paV[1] - paV[0]*p1V[1]) + + (paV[0]*p2V[1] - p2V[0]*paV[1]) + + (p2V[0]*p1V[1] - p1V[0]*p2V[1]); + + area_1ba = (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*paV[1] - paV[0]*pbV[1]) + + (paV[0]*p1V[1] - p1V[0]*paV[1]); + + area_21b = (p2V[0]*p1V[1] - p1V[0]*p2V[1]) + + (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); + + area_2ab = (p2V[0]*paV[1] - paV[0]*p2V[1]) + + (paV[0]*pbV[1] - pbV[0]*paV[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); + + bool use_tri1a2 = true; + bool tri_1a2 = true; + bool tri_21b = true; + + if (area_1a2 < 0) + { + tri_1a2 = false; + } + if (area_2ab < 0) + { + // Can't use, because it contains point b + tri_1a2 = false; + } + if (area_21b < 0) + { + tri_21b = false; + } + if (area_1ba < 0) + { + // Can't use, because it contains point b + tri_21b = false; + } + + if (!tri_1a2) + { + use_tri1a2 = false; + } + else if (!tri_21b) + { + use_tri1a2 = true; + } + else + { + LLVector4a d1; + d1.setSub(p1,pa); + LLVector4a d2; + d2.setSub(p2,pb); + + if (d1.dot3(d1) < d2.dot3(d2)) + { + use_tri1a2 = true; + } + else + { + use_tri1a2 = false; + } + } + + // Flipped backfacing from top + if (use_tri1a2) + { + mIndices[i++] = pt1; + mIndices[i++] = pt2; + mIndices[i++] = pt1 + 1; + pt1++; + } + else + { + mIndices[i++] = pt1; + mIndices[i++] = pt2; + mIndices[i++] = pt2 - 1; + pt2--; + } + } + } + } + else + { + // Not hollow, generate the triangle fan. + U16 v1 = 2; + U16 v2 = 1; + + if (mTypeMask & TOP_MASK) + { + v1 = 1; + v2 = 2; + } + + for (S32 i = 0; i < (num_vertices - 2); i++) + { + mIndices[3*i] = num_vertices - 1; + mIndices[3*i+v1] = i; + mIndices[3*i+v2] = i + 1; + } + + + } + + LLVector4a d0,d1; + LL_CHECK_MEMORY + + + 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 + if(normal.getF32ptr()[2] >= 0) + normal.set(0.f,0.f,1.f); + else + normal.set(0.f,0.f,-1.f); + } + + 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; +} + +void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, + const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent); + +void LLVolumeFace::createTangents() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + if (!mTangents) + { + allocateTangents(mNumVertices); + + //generate tangents + LLVector4a* ptr = (LLVector4a*)mTangents; + + LLVector4a* end = mTangents + mNumVertices; + while (ptr < end) + { + (*ptr++).clear(); + } + + CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents); + + //normalize normals + for (U32 i = 0; i < mNumVertices; i++) + { + //bump map/planar projection code requires normals to be normalized + mNormals[i].normalize3fast(); + } + } + +} + +void LLVolumeFace::resizeVertices(S32 num_verts) +{ + ll_aligned_free<64>(mPositions); + //DO NOT free mNormals and mTexCoords as they are part of mPositions buffer + ll_aligned_free_16(mTangents); + + mTangents = NULL; + + if (num_verts) + { + //pad texture coordinate block end to allow for QWORD reads + S32 tc_size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; + + mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+tc_size); + mNormals = mPositions+num_verts; + mTexCoords = (LLVector2*) (mNormals+num_verts); + + ll_assert_aligned(mPositions, 64); + } + else + { + mPositions = NULL; + mNormals = NULL; + mTexCoords = NULL; + } + + + if (mPositions) + { + mNumVertices = num_verts; + mNumAllocatedVertices = num_verts; + } + else + { + // Either num_verts is zero or allocation failure + mNumVertices = 0; + mNumAllocatedVertices = 0; + } + + // Force update + mJointRiggingInfoTab.clear(); +} + +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; + + if (new_verts > mNumAllocatedVertices) + { + // double buffer size on expansion + new_verts *= 2; + + S32 new_tc_size = ((new_verts*8)+0xF) & ~0xF; + S32 old_tc_size = ((mNumVertices*8)+0xF) & ~0xF; + + S32 old_vsize = mNumVertices*16; + + S32 new_size = new_verts*16*2+new_tc_size; + + LLVector4a* old_buf = mPositions; + + mPositions = (LLVector4a*) ll_aligned_malloc<64>(new_size); + mNormals = mPositions+new_verts; + mTexCoords = (LLVector2*) (mNormals+new_verts); + + if (old_buf != NULL) + { + // copy old positions into new buffer + LLVector4a::memcpyNonAliased16((F32*)mPositions, (F32*)old_buf, old_vsize); + + // normals + LLVector4a::memcpyNonAliased16((F32*)mNormals, (F32*)(old_buf + mNumVertices), old_vsize); + + // tex coords + LLVector4a::memcpyNonAliased16((F32*)mTexCoords, (F32*)(old_buf + mNumVertices * 2), old_tc_size); + } + + // just clear tangents + ll_aligned_free_16(mTangents); + mTangents = NULL; + ll_aligned_free<64>(old_buf); + + mNumAllocatedVertices = new_verts; + + } + + mPositions[mNumVertices] = pos; + mNormals[mNumVertices] = norm; + mTexCoords[mNumVertices] = tc; + + mNumVertices++; +} + +void LLVolumeFace::allocateTangents(S32 num_verts) +{ + ll_aligned_free_16(mTangents); + mTangents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); +} + +void LLVolumeFace::allocateWeights(S32 num_verts) +{ + ll_aligned_free_16(mWeights); + mWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + +} + +void LLVolumeFace::allocateJointIndices(S32 num_verts) +{ +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + ll_aligned_free_16(mJointIndices); + ll_aligned_free_16(mJustWeights); + + mJointIndices = (U8*)ll_aligned_malloc_16(sizeof(U8) * 4 * num_verts); + mJustWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * num_verts); +#endif +} + +void LLVolumeFace::resizeIndices(S32 num_indices) +{ + ll_aligned_free_16(mIndices); + llassert(num_indices % 3 == 0); + + if (num_indices) + { + //pad index block end to allow for QWORD reads + S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; + + mIndices = (U16*) ll_aligned_malloc_16(size); + } + else + { + mIndices = NULL; + } + + if (mIndices) + { + mNumIndices = num_indices; + } + else + { + // Either num_indices is zero or allocation failure + mNumIndices = 0; + } +} + +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) + { + mIndices = (U16*) ll_aligned_realloc_16(mIndices, new_size, old_size); + ll_assert_aligned(mIndices,16); + } + + mIndices[mNumIndices++] = idx; +} + +void LLVolumeFace::fillFromLegacyData(std::vector& v, std::vector& idx) +{ + resizeVertices(v.size()); + resizeIndices(idx.size()); + + for (U32 i = 0; i < v.size(); ++i) + { + 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]; + } +} + +bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + LL_CHECK_MEMORY + bool flat = mTypeMask & FLAT_MASK; + + U8 sculpt_type = volume->getParams().getSculptType(); + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + bool sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + bool sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + bool sculpt_reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror); // XOR + + S32 num_vertices, num_indices; + + const LLAlignedArray& mesh = volume->getMesh(); + const LLAlignedArray& profile = volume->getProfile().mProfile; + const LLAlignedArray& path_data = volume->getPath().mPath; + + S32 max_s = volume->getProfile().getTotal(); + + S32 s, t, i; + F32 ss, tt; + + num_vertices = mNumS*mNumT; + num_indices = (mNumS-1)*(mNumT-1)*6; + + partial_build = (num_vertices > mNumVertices || num_indices > mNumIndices) ? false : partial_build; + + if (!partial_build) + { + resizeVertices(num_vertices); + resizeIndices(num_indices); + + if (!volume->isMeshAssetLoaded()) + { + try + { + mEdge.resize(num_indices); + } + catch (std::bad_alloc&) + { + LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL; + return false; + } + } + } + + LL_CHECK_MEMORY + + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector2* tc = (LLVector2*) mTexCoords; + F32 begin_stex = floorf(profile[mBeginS][2]); + S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; + + S32 cur_vertex = 0; + S32 end_t = mBeginT+mNumT; + bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2; + + // Copy the vertices into the array + for (t = mBeginT; t < end_t; t++) + { + tt = path_data[t].mTexT; + for (s = 0; s < num_s; s++) + { + if (mTypeMask & END_MASK) + { + if (s) + { + ss = 1.f; + } + else + { + ss = 0.f; + } + } + else + { + // Get s value for tex-coord. + S32 index = mBeginS + s; + if (index >= profile.size()) + { + // edge? + ss = flat ? 1.f - begin_stex : 1.f; + } + else if (!flat) + { + ss = profile[index][2]; + } + else + { + ss = profile[index][2] - begin_stex; + } + } + + if (sculpt_reverse_horizontal) + { + ss = 1.f - ss; + } + + // Check to see if this triangle wraps around the array. + if (mBeginS + s >= max_s) + { + // We're wrapping + i = mBeginS + s + max_s*(t-1); + } + else + { + i = mBeginS + s + max_s*t; + } + + mesh[i].store4a((F32*)(pos+cur_vertex)); + tc[cur_vertex].set(ss,tt); + + cur_vertex++; + + if (test && s > 0) + { + mesh[i].store4a((F32*)(pos+cur_vertex)); + tc[cur_vertex].set(ss,tt); + cur_vertex++; + } + } + + if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) + { + if (mTypeMask & OPEN_MASK) + { + s = num_s-1; + } + else + { + s = 0; + } + + i = mBeginS + s + max_s*t; + ss = profile[mBeginS + s][2] - begin_stex; + + mesh[i].store4a((F32*)(pos+cur_vertex)); + tc[cur_vertex].set(ss,tt); + + cur_vertex++; + } + } + LL_CHECK_MEMORY + + mCenter->clear(); + + LLVector4a* cur_pos = pos; + LLVector4a* end_pos = pos + mNumVertices; + + //get bounding box for this side + LLVector4a face_min; + LLVector4a face_max; + + face_min = face_max = *cur_pos++; + + while (cur_pos < end_pos) + { + update_min_max(face_min, face_max, *cur_pos++); + } + // VFExtents change + mExtents[0] = face_min; + mExtents[1] = face_max; + + U32 tc_count = mNumVertices; + if (tc_count%2 == 1) + { //odd number of texture coordinates, duplicate last entry to padded end of array + tc_count++; + mTexCoords[mNumVertices] = mTexCoords[mNumVertices-1]; + } + + LLVector4a* cur_tc = (LLVector4a*) mTexCoords; + LLVector4a* end_tc = (LLVector4a*) (mTexCoords+tc_count); + + LLVector4a tc_min; + LLVector4a tc_max; + + tc_min = tc_max = *cur_tc++; + + while (cur_tc < end_tc) + { + update_min_max(tc_min, tc_max, *cur_tc++); + } + + F32* minp = tc_min.getF32ptr(); + F32* maxp = tc_max.getF32ptr(); + + mTexCoordExtents[0].mV[0] = llmin(minp[0], minp[2]); + mTexCoordExtents[0].mV[1] = llmin(minp[1], minp[3]); + mTexCoordExtents[1].mV[0] = llmax(maxp[0], maxp[2]); + mTexCoordExtents[1].mV[1] = llmax(maxp[1], maxp[3]); + + mCenter->setAdd(face_min, face_max); + mCenter->mul(0.5f); + + S32 cur_index = 0; + S32 cur_edge = 0; + bool flat_face = mTypeMask & FLAT_MASK; + + if (!partial_build) + { + // Now we generate the indices. + for (t = 0; t < (mNumT-1); t++) + { + for (s = 0; s < (mNumS-1); s++) + { + mIndices[cur_index++] = s + mNumS*t; //bottom left + mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right + mIndices[cur_index++] = s + mNumS*(t+1); //top left + mIndices[cur_index++] = s + mNumS*t; //bottom left + mIndices[cur_index++] = s+1 + mNumS*t; //bottom right + mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right + + // bottom left/top right neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; + + if (t < mNumT-2) + { // top right/top left neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; + } + else if (mNumT <= 3 || volume->getPath().isOpen()) + { // no neighbor + mEdge[cur_edge++] = -1; + } + else + { // wrap on T + mEdge[cur_edge++] = s*2+1; + } + + if (s > 0) + { // top left/bottom left neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; + } + else if (flat_face || volume->getProfile().isOpen()) + { // no neighbor + mEdge[cur_edge++] = -1; + } + else + { // wrap on S + mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; + } + + if (t > 0) + { // bottom left/bottom right neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; + } + else if (mNumT <= 3 || volume->getPath().isOpen()) + { // no neighbor + mEdge[cur_edge++] = -1; + } + else + { // wrap on T + mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; + } + + if (s < mNumS-2) + { // bottom right/top right neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; + } + else if (flat_face || volume->getProfile().isOpen()) + { // no neighbor + mEdge[cur_edge++] = -1; + } + else + { // wrap on S + mEdge[cur_edge++] = (mNumS-1)*2*t; + } + + // top right/bottom left neighbor face + mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; + } + } + } + + LL_CHECK_MEMORY + + //clear normals + F32* dst = (F32*) mNormals; + F32* end = (F32*) (mNormals+mNumVertices); + LLVector4a zero = LLVector4a::getZero(); + + while (dst < end) + { + zero.store4a(dst); + dst += 4; + } + + LL_CHECK_MEMORY + + //generate normals + U32 count = mNumIndices/3; + + LLVector4a* norm = mNormals; + + static thread_local LLAlignedArray triangle_normals; + try + { + triangle_normals.resize(count); + } + catch (std::bad_alloc&) + { + LL_WARNS("LLVOLUME") << "Resize of triangle_normals to " << count << " failed" << LL_ENDL; + return false; + } + LLVector4a* output = triangle_normals.mArray; + LLVector4a* end_output = output+count; + + U16* idx = mIndices; + + while (output < end_output) + { + LLVector4a b,v1,v2; + b.load4a((F32*) (pos+idx[0])); + v1.load4a((F32*) (pos+idx[1])); + v2.load4a((F32*) (pos+idx[2])); + + //calculate triangle normal + LLVector4a a; + + a.setSub(b, v1); + b.sub(v2); + + + LLQuad& vector1 = *((LLQuad*) &v1); + LLQuad& vector2 = *((LLQuad*) &v2); + + LLQuad& amQ = *((LLQuad*) &a); + LLQuad& bmQ = *((LLQuad*) &b); + + //v1.setCross3(t,v0); + //setCross3(const LLVector4a& a, const LLVector4a& b) + // Vectors are stored in memory in w, z, y, x order from high to low + // Set vector1 = { a[W], a[X], a[Z], a[Y] } + vector1 = _mm_shuffle_ps( amQ, amQ, _MM_SHUFFLE( 3, 0, 2, 1 )); + // Set vector2 = { b[W], b[Y], b[X], b[Z] } + vector2 = _mm_shuffle_ps( bmQ, bmQ, _MM_SHUFFLE( 3, 1, 0, 2 )); + // mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] } + vector2 = _mm_mul_ps( vector1, vector2 ); + // vector3 = { a[W], a[Y], a[X], a[Z] } + amQ = _mm_shuffle_ps( amQ, amQ, _MM_SHUFFLE( 3, 1, 0, 2 )); + // vector4 = { b[W], b[X], b[Z], b[Y] } + bmQ = _mm_shuffle_ps( bmQ, bmQ, _MM_SHUFFLE( 3, 0, 2, 1 )); + // mQ = { 0, a[X]*b[Y] - a[Y]*b[X], a[Z]*b[X] - a[X]*b[Z], a[Y]*b[Z] - a[Z]*b[Y] } + vector1 = _mm_sub_ps( vector2, _mm_mul_ps( amQ, bmQ )); + + llassert(v1.isFinite3()); + + v1.store4a((F32*) output); + + + output++; + idx += 3; + } + + idx = mIndices; + + LLVector4a* src = triangle_normals.mArray; + + for (U32 i = 0; i < count; i++) //for each triangle + { + LLVector4a c; + c.load4a((F32*) (src++)); + + LLVector4a* n0p = norm+idx[0]; + LLVector4a* n1p = norm+idx[1]; + LLVector4a* n2p = norm+idx[2]; + + idx += 3; + + LLVector4a n0,n1,n2; + n0.load4a((F32*) n0p); + n1.load4a((F32*) n1p); + n2.load4a((F32*) n2p); + + n0.add(c); + n1.add(c); + n2.add(c); + + llassert(c.isFinite3()); + + //even out quad contributions + switch (i%2+1) + { + case 0: n0.add(c); break; + case 1: n1.add(c); break; + case 2: n2.add(c); break; + }; + + n0.store4a((F32*) n0p); + n1.store4a((F32*) n1p); + n2.store4a((F32*) n2p); + } + + LL_CHECK_MEMORY + + // adjust normals based on wrapping and stitching + + 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()) + { //wrap normals on T + for (S32 i = 0; i < mNumS; i++) + { + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; + } + } + + if (!volume->getProfile().isOpen() && !s_bottom_converges) + { //wrap normals on S + for (S32 i = 0; i < mNumT; i++) + { + LLVector4a n; + n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); + norm[mNumS * i] = n; + norm[mNumS * i+mNumS-1] = n; + } + } + + if (volume->getPathType() == LL_PCODE_PATH_CIRCLE && + ((volume->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) + { + if (s_bottom_converges) + { //all lower S have same normal + for (S32 i = 0; i < mNumT; i++) + { + norm[mNumS*i].set(1,0,0); + } + } + + if (s_top_converges) + { //all upper S have same normal + for (S32 i = 0; i < mNumT; i++) + { + norm[mNumS*i+mNumS-1].set(-1,0,0); + } + } + } + } + else // logic for sculpt volumes + { + bool average_poles = false; + bool wrap_s = false; + bool wrap_t = false; + + if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) + average_poles = true; + + if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || + (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || + (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) + wrap_s = true; + + if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) + wrap_t = true; + + + if (average_poles) + { + // average normals for north pole + + LLVector4a average; + average.clear(); + + for (S32 i = 0; i < mNumS; i++) + { + average.add(norm[i]); + } + + // set average + for (S32 i = 0; i < mNumS; i++) + { + norm[i] = average; + } + + // average normals for south pole + + average.clear(); + + for (S32 i = 0; i < mNumS; i++) + { + average.add(norm[i + mNumS * (mNumT - 1)]); + } + + // set average + for (S32 i = 0; i < mNumS; i++) + { + norm[i + mNumS * (mNumT - 1)] = average; + } + + } + + + if (wrap_s) + { + for (S32 i = 0; i < mNumT; i++) + { + 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++) + { + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; + } + } + + } + + LL_CHECK_MEMORY + + return true; +} + +//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) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + + //LLVector4a *tan1 = new LLVector4a[vertexCount * 2]; + LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a)); + // new(tan1) LLVector4a; + + LLVector4a* tan2 = tan1 + vertexCount; + + U32 count = vertexCount * 2; + for (U32 i = 0; i < count; i++) + { + tan1[i].clear(); + } + + for (U32 a = 0; a < triangleCount; a++) + { + U32 i1 = *index_array++; + U32 i2 = *index_array++; + U32 i3 = *index_array++; + + const LLVector4a& v1 = vertex[i1]; + const LLVector4a& v2 = vertex[i2]; + const LLVector4a& v3 = vertex[i3]; + + const LLVector2& w1 = texcoord[i1]; + const LLVector2& w2 = texcoord[i2]; + const LLVector2& w3 = texcoord[i3]; + + 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) + : ((rd > 0.0f) ? 1024.f : -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); + + tan1[i1].add(sdir); + tan1[i2].add(sdir); + tan1[i3].add(sdir); + + tan2[i1].add(tdir); + tan2[i2].add(tdir); + tan2[i3].add(tdir); + } + + for (U32 a = 0; a < vertexCount; a++) + { + LLVector4a n = normal[a]; + + const LLVector4a& t = tan1[a]; + + 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(); + + // Calculate handedness + F32 handedness = ncrosst.dot3(tan2[a]).getF32() < 0.f ? -1.f : 1.f; + + tsubn.getF32ptr()[3] = handedness; + + tangent[a] = tsubn; + } + else + { //degenerate, make up a value + tangent[a].set(0,0,1,1); + } + } + + ll_aligned_free_16(tan1); +} + + diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 4f8d9bef84..44a24f8496 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1,1152 +1,1152 @@ -/** - * @file llvolume.h - * @brief LLVolume base class. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVOLUME_H -#define LL_LLVOLUME_H - -#include - -class LLProfileParams; -class LLPathParams; -class LLVolumeParams; -class LLProfile; -class LLPath; - -template class LLPointer; -template class LLOctreeNode; - -class LLVolumeFace; -class LLVolume; -class LLVolumeTriangle; - -#include "lluuid.h" -#include "v4color.h" -//#include "vmath.h" -#include "v2math.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "llvector4a.h" -#include "llmatrix4a.h" -#include "llquaternion.h" -#include "llstrider.h" -#include "v4coloru.h" -#include "llrefcount.h" -#include "llpointer.h" -#include "llfile.h" -#include "llalignedarray.h" -#include "llrigginginfo.h" - -//============================================================================ - -constexpr S32 MIN_DETAIL_FACES = 6; -constexpr S32 MIN_LOD = 0; -constexpr S32 MAX_LOD = 3; - -// These are defined here but are not enforced at this level, -// rather they are here for the convenience of code that uses -// the LLVolume class. -constexpr F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; -constexpr F32 MIN_VOLUME_PATH_WIDTH = 0.05f; - -constexpr F32 CUT_QUANTA = 0.00002f; -constexpr F32 SCALE_QUANTA = 0.01f; -constexpr F32 SHEAR_QUANTA = 0.01f; -constexpr F32 TAPER_QUANTA = 0.01f; -constexpr F32 REV_QUANTA = 0.015f; -constexpr F32 HOLLOW_QUANTA = 0.00002f; - -constexpr S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; - -//============================================================================ - -// useful masks -constexpr LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness -constexpr LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) -constexpr LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) -constexpr LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum -constexpr LLPCode LL_PCODE_BASE_MASK = 0x0F; - - // primitive shapes -constexpr LLPCode LL_PCODE_CUBE = 1; -constexpr LLPCode LL_PCODE_PRISM = 2; -constexpr LLPCode LL_PCODE_TETRAHEDRON = 3; -constexpr LLPCode LL_PCODE_PYRAMID = 4; -constexpr LLPCode LL_PCODE_CYLINDER = 5; -constexpr LLPCode LL_PCODE_CONE = 6; -constexpr LLPCode LL_PCODE_SPHERE = 7; -constexpr LLPCode LL_PCODE_TORUS = 8; -constexpr LLPCode LL_PCODE_VOLUME = 9; - - // surfaces -//constexpr LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; -//constexpr LLPCode LL_PCODE_SURFACE_SQUARE = 11; -//constexpr LLPCode LL_PCODE_SURFACE_DISC = 12; - -constexpr LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) -constexpr LLPCode LL_PCODE_LEGACY = 15; - -// Pcodes for legacy objects -//constexpr LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR -constexpr LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER -//constexpr LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD -//constexpr LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON -constexpr LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS -constexpr LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees -//constexpr LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE -constexpr LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS -constexpr LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK -//constexpr LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT -//constexpr LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; -//constexpr LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE -//constexpr LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK -constexpr LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE -constexpr LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE - - // hemis -constexpr LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; -constexpr LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; -constexpr LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; -constexpr LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; - - -// Volumes consist of a profile at the base that is swept around -// a path to make a volume. -// The profile code -constexpr U8 LL_PCODE_PROFILE_MASK = 0x0f; -constexpr U8 LL_PCODE_PROFILE_MIN = 0x00; -constexpr U8 LL_PCODE_PROFILE_CIRCLE = 0x00; -constexpr U8 LL_PCODE_PROFILE_SQUARE = 0x01; -constexpr U8 LL_PCODE_PROFILE_ISOTRI = 0x02; -constexpr U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; -constexpr U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; -constexpr U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; -constexpr U8 LL_PCODE_PROFILE_MAX = 0x05; - -// Stored in the profile byte -constexpr U8 LL_PCODE_HOLE_MASK = 0xf0; -constexpr U8 LL_PCODE_HOLE_MIN = 0x00; -constexpr U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile -constexpr U8 LL_PCODE_HOLE_CIRCLE = 0x10; -constexpr U8 LL_PCODE_HOLE_SQUARE = 0x20; -constexpr U8 LL_PCODE_HOLE_TRIANGLE = 0x30; -constexpr U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max - -constexpr U8 LL_PCODE_PATH_IGNORE = 0x00; -constexpr U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max -constexpr U8 LL_PCODE_PATH_LINE = 0x10; -constexpr U8 LL_PCODE_PATH_CIRCLE = 0x20; -constexpr U8 LL_PCODE_PATH_CIRCLE2 = 0x30; -constexpr U8 LL_PCODE_PATH_TEST = 0x40; -constexpr U8 LL_PCODE_PATH_FLEXIBLE = 0x80; -constexpr U8 LL_PCODE_PATH_MAX = 0x08; - -//============================================================================ - -// face identifiers -typedef U16 LLFaceID; - -constexpr LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; -constexpr LLFaceID LL_FACE_PATH_END = 0x1 << 1; -constexpr LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; -constexpr LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; -constexpr LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; -constexpr LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; -constexpr LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; -constexpr LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; -constexpr LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; - -//============================================================================ - -// sculpt types + flags - -constexpr U8 LL_SCULPT_TYPE_NONE = 0; -constexpr U8 LL_SCULPT_TYPE_SPHERE = 1; -constexpr U8 LL_SCULPT_TYPE_TORUS = 2; -constexpr U8 LL_SCULPT_TYPE_PLANE = 3; -constexpr U8 LL_SCULPT_TYPE_CYLINDER = 4; -constexpr U8 LL_SCULPT_TYPE_MESH = 5; -constexpr 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; - -// for value checks, assign new value after adding new types -constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; - -constexpr U8 LL_SCULPT_FLAG_INVERT = 64; -constexpr U8 LL_SCULPT_FLAG_MIRROR = 128; -constexpr U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; - -constexpr S32 LL_SCULPT_MESH_MAX_FACES = 8; - -extern bool gDebugGL; - -class LLProfileParams -{ -public: - LLProfileParams() - : mCurveType(LL_PCODE_PROFILE_SQUARE), - mBegin(0.f), - mEnd(1.f), - mHollow(0.f), - mCRC(0) - { - } - - LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) - : mCurveType(curve), - mBegin(begin), - mEnd(end), - mHollow(hollow), - mCRC(0) - { - } - - LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow) - { - mCurveType = curve; - F32 temp_f32 = begin * CUT_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mBegin = temp_f32; - temp_f32 = end * CUT_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mEnd = 1.f - temp_f32; - temp_f32 = hollow * HOLLOW_QUANTA; - if (temp_f32 > 1.f) - { - temp_f32 = 1.f; - } - mHollow = temp_f32; - mCRC = 0; - } - - bool operator==(const LLProfileParams ¶ms) const; - bool operator!=(const LLProfileParams ¶ms) const; - bool operator<(const LLProfileParams ¶ms) const; - - void copyParams(const LLProfileParams ¶ms); - - bool importFile(LLFILE *fp); - bool exportFile(LLFILE *fp) const; - - bool importLegacyStream(std::istream& input_stream); - bool exportLegacyStream(std::ostream& output_stream) const; - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - const F32& getBegin () const { return mBegin; } - const F32& getEnd () const { return mEnd; } - const F32& getHollow() const { return mHollow; } - const U8& getCurveType () const { return mCurveType; } - - void setCurveType(const U32 type) { mCurveType = type;} - void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;} - void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;} - void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 100000))/100000.0f;} - - friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params); - -protected: - // Profile params - U8 mCurveType; - F32 mBegin; - F32 mEnd; - F32 mHollow; - - U32 mCRC; -}; - -inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const -{ - return - (getCurveType() == params.getCurveType()) && - (getBegin() == params.getBegin()) && - (getEnd() == params.getEnd()) && - (getHollow() == params.getHollow()); -} - -inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const -{ - return - (getCurveType() != params.getCurveType()) || - (getBegin() != params.getBegin()) || - (getEnd() != params.getEnd()) || - (getHollow() != params.getHollow()); -} - - -inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) const -{ - if (getCurveType() != params.getCurveType()) - { - return getCurveType() < params.getCurveType(); - } - else - if (getBegin() != params.getBegin()) - { - return getBegin() < params.getBegin(); - } - else - if (getEnd() != params.getEnd()) - { - return getEnd() < params.getEnd(); - } - else - { - return getHollow() < params.getHollow(); - } -} - -#define U8_TO_F32(x) (F32)(*((S8 *)&x)) - -class LLPathParams -{ -public: - LLPathParams() - : - mCurveType(LL_PCODE_PATH_LINE), - mBegin(0.f), - mEnd(1.f), - mScale(1.f,1.f), - mShear(0.f,0.f), - mTwistBegin(0.f), - mTwistEnd(0.f), - mRadiusOffset(0.f), - mTaper(0.f,0.f), - mRevolutions(1.f), - mSkew(0.f), - mCRC(0) - { - } - - LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) - : mCurveType(curve), - mBegin(begin), - mEnd(end), - mScale(scx,scy), - mShear(shx,shy), - mTwistBegin(twistbegin), - mTwistEnd(twistend), - mRadiusOffset(radiusoffset), - mTaper(tx,ty), - mRevolutions(revolutions), - mSkew(skew), - mCRC(0) - { - } - - LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew) - { - mCurveType = curve; - mBegin = (F32)(begin * CUT_QUANTA); - mEnd = (F32)(100.f - end) * CUT_QUANTA; - if (mEnd > 1.f) - mEnd = 1.f; - mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA); - mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA); - mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA; - mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA; - mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA; - mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA); - mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f; - mSkew = U8_TO_F32(skew) * SCALE_QUANTA; - - mCRC = 0; - } - - bool operator==(const LLPathParams ¶ms) const; - bool operator!=(const LLPathParams ¶ms) const; - bool operator<(const LLPathParams ¶ms) const; - - void copyParams(const LLPathParams ¶ms); - - bool importFile(LLFILE *fp); - bool exportFile(LLFILE *fp) const; - - bool importLegacyStream(std::istream& input_stream); - bool exportLegacyStream(std::ostream& output_stream) const; - - LLSD asLLSD() const; - operator LLSD() const { return asLLSD(); } - bool fromLLSD(LLSD& sd); - - const F32& getBegin() const { return mBegin; } - const F32& getEnd() const { return mEnd; } - const LLVector2 &getScale() const { return mScale; } - const F32& getScaleX() const { return mScale.mV[0]; } - const F32& getScaleY() const { return mScale.mV[1]; } - const LLVector2 getBeginScale() const; - const LLVector2 getEndScale() const; - const LLVector2 &getShear() const { return mShear; } - const F32& getShearX() const { return mShear.mV[0]; } - const F32& getShearY() const { return mShear.mV[1]; } - const U8& getCurveType () const { return mCurveType; } - - const F32& getTwistBegin() const { return mTwistBegin; } - const F32& getTwistEnd() const { return mTwistEnd; } - const F32& getTwist() const { return mTwistEnd; } // deprecated - const F32& getRadiusOffset() const { return mRadiusOffset; } - const LLVector2 &getTaper() const { return mTaper; } - const F32& getTaperX() const { return mTaper.mV[0]; } - const F32& getTaperY() const { return mTaper.mV[1]; } - const F32& getRevolutions() const { return mRevolutions; } - const F32& getSkew() const { return mSkew; } - - void setCurveType(const U8 type) { mCurveType = type; } - void setBegin(const F32 begin) { mBegin = begin; } - void setEnd(const F32 end) { mEnd = end; } - - void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); } - void setScaleX(const F32 v) { mScale.mV[VX] = v; } - void setScaleY(const F32 v) { mScale.mV[VY] = v; } - void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); } - void setShearX(const F32 v) { mShear.mV[VX] = v; } - void setShearY(const F32 v) { mShear.mV[VY] = v; } - - void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; } - void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; } - void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated - void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; } - void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); } - void setTaperX(const F32 v) { mTaper.mV[VX] = v; } - void setTaperY(const F32 v) { mTaper.mV[VY] = v; } - void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; } - void setSkew(const F32 skew) { mSkew = skew; } - - friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params); - -protected: - // Path params - U8 mCurveType; - F32 mBegin; - F32 mEnd; - LLVector2 mScale; - LLVector2 mShear; - - F32 mTwistBegin; - F32 mTwistEnd; - F32 mRadiusOffset; - LLVector2 mTaper; - F32 mRevolutions; - F32 mSkew; - - U32 mCRC; -}; - -inline bool LLPathParams::operator==(const LLPathParams ¶ms) const -{ - return - (getCurveType() == params.getCurveType()) && - (getScale() == params.getScale()) && - (getBegin() == params.getBegin()) && - (getEnd() == params.getEnd()) && - (getShear() == params.getShear()) && - (getTwist() == params.getTwist()) && - (getTwistBegin() == params.getTwistBegin()) && - (getRadiusOffset() == params.getRadiusOffset()) && - (getTaper() == params.getTaper()) && - (getRevolutions() == params.getRevolutions()) && - (getSkew() == params.getSkew()); -} - -inline bool LLPathParams::operator!=(const LLPathParams ¶ms) const -{ - return - (getCurveType() != params.getCurveType()) || - (getScale() != params.getScale()) || - (getBegin() != params.getBegin()) || - (getEnd() != params.getEnd()) || - (getShear() != params.getShear()) || - (getTwist() != params.getTwist()) || - (getTwistBegin() !=params.getTwistBegin()) || - (getRadiusOffset() != params.getRadiusOffset()) || - (getTaper() != params.getTaper()) || - (getRevolutions() != params.getRevolutions()) || - (getSkew() != params.getSkew()); -} - - -inline bool LLPathParams::operator<(const LLPathParams ¶ms) const -{ - if( getCurveType() != params.getCurveType()) - { - return getCurveType() < params.getCurveType(); - } - else - if( getScale() != params.getScale()) - { - return getScale() < params.getScale(); - } - else - if( getBegin() != params.getBegin()) - { - return getBegin() < params.getBegin(); - } - else - if( getEnd() != params.getEnd()) - { - return getEnd() < params.getEnd(); - } - else - if( getShear() != params.getShear()) - { - return getShear() < params.getShear(); - } - else - if( getTwist() != params.getTwist()) - { - return getTwist() < params.getTwist(); - } - else - if( getTwistBegin() != params.getTwistBegin()) - { - return getTwistBegin() < params.getTwistBegin(); - } - else - if( getRadiusOffset() != params.getRadiusOffset()) - { - return getRadiusOffset() < params.getRadiusOffset(); - } - else - if( getTaper() != params.getTaper()) - { - return getTaper() < params.getTaper(); - } - else - if( getRevolutions() != params.getRevolutions()) - { - return getRevolutions() < params.getRevolutions(); - } - else - { - return getSkew() < params.getSkew(); - } -} - -typedef LLVolumeParams* LLVolumeParamsPtr; -typedef const LLVolumeParams* const_LLVolumeParamsPtr; - -class LLVolumeParams -{ -public: - LLVolumeParams() - : mSculptType(LL_SCULPT_TYPE_NONE) - { - } - - LLVolumeParams(LLProfileParams &profile, LLPathParams &path, - LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE) - : mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type) - { - } - - bool operator==(const LLVolumeParams ¶ms) const; - bool operator!=(const LLVolumeParams ¶ms) const; - bool operator<(const LLVolumeParams ¶ms) const; - - - void copyParams(const LLVolumeParams ¶ms); - - const LLProfileParams &getProfileParams() const {return mProfileParams;} - LLProfileParams &getProfileParams() {return mProfileParams;} - const LLPathParams &getPathParams() const {return mPathParams;} - LLPathParams &getPathParams() {return mPathParams;} - - bool importFile(LLFILE *fp); - bool exportFile(LLFILE *fp) const; - - 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); - - bool setType(U8 profile, U8 path); - - //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1 - //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1 - //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin - //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin - - bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end - bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end - - bool setHollow(const F32 hollow); // range 0 to 1 - bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base - bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement, - bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base - bool setShear(const F32 x, const F32 y); // 0 = no movement - - bool setTwistBegin(const F32 twist_begin); // range -1 to 1 - bool setTwistEnd(const F32 twist_end); // range -1 to 1 - bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated - bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; } - bool setTaperX(const F32 v); // -1 to 1 - bool setTaperY(const F32 v); // -1 to 1 - bool setRevolutions(const F32 revolutions); // 1 to 4 - bool setRadiusOffset(const F32 radius_offset); - bool setSkew(const F32 skew); - bool setSculptID(const LLUUID& sculpt_id, U8 sculpt_type); - - static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, - U8 path_curve, F32 path_begin, F32 path_end, - F32 scx, F32 scy, F32 shx, F32 shy, - F32 twistend, F32 twistbegin, F32 radiusoffset, - F32 tx, F32 ty, F32 revolutions, F32 skew); - - const F32& getBeginS() const { return mProfileParams.getBegin(); } - const F32& getBeginT() const { return mPathParams.getBegin(); } - const F32& getEndS() const { return mProfileParams.getEnd(); } - const F32& getEndT() const { return mPathParams.getEnd(); } - - const F32& getHollow() const { return mProfileParams.getHollow(); } - const F32& getTwist() const { return mPathParams.getTwist(); } - const F32& getRatio() const { return mPathParams.getScaleX(); } - const F32& getRatioX() const { return mPathParams.getScaleX(); } - const F32& getRatioY() const { return mPathParams.getScaleY(); } - const F32& getShearX() const { return mPathParams.getShearX(); } - const F32& getShearY() const { return mPathParams.getShearY(); } - - const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); } - const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); } - const F32& getTaper() const { return mPathParams.getTaperX(); } - const F32& getTaperX() const { return mPathParams.getTaperX(); } - const F32& getTaperY() const { return mPathParams.getTaperY(); } - const F32& getRevolutions() const { return mPathParams.getRevolutions(); } - const F32& getSkew() const { return mPathParams.getSkew(); } - const LLUUID& getSculptID() const { return mSculptID; } - const U8& getSculptType() const { return mSculptType; } - bool isSculpt() const; - bool isMeshSculpt() const; - bool isConvex() const; - - // 'begin' and 'end' should be in range [0, 1] (they will be clamped) - // (begin, end) = (0, 1) will not change the volume - // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T) - void reduceS(F32 begin, F32 end); - void reduceT(F32 begin, F32 end); - - struct compare - { - bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const - { - return (*first < *second); - } - }; - - friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); - - // debug helper functions - void setCube(); - -protected: - LLProfileParams mProfileParams; - LLPathParams mPathParams; - LLUUID mSculptID; - U8 mSculptType; -}; - - -class LLProfile -{ - friend class LLVolume; - -public: - LLProfile() - : mOpen(false), - mConcave(false), - mDirty(true), - mTotalOut(0), - mTotal(2) - { - } - - S32 getTotal() const { return mTotal; } - S32 getTotalOut() const { return mTotalOut; } // Total number of outside points - bool isFlat(S32 face) const { return (mFaces[face].mCount == 2); } - bool isOpen() const { return mOpen; } - void setDirty() { mDirty = true; } - - static S32 getNumPoints(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, - bool is_sculpted = false, S32 sculpt_size = 0); - bool generate(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, - bool is_sculpted = false, S32 sculpt_size = 0); - bool isConcave() const { return mConcave; } -public: - struct Face - { - S32 mIndex; - S32 mCount; - F32 mScaleU; - bool mCap; - bool mFlat; - LLFaceID mFaceID; - }; - - LLAlignedArray mProfile; - //LLAlignedArray mNormals; - std::vector mFaces; - - //LLAlignedArray mEdgeNormals; - //LLAlignedArray mEdgeCenters; - - friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); - -protected: - ~LLProfile(); - - static S32 getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); - void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); - - Face* addHole(const LLProfileParams& params, bool flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); - Face* addCap (S16 faceID); - Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, bool flat); - -protected: - bool mOpen; - bool mConcave; - bool mDirty; - - S32 mTotalOut; - S32 mTotal; -}; - -//------------------------------------------------------------------- -// SWEEP/EXTRUDE PATHS -//------------------------------------------------------------------- - -class LLPath -{ -public: - class PathPt - { - public: - LLMatrix4a mRot; - LLVector4a mPos; - - LLVector4a mScale; - F32 mTexT; - F32 pad[3]; //for alignment - PathPt() - { - mPos.clear(); - mTexT = 0; - mScale.clear(); - mRot.setRows(LLVector4a(1,0,0,0), - LLVector4a(0,1,0,0), - LLVector4a(0,0,1,0)); - - //distinguished data in the pad for debugging - pad[0] = 3.14159f; - pad[1] = -3.14159f; - pad[2] = 0.585f; - } - }; - -public: - LLPath() - : mOpen(false), - mTotal(0), - mDirty(true), - mStep(1) - { - } - - virtual ~LLPath(); - - static S32 getNumPoints(const LLPathParams& params, F32 detail); - static S32 getNumNGonPoints(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); - - void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); - virtual bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - bool is_sculpted = false, S32 sculpt_size = 0); - - bool isOpen() const { return mOpen; } - F32 getStep() const { return mStep; } - void setDirty() { mDirty = true; } - - S32 getPathLength() const { return (S32)mPath.size(); } - - void resizePath(S32 length) { mPath.resize(length); } - - friend std::ostream& operator<<(std::ostream &s, const LLPath &path); - -public: - LLAlignedArray mPath; - -protected: - bool mOpen; - S32 mTotal; - bool mDirty; - F32 mStep; -}; - -class LLDynamicPath : public LLPath -{ -public: - LLDynamicPath() : LLPath() { } - /*virtual*/ bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, - bool is_sculpted = false, S32 sculpt_size = 0); -}; - -// Yet another "face" class - caches volume-specific, but not instance-specific data for faces) -class LLVolumeFace -{ -public: - 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 createTangents(); - - void resizeVertices(S32 num_verts); - void allocateTangents(S32 num_verts); - void allocateWeights(S32 num_verts); - void allocateJointIndices(S32 num_verts); - void resizeIndices(S32 num_indices); - void fillFromLegacyData(std::vector& v, std::vector& 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: - U16 mIndex; - - bool operator==(const LLVolumeFace::VertexData& rhs) const; - - struct ComparePosition - { - bool operator()(const LLVector3& a, const LLVector3& b) const; - }; - - typedef std::map, VertexMapData::ComparePosition > PointMap; - }; - - // Eliminates non unique triangles, takes positions, - // normals and texture coordinates into account. - void remap(); - - void optimize(F32 angle_cutoff = 2.f); - bool cacheOptimize(bool gen_tangents = false); - - void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); - void destroyOctree(); - // Get a reference to the octree, which may be null - const LLOctreeNode* getOctree() const; - - enum - { - SINGLE_MASK = 0x0001, - CAP_MASK = 0x0002, - END_MASK = 0x0004, - SIDE_MASK = 0x0008, - INNER_MASK = 0x0010, - OUTER_MASK = 0x0020, - HOLLOW_MASK = 0x0040, - OPEN_MASK = 0x0080, - FLAT_MASK = 0x0100, - TOP_MASK = 0x0200, - BOTTOM_MASK = 0x0400 - }; - -public: - S32 mID; - U32 mTypeMask; - - // Only used for INNER/OUTER faces - S32 mBeginS; - S32 mBeginT; - S32 mNumS; - S32 mNumT; - - LLVector4a* mExtents; //minimum and maximum point of face - LLVector4a* mCenter; - LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. - - S32 mNumVertices; // num vertices == num normals == num texcoords - S32 mNumAllocatedVertices; - S32 mNumIndices; - - LLVector4a* mPositions; // Contains vertices, nortmals and texcoords - LLVector4a* mNormals; // pointer into mPositions - LLVector4a* mTangents; - LLVector2* mTexCoords; // pointer into mPositions - - // mIndices contains mNumIndices amount of elements. - // It contains triangles, each 3 indices describe one triangle. - // If mIndices contains {0, 2, 3, 1, 2, 4}, it means there - // are two triangles {0, 2, 3} and {1, 2, 4} with values being - // indexes for mPositions/mNormals/mTexCoords - U16* mIndices; - - std::vector mEdge; - - //list of skin weights for rigged volumes - // format is mWeights[vertex_index].mV[influence] = . - // mWeights.size() should be empty or match mVertices.size() - LLVector4a* mWeights; - -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - LLVector4a* mJustWeights; - U8* mJointIndices; -#endif - - mutable bool mWeightsScrubbed; - - // Which joints are rigged to, and the bounding box of any rigged - // vertices per joint. - LLJointRiggingInfoTab mJointRiggingInfoTab; - - //whether or not face has been cache optimized - bool mOptimized; - - // if this is a mesh asset, scale and translation that were applied - // when encoding the source mesh into a unit cube - // used for regenerating tangents - LLVector3 mNormalizedScale = LLVector3(1,1,1); - -private: - LLOctreeNode* mOctree; - LLVolumeTriangle* mOctreeTriangles; - - bool createUnCutCubeCap(LLVolume* volume, bool partial_build = false); - bool createCap(LLVolume* volume, bool partial_build = false); - bool createSide(LLVolume* volume, bool partial_build = false); -}; - -class LLVolume : public LLRefCount -{ - friend class LLVolumeLODGroup; - -protected: - virtual ~LLVolume(); // use unref - -public: - typedef std::vector face_list_t; - - struct FaceParams - { - LLFaceID mFaceID; - S32 mBeginS; - S32 mCountS; - S32 mBeginT; - S32 mCountT; - }; - - LLVolume(const LLVolumeParams ¶ms, const F32 detail, const bool generate_single_face = false, const bool is_unique = false); - - U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } - U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const; - S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } - F32 getDetail() const { return mDetail; } - F32 getSurfaceArea() const { return mSurfaceArea; } - const LLVolumeParams& getParams() const { return mParams; } - LLVolumeParams getCopyOfParams() const { return mParams; } - const LLProfile& getProfile() const { return *mProfilep; } - LLPath& getPath() const { return *mPathp; } - void resizePath(S32 length); - const LLAlignedArray& getMesh() const { return mMesh; } - const LLVector4a& getMeshPt(const U32 i) const { return mMesh[i]; } - - - void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } - - void regen(); - void genTangents(S32 face); - - bool isConvex() const; - bool isCap(S32 face); - bool isFlat(S32 face); - bool isUnique() const { return mUnique; } - - S32 getSculptLevel() const { return mSculptLevel; } - void setSculptLevel(S32 level) { mSculptLevel = level; } - - - static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts); - - S32 getNumTriangles(S32* vcount = nullptr) const; - - void generateSilhouetteVertices(std::vector &vertices, - std::vector &normals, - const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat, - S32 face_index); - - //get the face index of the face that intersects with the given line segment at the point - //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. - //Line segment must be in volume space. - S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - LLVector4a* intersection = nullptr, // return the intersection point - LLVector2* tex_coord = nullptr, // return the texture coordinates of the intersection point - LLVector4a* normal = nullptr, // return the surface normal at the intersection point - LLVector4a* tangent = nullptr // return the surface tangent at the intersection point - ); - - LLFaceID generateFaceMask(); - - bool isFaceMaskValid(LLFaceID face_mask); - static S32 sNumMeshPoints; - - friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); - friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over - // conversion if *(LLVolume*) to LLVolume& - const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE - - LLVolumeFace &getVolumeFace(const S32 f) {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE - - face_list_t& getVolumeFaces() { return mVolumeFaces; } - - U32 mFaceMask; // bit array of which faces exist in this volume - 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, bool visible_placeholder); - void copyVolumeFaces(const LLVolume* volume); - void copyFacesTo(std::vector &faces) const; - void copyFacesFrom(const std::vector &faces); - - // use meshoptimizer to optimize index buffer for vertex shader cache - // gen_tangents - if true, generate MikkTSpace tangents if needed before optimizing index buffer - bool cacheOptimize(bool gen_tangents = false); - -private: - void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); - F32 sculptGetSurfaceArea(); - void sculptGenerateEmptyPlaceholder(); - void sculptGenerateSpherePlaceholder(); - -protected: - bool generate(); - void createVolumeFaces(); -public: - bool unpackVolumeFaces(std::istream& is, S32 size); - bool unpackVolumeFaces(U8* in_data, S32 size); -private: - bool unpackVolumeFacesInternal(const LLSD& mdl); - -public: - virtual void setMeshAssetLoaded(bool loaded); - virtual bool isMeshAssetLoaded(); - virtual void setMeshAssetUnavaliable(bool unavaliable); - virtual bool isMeshAssetUnavaliable(); - - protected: - bool mUnique; - F32 mDetail; - S32 mSculptLevel; - F32 mSurfaceArea; //unscaled surface area - bool mIsMeshAssetLoaded; - bool mIsMeshAssetUnavaliable; - - const LLVolumeParams mParams; - LLPath *mPathp; - LLProfile *mProfilep; - LLAlignedArray mMesh; - - - bool mGenerateSingleFace; - face_list_t mVolumeFaces; - -public: - LLVector4a* mHullPoints; - U16* mHullIndices; - S32 mNumHullPoints; - S32 mNumHullIndices; -}; - -std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); - -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 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); - -#endif +/** + * @file llvolume.h + * @brief LLVolume base class. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVOLUME_H +#define LL_LLVOLUME_H + +#include + +class LLProfileParams; +class LLPathParams; +class LLVolumeParams; +class LLProfile; +class LLPath; + +template class LLPointer; +template class LLOctreeNode; + +class LLVolumeFace; +class LLVolume; +class LLVolumeTriangle; + +#include "lluuid.h" +#include "v4color.h" +//#include "vmath.h" +#include "v2math.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" +#include "llvector4a.h" +#include "llmatrix4a.h" +#include "llquaternion.h" +#include "llstrider.h" +#include "v4coloru.h" +#include "llrefcount.h" +#include "llpointer.h" +#include "llfile.h" +#include "llalignedarray.h" +#include "llrigginginfo.h" + +//============================================================================ + +constexpr S32 MIN_DETAIL_FACES = 6; +constexpr S32 MIN_LOD = 0; +constexpr S32 MAX_LOD = 3; + +// These are defined here but are not enforced at this level, +// rather they are here for the convenience of code that uses +// the LLVolume class. +constexpr F32 MIN_VOLUME_PROFILE_WIDTH = 0.05f; +constexpr F32 MIN_VOLUME_PATH_WIDTH = 0.05f; + +constexpr F32 CUT_QUANTA = 0.00002f; +constexpr F32 SCALE_QUANTA = 0.01f; +constexpr F32 SHEAR_QUANTA = 0.01f; +constexpr F32 TAPER_QUANTA = 0.01f; +constexpr F32 REV_QUANTA = 0.015f; +constexpr F32 HOLLOW_QUANTA = 0.00002f; + +constexpr S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; + +//============================================================================ + +// useful masks +constexpr LLPCode LL_PCODE_HOLLOW_MASK = 0x80; // has a thickness +constexpr LLPCode LL_PCODE_SEGMENT_MASK = 0x40; // segments (1 angle) +constexpr LLPCode LL_PCODE_PATCH_MASK = 0x20; // segmented segments (2 angles) +constexpr LLPCode LL_PCODE_HEMI_MASK = 0x10; // half-primitives get their own type per PR's dictum +constexpr LLPCode LL_PCODE_BASE_MASK = 0x0F; + + // primitive shapes +constexpr LLPCode LL_PCODE_CUBE = 1; +constexpr LLPCode LL_PCODE_PRISM = 2; +constexpr LLPCode LL_PCODE_TETRAHEDRON = 3; +constexpr LLPCode LL_PCODE_PYRAMID = 4; +constexpr LLPCode LL_PCODE_CYLINDER = 5; +constexpr LLPCode LL_PCODE_CONE = 6; +constexpr LLPCode LL_PCODE_SPHERE = 7; +constexpr LLPCode LL_PCODE_TORUS = 8; +constexpr LLPCode LL_PCODE_VOLUME = 9; + + // surfaces +//constexpr LLPCode LL_PCODE_SURFACE_TRIANGLE = 10; +//constexpr LLPCode LL_PCODE_SURFACE_SQUARE = 11; +//constexpr LLPCode LL_PCODE_SURFACE_DISC = 12; + +constexpr LLPCode LL_PCODE_APP = 14; // App specific pcode (for viewer/sim side only objects) +constexpr LLPCode LL_PCODE_LEGACY = 15; + +// Pcodes for legacy objects +//constexpr LLPCode LL_PCODE_LEGACY_ATOR = 0x10 | LL_PCODE_LEGACY; // ATOR +constexpr LLPCode LL_PCODE_LEGACY_AVATAR = 0x20 | LL_PCODE_LEGACY; // PLAYER +//constexpr LLPCode LL_PCODE_LEGACY_BIRD = 0x30 | LL_PCODE_LEGACY; // BIRD +//constexpr LLPCode LL_PCODE_LEGACY_DEMON = 0x40 | LL_PCODE_LEGACY; // DEMON +constexpr LLPCode LL_PCODE_LEGACY_GRASS = 0x50 | LL_PCODE_LEGACY; // GRASS +constexpr LLPCode LL_PCODE_TREE_NEW = 0x60 | LL_PCODE_LEGACY; // new trees +//constexpr LLPCode LL_PCODE_LEGACY_ORACLE = 0x70 | LL_PCODE_LEGACY; // ORACLE +constexpr LLPCode LL_PCODE_LEGACY_PART_SYS = 0x80 | LL_PCODE_LEGACY; // PART_SYS +constexpr LLPCode LL_PCODE_LEGACY_ROCK = 0x90 | LL_PCODE_LEGACY; // ROCK +//constexpr LLPCode LL_PCODE_LEGACY_SHOT = 0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT +//constexpr LLPCode LL_PCODE_LEGACY_SHOT_BIG = 0xB0 | LL_PCODE_LEGACY; +//constexpr LLPCode LL_PCODE_LEGACY_SMOKE = 0xC0 | LL_PCODE_LEGACY; // SMOKE +//constexpr LLPCode LL_PCODE_LEGACY_SPARK = 0xD0 | LL_PCODE_LEGACY;// SPARK +constexpr LLPCode LL_PCODE_LEGACY_TEXT_BUBBLE = 0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE +constexpr LLPCode LL_PCODE_LEGACY_TREE = 0xF0 | LL_PCODE_LEGACY; // TREE + + // hemis +constexpr LLPCode LL_PCODE_CYLINDER_HEMI = LL_PCODE_CYLINDER | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_CONE_HEMI = LL_PCODE_CONE | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_SPHERE_HEMI = LL_PCODE_SPHERE | LL_PCODE_HEMI_MASK; +constexpr LLPCode LL_PCODE_TORUS_HEMI = LL_PCODE_TORUS | LL_PCODE_HEMI_MASK; + + +// Volumes consist of a profile at the base that is swept around +// a path to make a volume. +// The profile code +constexpr U8 LL_PCODE_PROFILE_MASK = 0x0f; +constexpr U8 LL_PCODE_PROFILE_MIN = 0x00; +constexpr U8 LL_PCODE_PROFILE_CIRCLE = 0x00; +constexpr U8 LL_PCODE_PROFILE_SQUARE = 0x01; +constexpr U8 LL_PCODE_PROFILE_ISOTRI = 0x02; +constexpr U8 LL_PCODE_PROFILE_EQUALTRI = 0x03; +constexpr U8 LL_PCODE_PROFILE_RIGHTTRI = 0x04; +constexpr U8 LL_PCODE_PROFILE_CIRCLE_HALF = 0x05; +constexpr U8 LL_PCODE_PROFILE_MAX = 0x05; + +// Stored in the profile byte +constexpr U8 LL_PCODE_HOLE_MASK = 0xf0; +constexpr U8 LL_PCODE_HOLE_MIN = 0x00; +constexpr U8 LL_PCODE_HOLE_SAME = 0x00; // same as outside profile +constexpr U8 LL_PCODE_HOLE_CIRCLE = 0x10; +constexpr U8 LL_PCODE_HOLE_SQUARE = 0x20; +constexpr U8 LL_PCODE_HOLE_TRIANGLE = 0x30; +constexpr U8 LL_PCODE_HOLE_MAX = 0x03; // min/max needs to be >> 4 of real min/max + +constexpr U8 LL_PCODE_PATH_IGNORE = 0x00; +constexpr U8 LL_PCODE_PATH_MIN = 0x01; // min/max needs to be >> 4 of real min/max +constexpr U8 LL_PCODE_PATH_LINE = 0x10; +constexpr U8 LL_PCODE_PATH_CIRCLE = 0x20; +constexpr U8 LL_PCODE_PATH_CIRCLE2 = 0x30; +constexpr U8 LL_PCODE_PATH_TEST = 0x40; +constexpr U8 LL_PCODE_PATH_FLEXIBLE = 0x80; +constexpr U8 LL_PCODE_PATH_MAX = 0x08; + +//============================================================================ + +// face identifiers +typedef U16 LLFaceID; + +constexpr LLFaceID LL_FACE_PATH_BEGIN = 0x1 << 0; +constexpr LLFaceID LL_FACE_PATH_END = 0x1 << 1; +constexpr LLFaceID LL_FACE_INNER_SIDE = 0x1 << 2; +constexpr LLFaceID LL_FACE_PROFILE_BEGIN = 0x1 << 3; +constexpr LLFaceID LL_FACE_PROFILE_END = 0x1 << 4; +constexpr LLFaceID LL_FACE_OUTER_SIDE_0 = 0x1 << 5; +constexpr LLFaceID LL_FACE_OUTER_SIDE_1 = 0x1 << 6; +constexpr LLFaceID LL_FACE_OUTER_SIDE_2 = 0x1 << 7; +constexpr LLFaceID LL_FACE_OUTER_SIDE_3 = 0x1 << 8; + +//============================================================================ + +// sculpt types + flags + +constexpr U8 LL_SCULPT_TYPE_NONE = 0; +constexpr U8 LL_SCULPT_TYPE_SPHERE = 1; +constexpr U8 LL_SCULPT_TYPE_TORUS = 2; +constexpr U8 LL_SCULPT_TYPE_PLANE = 3; +constexpr U8 LL_SCULPT_TYPE_CYLINDER = 4; +constexpr U8 LL_SCULPT_TYPE_MESH = 5; +constexpr 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; + +// for value checks, assign new value after adding new types +constexpr U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; + +constexpr U8 LL_SCULPT_FLAG_INVERT = 64; +constexpr U8 LL_SCULPT_FLAG_MIRROR = 128; +constexpr U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; + +constexpr S32 LL_SCULPT_MESH_MAX_FACES = 8; + +extern bool gDebugGL; + +class LLProfileParams +{ +public: + LLProfileParams() + : mCurveType(LL_PCODE_PROFILE_SQUARE), + mBegin(0.f), + mEnd(1.f), + mHollow(0.f), + mCRC(0) + { + } + + LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) + : mCurveType(curve), + mBegin(begin), + mEnd(end), + mHollow(hollow), + mCRC(0) + { + } + + LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow) + { + mCurveType = curve; + F32 temp_f32 = begin * CUT_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mBegin = temp_f32; + temp_f32 = end * CUT_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mEnd = 1.f - temp_f32; + temp_f32 = hollow * HOLLOW_QUANTA; + if (temp_f32 > 1.f) + { + temp_f32 = 1.f; + } + mHollow = temp_f32; + mCRC = 0; + } + + bool operator==(const LLProfileParams ¶ms) const; + bool operator!=(const LLProfileParams ¶ms) const; + bool operator<(const LLProfileParams ¶ms) const; + + void copyParams(const LLProfileParams ¶ms); + + bool importFile(LLFILE *fp); + bool exportFile(LLFILE *fp) const; + + bool importLegacyStream(std::istream& input_stream); + bool exportLegacyStream(std::ostream& output_stream) const; + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + const F32& getBegin () const { return mBegin; } + const F32& getEnd () const { return mEnd; } + const F32& getHollow() const { return mHollow; } + const U8& getCurveType () const { return mCurveType; } + + void setCurveType(const U32 type) { mCurveType = type;} + void setBegin(const F32 begin) { mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;} + void setEnd(const F32 end) { mEnd = (end <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;} + void setHollow(const F32 hollow) { mHollow = ((int) (hollow * 100000))/100000.0f;} + + friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params); + +protected: + // Profile params + U8 mCurveType; + F32 mBegin; + F32 mEnd; + F32 mHollow; + + U32 mCRC; +}; + +inline bool LLProfileParams::operator==(const LLProfileParams ¶ms) const +{ + return + (getCurveType() == params.getCurveType()) && + (getBegin() == params.getBegin()) && + (getEnd() == params.getEnd()) && + (getHollow() == params.getHollow()); +} + +inline bool LLProfileParams::operator!=(const LLProfileParams ¶ms) const +{ + return + (getCurveType() != params.getCurveType()) || + (getBegin() != params.getBegin()) || + (getEnd() != params.getEnd()) || + (getHollow() != params.getHollow()); +} + + +inline bool LLProfileParams::operator<(const LLProfileParams ¶ms) const +{ + if (getCurveType() != params.getCurveType()) + { + return getCurveType() < params.getCurveType(); + } + else + if (getBegin() != params.getBegin()) + { + return getBegin() < params.getBegin(); + } + else + if (getEnd() != params.getEnd()) + { + return getEnd() < params.getEnd(); + } + else + { + return getHollow() < params.getHollow(); + } +} + +#define U8_TO_F32(x) (F32)(*((S8 *)&x)) + +class LLPathParams +{ +public: + LLPathParams() + : + mCurveType(LL_PCODE_PATH_LINE), + mBegin(0.f), + mEnd(1.f), + mScale(1.f,1.f), + mShear(0.f,0.f), + mTwistBegin(0.f), + mTwistEnd(0.f), + mRadiusOffset(0.f), + mTaper(0.f,0.f), + mRevolutions(1.f), + mSkew(0.f), + mCRC(0) + { + } + + LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) + : mCurveType(curve), + mBegin(begin), + mEnd(end), + mScale(scx,scy), + mShear(shx,shy), + mTwistBegin(twistbegin), + mTwistEnd(twistend), + mRadiusOffset(radiusoffset), + mTaper(tx,ty), + mRevolutions(revolutions), + mSkew(skew), + mCRC(0) + { + } + + LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew) + { + mCurveType = curve; + mBegin = (F32)(begin * CUT_QUANTA); + mEnd = (F32)(100.f - end) * CUT_QUANTA; + if (mEnd > 1.f) + mEnd = 1.f; + mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA); + mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA); + mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA; + mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA; + mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA; + mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA); + mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f; + mSkew = U8_TO_F32(skew) * SCALE_QUANTA; + + mCRC = 0; + } + + bool operator==(const LLPathParams ¶ms) const; + bool operator!=(const LLPathParams ¶ms) const; + bool operator<(const LLPathParams ¶ms) const; + + void copyParams(const LLPathParams ¶ms); + + bool importFile(LLFILE *fp); + bool exportFile(LLFILE *fp) const; + + bool importLegacyStream(std::istream& input_stream); + bool exportLegacyStream(std::ostream& output_stream) const; + + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + const F32& getBegin() const { return mBegin; } + const F32& getEnd() const { return mEnd; } + const LLVector2 &getScale() const { return mScale; } + const F32& getScaleX() const { return mScale.mV[0]; } + const F32& getScaleY() const { return mScale.mV[1]; } + const LLVector2 getBeginScale() const; + const LLVector2 getEndScale() const; + const LLVector2 &getShear() const { return mShear; } + const F32& getShearX() const { return mShear.mV[0]; } + const F32& getShearY() const { return mShear.mV[1]; } + const U8& getCurveType () const { return mCurveType; } + + const F32& getTwistBegin() const { return mTwistBegin; } + const F32& getTwistEnd() const { return mTwistEnd; } + const F32& getTwist() const { return mTwistEnd; } // deprecated + const F32& getRadiusOffset() const { return mRadiusOffset; } + const LLVector2 &getTaper() const { return mTaper; } + const F32& getTaperX() const { return mTaper.mV[0]; } + const F32& getTaperY() const { return mTaper.mV[1]; } + const F32& getRevolutions() const { return mRevolutions; } + const F32& getSkew() const { return mSkew; } + + void setCurveType(const U8 type) { mCurveType = type; } + void setBegin(const F32 begin) { mBegin = begin; } + void setEnd(const F32 end) { mEnd = end; } + + void setScale(const F32 x, const F32 y) { mScale.setVec(x,y); } + void setScaleX(const F32 v) { mScale.mV[VX] = v; } + void setScaleY(const F32 v) { mScale.mV[VY] = v; } + void setShear(const F32 x, const F32 y) { mShear.setVec(x,y); } + void setShearX(const F32 v) { mShear.mV[VX] = v; } + void setShearY(const F32 v) { mShear.mV[VY] = v; } + + void setTwistBegin(const F32 twist_begin) { mTwistBegin = twist_begin; } + void setTwistEnd(const F32 twist_end) { mTwistEnd = twist_end; } + void setTwist(const F32 twist) { setTwistEnd(twist); } // deprecated + void setRadiusOffset(const F32 radius_offset){ mRadiusOffset = radius_offset; } + void setTaper(const F32 x, const F32 y) { mTaper.setVec(x,y); } + void setTaperX(const F32 v) { mTaper.mV[VX] = v; } + void setTaperY(const F32 v) { mTaper.mV[VY] = v; } + void setRevolutions(const F32 revolutions) { mRevolutions = revolutions; } + void setSkew(const F32 skew) { mSkew = skew; } + + friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params); + +protected: + // Path params + U8 mCurveType; + F32 mBegin; + F32 mEnd; + LLVector2 mScale; + LLVector2 mShear; + + F32 mTwistBegin; + F32 mTwistEnd; + F32 mRadiusOffset; + LLVector2 mTaper; + F32 mRevolutions; + F32 mSkew; + + U32 mCRC; +}; + +inline bool LLPathParams::operator==(const LLPathParams ¶ms) const +{ + return + (getCurveType() == params.getCurveType()) && + (getScale() == params.getScale()) && + (getBegin() == params.getBegin()) && + (getEnd() == params.getEnd()) && + (getShear() == params.getShear()) && + (getTwist() == params.getTwist()) && + (getTwistBegin() == params.getTwistBegin()) && + (getRadiusOffset() == params.getRadiusOffset()) && + (getTaper() == params.getTaper()) && + (getRevolutions() == params.getRevolutions()) && + (getSkew() == params.getSkew()); +} + +inline bool LLPathParams::operator!=(const LLPathParams ¶ms) const +{ + return + (getCurveType() != params.getCurveType()) || + (getScale() != params.getScale()) || + (getBegin() != params.getBegin()) || + (getEnd() != params.getEnd()) || + (getShear() != params.getShear()) || + (getTwist() != params.getTwist()) || + (getTwistBegin() !=params.getTwistBegin()) || + (getRadiusOffset() != params.getRadiusOffset()) || + (getTaper() != params.getTaper()) || + (getRevolutions() != params.getRevolutions()) || + (getSkew() != params.getSkew()); +} + + +inline bool LLPathParams::operator<(const LLPathParams ¶ms) const +{ + if( getCurveType() != params.getCurveType()) + { + return getCurveType() < params.getCurveType(); + } + else + if( getScale() != params.getScale()) + { + return getScale() < params.getScale(); + } + else + if( getBegin() != params.getBegin()) + { + return getBegin() < params.getBegin(); + } + else + if( getEnd() != params.getEnd()) + { + return getEnd() < params.getEnd(); + } + else + if( getShear() != params.getShear()) + { + return getShear() < params.getShear(); + } + else + if( getTwist() != params.getTwist()) + { + return getTwist() < params.getTwist(); + } + else + if( getTwistBegin() != params.getTwistBegin()) + { + return getTwistBegin() < params.getTwistBegin(); + } + else + if( getRadiusOffset() != params.getRadiusOffset()) + { + return getRadiusOffset() < params.getRadiusOffset(); + } + else + if( getTaper() != params.getTaper()) + { + return getTaper() < params.getTaper(); + } + else + if( getRevolutions() != params.getRevolutions()) + { + return getRevolutions() < params.getRevolutions(); + } + else + { + return getSkew() < params.getSkew(); + } +} + +typedef LLVolumeParams* LLVolumeParamsPtr; +typedef const LLVolumeParams* const_LLVolumeParamsPtr; + +class LLVolumeParams +{ +public: + LLVolumeParams() + : mSculptType(LL_SCULPT_TYPE_NONE) + { + } + + LLVolumeParams(LLProfileParams &profile, LLPathParams &path, + LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE) + : mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type) + { + } + + bool operator==(const LLVolumeParams ¶ms) const; + bool operator!=(const LLVolumeParams ¶ms) const; + bool operator<(const LLVolumeParams ¶ms) const; + + + void copyParams(const LLVolumeParams ¶ms); + + const LLProfileParams &getProfileParams() const {return mProfileParams;} + LLProfileParams &getProfileParams() {return mProfileParams;} + const LLPathParams &getPathParams() const {return mPathParams;} + LLPathParams &getPathParams() {return mPathParams;} + + bool importFile(LLFILE *fp); + bool exportFile(LLFILE *fp) const; + + 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); + + bool setType(U8 profile, U8 path); + + //void setBeginS(const F32 beginS) { mProfileParams.setBegin(beginS); } // range 0 to 1 + //void setBeginT(const F32 beginT) { mPathParams.setBegin(beginT); } // range 0 to 1 + //void setEndS(const F32 endS) { mProfileParams.setEnd(endS); } // range 0 to 1, must be greater than begin + //void setEndT(const F32 endT) { mPathParams.setEnd(endT); } // range 0 to 1, must be greater than begin + + bool setBeginAndEndS(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end + bool setBeginAndEndT(const F32 begin, const F32 end); // both range from 0 to 1, begin must be less than end + + bool setHollow(const F32 hollow); // range 0 to 1 + bool setRatio(const F32 x) { return setRatio(x,x); } // 0 = point, 1 = same as base + bool setShear(const F32 x) { return setShear(x,x); } // 0 = no movement, + bool setRatio(const F32 x, const F32 y); // 0 = point, 1 = same as base + bool setShear(const F32 x, const F32 y); // 0 = no movement + + bool setTwistBegin(const F32 twist_begin); // range -1 to 1 + bool setTwistEnd(const F32 twist_end); // range -1 to 1 + bool setTwist(const F32 twist) { return setTwistEnd(twist); } // deprecated + bool setTaper(const F32 x, const F32 y) { bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; } + bool setTaperX(const F32 v); // -1 to 1 + bool setTaperY(const F32 v); // -1 to 1 + bool setRevolutions(const F32 revolutions); // 1 to 4 + bool setRadiusOffset(const F32 radius_offset); + bool setSkew(const F32 skew); + bool setSculptID(const LLUUID& sculpt_id, U8 sculpt_type); + + static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow, + U8 path_curve, F32 path_begin, F32 path_end, + F32 scx, F32 scy, F32 shx, F32 shy, + F32 twistend, F32 twistbegin, F32 radiusoffset, + F32 tx, F32 ty, F32 revolutions, F32 skew); + + const F32& getBeginS() const { return mProfileParams.getBegin(); } + const F32& getBeginT() const { return mPathParams.getBegin(); } + const F32& getEndS() const { return mProfileParams.getEnd(); } + const F32& getEndT() const { return mPathParams.getEnd(); } + + const F32& getHollow() const { return mProfileParams.getHollow(); } + const F32& getTwist() const { return mPathParams.getTwist(); } + const F32& getRatio() const { return mPathParams.getScaleX(); } + const F32& getRatioX() const { return mPathParams.getScaleX(); } + const F32& getRatioY() const { return mPathParams.getScaleY(); } + const F32& getShearX() const { return mPathParams.getShearX(); } + const F32& getShearY() const { return mPathParams.getShearY(); } + + const F32& getTwistBegin()const { return mPathParams.getTwistBegin(); } + const F32& getRadiusOffset() const { return mPathParams.getRadiusOffset(); } + const F32& getTaper() const { return mPathParams.getTaperX(); } + const F32& getTaperX() const { return mPathParams.getTaperX(); } + const F32& getTaperY() const { return mPathParams.getTaperY(); } + const F32& getRevolutions() const { return mPathParams.getRevolutions(); } + const F32& getSkew() const { return mPathParams.getSkew(); } + const LLUUID& getSculptID() const { return mSculptID; } + const U8& getSculptType() const { return mSculptType; } + bool isSculpt() const; + bool isMeshSculpt() const; + bool isConvex() const; + + // 'begin' and 'end' should be in range [0, 1] (they will be clamped) + // (begin, end) = (0, 1) will not change the volume + // (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T) + void reduceS(F32 begin, F32 end); + void reduceT(F32 begin, F32 end); + + struct compare + { + bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const + { + return (*first < *second); + } + }; + + friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); + + // debug helper functions + void setCube(); + +protected: + LLProfileParams mProfileParams; + LLPathParams mPathParams; + LLUUID mSculptID; + U8 mSculptType; +}; + + +class LLProfile +{ + friend class LLVolume; + +public: + LLProfile() + : mOpen(false), + mConcave(false), + mDirty(true), + mTotalOut(0), + mTotal(2) + { + } + + S32 getTotal() const { return mTotal; } + S32 getTotalOut() const { return mTotalOut; } // Total number of outside points + bool isFlat(S32 face) const { return (mFaces[face].mCount == 2); } + bool isOpen() const { return mOpen; } + void setDirty() { mDirty = true; } + + static S32 getNumPoints(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); + bool generate(const LLProfileParams& params, bool path_open, F32 detail = 1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); + bool isConcave() const { return mConcave; } +public: + struct Face + { + S32 mIndex; + S32 mCount; + F32 mScaleU; + bool mCap; + bool mFlat; + LLFaceID mFaceID; + }; + + LLAlignedArray mProfile; + //LLAlignedArray mNormals; + std::vector mFaces; + + //LLAlignedArray mEdgeNormals; + //LLAlignedArray mEdgeCenters; + + friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); + +protected: + ~LLProfile(); + + static S32 getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); + void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); + + Face* addHole(const LLProfileParams& params, bool flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); + Face* addCap (S16 faceID); + Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, bool flat); + +protected: + bool mOpen; + bool mConcave; + bool mDirty; + + S32 mTotalOut; + S32 mTotal; +}; + +//------------------------------------------------------------------- +// SWEEP/EXTRUDE PATHS +//------------------------------------------------------------------- + +class LLPath +{ +public: + class PathPt + { + public: + LLMatrix4a mRot; + LLVector4a mPos; + + LLVector4a mScale; + F32 mTexT; + F32 pad[3]; //for alignment + PathPt() + { + mPos.clear(); + mTexT = 0; + mScale.clear(); + mRot.setRows(LLVector4a(1,0,0,0), + LLVector4a(0,1,0,0), + LLVector4a(0,0,1,0)); + + //distinguished data in the pad for debugging + pad[0] = 3.14159f; + pad[1] = -3.14159f; + pad[2] = 0.585f; + } + }; + +public: + LLPath() + : mOpen(false), + mTotal(0), + mDirty(true), + mStep(1) + { + } + + virtual ~LLPath(); + + static S32 getNumPoints(const LLPathParams& params, F32 detail); + static S32 getNumNGonPoints(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); + + void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); + virtual bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); + + bool isOpen() const { return mOpen; } + F32 getStep() const { return mStep; } + void setDirty() { mDirty = true; } + + S32 getPathLength() const { return (S32)mPath.size(); } + + void resizePath(S32 length) { mPath.resize(length); } + + friend std::ostream& operator<<(std::ostream &s, const LLPath &path); + +public: + LLAlignedArray mPath; + +protected: + bool mOpen; + S32 mTotal; + bool mDirty; + F32 mStep; +}; + +class LLDynamicPath : public LLPath +{ +public: + LLDynamicPath() : LLPath() { } + /*virtual*/ bool generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, + bool is_sculpted = false, S32 sculpt_size = 0); +}; + +// Yet another "face" class - caches volume-specific, but not instance-specific data for faces) +class LLVolumeFace +{ +public: + 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 createTangents(); + + void resizeVertices(S32 num_verts); + void allocateTangents(S32 num_verts); + void allocateWeights(S32 num_verts); + void allocateJointIndices(S32 num_verts); + void resizeIndices(S32 num_indices); + void fillFromLegacyData(std::vector& v, std::vector& 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: + U16 mIndex; + + bool operator==(const LLVolumeFace::VertexData& rhs) const; + + struct ComparePosition + { + bool operator()(const LLVector3& a, const LLVector3& b) const; + }; + + typedef std::map, VertexMapData::ComparePosition > PointMap; + }; + + // Eliminates non unique triangles, takes positions, + // normals and texture coordinates into account. + void remap(); + + void optimize(F32 angle_cutoff = 2.f); + bool cacheOptimize(bool gen_tangents = false); + + void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); + void destroyOctree(); + // Get a reference to the octree, which may be null + const LLOctreeNode* getOctree() const; + + enum + { + SINGLE_MASK = 0x0001, + CAP_MASK = 0x0002, + END_MASK = 0x0004, + SIDE_MASK = 0x0008, + INNER_MASK = 0x0010, + OUTER_MASK = 0x0020, + HOLLOW_MASK = 0x0040, + OPEN_MASK = 0x0080, + FLAT_MASK = 0x0100, + TOP_MASK = 0x0200, + BOTTOM_MASK = 0x0400 + }; + +public: + S32 mID; + U32 mTypeMask; + + // Only used for INNER/OUTER faces + S32 mBeginS; + S32 mBeginT; + S32 mNumS; + S32 mNumT; + + LLVector4a* mExtents; //minimum and maximum point of face + LLVector4a* mCenter; + LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. + + S32 mNumVertices; // num vertices == num normals == num texcoords + S32 mNumAllocatedVertices; + S32 mNumIndices; + + LLVector4a* mPositions; // Contains vertices, nortmals and texcoords + LLVector4a* mNormals; // pointer into mPositions + LLVector4a* mTangents; + LLVector2* mTexCoords; // pointer into mPositions + + // mIndices contains mNumIndices amount of elements. + // It contains triangles, each 3 indices describe one triangle. + // If mIndices contains {0, 2, 3, 1, 2, 4}, it means there + // are two triangles {0, 2, 3} and {1, 2, 4} with values being + // indexes for mPositions/mNormals/mTexCoords + U16* mIndices; + + std::vector mEdge; + + //list of skin weights for rigged volumes + // format is mWeights[vertex_index].mV[influence] = . + // mWeights.size() should be empty or match mVertices.size() + LLVector4a* mWeights; + +#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS + LLVector4a* mJustWeights; + U8* mJointIndices; +#endif + + mutable bool mWeightsScrubbed; + + // Which joints are rigged to, and the bounding box of any rigged + // vertices per joint. + LLJointRiggingInfoTab mJointRiggingInfoTab; + + //whether or not face has been cache optimized + bool mOptimized; + + // if this is a mesh asset, scale and translation that were applied + // when encoding the source mesh into a unit cube + // used for regenerating tangents + LLVector3 mNormalizedScale = LLVector3(1,1,1); + +private: + LLOctreeNode* mOctree; + LLVolumeTriangle* mOctreeTriangles; + + bool createUnCutCubeCap(LLVolume* volume, bool partial_build = false); + bool createCap(LLVolume* volume, bool partial_build = false); + bool createSide(LLVolume* volume, bool partial_build = false); +}; + +class LLVolume : public LLRefCount +{ + friend class LLVolumeLODGroup; + +protected: + virtual ~LLVolume(); // use unref + +public: + typedef std::vector face_list_t; + + struct FaceParams + { + LLFaceID mFaceID; + S32 mBeginS; + S32 mCountS; + S32 mBeginT; + S32 mCountT; + }; + + LLVolume(const LLVolumeParams ¶ms, const F32 detail, const bool generate_single_face = false, const bool is_unique = false); + + U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } + U8 getPathType() const { return mParams.getPathParams().getCurveType(); } + S32 getNumFaces() const; + S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } + F32 getDetail() const { return mDetail; } + F32 getSurfaceArea() const { return mSurfaceArea; } + const LLVolumeParams& getParams() const { return mParams; } + LLVolumeParams getCopyOfParams() const { return mParams; } + const LLProfile& getProfile() const { return *mProfilep; } + LLPath& getPath() const { return *mPathp; } + void resizePath(S32 length); + const LLAlignedArray& getMesh() const { return mMesh; } + const LLVector4a& getMeshPt(const U32 i) const { return mMesh[i]; } + + + void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } + + void regen(); + void genTangents(S32 face); + + bool isConvex() const; + bool isCap(S32 face); + bool isFlat(S32 face); + bool isUnique() const { return mUnique; } + + S32 getSculptLevel() const { return mSculptLevel; } + void setSculptLevel(S32 level) { mSculptLevel = level; } + + + static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts); + + S32 getNumTriangles(S32* vcount = nullptr) const; + + void generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat, + S32 face_index); + + //get the face index of the face that intersects with the given line segment at the point + //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. + //Line segment must be in volume space. + S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + LLVector4a* intersection = nullptr, // return the intersection point + LLVector2* tex_coord = nullptr, // return the texture coordinates of the intersection point + LLVector4a* normal = nullptr, // return the surface normal at the intersection point + LLVector4a* tangent = nullptr // return the surface tangent at the intersection point + ); + + LLFaceID generateFaceMask(); + + bool isFaceMaskValid(LLFaceID face_mask); + static S32 sNumMeshPoints; + + friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume); + friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep); // HACK to bypass Windoze confusion over + // conversion if *(LLVolume*) to LLVolume& + const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + + LLVolumeFace &getVolumeFace(const S32 f) {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + + face_list_t& getVolumeFaces() { return mVolumeFaces; } + + U32 mFaceMask; // bit array of which faces exist in this volume + 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, bool visible_placeholder); + void copyVolumeFaces(const LLVolume* volume); + void copyFacesTo(std::vector &faces) const; + void copyFacesFrom(const std::vector &faces); + + // use meshoptimizer to optimize index buffer for vertex shader cache + // gen_tangents - if true, generate MikkTSpace tangents if needed before optimizing index buffer + bool cacheOptimize(bool gen_tangents = false); + +private: + void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); + F32 sculptGetSurfaceArea(); + void sculptGenerateEmptyPlaceholder(); + void sculptGenerateSpherePlaceholder(); + +protected: + bool generate(); + void createVolumeFaces(); +public: + bool unpackVolumeFaces(std::istream& is, S32 size); + bool unpackVolumeFaces(U8* in_data, S32 size); +private: + bool unpackVolumeFacesInternal(const LLSD& mdl); + +public: + virtual void setMeshAssetLoaded(bool loaded); + virtual bool isMeshAssetLoaded(); + virtual void setMeshAssetUnavaliable(bool unavaliable); + virtual bool isMeshAssetUnavaliable(); + + protected: + bool mUnique; + F32 mDetail; + S32 mSculptLevel; + F32 mSurfaceArea; //unscaled surface area + bool mIsMeshAssetLoaded; + bool mIsMeshAssetUnavaliable; + + const LLVolumeParams mParams; + LLPath *mPathp; + LLProfile *mProfilep; + LLAlignedArray mMesh; + + + bool mGenerateSingleFace; + face_list_t mVolumeFaces; + +public: + LLVector4a* mHullPoints; + U16* mHullIndices; + S32 mNumHullPoints; + S32 mNumHullIndices; +}; + +std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); + +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 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); + +#endif diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index f796fbf551..bb0c94d513 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -1,408 +1,408 @@ -/** - * @file llvolumemgr.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llvolumemgr.h" -#include "llvolume.h" - - -const F32 BASE_THRESHOLD = 0.03f; - -//static -F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD, - 2*BASE_THRESHOLD, - 8*BASE_THRESHOLD, - 100*BASE_THRESHOLD}; - -//static -F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f}; - - -//============================================================================ - -LLVolumeMgr::LLVolumeMgr() -: mDataMutex(NULL) -{ - // the LLMutex magic interferes with easy unit testing, - // so you now must manually call useMutex() to use it - //mDataMutex = new LLMutex(); -} - -LLVolumeMgr::~LLVolumeMgr() -{ - cleanup(); - - delete mDataMutex; - mDataMutex = NULL; -} - -bool LLVolumeMgr::cleanup() -{ - bool no_refs = true; - if (mDataMutex) - { - mDataMutex->lock(); - } - for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(), - end = mVolumeLODGroups.end(); - iter != end; iter++) - { - LLVolumeLODGroup *volgroupp = iter->second; - if (!volgroupp->cleanupRefs()) - { - no_refs = false; - } - delete volgroupp; - } - mVolumeLODGroups.clear(); - if (mDataMutex) - { - mDataMutex->unlock(); - } - return no_refs; -} - -// Always only ever store the results of refVolume in a LLPointer -// Note however that LLVolumeLODGroup that contains the volume -// also holds a LLPointer so the volume will only go away after -// anything holding the volume and the LODGroup are destroyed -LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 lod) -{ - LLVolumeLODGroup* volgroupp; - if (mDataMutex) - { - mDataMutex->lock(); - } - volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params); - if( iter == mVolumeLODGroups.end() ) - { - volgroupp = createNewGroup(volume_params); - } - else - { - volgroupp = iter->second; - } - if (mDataMutex) - { - mDataMutex->unlock(); - } - return volgroupp->refLOD(lod); -} - -// virtual -LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const -{ - LLVolumeLODGroup* volgroupp = NULL; - if (mDataMutex) - { - mDataMutex->lock(); - } - volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params); - if( iter != mVolumeLODGroups.end() ) - { - volgroupp = iter->second; - } - if (mDataMutex) - { - mDataMutex->unlock(); - } - return volgroupp; -} - -void LLVolumeMgr::unrefVolume(LLVolume *volumep) -{ - if (volumep->isUnique()) - { - // TomY: Don't need to manage this volume. It is a unique instance. - return; - } - const LLVolumeParams* params = &(volumep->getParams()); - if (mDataMutex) - { - mDataMutex->lock(); - } - volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params); - if( iter == mVolumeLODGroups.end() ) - { - LL_ERRS() << "Warning! Tried to cleanup unknown volume type! " << *params << LL_ENDL; - if (mDataMutex) - { - mDataMutex->unlock(); - } - return; - } - else - { - LLVolumeLODGroup* volgroupp = iter->second; - - volgroupp->derefLOD(volumep); - if (volgroupp->getNumRefs() == 0) - { - mVolumeLODGroups.erase(params); - delete volgroupp; - } - } - if (mDataMutex) - { - mDataMutex->unlock(); - } - -} - -// protected -void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup) -{ - mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup; -} - -// protected -LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params) -{ - LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params); - insertGroup(volgroup); - return volgroup; -} - -// virtual -void LLVolumeMgr::dump() -{ - F32 avg = 0.f; - if (mDataMutex) - { - mDataMutex->lock(); - } - for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(), - end = mVolumeLODGroups.end(); - iter != end; iter++) - { - LLVolumeLODGroup *volgroupp = iter->second; - avg += volgroupp->dump(); - } - int count = (int)mVolumeLODGroups.size(); - avg = count ? avg / (F32)count : 0.0f; - if (mDataMutex) - { - mDataMutex->unlock(); - } - LL_INFOS() << "Average usage of LODs " << avg << LL_ENDL; -} - -void LLVolumeMgr::useMutex() -{ - if (!mDataMutex) - { - mDataMutex = new LLMutex(); - } -} - -std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr) -{ - s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", "; - - S32 total_refs = 0; - if (volume_mgr.mDataMutex) - { - volume_mgr.mDataMutex->lock(); - } - - for (LLVolumeMgr::volume_lod_group_map_t::const_iterator iter = volume_mgr.mVolumeLODGroups.begin(); - iter != volume_mgr.mVolumeLODGroups.end(); ++iter) - { - LLVolumeLODGroup *volgroupp = iter->second; - total_refs += volgroupp->getNumRefs(); - s << ", " << (*volgroupp); - } - - if (volume_mgr.mDataMutex) - { - volume_mgr.mDataMutex->unlock(); - } - - s << ", total_refs=" << total_refs << " }"; - return s; -} - -LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms) - : mVolumeParams(params), - mRefs(0) -{ - for (S32 i = 0; i < NUM_LODS; i++) - { - mLODRefs[i] = 0; - mAccessCount[i] = 0; - } -} - -LLVolumeLODGroup::~LLVolumeLODGroup() -{ - for (S32 i = 0; i < NUM_LODS; i++) - { - llassert_always(mLODRefs[i] == 0); - } -} - -// Called from LLVolumeMgr::cleanup -bool LLVolumeLODGroup::cleanupRefs() -{ - bool res = true; - if (mRefs != 0) - { - LL_WARNS() << "Volume group has remaining refs:" << getNumRefs() << LL_ENDL; - mRefs = 0; - for (S32 i = 0; i < NUM_LODS; i++) - { - if (mLODRefs[i] > 0) - { - LL_WARNS() << " LOD " << i << " refs = " << mLODRefs[i] << LL_ENDL; - mLODRefs[i] = 0; - mVolumeLODs[i] = NULL; - } - } - LL_WARNS() << *getVolumeParams() << LL_ENDL; - res = false; - } - return res; -} - -LLVolume* LLVolumeLODGroup::refLOD(const S32 lod) -{ - llassert(lod >=0 && lod < NUM_LODS); - mAccessCount[lod]++; - - mRefs++; - if (mVolumeLODs[lod].isNull()) - { - mVolumeLODs[lod] = new LLVolume(mVolumeParams, mDetailScales[lod]); - } - mLODRefs[lod]++; - return mVolumeLODs[lod]; -} - -bool LLVolumeLODGroup::derefLOD(LLVolume *volumep) -{ - llassert_always(mRefs > 0); - mRefs--; - for (S32 i = 0; i < NUM_LODS; i++) - { - if (mVolumeLODs[i] == volumep) - { - llassert_always(mLODRefs[i] > 0); - mLODRefs[i]--; -#if 0 // SJB: Possible opt: keep other lods around - if (!mLODRefs[i]) - { - mVolumeLODs[i] = NULL; - } -#endif - return true; - } - } - LL_ERRS() << "Deref of non-matching LOD in volume LOD group" << LL_ENDL; - return false; -} - -S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle) -{ - S32 i = 0; - while (i < (NUM_LODS - 1)) - { - if (tan_angle <= mDetailThresholds[i]) - { - return i; - } - i++; - } - return NUM_LODS - 1; -} - -void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher) -{ - S32 detail = getDetailFromTan(tan_angle); - - if (detail > 0) - { - to_lower = tan_angle - mDetailThresholds[detail]; - } - else - { - to_lower = 1024.f*1024.f; - } - - if (detail < NUM_LODS-1) - { - to_higher = mDetailThresholds[detail+1] - tan_angle; - } - else - { - to_higher = 1024.f*1024.f; - } -} - -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; - for (S32 i = 0; i < NUM_LODS; i++) - { - if (mAccessCount[i] > 0) - { - usage += 1.f; - } - } - usage = usage / (F32)NUM_LODS; - - std::string dump_str = llformat("%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]); - - LL_INFOS() << dump_str << LL_ENDL; - return usage; -} - -std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup) -{ - s << "{ numRefs=" << volgroup.getNumRefs(); - s << ", mParams=" << volgroup.getVolumeParams(); - s << " }"; - - return s; -} - +/** + * @file llvolumemgr.cpp + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llvolumemgr.h" +#include "llvolume.h" + + +const F32 BASE_THRESHOLD = 0.03f; + +//static +F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD, + 2*BASE_THRESHOLD, + 8*BASE_THRESHOLD, + 100*BASE_THRESHOLD}; + +//static +F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f}; + + +//============================================================================ + +LLVolumeMgr::LLVolumeMgr() +: mDataMutex(NULL) +{ + // the LLMutex magic interferes with easy unit testing, + // so you now must manually call useMutex() to use it + //mDataMutex = new LLMutex(); +} + +LLVolumeMgr::~LLVolumeMgr() +{ + cleanup(); + + delete mDataMutex; + mDataMutex = NULL; +} + +bool LLVolumeMgr::cleanup() +{ + bool no_refs = true; + if (mDataMutex) + { + mDataMutex->lock(); + } + for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(), + end = mVolumeLODGroups.end(); + iter != end; iter++) + { + LLVolumeLODGroup *volgroupp = iter->second; + if (!volgroupp->cleanupRefs()) + { + no_refs = false; + } + delete volgroupp; + } + mVolumeLODGroups.clear(); + if (mDataMutex) + { + mDataMutex->unlock(); + } + return no_refs; +} + +// Always only ever store the results of refVolume in a LLPointer +// Note however that LLVolumeLODGroup that contains the volume +// also holds a LLPointer so the volume will only go away after +// anything holding the volume and the LODGroup are destroyed +LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 lod) +{ + LLVolumeLODGroup* volgroupp; + if (mDataMutex) + { + mDataMutex->lock(); + } + volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params); + if( iter == mVolumeLODGroups.end() ) + { + volgroupp = createNewGroup(volume_params); + } + else + { + volgroupp = iter->second; + } + if (mDataMutex) + { + mDataMutex->unlock(); + } + return volgroupp->refLOD(lod); +} + +// virtual +LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const +{ + LLVolumeLODGroup* volgroupp = NULL; + if (mDataMutex) + { + mDataMutex->lock(); + } + volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params); + if( iter != mVolumeLODGroups.end() ) + { + volgroupp = iter->second; + } + if (mDataMutex) + { + mDataMutex->unlock(); + } + return volgroupp; +} + +void LLVolumeMgr::unrefVolume(LLVolume *volumep) +{ + if (volumep->isUnique()) + { + // TomY: Don't need to manage this volume. It is a unique instance. + return; + } + const LLVolumeParams* params = &(volumep->getParams()); + if (mDataMutex) + { + mDataMutex->lock(); + } + volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params); + if( iter == mVolumeLODGroups.end() ) + { + LL_ERRS() << "Warning! Tried to cleanup unknown volume type! " << *params << LL_ENDL; + if (mDataMutex) + { + mDataMutex->unlock(); + } + return; + } + else + { + LLVolumeLODGroup* volgroupp = iter->second; + + volgroupp->derefLOD(volumep); + if (volgroupp->getNumRefs() == 0) + { + mVolumeLODGroups.erase(params); + delete volgroupp; + } + } + if (mDataMutex) + { + mDataMutex->unlock(); + } + +} + +// protected +void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup) +{ + mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup; +} + +// protected +LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params) +{ + LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params); + insertGroup(volgroup); + return volgroup; +} + +// virtual +void LLVolumeMgr::dump() +{ + F32 avg = 0.f; + if (mDataMutex) + { + mDataMutex->lock(); + } + for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(), + end = mVolumeLODGroups.end(); + iter != end; iter++) + { + LLVolumeLODGroup *volgroupp = iter->second; + avg += volgroupp->dump(); + } + int count = (int)mVolumeLODGroups.size(); + avg = count ? avg / (F32)count : 0.0f; + if (mDataMutex) + { + mDataMutex->unlock(); + } + LL_INFOS() << "Average usage of LODs " << avg << LL_ENDL; +} + +void LLVolumeMgr::useMutex() +{ + if (!mDataMutex) + { + mDataMutex = new LLMutex(); + } +} + +std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr) +{ + s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", "; + + S32 total_refs = 0; + if (volume_mgr.mDataMutex) + { + volume_mgr.mDataMutex->lock(); + } + + for (LLVolumeMgr::volume_lod_group_map_t::const_iterator iter = volume_mgr.mVolumeLODGroups.begin(); + iter != volume_mgr.mVolumeLODGroups.end(); ++iter) + { + LLVolumeLODGroup *volgroupp = iter->second; + total_refs += volgroupp->getNumRefs(); + s << ", " << (*volgroupp); + } + + if (volume_mgr.mDataMutex) + { + volume_mgr.mDataMutex->unlock(); + } + + s << ", total_refs=" << total_refs << " }"; + return s; +} + +LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms) + : mVolumeParams(params), + mRefs(0) +{ + for (S32 i = 0; i < NUM_LODS; i++) + { + mLODRefs[i] = 0; + mAccessCount[i] = 0; + } +} + +LLVolumeLODGroup::~LLVolumeLODGroup() +{ + for (S32 i = 0; i < NUM_LODS; i++) + { + llassert_always(mLODRefs[i] == 0); + } +} + +// Called from LLVolumeMgr::cleanup +bool LLVolumeLODGroup::cleanupRefs() +{ + bool res = true; + if (mRefs != 0) + { + LL_WARNS() << "Volume group has remaining refs:" << getNumRefs() << LL_ENDL; + mRefs = 0; + for (S32 i = 0; i < NUM_LODS; i++) + { + if (mLODRefs[i] > 0) + { + LL_WARNS() << " LOD " << i << " refs = " << mLODRefs[i] << LL_ENDL; + mLODRefs[i] = 0; + mVolumeLODs[i] = NULL; + } + } + LL_WARNS() << *getVolumeParams() << LL_ENDL; + res = false; + } + return res; +} + +LLVolume* LLVolumeLODGroup::refLOD(const S32 lod) +{ + llassert(lod >=0 && lod < NUM_LODS); + mAccessCount[lod]++; + + mRefs++; + if (mVolumeLODs[lod].isNull()) + { + mVolumeLODs[lod] = new LLVolume(mVolumeParams, mDetailScales[lod]); + } + mLODRefs[lod]++; + return mVolumeLODs[lod]; +} + +bool LLVolumeLODGroup::derefLOD(LLVolume *volumep) +{ + llassert_always(mRefs > 0); + mRefs--; + for (S32 i = 0; i < NUM_LODS; i++) + { + if (mVolumeLODs[i] == volumep) + { + llassert_always(mLODRefs[i] > 0); + mLODRefs[i]--; +#if 0 // SJB: Possible opt: keep other lods around + if (!mLODRefs[i]) + { + mVolumeLODs[i] = NULL; + } +#endif + return true; + } + } + LL_ERRS() << "Deref of non-matching LOD in volume LOD group" << LL_ENDL; + return false; +} + +S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle) +{ + S32 i = 0; + while (i < (NUM_LODS - 1)) + { + if (tan_angle <= mDetailThresholds[i]) + { + return i; + } + i++; + } + return NUM_LODS - 1; +} + +void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher) +{ + S32 detail = getDetailFromTan(tan_angle); + + if (detail > 0) + { + to_lower = tan_angle - mDetailThresholds[detail]; + } + else + { + to_lower = 1024.f*1024.f; + } + + if (detail < NUM_LODS-1) + { + to_higher = mDetailThresholds[detail+1] - tan_angle; + } + else + { + to_higher = 1024.f*1024.f; + } +} + +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; + for (S32 i = 0; i < NUM_LODS; i++) + { + if (mAccessCount[i] > 0) + { + usage += 1.f; + } + } + usage = usage / (F32)NUM_LODS; + + std::string dump_str = llformat("%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]); + + LL_INFOS() << dump_str << LL_ENDL; + return usage; +} + +std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup) +{ + s << "{ numRefs=" << volgroup.getNumRefs(); + s << ", mParams=" << volgroup.getVolumeParams(); + s << " }"; + + return s; +} + diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index daeaf378d2..2e0ce3e88a 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -1,112 +1,112 @@ -/** - * @file llvolumemgr.h - * @brief LLVolumeMgr class. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVOLUMEMGR_H -#define LL_LLVOLUMEMGR_H - -#include - -#include "llvolume.h" -#include "llpointer.h" -#include "llthread.h" - -class LLVolumeParams; -class LLVolumeLODGroup; - -class LLVolumeLODGroup -{ - LOG_CLASS(LLVolumeLODGroup); - -public: - enum - { - NUM_LODS = 4 - }; - - LLVolumeLODGroup(const LLVolumeParams ¶ms); - ~LLVolumeLODGroup(); - bool cleanupRefs(); - - 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); - S32 getNumRefs() const { return mRefs; } - - const LLVolumeParams* getVolumeParams() const { return &mVolumeParams; }; - - F32 dump(); - friend std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup); - -protected: - LLVolumeParams mVolumeParams; - - S32 mRefs; - S32 mLODRefs[NUM_LODS]; - LLPointer mVolumeLODs[NUM_LODS]; - static F32 mDetailThresholds[NUM_LODS]; - static F32 mDetailScales[NUM_LODS]; - S32 mAccessCount[NUM_LODS]; -}; - -class LLVolumeMgr -{ -public: - LLVolumeMgr(); - virtual ~LLVolumeMgr(); - bool cleanup(); // Cleanup all volumes being managed, returns true if no dangling references - - virtual LLVolumeLODGroup* getGroup( const LLVolumeParams& volume_params ) const; - - // whatever calls getVolume() never owns the LLVolume* and - // cannot keep references for long since it may be deleted - // later. For best results hold it in an LLPointer. - virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail); - virtual void unrefVolume(LLVolume *volumep); - - void dump(); - - // manually call this for mutex magic - void useMutex(); - - friend std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr); - -protected: - void insertGroup(LLVolumeLODGroup* volgroup); - // Overridden in llphysics/abstract/utils/llphysicsvolumemanager.h - virtual LLVolumeLODGroup* createNewGroup(const LLVolumeParams& volume_params); - -protected: - typedef std::map volume_lod_group_map_t; - volume_lod_group_map_t mVolumeLODGroups; - - LLMutex* mDataMutex; -}; - -#endif // LL_LLVOLUMEMGR_H +/** + * @file llvolumemgr.h + * @brief LLVolumeMgr class. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVOLUMEMGR_H +#define LL_LLVOLUMEMGR_H + +#include + +#include "llvolume.h" +#include "llpointer.h" +#include "llthread.h" + +class LLVolumeParams; +class LLVolumeLODGroup; + +class LLVolumeLODGroup +{ + LOG_CLASS(LLVolumeLODGroup); + +public: + enum + { + NUM_LODS = 4 + }; + + LLVolumeLODGroup(const LLVolumeParams ¶ms); + ~LLVolumeLODGroup(); + bool cleanupRefs(); + + 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); + S32 getNumRefs() const { return mRefs; } + + const LLVolumeParams* getVolumeParams() const { return &mVolumeParams; }; + + F32 dump(); + friend std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup); + +protected: + LLVolumeParams mVolumeParams; + + S32 mRefs; + S32 mLODRefs[NUM_LODS]; + LLPointer mVolumeLODs[NUM_LODS]; + static F32 mDetailThresholds[NUM_LODS]; + static F32 mDetailScales[NUM_LODS]; + S32 mAccessCount[NUM_LODS]; +}; + +class LLVolumeMgr +{ +public: + LLVolumeMgr(); + virtual ~LLVolumeMgr(); + bool cleanup(); // Cleanup all volumes being managed, returns true if no dangling references + + virtual LLVolumeLODGroup* getGroup( const LLVolumeParams& volume_params ) const; + + // whatever calls getVolume() never owns the LLVolume* and + // cannot keep references for long since it may be deleted + // later. For best results hold it in an LLPointer. + virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail); + virtual void unrefVolume(LLVolume *volumep); + + void dump(); + + // manually call this for mutex magic + void useMutex(); + + friend std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr); + +protected: + void insertGroup(LLVolumeLODGroup* volgroup); + // Overridden in llphysics/abstract/utils/llphysicsvolumemanager.h + virtual LLVolumeLODGroup* createNewGroup(const LLVolumeParams& volume_params); + +protected: + typedef std::map volume_lod_group_map_t; + volume_lod_group_map_t mVolumeLODGroups; + + LLMutex* mDataMutex; +}; + +#endif // LL_LLVOLUMEMGR_H diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index ebac5522e7..74d496fa02 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -1,273 +1,273 @@ -/** - - * @file llvolumeoctree.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llvolumeoctree.h" -#include "llvector4a.h" - -bool LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size) -{ - LLVector4a fAWdU; - LLVector4a dir; - LLVector4a diff; - - dir.setSub(end, start); - dir.mul(0.5f); - - diff.setAdd(end,start); - diff.mul(0.5f); - diff.sub(center); - fAWdU.setAbs(dir); - - LLVector4a rhs; - rhs.setAdd(size, fAWdU); - - LLVector4a lhs; - lhs.setAbs(diff); - - U32 grt = lhs.greaterThan(rhs).getGatheredBits(); - - if (grt & 0x7) - { - return false; - } - - LLVector4a f; - f.setCross3(dir, diff); - f.setAbs(f); - - LLVector4a v0, v1; - - v0 = _mm_shuffle_ps(size, size,_MM_SHUFFLE(3,0,0,1)); - v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,1,2,2)); - lhs.setMul(v0, v1); - - v0 = _mm_shuffle_ps(size, size, _MM_SHUFFLE(3,1,2,2)); - v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,0,0,1)); - rhs.setMul(v0, v1); - rhs.add(lhs); - - grt = f.greaterThan(rhs).getGatheredBits(); - - return (grt & 0x7) == 0; -} - -LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode* node) -{ - node->addListener(this); -} - -LLVolumeOctreeListener::~LLVolumeOctreeListener() -{ - -} - -void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode* parent, - LLOctreeNode* child) -{ - new LLVolumeOctreeListener(child); -} - -LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, - const LLVolumeFace* face, F32* closest_t, - LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) - : mFace(face), - mStart(start), - mDir(dir), - mIntersection(intersection), - mTexCoord(tex_coord), - mNormal(normal), - mTangent(tangent), - mClosestT(closest_t), - mHitFace(false) -{ - mEnd.setAdd(mStart, mDir); -} - -void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode* node) -{ - LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0); - - if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1])) - { - node->accept(this); - for (S32 i = 0; i < node->getChildCount(); ++i) - { - traverse(node->getChild(i)); - } - } -} - -void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode* node) -{ - for (typename LLOctreeNode::const_element_iter iter = - node->getDataBegin(); iter != node->getDataEnd(); ++iter) - { - const LLVolumeTriangle* tri = *iter; - - F32 a, b, t; - - if (LLTriangleRayIntersect(*tri->mV[0], *tri->mV[1], *tri->mV[2], - mStart, mDir, a, b, t)) - { - if ((t >= 0.f) && // if hit is after start - (t <= 1.f) && // and before end - (t < *mClosestT)) // and this hit is closer - { - *mClosestT = t; - mHitFace = true; - - if (mIntersection != NULL) - { - LLVector4a intersect = mDir; - intersect.mul(*mClosestT); - intersect.add(mStart); - *mIntersection = intersect; - } - - U32 idx0 = tri->mIndex[0]; - U32 idx1 = tri->mIndex[1]; - U32 idx2 = tri->mIndex[2]; - - if (mTexCoord != NULL) - { - LLVector2* tc = (LLVector2*) mFace->mTexCoords; - *mTexCoord = ((1.f - a - b) * tc[idx0] + - a * tc[idx1] + - b * tc[idx2]); - - } - - if (mNormal != NULL) - { - LLVector4a* norm = mFace->mNormals; - - LLVector4a n1,n2,n3; - n1 = norm[idx0]; - n1.mul(1.f-a-b); - - n2 = norm[idx1]; - n2.mul(a); - - n3 = norm[idx2]; - n3.mul(b); - - n1.add(n2); - n1.add(n3); - - *mNormal = n1; - } - - if (mTangent != NULL) - { - LLVector4a* tangents = mFace->mTangents; - - LLVector4a t1,t2,t3; - t1 = tangents[idx0]; - t1.mul(1.f-a-b); - - t2 = tangents[idx1]; - t2.mul(a); - - t3 = tangents[idx2]; - t3.mul(b); - - t1.add(t2); - t1.add(t3); - - *mTangent = t1; - } - } - } - } -} - -const LLVector4a& LLVolumeTriangle::getPositionGroup() const -{ - return mPositionGroup; -} - -const F32& LLVolumeTriangle::getBinRadius() const -{ - return mRadius; -} - - -//TEST CODE - -void LLVolumeOctreeValidate::visit(const LLOctreeNode* branch) -{ - LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); - - //make sure bounds matches extents - LLVector4a& min = node->mExtents[0]; - LLVector4a& max = node->mExtents[1]; - - LLVector4a& center = node->mBounds[0]; - LLVector4a& size = node->mBounds[1]; - - LLVector4a test_min, test_max; - test_min.setSub(center, size); - test_max.setAdd(center, size); - - if (!test_min.equals3(min, 0.001f) || - !test_max.equals3(max, 0.001f)) - { - LL_ERRS() << "Bad bounding box data found." << LL_ENDL; - } - - test_min.sub(LLVector4a(0.001f)); - test_max.add(LLVector4a(0.001f)); - - for (U32 i = 0; i < branch->getChildCount(); ++i) - { - LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); - - //make sure all children fit inside this node - if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) || - child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ)) - { - LL_ERRS() << "Child protrudes from bounding box." << LL_ENDL; - } - } - - //children fit, check data - for (typename LLOctreeNode::const_element_iter iter = branch->getDataBegin(); - iter != branch->getDataEnd(); ++iter) - { - const LLVolumeTriangle* tri = *iter; - - //validate triangle - for (U32 i = 0; i < 3; i++) - { - if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) || - tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ)) - { - LL_ERRS() << "Triangle protrudes from node." << LL_ENDL; - } - } - } -} - +/** + + * @file llvolumeoctree.cpp + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llvolumeoctree.h" +#include "llvector4a.h" + +bool LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size) +{ + LLVector4a fAWdU; + LLVector4a dir; + LLVector4a diff; + + dir.setSub(end, start); + dir.mul(0.5f); + + diff.setAdd(end,start); + diff.mul(0.5f); + diff.sub(center); + fAWdU.setAbs(dir); + + LLVector4a rhs; + rhs.setAdd(size, fAWdU); + + LLVector4a lhs; + lhs.setAbs(diff); + + U32 grt = lhs.greaterThan(rhs).getGatheredBits(); + + if (grt & 0x7) + { + return false; + } + + LLVector4a f; + f.setCross3(dir, diff); + f.setAbs(f); + + LLVector4a v0, v1; + + v0 = _mm_shuffle_ps(size, size,_MM_SHUFFLE(3,0,0,1)); + v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,1,2,2)); + lhs.setMul(v0, v1); + + v0 = _mm_shuffle_ps(size, size, _MM_SHUFFLE(3,1,2,2)); + v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,0,0,1)); + rhs.setMul(v0, v1); + rhs.add(lhs); + + grt = f.greaterThan(rhs).getGatheredBits(); + + return (grt & 0x7) == 0; +} + +LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode* node) +{ + node->addListener(this); +} + +LLVolumeOctreeListener::~LLVolumeOctreeListener() +{ + +} + +void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode* parent, + LLOctreeNode* child) +{ + new LLVolumeOctreeListener(child); +} + +LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, + const LLVolumeFace* face, F32* closest_t, + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) + : mFace(face), + mStart(start), + mDir(dir), + mIntersection(intersection), + mTexCoord(tex_coord), + mNormal(normal), + mTangent(tangent), + mClosestT(closest_t), + mHitFace(false) +{ + mEnd.setAdd(mStart, mDir); +} + +void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode* node) +{ + LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0); + + if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1])) + { + node->accept(this); + for (S32 i = 0; i < node->getChildCount(); ++i) + { + traverse(node->getChild(i)); + } + } +} + +void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode* node) +{ + for (typename LLOctreeNode::const_element_iter iter = + node->getDataBegin(); iter != node->getDataEnd(); ++iter) + { + const LLVolumeTriangle* tri = *iter; + + F32 a, b, t; + + if (LLTriangleRayIntersect(*tri->mV[0], *tri->mV[1], *tri->mV[2], + mStart, mDir, a, b, t)) + { + if ((t >= 0.f) && // if hit is after start + (t <= 1.f) && // and before end + (t < *mClosestT)) // and this hit is closer + { + *mClosestT = t; + mHitFace = true; + + if (mIntersection != NULL) + { + LLVector4a intersect = mDir; + intersect.mul(*mClosestT); + intersect.add(mStart); + *mIntersection = intersect; + } + + U32 idx0 = tri->mIndex[0]; + U32 idx1 = tri->mIndex[1]; + U32 idx2 = tri->mIndex[2]; + + if (mTexCoord != NULL) + { + LLVector2* tc = (LLVector2*) mFace->mTexCoords; + *mTexCoord = ((1.f - a - b) * tc[idx0] + + a * tc[idx1] + + b * tc[idx2]); + + } + + if (mNormal != NULL) + { + LLVector4a* norm = mFace->mNormals; + + LLVector4a n1,n2,n3; + n1 = norm[idx0]; + n1.mul(1.f-a-b); + + n2 = norm[idx1]; + n2.mul(a); + + n3 = norm[idx2]; + n3.mul(b); + + n1.add(n2); + n1.add(n3); + + *mNormal = n1; + } + + if (mTangent != NULL) + { + LLVector4a* tangents = mFace->mTangents; + + LLVector4a t1,t2,t3; + t1 = tangents[idx0]; + t1.mul(1.f-a-b); + + t2 = tangents[idx1]; + t2.mul(a); + + t3 = tangents[idx2]; + t3.mul(b); + + t1.add(t2); + t1.add(t3); + + *mTangent = t1; + } + } + } + } +} + +const LLVector4a& LLVolumeTriangle::getPositionGroup() const +{ + return mPositionGroup; +} + +const F32& LLVolumeTriangle::getBinRadius() const +{ + return mRadius; +} + + +//TEST CODE + +void LLVolumeOctreeValidate::visit(const LLOctreeNode* branch) +{ + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); + + //make sure bounds matches extents + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + LLVector4a& center = node->mBounds[0]; + LLVector4a& size = node->mBounds[1]; + + LLVector4a test_min, test_max; + test_min.setSub(center, size); + test_max.setAdd(center, size); + + if (!test_min.equals3(min, 0.001f) || + !test_max.equals3(max, 0.001f)) + { + LL_ERRS() << "Bad bounding box data found." << LL_ENDL; + } + + test_min.sub(LLVector4a(0.001f)); + test_max.add(LLVector4a(0.001f)); + + for (U32 i = 0; i < branch->getChildCount(); ++i) + { + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + + //make sure all children fit inside this node + if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) || + child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ)) + { + LL_ERRS() << "Child protrudes from bounding box." << LL_ENDL; + } + } + + //children fit, check data + for (typename LLOctreeNode::const_element_iter iter = branch->getDataBegin(); + iter != branch->getDataEnd(); ++iter) + { + const LLVolumeTriangle* tri = *iter; + + //validate triangle + for (U32 i = 0; i < 3; i++) + { + if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) || + tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ)) + { + LL_ERRS() << "Triangle protrudes from node." << LL_ENDL; + } + } + } +} + diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index e48c47d1ef..472d340af5 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -1,590 +1,590 @@ -/** - * @file m3math.cpp - * @brief LLMatrix3 class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -//#include "vmath.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquaternion.h" - -// LLMatrix3 - -// ji -// LLMatrix3 = |00 01 02 | -// |10 11 12 | -// |20 21 22 | - -// LLMatrix3 = |fx fy fz | forward-axis -// |lx ly lz | left-axis -// |ux uy uz | up-axis - - -// Constructors - - -LLMatrix3::LLMatrix3(const LLQuaternion &q) -{ - setRot(q); -} - - -LLMatrix3::LLMatrix3(const F32 angle, const LLVector3 &vec) -{ - LLQuaternion quat(angle, vec); - setRot(quat); -} - -LLMatrix3::LLMatrix3(const F32 angle, const LLVector3d &vec) -{ - LLVector3 vec_f; - vec_f.setVec(vec); - LLQuaternion quat(angle, vec_f); - setRot(quat); -} - -LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec) -{ - LLQuaternion quat(angle, vec); - setRot(quat); -} - -LLMatrix3::LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw) -{ - setRot(roll,pitch,yaw); -} - -// From Matrix and Quaternion FAQ -void LLMatrix3::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const -{ - F64 angle_x, angle_y, angle_z; - F64 cx, cy, cz; // cosine of angle_x, angle_y, angle_z - F64 sx, sz; // sine of angle_x, angle_y, angle_z - - angle_y = asin(llclamp(mMatrix[2][0], -1.f, 1.f)); - cy = cos(angle_y); - - if (fabs(cy) > 0.005) // non-zero - { - // no gimbal lock - cx = mMatrix[2][2] / cy; - sx = - mMatrix[2][1] / cy; - - angle_x = (F32) atan2(sx, cx); - - cz = mMatrix[0][0] / cy; - sz = - mMatrix[1][0] / cy; - - angle_z = (F32) atan2(sz, cz); - } - else - { - // yup, gimbal lock - angle_x = 0; - - // some tricky math thereby avoided, see article - - cz = mMatrix[1][1]; - sz = mMatrix[0][1]; - - angle_z = atan2(sz, cz); - } - - *roll = (F32)angle_x; - *pitch = (F32)angle_y; - *yaw = (F32)angle_z; -} - - -// Clear and Assignment Functions - -const LLMatrix3& LLMatrix3::setIdentity() -{ - mMatrix[0][0] = 1.f; - mMatrix[0][1] = 0.f; - mMatrix[0][2] = 0.f; - - mMatrix[1][0] = 0.f; - mMatrix[1][1] = 1.f; - mMatrix[1][2] = 0.f; - - mMatrix[2][0] = 0.f; - mMatrix[2][1] = 0.f; - mMatrix[2][2] = 1.f; - return (*this); -} - -const LLMatrix3& LLMatrix3::clear() -{ - mMatrix[0][0] = 0.f; - mMatrix[0][1] = 0.f; - mMatrix[0][2] = 0.f; - - mMatrix[1][0] = 0.f; - mMatrix[1][1] = 0.f; - mMatrix[1][2] = 0.f; - - mMatrix[2][0] = 0.f; - mMatrix[2][1] = 0.f; - mMatrix[2][2] = 0.f; - return (*this); -} - -const LLMatrix3& LLMatrix3::setZero() -{ - mMatrix[0][0] = 0.f; - mMatrix[0][1] = 0.f; - mMatrix[0][2] = 0.f; - - mMatrix[1][0] = 0.f; - mMatrix[1][1] = 0.f; - mMatrix[1][2] = 0.f; - - mMatrix[2][0] = 0.f; - mMatrix[2][1] = 0.f; - mMatrix[2][2] = 0.f; - return (*this); -} - -// various useful mMatrix functions - -const LLMatrix3& LLMatrix3::transpose() -{ - // transpose the matrix - F32 temp; - temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp; - temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp; - temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp; - return *this; -} - - -F32 LLMatrix3::determinant() const -{ - // Is this a useful method when we assume the matrices are valid rotation - // matrices throughout this implementation? - return mMatrix[0][0] * (mMatrix[1][1] * mMatrix[2][2] - mMatrix[1][2] * mMatrix[2][1]) + - mMatrix[0][1] * (mMatrix[1][2] * mMatrix[2][0] - mMatrix[1][0] * mMatrix[2][2]) + - mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] - mMatrix[1][1] * mMatrix[2][0]); -} - -// inverts this matrix -void LLMatrix3::invert() -{ - // fails silently if determinant is zero too small - F32 det = determinant(); - const F32 VERY_SMALL_DETERMINANT = 0.000001f; - if (fabs(det) > VERY_SMALL_DETERMINANT) - { - // invertiable - LLMatrix3 t(*this); - mMatrix[VX][VX] = ( t.mMatrix[VY][VY] * t.mMatrix[VZ][VZ] - t.mMatrix[VY][VZ] * t.mMatrix[VZ][VY] ) / det; - mMatrix[VY][VX] = ( t.mMatrix[VY][VZ] * t.mMatrix[VZ][VX] - t.mMatrix[VY][VX] * t.mMatrix[VZ][VZ] ) / det; - mMatrix[VZ][VX] = ( t.mMatrix[VY][VX] * t.mMatrix[VZ][VY] - t.mMatrix[VY][VY] * t.mMatrix[VZ][VX] ) / det; - mMatrix[VX][VY] = ( t.mMatrix[VZ][VY] * t.mMatrix[VX][VZ] - t.mMatrix[VZ][VZ] * t.mMatrix[VX][VY] ) / det; - mMatrix[VY][VY] = ( t.mMatrix[VZ][VZ] * t.mMatrix[VX][VX] - t.mMatrix[VZ][VX] * t.mMatrix[VX][VZ] ) / det; - mMatrix[VZ][VY] = ( t.mMatrix[VZ][VX] * t.mMatrix[VX][VY] - t.mMatrix[VZ][VY] * t.mMatrix[VX][VX] ) / det; - mMatrix[VX][VZ] = ( t.mMatrix[VX][VY] * t.mMatrix[VY][VZ] - t.mMatrix[VX][VZ] * t.mMatrix[VY][VY] ) / det; - mMatrix[VY][VZ] = ( t.mMatrix[VX][VZ] * t.mMatrix[VY][VX] - t.mMatrix[VX][VX] * t.mMatrix[VY][VZ] ) / det; - mMatrix[VZ][VZ] = ( t.mMatrix[VX][VX] * t.mMatrix[VY][VY] - t.mMatrix[VX][VY] * t.mMatrix[VY][VX] ) / det; - } -} - -// does not assume a rotation matrix, and does not divide by determinant, assuming results will be renormalized -const LLMatrix3& LLMatrix3::adjointTranspose() -{ - LLMatrix3 adjoint_transpose; - adjoint_transpose.mMatrix[VX][VX] = mMatrix[VY][VY] * mMatrix[VZ][VZ] - mMatrix[VY][VZ] * mMatrix[VZ][VY] ; - adjoint_transpose.mMatrix[VY][VX] = mMatrix[VY][VZ] * mMatrix[VZ][VX] - mMatrix[VY][VX] * mMatrix[VZ][VZ] ; - adjoint_transpose.mMatrix[VZ][VX] = mMatrix[VY][VX] * mMatrix[VZ][VY] - mMatrix[VY][VY] * mMatrix[VZ][VX] ; - adjoint_transpose.mMatrix[VX][VY] = mMatrix[VZ][VY] * mMatrix[VX][VZ] - mMatrix[VZ][VZ] * mMatrix[VX][VY] ; - adjoint_transpose.mMatrix[VY][VY] = mMatrix[VZ][VZ] * mMatrix[VX][VX] - mMatrix[VZ][VX] * mMatrix[VX][VZ] ; - adjoint_transpose.mMatrix[VZ][VY] = mMatrix[VZ][VX] * mMatrix[VX][VY] - mMatrix[VZ][VY] * mMatrix[VX][VX] ; - adjoint_transpose.mMatrix[VX][VZ] = mMatrix[VX][VY] * mMatrix[VY][VZ] - mMatrix[VX][VZ] * mMatrix[VY][VY] ; - adjoint_transpose.mMatrix[VY][VZ] = mMatrix[VX][VZ] * mMatrix[VY][VX] - mMatrix[VX][VX] * mMatrix[VY][VZ] ; - adjoint_transpose.mMatrix[VZ][VZ] = mMatrix[VX][VX] * mMatrix[VY][VY] - mMatrix[VX][VY] * mMatrix[VY][VX] ; - - *this = adjoint_transpose; - return *this; -} - -// SJB: This code is correct for a logicly stored (non-transposed) matrix; -// Our matrices are stored transposed, OpenGL style, so this generates the -// INVERSE quaternion (-x, -y, -z, w)! -// Because we use similar logic in LLQuaternion::getMatrix3, -// we are internally consistant so everything works OK :) -LLQuaternion LLMatrix3::quaternion() const -{ - LLQuaternion quat; - F32 tr, s, q[4]; - U32 i, j, k; - U32 nxt[3] = {1, 2, 0}; - - tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2]; - - // check the diagonal - if (tr > 0.f) - { - s = (F32)sqrt (tr + 1.f); - quat.mQ[VS] = s / 2.f; - s = 0.5f / s; - quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s; - quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s; - quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s; - } - else - { - // diagonal is negative - i = 0; - if (mMatrix[1][1] > mMatrix[0][0]) - i = 1; - if (mMatrix[2][2] > mMatrix[i][i]) - i = 2; - - j = nxt[i]; - k = nxt[j]; - - - s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f); - - q[i] = s * 0.5f; - - if (s != 0.f) - s = 0.5f / s; - - q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s; - q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s; - q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s; - - quat.setQuat(q); - } - return quat; -} - -const LLMatrix3& LLMatrix3::setRot(const F32 angle, const LLVector3 &vec) -{ - setRot(LLQuaternion(angle, vec)); - return *this; -} - -const LLMatrix3& LLMatrix3::setRot(const F32 roll, const F32 pitch, const F32 yaw) -{ - // Rotates RH about x-axis by 'roll' then - // rotates RH about the old y-axis by 'pitch' then - // rotates RH about the original z-axis by 'yaw'. - // . - // /|\ yaw axis - // | __. - // ._ ___| /| pitch axis - // _||\ \\ |-. / - // \|| \_______\_|__\_/_______ - // | _ _ o o o_o_o_o o /_\_ ________\ roll axis - // // /_______/ /__________> / - // /_,-' // / - // /__,-' - - F32 cx, sx, cy, sy, cz, sz; - F32 cxsy, sxsy; - - cx = (F32)cos(roll); //A - sx = (F32)sin(roll); //B - cy = (F32)cos(pitch); //C - sy = (F32)sin(pitch); //D - cz = (F32)cos(yaw); //E - sz = (F32)sin(yaw); //F - - cxsy = cx * sy; //AD - sxsy = sx * sy; //BD - - mMatrix[0][0] = cy * cz; - mMatrix[1][0] = -cy * sz; - mMatrix[2][0] = sy; - mMatrix[0][1] = sxsy * cz + cx * sz; - mMatrix[1][1] = -sxsy * sz + cx * cz; - mMatrix[2][1] = -sx * cy; - mMatrix[0][2] = -cxsy * cz + sx * sz; - mMatrix[1][2] = cxsy * sz + sx * cz; - mMatrix[2][2] = cx * cy; - return *this; -} - - -const LLMatrix3& LLMatrix3::setRot(const LLQuaternion &q) -{ - *this = q.getMatrix3(); - return *this; -} - -const LLMatrix3& LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left, const LLVector3 &up) -{ - mMatrix[0][0] = fwd.mV[0]; - mMatrix[0][1] = fwd.mV[1]; - mMatrix[0][2] = fwd.mV[2]; - - mMatrix[1][0] = left.mV[0]; - mMatrix[1][1] = left.mV[1]; - mMatrix[1][2] = left.mV[2]; - - mMatrix[2][0] = up.mV[0]; - mMatrix[2][1] = up.mV[1]; - mMatrix[2][2] = up.mV[2]; - - return *this; -} - -const LLMatrix3& LLMatrix3::setRow( U32 rowIndex, const LLVector3& row ) -{ - llassert( rowIndex >= 0 && rowIndex < NUM_VALUES_IN_MAT3 ); - - mMatrix[rowIndex][0] = row[0]; - mMatrix[rowIndex][1] = row[1]; - mMatrix[rowIndex][2] = row[2]; - - return *this; -} - -const LLMatrix3& LLMatrix3::setCol( U32 colIndex, const LLVector3& col ) -{ - llassert( colIndex >= 0 && colIndex < NUM_VALUES_IN_MAT3 ); - - mMatrix[0][colIndex] = col[0]; - mMatrix[1][colIndex] = col[1]; - mMatrix[2][colIndex] = col[2]; - - return *this; -} - -const LLMatrix3& LLMatrix3::rotate(const F32 angle, const LLVector3 &vec) -{ - LLMatrix3 mat(angle, vec); - *this *= mat; - return *this; -} - - -const LLMatrix3& LLMatrix3::rotate(const F32 roll, const F32 pitch, const F32 yaw) -{ - LLMatrix3 mat(roll, pitch, yaw); - *this *= mat; - return *this; -} - - -const LLMatrix3& LLMatrix3::rotate(const LLQuaternion &q) -{ - LLMatrix3 mat(q); - *this *= mat; - return *this; -} - -void LLMatrix3::add(const LLMatrix3& other_matrix) -{ - for (S32 i = 0; i < 3; ++i) - { - for (S32 j = 0; j < 3; ++j) - { - mMatrix[i][j] += other_matrix.mMatrix[i][j]; - } - } -} - -LLVector3 LLMatrix3::getFwdRow() const -{ - return LLVector3(mMatrix[VX]); -} - -LLVector3 LLMatrix3::getLeftRow() const -{ - return LLVector3(mMatrix[VY]); -} - -LLVector3 LLMatrix3::getUpRow() const -{ - return LLVector3(mMatrix[VZ]); -} - - - -const LLMatrix3& LLMatrix3::orthogonalize() -{ - LLVector3 x_axis(mMatrix[VX]); - LLVector3 y_axis(mMatrix[VY]); - LLVector3 z_axis(mMatrix[VZ]); - - x_axis.normVec(); - y_axis -= x_axis * (x_axis * y_axis); - y_axis.normVec(); - z_axis = x_axis % y_axis; - setRows(x_axis, y_axis, z_axis); - return (*this); -} - - -// LLMatrix3 Operators - -LLMatrix3 operator*(const LLMatrix3 &a, const LLMatrix3 &b) -{ - U32 i, j; - LLMatrix3 mat; - for (i = 0; i < NUM_VALUES_IN_MAT3; i++) - { - for (j = 0; j < NUM_VALUES_IN_MAT3; j++) - { - mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + - a.mMatrix[j][1] * b.mMatrix[1][i] + - a.mMatrix[j][2] * b.mMatrix[2][i]; - } - } - return mat; -} - -/* Not implemented to help enforce code consistency with the syntax of - row-major notation. This is a Good Thing. -LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b) -{ - LLVector3 vec; - // matrix operates "from the left" on column vector - vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + - a.mMatrix[VX][VY] * b.mV[VY] + - a.mMatrix[VX][VZ] * b.mV[VZ]; - - vec.mV[VY] = a.mMatrix[VY][VX] * b.mV[VX] + - a.mMatrix[VY][VY] * b.mV[VY] + - a.mMatrix[VY][VZ] * b.mV[VZ]; - - vec.mV[VZ] = a.mMatrix[VZ][VX] * b.mV[VX] + - a.mMatrix[VZ][VY] * b.mV[VY] + - a.mMatrix[VZ][VZ] * b.mV[VZ]; - return vec; -} -*/ - - -LLVector3 operator*(const LLVector3 &a, const LLMatrix3 &b) -{ - // matrix operates "from the right" on row vector - return LLVector3( - a.mV[VX] * b.mMatrix[VX][VX] + - a.mV[VY] * b.mMatrix[VY][VX] + - a.mV[VZ] * b.mMatrix[VZ][VX], - - a.mV[VX] * b.mMatrix[VX][VY] + - a.mV[VY] * b.mMatrix[VY][VY] + - a.mV[VZ] * b.mMatrix[VZ][VY], - - a.mV[VX] * b.mMatrix[VX][VZ] + - a.mV[VY] * b.mMatrix[VY][VZ] + - a.mV[VZ] * b.mMatrix[VZ][VZ] ); -} - -LLVector3d operator*(const LLVector3d &a, const LLMatrix3 &b) -{ - // matrix operates "from the right" on row vector - return LLVector3d( - a.mdV[VX] * b.mMatrix[VX][VX] + - a.mdV[VY] * b.mMatrix[VY][VX] + - a.mdV[VZ] * b.mMatrix[VZ][VX], - - a.mdV[VX] * b.mMatrix[VX][VY] + - a.mdV[VY] * b.mMatrix[VY][VY] + - a.mdV[VZ] * b.mMatrix[VZ][VY], - - a.mdV[VX] * b.mMatrix[VX][VZ] + - a.mdV[VY] * b.mMatrix[VY][VZ] + - a.mdV[VZ] * b.mMatrix[VZ][VZ] ); -} - -bool operator==(const LLMatrix3 &a, const LLMatrix3 &b) -{ - U32 i, j; - for (i = 0; i < NUM_VALUES_IN_MAT3; i++) - { - for (j = 0; j < NUM_VALUES_IN_MAT3; j++) - { - if (a.mMatrix[j][i] != b.mMatrix[j][i]) - return false; - } - } - return true; -} - -bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b) -{ - U32 i, j; - for (i = 0; i < NUM_VALUES_IN_MAT3; i++) - { - for (j = 0; j < NUM_VALUES_IN_MAT3; j++) - { - if (a.mMatrix[j][i] != b.mMatrix[j][i]) - return true; - } - } - return false; -} - -const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b) -{ - U32 i, j; - LLMatrix3 mat; - for (i = 0; i < NUM_VALUES_IN_MAT3; i++) - { - for (j = 0; j < NUM_VALUES_IN_MAT3; j++) - { - mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + - a.mMatrix[j][1] * b.mMatrix[1][i] + - a.mMatrix[j][2] * b.mMatrix[2][i]; - } - } - a = mat; - return a; -} - -const LLMatrix3& operator*=(LLMatrix3 &a, F32 scalar ) -{ - for( U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i ) - { - for( U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j ) - { - a.mMatrix[i][j] *= scalar; - } - } - - return a; -} - -std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a) -{ - s << "{ " - << a.mMatrix[VX][VX] << ", " << a.mMatrix[VX][VY] << ", " << a.mMatrix[VX][VZ] << "; " - << a.mMatrix[VY][VX] << ", " << a.mMatrix[VY][VY] << ", " << a.mMatrix[VY][VZ] << "; " - << a.mMatrix[VZ][VX] << ", " << a.mMatrix[VZ][VY] << ", " << a.mMatrix[VZ][VZ] - << " }"; - return s; -} - +/** + * @file m3math.cpp + * @brief LLMatrix3 class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +//#include "vmath.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquaternion.h" + +// LLMatrix3 + +// ji +// LLMatrix3 = |00 01 02 | +// |10 11 12 | +// |20 21 22 | + +// LLMatrix3 = |fx fy fz | forward-axis +// |lx ly lz | left-axis +// |ux uy uz | up-axis + + +// Constructors + + +LLMatrix3::LLMatrix3(const LLQuaternion &q) +{ + setRot(q); +} + + +LLMatrix3::LLMatrix3(const F32 angle, const LLVector3 &vec) +{ + LLQuaternion quat(angle, vec); + setRot(quat); +} + +LLMatrix3::LLMatrix3(const F32 angle, const LLVector3d &vec) +{ + LLVector3 vec_f; + vec_f.setVec(vec); + LLQuaternion quat(angle, vec_f); + setRot(quat); +} + +LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec) +{ + LLQuaternion quat(angle, vec); + setRot(quat); +} + +LLMatrix3::LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw) +{ + setRot(roll,pitch,yaw); +} + +// From Matrix and Quaternion FAQ +void LLMatrix3::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const +{ + F64 angle_x, angle_y, angle_z; + F64 cx, cy, cz; // cosine of angle_x, angle_y, angle_z + F64 sx, sz; // sine of angle_x, angle_y, angle_z + + angle_y = asin(llclamp(mMatrix[2][0], -1.f, 1.f)); + cy = cos(angle_y); + + if (fabs(cy) > 0.005) // non-zero + { + // no gimbal lock + cx = mMatrix[2][2] / cy; + sx = - mMatrix[2][1] / cy; + + angle_x = (F32) atan2(sx, cx); + + cz = mMatrix[0][0] / cy; + sz = - mMatrix[1][0] / cy; + + angle_z = (F32) atan2(sz, cz); + } + else + { + // yup, gimbal lock + angle_x = 0; + + // some tricky math thereby avoided, see article + + cz = mMatrix[1][1]; + sz = mMatrix[0][1]; + + angle_z = atan2(sz, cz); + } + + *roll = (F32)angle_x; + *pitch = (F32)angle_y; + *yaw = (F32)angle_z; +} + + +// Clear and Assignment Functions + +const LLMatrix3& LLMatrix3::setIdentity() +{ + mMatrix[0][0] = 1.f; + mMatrix[0][1] = 0.f; + mMatrix[0][2] = 0.f; + + mMatrix[1][0] = 0.f; + mMatrix[1][1] = 1.f; + mMatrix[1][2] = 0.f; + + mMatrix[2][0] = 0.f; + mMatrix[2][1] = 0.f; + mMatrix[2][2] = 1.f; + return (*this); +} + +const LLMatrix3& LLMatrix3::clear() +{ + mMatrix[0][0] = 0.f; + mMatrix[0][1] = 0.f; + mMatrix[0][2] = 0.f; + + mMatrix[1][0] = 0.f; + mMatrix[1][1] = 0.f; + mMatrix[1][2] = 0.f; + + mMatrix[2][0] = 0.f; + mMatrix[2][1] = 0.f; + mMatrix[2][2] = 0.f; + return (*this); +} + +const LLMatrix3& LLMatrix3::setZero() +{ + mMatrix[0][0] = 0.f; + mMatrix[0][1] = 0.f; + mMatrix[0][2] = 0.f; + + mMatrix[1][0] = 0.f; + mMatrix[1][1] = 0.f; + mMatrix[1][2] = 0.f; + + mMatrix[2][0] = 0.f; + mMatrix[2][1] = 0.f; + mMatrix[2][2] = 0.f; + return (*this); +} + +// various useful mMatrix functions + +const LLMatrix3& LLMatrix3::transpose() +{ + // transpose the matrix + F32 temp; + temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp; + temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp; + temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp; + return *this; +} + + +F32 LLMatrix3::determinant() const +{ + // Is this a useful method when we assume the matrices are valid rotation + // matrices throughout this implementation? + return mMatrix[0][0] * (mMatrix[1][1] * mMatrix[2][2] - mMatrix[1][2] * mMatrix[2][1]) + + mMatrix[0][1] * (mMatrix[1][2] * mMatrix[2][0] - mMatrix[1][0] * mMatrix[2][2]) + + mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] - mMatrix[1][1] * mMatrix[2][0]); +} + +// inverts this matrix +void LLMatrix3::invert() +{ + // fails silently if determinant is zero too small + F32 det = determinant(); + const F32 VERY_SMALL_DETERMINANT = 0.000001f; + if (fabs(det) > VERY_SMALL_DETERMINANT) + { + // invertiable + LLMatrix3 t(*this); + mMatrix[VX][VX] = ( t.mMatrix[VY][VY] * t.mMatrix[VZ][VZ] - t.mMatrix[VY][VZ] * t.mMatrix[VZ][VY] ) / det; + mMatrix[VY][VX] = ( t.mMatrix[VY][VZ] * t.mMatrix[VZ][VX] - t.mMatrix[VY][VX] * t.mMatrix[VZ][VZ] ) / det; + mMatrix[VZ][VX] = ( t.mMatrix[VY][VX] * t.mMatrix[VZ][VY] - t.mMatrix[VY][VY] * t.mMatrix[VZ][VX] ) / det; + mMatrix[VX][VY] = ( t.mMatrix[VZ][VY] * t.mMatrix[VX][VZ] - t.mMatrix[VZ][VZ] * t.mMatrix[VX][VY] ) / det; + mMatrix[VY][VY] = ( t.mMatrix[VZ][VZ] * t.mMatrix[VX][VX] - t.mMatrix[VZ][VX] * t.mMatrix[VX][VZ] ) / det; + mMatrix[VZ][VY] = ( t.mMatrix[VZ][VX] * t.mMatrix[VX][VY] - t.mMatrix[VZ][VY] * t.mMatrix[VX][VX] ) / det; + mMatrix[VX][VZ] = ( t.mMatrix[VX][VY] * t.mMatrix[VY][VZ] - t.mMatrix[VX][VZ] * t.mMatrix[VY][VY] ) / det; + mMatrix[VY][VZ] = ( t.mMatrix[VX][VZ] * t.mMatrix[VY][VX] - t.mMatrix[VX][VX] * t.mMatrix[VY][VZ] ) / det; + mMatrix[VZ][VZ] = ( t.mMatrix[VX][VX] * t.mMatrix[VY][VY] - t.mMatrix[VX][VY] * t.mMatrix[VY][VX] ) / det; + } +} + +// does not assume a rotation matrix, and does not divide by determinant, assuming results will be renormalized +const LLMatrix3& LLMatrix3::adjointTranspose() +{ + LLMatrix3 adjoint_transpose; + adjoint_transpose.mMatrix[VX][VX] = mMatrix[VY][VY] * mMatrix[VZ][VZ] - mMatrix[VY][VZ] * mMatrix[VZ][VY] ; + adjoint_transpose.mMatrix[VY][VX] = mMatrix[VY][VZ] * mMatrix[VZ][VX] - mMatrix[VY][VX] * mMatrix[VZ][VZ] ; + adjoint_transpose.mMatrix[VZ][VX] = mMatrix[VY][VX] * mMatrix[VZ][VY] - mMatrix[VY][VY] * mMatrix[VZ][VX] ; + adjoint_transpose.mMatrix[VX][VY] = mMatrix[VZ][VY] * mMatrix[VX][VZ] - mMatrix[VZ][VZ] * mMatrix[VX][VY] ; + adjoint_transpose.mMatrix[VY][VY] = mMatrix[VZ][VZ] * mMatrix[VX][VX] - mMatrix[VZ][VX] * mMatrix[VX][VZ] ; + adjoint_transpose.mMatrix[VZ][VY] = mMatrix[VZ][VX] * mMatrix[VX][VY] - mMatrix[VZ][VY] * mMatrix[VX][VX] ; + adjoint_transpose.mMatrix[VX][VZ] = mMatrix[VX][VY] * mMatrix[VY][VZ] - mMatrix[VX][VZ] * mMatrix[VY][VY] ; + adjoint_transpose.mMatrix[VY][VZ] = mMatrix[VX][VZ] * mMatrix[VY][VX] - mMatrix[VX][VX] * mMatrix[VY][VZ] ; + adjoint_transpose.mMatrix[VZ][VZ] = mMatrix[VX][VX] * mMatrix[VY][VY] - mMatrix[VX][VY] * mMatrix[VY][VX] ; + + *this = adjoint_transpose; + return *this; +} + +// SJB: This code is correct for a logicly stored (non-transposed) matrix; +// Our matrices are stored transposed, OpenGL style, so this generates the +// INVERSE quaternion (-x, -y, -z, w)! +// Because we use similar logic in LLQuaternion::getMatrix3, +// we are internally consistant so everything works OK :) +LLQuaternion LLMatrix3::quaternion() const +{ + LLQuaternion quat; + F32 tr, s, q[4]; + U32 i, j, k; + U32 nxt[3] = {1, 2, 0}; + + tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2]; + + // check the diagonal + if (tr > 0.f) + { + s = (F32)sqrt (tr + 1.f); + quat.mQ[VS] = s / 2.f; + s = 0.5f / s; + quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s; + quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s; + quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s; + } + else + { + // diagonal is negative + i = 0; + if (mMatrix[1][1] > mMatrix[0][0]) + i = 1; + if (mMatrix[2][2] > mMatrix[i][i]) + i = 2; + + j = nxt[i]; + k = nxt[j]; + + + s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f); + + q[i] = s * 0.5f; + + if (s != 0.f) + s = 0.5f / s; + + q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s; + q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s; + q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s; + + quat.setQuat(q); + } + return quat; +} + +const LLMatrix3& LLMatrix3::setRot(const F32 angle, const LLVector3 &vec) +{ + setRot(LLQuaternion(angle, vec)); + return *this; +} + +const LLMatrix3& LLMatrix3::setRot(const F32 roll, const F32 pitch, const F32 yaw) +{ + // Rotates RH about x-axis by 'roll' then + // rotates RH about the old y-axis by 'pitch' then + // rotates RH about the original z-axis by 'yaw'. + // . + // /|\ yaw axis + // | __. + // ._ ___| /| pitch axis + // _||\ \\ |-. / + // \|| \_______\_|__\_/_______ + // | _ _ o o o_o_o_o o /_\_ ________\ roll axis + // // /_______/ /__________> / + // /_,-' // / + // /__,-' + + F32 cx, sx, cy, sy, cz, sz; + F32 cxsy, sxsy; + + cx = (F32)cos(roll); //A + sx = (F32)sin(roll); //B + cy = (F32)cos(pitch); //C + sy = (F32)sin(pitch); //D + cz = (F32)cos(yaw); //E + sz = (F32)sin(yaw); //F + + cxsy = cx * sy; //AD + sxsy = sx * sy; //BD + + mMatrix[0][0] = cy * cz; + mMatrix[1][0] = -cy * sz; + mMatrix[2][0] = sy; + mMatrix[0][1] = sxsy * cz + cx * sz; + mMatrix[1][1] = -sxsy * sz + cx * cz; + mMatrix[2][1] = -sx * cy; + mMatrix[0][2] = -cxsy * cz + sx * sz; + mMatrix[1][2] = cxsy * sz + sx * cz; + mMatrix[2][2] = cx * cy; + return *this; +} + + +const LLMatrix3& LLMatrix3::setRot(const LLQuaternion &q) +{ + *this = q.getMatrix3(); + return *this; +} + +const LLMatrix3& LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left, const LLVector3 &up) +{ + mMatrix[0][0] = fwd.mV[0]; + mMatrix[0][1] = fwd.mV[1]; + mMatrix[0][2] = fwd.mV[2]; + + mMatrix[1][0] = left.mV[0]; + mMatrix[1][1] = left.mV[1]; + mMatrix[1][2] = left.mV[2]; + + mMatrix[2][0] = up.mV[0]; + mMatrix[2][1] = up.mV[1]; + mMatrix[2][2] = up.mV[2]; + + return *this; +} + +const LLMatrix3& LLMatrix3::setRow( U32 rowIndex, const LLVector3& row ) +{ + llassert( rowIndex >= 0 && rowIndex < NUM_VALUES_IN_MAT3 ); + + mMatrix[rowIndex][0] = row[0]; + mMatrix[rowIndex][1] = row[1]; + mMatrix[rowIndex][2] = row[2]; + + return *this; +} + +const LLMatrix3& LLMatrix3::setCol( U32 colIndex, const LLVector3& col ) +{ + llassert( colIndex >= 0 && colIndex < NUM_VALUES_IN_MAT3 ); + + mMatrix[0][colIndex] = col[0]; + mMatrix[1][colIndex] = col[1]; + mMatrix[2][colIndex] = col[2]; + + return *this; +} + +const LLMatrix3& LLMatrix3::rotate(const F32 angle, const LLVector3 &vec) +{ + LLMatrix3 mat(angle, vec); + *this *= mat; + return *this; +} + + +const LLMatrix3& LLMatrix3::rotate(const F32 roll, const F32 pitch, const F32 yaw) +{ + LLMatrix3 mat(roll, pitch, yaw); + *this *= mat; + return *this; +} + + +const LLMatrix3& LLMatrix3::rotate(const LLQuaternion &q) +{ + LLMatrix3 mat(q); + *this *= mat; + return *this; +} + +void LLMatrix3::add(const LLMatrix3& other_matrix) +{ + for (S32 i = 0; i < 3; ++i) + { + for (S32 j = 0; j < 3; ++j) + { + mMatrix[i][j] += other_matrix.mMatrix[i][j]; + } + } +} + +LLVector3 LLMatrix3::getFwdRow() const +{ + return LLVector3(mMatrix[VX]); +} + +LLVector3 LLMatrix3::getLeftRow() const +{ + return LLVector3(mMatrix[VY]); +} + +LLVector3 LLMatrix3::getUpRow() const +{ + return LLVector3(mMatrix[VZ]); +} + + + +const LLMatrix3& LLMatrix3::orthogonalize() +{ + LLVector3 x_axis(mMatrix[VX]); + LLVector3 y_axis(mMatrix[VY]); + LLVector3 z_axis(mMatrix[VZ]); + + x_axis.normVec(); + y_axis -= x_axis * (x_axis * y_axis); + y_axis.normVec(); + z_axis = x_axis % y_axis; + setRows(x_axis, y_axis, z_axis); + return (*this); +} + + +// LLMatrix3 Operators + +LLMatrix3 operator*(const LLMatrix3 &a, const LLMatrix3 &b) +{ + U32 i, j; + LLMatrix3 mat; + for (i = 0; i < NUM_VALUES_IN_MAT3; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT3; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + + a.mMatrix[j][1] * b.mMatrix[1][i] + + a.mMatrix[j][2] * b.mMatrix[2][i]; + } + } + return mat; +} + +/* Not implemented to help enforce code consistency with the syntax of + row-major notation. This is a Good Thing. +LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b) +{ + LLVector3 vec; + // matrix operates "from the left" on column vector + vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + + a.mMatrix[VX][VY] * b.mV[VY] + + a.mMatrix[VX][VZ] * b.mV[VZ]; + + vec.mV[VY] = a.mMatrix[VY][VX] * b.mV[VX] + + a.mMatrix[VY][VY] * b.mV[VY] + + a.mMatrix[VY][VZ] * b.mV[VZ]; + + vec.mV[VZ] = a.mMatrix[VZ][VX] * b.mV[VX] + + a.mMatrix[VZ][VY] * b.mV[VY] + + a.mMatrix[VZ][VZ] * b.mV[VZ]; + return vec; +} +*/ + + +LLVector3 operator*(const LLVector3 &a, const LLMatrix3 &b) +{ + // matrix operates "from the right" on row vector + return LLVector3( + a.mV[VX] * b.mMatrix[VX][VX] + + a.mV[VY] * b.mMatrix[VY][VX] + + a.mV[VZ] * b.mMatrix[VZ][VX], + + a.mV[VX] * b.mMatrix[VX][VY] + + a.mV[VY] * b.mMatrix[VY][VY] + + a.mV[VZ] * b.mMatrix[VZ][VY], + + a.mV[VX] * b.mMatrix[VX][VZ] + + a.mV[VY] * b.mMatrix[VY][VZ] + + a.mV[VZ] * b.mMatrix[VZ][VZ] ); +} + +LLVector3d operator*(const LLVector3d &a, const LLMatrix3 &b) +{ + // matrix operates "from the right" on row vector + return LLVector3d( + a.mdV[VX] * b.mMatrix[VX][VX] + + a.mdV[VY] * b.mMatrix[VY][VX] + + a.mdV[VZ] * b.mMatrix[VZ][VX], + + a.mdV[VX] * b.mMatrix[VX][VY] + + a.mdV[VY] * b.mMatrix[VY][VY] + + a.mdV[VZ] * b.mMatrix[VZ][VY], + + a.mdV[VX] * b.mMatrix[VX][VZ] + + a.mdV[VY] * b.mMatrix[VY][VZ] + + a.mdV[VZ] * b.mMatrix[VZ][VZ] ); +} + +bool operator==(const LLMatrix3 &a, const LLMatrix3 &b) +{ + U32 i, j; + for (i = 0; i < NUM_VALUES_IN_MAT3; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT3; j++) + { + if (a.mMatrix[j][i] != b.mMatrix[j][i]) + return false; + } + } + return true; +} + +bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b) +{ + U32 i, j; + for (i = 0; i < NUM_VALUES_IN_MAT3; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT3; j++) + { + if (a.mMatrix[j][i] != b.mMatrix[j][i]) + return true; + } + } + return false; +} + +const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b) +{ + U32 i, j; + LLMatrix3 mat; + for (i = 0; i < NUM_VALUES_IN_MAT3; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT3; j++) + { + mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + + a.mMatrix[j][1] * b.mMatrix[1][i] + + a.mMatrix[j][2] * b.mMatrix[2][i]; + } + } + a = mat; + return a; +} + +const LLMatrix3& operator*=(LLMatrix3 &a, F32 scalar ) +{ + for( U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i ) + { + for( U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j ) + { + a.mMatrix[i][j] *= scalar; + } + } + + return a; +} + +std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a) +{ + s << "{ " + << a.mMatrix[VX][VX] << ", " << a.mMatrix[VX][VY] << ", " << a.mMatrix[VX][VZ] << "; " + << a.mMatrix[VY][VX] << ", " << a.mMatrix[VY][VY] << ", " << a.mMatrix[VY][VZ] << "; " + << a.mMatrix[VZ][VX] << ", " << a.mMatrix[VZ][VY] << ", " << a.mMatrix[VZ][VZ] + << " }"; + return s; +} + diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 976535dd84..c46ee587cb 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -1,873 +1,873 @@ -/** - * @file m4math.cpp - * @brief LLMatrix4 class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -//#include "vmath.h" -#include "v3math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquaternion.h" -#include "llmatrix4a.h" - - -// LLMatrix4 - -// Constructors - - -LLMatrix4::LLMatrix4(const F32 *mat) -{ - mMatrix[0][0] = mat[0]; - mMatrix[0][1] = mat[1]; - mMatrix[0][2] = mat[2]; - mMatrix[0][3] = mat[3]; - - mMatrix[1][0] = mat[4]; - mMatrix[1][1] = mat[5]; - mMatrix[1][2] = mat[6]; - mMatrix[1][3] = mat[7]; - - mMatrix[2][0] = mat[8]; - mMatrix[2][1] = mat[9]; - mMatrix[2][2] = mat[10]; - mMatrix[2][3] = mat[11]; - - mMatrix[3][0] = mat[12]; - mMatrix[3][1] = mat[13]; - mMatrix[3][2] = mat[14]; - mMatrix[3][3] = mat[15]; -} - -LLMatrix4::LLMatrix4(const LLMatrix3 &mat, const LLVector4 &vec) -{ - mMatrix[0][0] = mat.mMatrix[0][0]; - mMatrix[0][1] = mat.mMatrix[0][1]; - mMatrix[0][2] = mat.mMatrix[0][2]; - mMatrix[0][3] = 0.f; - - mMatrix[1][0] = mat.mMatrix[1][0]; - mMatrix[1][1] = mat.mMatrix[1][1]; - mMatrix[1][2] = mat.mMatrix[1][2]; - mMatrix[1][3] = 0.f; - - mMatrix[2][0] = mat.mMatrix[2][0]; - mMatrix[2][1] = mat.mMatrix[2][1]; - mMatrix[2][2] = mat.mMatrix[2][2]; - mMatrix[2][3] = 0.f; - - mMatrix[3][0] = vec.mV[0]; - mMatrix[3][1] = vec.mV[1]; - mMatrix[3][2] = vec.mV[2]; - mMatrix[3][3] = 1.f; -} - -LLMatrix4::LLMatrix4(const LLMatrix3 &mat) -{ - mMatrix[0][0] = mat.mMatrix[0][0]; - mMatrix[0][1] = mat.mMatrix[0][1]; - mMatrix[0][2] = mat.mMatrix[0][2]; - mMatrix[0][3] = 0.f; - - mMatrix[1][0] = mat.mMatrix[1][0]; - mMatrix[1][1] = mat.mMatrix[1][1]; - mMatrix[1][2] = mat.mMatrix[1][2]; - mMatrix[1][3] = 0.f; - - mMatrix[2][0] = mat.mMatrix[2][0]; - mMatrix[2][1] = mat.mMatrix[2][1]; - mMatrix[2][2] = mat.mMatrix[2][2]; - mMatrix[2][3] = 0.f; - - mMatrix[3][0] = 0.f; - mMatrix[3][1] = 0.f; - mMatrix[3][2] = 0.f; - mMatrix[3][3] = 1.f; -} - -LLMatrix4::LLMatrix4(const LLQuaternion &q) -{ - *this = initRotation(q); -} - -LLMatrix4::LLMatrix4(const LLMatrix4a& mat) - : LLMatrix4(mat.getF32ptr()) -{ - -} - -LLMatrix4::LLMatrix4(const LLQuaternion &q, const LLVector4 &pos) -{ - *this = initRotTrans(q, pos); -} - -LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec, const LLVector4 &pos) -{ - initRotTrans(LLQuaternion(angle, vec), pos); -} - -LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec) -{ - initRotation(LLQuaternion(angle, vec)); - - mMatrix[3][0] = 0.f; - mMatrix[3][1] = 0.f; - mMatrix[3][2] = 0.f; - mMatrix[3][3] = 1.f; -} - -LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos) -{ - LLMatrix3 mat(roll, pitch, yaw); - initRotTrans(LLQuaternion(mat), pos); -} - -LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw) -{ - LLMatrix3 mat(roll, pitch, yaw); - initRotation(LLQuaternion(mat)); - - mMatrix[3][0] = 0.f; - mMatrix[3][1] = 0.f; - mMatrix[3][2] = 0.f; - mMatrix[3][3] = 1.f; -} - -LLMatrix4::~LLMatrix4(void) -{ -} - -// Clear and Assignment Functions - -const LLMatrix4& LLMatrix4::setZero() -{ - mMatrix[0][0] = 0.f; - mMatrix[0][1] = 0.f; - mMatrix[0][2] = 0.f; - mMatrix[0][3] = 0.f; - - mMatrix[1][0] = 0.f; - mMatrix[1][1] = 0.f; - mMatrix[1][2] = 0.f; - mMatrix[1][3] = 0.f; - - mMatrix[2][0] = 0.f; - mMatrix[2][1] = 0.f; - mMatrix[2][2] = 0.f; - mMatrix[2][3] = 0.f; - - mMatrix[3][0] = 0.f; - mMatrix[3][1] = 0.f; - mMatrix[3][2] = 0.f; - mMatrix[3][3] = 0.f; - return *this; -} - - -// various useful mMatrix functions - -const LLMatrix4& LLMatrix4::transpose() -{ - LLMatrix4 mat; - mat.mMatrix[0][0] = mMatrix[0][0]; - mat.mMatrix[1][0] = mMatrix[0][1]; - mat.mMatrix[2][0] = mMatrix[0][2]; - mat.mMatrix[3][0] = mMatrix[0][3]; - - mat.mMatrix[0][1] = mMatrix[1][0]; - mat.mMatrix[1][1] = mMatrix[1][1]; - mat.mMatrix[2][1] = mMatrix[1][2]; - mat.mMatrix[3][1] = mMatrix[1][3]; - - mat.mMatrix[0][2] = mMatrix[2][0]; - mat.mMatrix[1][2] = mMatrix[2][1]; - mat.mMatrix[2][2] = mMatrix[2][2]; - mat.mMatrix[3][2] = mMatrix[2][3]; - - mat.mMatrix[0][3] = mMatrix[3][0]; - mat.mMatrix[1][3] = mMatrix[3][1]; - mat.mMatrix[2][3] = mMatrix[3][2]; - mat.mMatrix[3][3] = mMatrix[3][3]; - - *this = mat; - return *this; -} - - -F32 LLMatrix4::determinant() const -{ - 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. -const LLMatrix4& LLMatrix4::invert(void) -{ - // transpose the rotation part - F32 temp; - temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp; - temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp; - temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp; - - // rotate the translation part by the new rotation - // (temporarily store in empty column of matrix) - U32 j; - for (j=0; j<3; j++) - { - mMatrix[j][VW] = mMatrix[VW][VX] * mMatrix[VX][j] + - mMatrix[VW][VY] * mMatrix[VY][j] + - mMatrix[VW][VZ] * mMatrix[VZ][j]; - } - - // negate and copy the temporary vector back to the tranlation row - mMatrix[VW][VX] = -mMatrix[VX][VW]; - mMatrix[VW][VY] = -mMatrix[VY][VW]; - mMatrix[VW][VZ] = -mMatrix[VZ][VW]; - - // zero the empty column again - mMatrix[VX][VW] = mMatrix[VY][VW] = mMatrix[VZ][VW] = 0.0f; - - return *this; -} - -// Convenience func for simplifying comparison-heavy code by -// intentionally stomping values in [-FLT_EPS,FLT_EPS] to 0.0f -// -void LLMatrix4::condition(void) -{ - U32 i; - U32 j; - for (i = 0; i < 3;i++) - for (j = 0; j < 3;j++) - mMatrix[i][j] = ((mMatrix[i][j] > -FLT_EPSILON) - && (mMatrix[i][j] < FLT_EPSILON)) ? 0.0f : mMatrix[i][j]; -} - -LLVector4 LLMatrix4::getFwdRow4() const -{ - return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]); -} - -LLVector4 LLMatrix4::getLeftRow4() const -{ - return LLVector4(mMatrix[VY][VX], mMatrix[VY][VY], mMatrix[VY][VZ], mMatrix[VY][VW]); -} - -LLVector4 LLMatrix4::getUpRow4() const -{ - return LLVector4(mMatrix[VZ][VX], mMatrix[VZ][VY], mMatrix[VZ][VZ], mMatrix[VZ][VW]); -} - -// SJB: This code is correct for a logicly stored (non-transposed) matrix; -// Our matrices are stored transposed, OpenGL style, so this generates the -// INVERSE quaternion (-x, -y, -z, w)! -// Because we use similar logic in LLQuaternion::getMatrix3, -// we are internally consistant so everything works OK :) -LLQuaternion LLMatrix4::quaternion() const -{ - LLQuaternion quat; - F32 tr, s, q[4]; - U32 i, j, k; - U32 nxt[3] = {1, 2, 0}; - - tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2]; - - // check the diagonal - if (tr > 0.f) - { - s = (F32)sqrt (tr + 1.f); - quat.mQ[VS] = s / 2.f; - s = 0.5f / s; - quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s; - quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s; - quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s; - } - else - { - // diagonal is negative - i = 0; - if (mMatrix[1][1] > mMatrix[0][0]) - i = 1; - if (mMatrix[2][2] > mMatrix[i][i]) - i = 2; - - j = nxt[i]; - k = nxt[j]; - - - s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f); - - q[i] = s * 0.5f; - - if (s != 0.f) - s = 0.5f / s; - - q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s; - q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s; - q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s; - - quat.setQuat(q); - } - return quat; -} - - - -void LLMatrix4::initRows(const LLVector4 &row0, - const LLVector4 &row1, - const LLVector4 &row2, - const LLVector4 &row3) -{ - mMatrix[0][0] = row0.mV[0]; - mMatrix[0][1] = row0.mV[1]; - mMatrix[0][2] = row0.mV[2]; - mMatrix[0][3] = row0.mV[3]; - - mMatrix[1][0] = row1.mV[0]; - mMatrix[1][1] = row1.mV[1]; - mMatrix[1][2] = row1.mV[2]; - mMatrix[1][3] = row1.mV[3]; - - mMatrix[2][0] = row2.mV[0]; - mMatrix[2][1] = row2.mV[1]; - mMatrix[2][2] = row2.mV[2]; - mMatrix[2][3] = row2.mV[3]; - - mMatrix[3][0] = row3.mV[0]; - mMatrix[3][1] = row3.mV[1]; - mMatrix[3][2] = row3.mV[2]; - mMatrix[3][3] = row3.mV[3]; -} - - -const LLMatrix4& LLMatrix4::initRotation(F32 angle, const LLVector4 &vec) -{ - LLMatrix3 mat(angle, vec); - return initMatrix(mat); -} - - -const LLMatrix4& LLMatrix4::initRotation(const F32 roll, const F32 pitch, const F32 yaw) -{ - LLMatrix3 mat(roll, pitch, yaw); - return initMatrix(mat); -} - - -const LLMatrix4& LLMatrix4::initRotation(const LLQuaternion &q) -{ - LLMatrix3 mat(q); - return initMatrix(mat); -} - - -const LLMatrix4& LLMatrix4::initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3&translation) -{ - LLMatrix3 mat(angle, axis); - initMatrix(mat); - setTranslation(translation); - return (*this); -} - -const LLMatrix4& LLMatrix4::initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &translation) -{ - LLMatrix3 mat(roll, pitch, yaw); - initMatrix(mat); - setTranslation(translation); - return (*this); -} - -/* -const LLMatrix4& LLMatrix4::initRotTrans(const LLVector4 &fwd, - const LLVector4 &left, - const LLVector4 &up, - const LLVector4 &translation) -{ - LLMatrix3 mat(fwd, left, up); - initMatrix(mat); - setTranslation(translation); - return (*this); -} -*/ - -const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector4 &translation) -{ - LLMatrix3 mat(q); - initMatrix(mat); - setTranslation(translation); - 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; - F32 xx, xy, xz, xw, yy, yz, yw, zz, zw; - - sx = scale.mV[0]; - sy = scale.mV[1]; - sz = scale.mV[2]; - - xx = q.mQ[VX] * q.mQ[VX]; - xy = q.mQ[VX] * q.mQ[VY]; - xz = q.mQ[VX] * q.mQ[VZ]; - xw = q.mQ[VX] * q.mQ[VW]; - - yy = q.mQ[VY] * q.mQ[VY]; - yz = q.mQ[VY] * q.mQ[VZ]; - yw = q.mQ[VY] * q.mQ[VW]; - - zz = q.mQ[VZ] * q.mQ[VZ]; - zw = q.mQ[VZ] * q.mQ[VW]; - - mMatrix[0][0] = (1.f - 2.f * ( yy + zz )) *sx; - mMatrix[0][1] = ( 2.f * ( xy + zw )) *sx; - mMatrix[0][2] = ( 2.f * ( xz - yw )) *sx; - - mMatrix[1][0] = ( 2.f * ( xy - zw )) *sy; - mMatrix[1][1] = (1.f - 2.f * ( xx + zz )) *sy; - mMatrix[1][2] = ( 2.f * ( yz + xw )) *sy; - - mMatrix[2][0] = ( 2.f * ( xz + yw )) *sz; - mMatrix[2][1] = ( 2.f * ( yz - xw )) *sz; - mMatrix[2][2] = (1.f - 2.f * ( xx + yy )) *sz; - - mMatrix[3][0] = pos.mV[0]; - mMatrix[3][1] = pos.mV[1]; - mMatrix[3][2] = pos.mV[2]; - mMatrix[3][3] = 1.0; - - // TODO -- should we set the translation portion to zero? - return (*this); -} - -const LLMatrix4& LLMatrix4::rotate(const F32 angle, const LLVector4 &vec) -{ - LLMatrix4 mat(angle, vec); - *this *= mat; - return *this; -} - -const LLMatrix4& LLMatrix4::rotate(const F32 roll, const F32 pitch, const F32 yaw) -{ - LLMatrix4 mat(roll, pitch, yaw); - *this *= mat; - return *this; -} - -const LLMatrix4& LLMatrix4::rotate(const LLQuaternion &q) -{ - LLMatrix4 mat(q); - *this *= mat; - return *this; -} - - -const LLMatrix4& LLMatrix4::translate(const LLVector3 &vec) -{ - mMatrix[3][0] += vec.mV[0]; - mMatrix[3][1] += vec.mV[1]; - mMatrix[3][2] += vec.mV[2]; - return (*this); -} - - -void LLMatrix4::setFwdRow(const LLVector3 &row) -{ - mMatrix[VX][VX] = row.mV[VX]; - mMatrix[VX][VY] = row.mV[VY]; - mMatrix[VX][VZ] = row.mV[VZ]; -} - -void LLMatrix4::setLeftRow(const LLVector3 &row) -{ - mMatrix[VY][VX] = row.mV[VX]; - mMatrix[VY][VY] = row.mV[VY]; - mMatrix[VY][VZ] = row.mV[VZ]; -} - -void LLMatrix4::setUpRow(const LLVector3 &row) -{ - mMatrix[VZ][VX] = row.mV[VX]; - mMatrix[VZ][VY] = row.mV[VY]; - mMatrix[VZ][VZ] = row.mV[VZ]; -} - - -void LLMatrix4::setFwdCol(const LLVector3 &col) -{ - mMatrix[VX][VX] = col.mV[VX]; - mMatrix[VY][VX] = col.mV[VY]; - mMatrix[VZ][VX] = col.mV[VZ]; -} - -void LLMatrix4::setLeftCol(const LLVector3 &col) -{ - mMatrix[VX][VY] = col.mV[VX]; - mMatrix[VY][VY] = col.mV[VY]; - mMatrix[VZ][VY] = col.mV[VZ]; -} - -void LLMatrix4::setUpCol(const LLVector3 &col) -{ - mMatrix[VX][VZ] = col.mV[VX]; - mMatrix[VY][VZ] = col.mV[VY]; - mMatrix[VZ][VZ] = col.mV[VZ]; -} - - -const LLMatrix4& LLMatrix4::setTranslation(const F32 tx, const F32 ty, const F32 tz) -{ - mMatrix[VW][VX] = tx; - mMatrix[VW][VY] = ty; - mMatrix[VW][VZ] = tz; - return (*this); -} - -const LLMatrix4& LLMatrix4::setTranslation(const LLVector3 &translation) -{ - mMatrix[VW][VX] = translation.mV[VX]; - mMatrix[VW][VY] = translation.mV[VY]; - mMatrix[VW][VZ] = translation.mV[VZ]; - return (*this); -} - -const LLMatrix4& LLMatrix4::setTranslation(const LLVector4 &translation) -{ - mMatrix[VW][VX] = translation.mV[VX]; - mMatrix[VW][VY] = translation.mV[VY]; - mMatrix[VW][VZ] = translation.mV[VZ]; - return (*this); -} - -// LLMatrix3 Extraction and Setting -LLMatrix3 LLMatrix4::getMat3() const -{ - LLMatrix3 retmat; - - retmat.mMatrix[0][0] = mMatrix[0][0]; - retmat.mMatrix[0][1] = mMatrix[0][1]; - retmat.mMatrix[0][2] = mMatrix[0][2]; - - retmat.mMatrix[1][0] = mMatrix[1][0]; - retmat.mMatrix[1][1] = mMatrix[1][1]; - retmat.mMatrix[1][2] = mMatrix[1][2]; - - retmat.mMatrix[2][0] = mMatrix[2][0]; - retmat.mMatrix[2][1] = mMatrix[2][1]; - retmat.mMatrix[2][2] = mMatrix[2][2]; - - return retmat; -} - -const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat) -{ - mMatrix[0][0] = mat.mMatrix[0][0]; - mMatrix[0][1] = mat.mMatrix[0][1]; - mMatrix[0][2] = mat.mMatrix[0][2]; - mMatrix[0][3] = 0.f; - - mMatrix[1][0] = mat.mMatrix[1][0]; - mMatrix[1][1] = mat.mMatrix[1][1]; - mMatrix[1][2] = mat.mMatrix[1][2]; - mMatrix[1][3] = 0.f; - - mMatrix[2][0] = mat.mMatrix[2][0]; - mMatrix[2][1] = mat.mMatrix[2][1]; - mMatrix[2][2] = mat.mMatrix[2][2]; - mMatrix[2][3] = 0.f; - - mMatrix[3][0] = 0.f; - mMatrix[3][1] = 0.f; - mMatrix[3][2] = 0.f; - mMatrix[3][3] = 1.f; - return (*this); -} - -const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 &translation) -{ - mMatrix[0][0] = mat.mMatrix[0][0]; - mMatrix[0][1] = mat.mMatrix[0][1]; - mMatrix[0][2] = mat.mMatrix[0][2]; - mMatrix[0][3] = 0.f; - - mMatrix[1][0] = mat.mMatrix[1][0]; - mMatrix[1][1] = mat.mMatrix[1][1]; - mMatrix[1][2] = mat.mMatrix[1][2]; - mMatrix[1][3] = 0.f; - - mMatrix[2][0] = mat.mMatrix[2][0]; - mMatrix[2][1] = mat.mMatrix[2][1]; - mMatrix[2][2] = mat.mMatrix[2][2]; - mMatrix[2][3] = 0.f; - - mMatrix[3][0] = translation.mV[0]; - mMatrix[3][1] = translation.mV[1]; - mMatrix[3][2] = translation.mV[2]; - mMatrix[3][3] = 1.f; - return (*this); -} - -// LLMatrix4 Operators - -LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b) -{ - // Operate "to the left" on row-vector a - return LLVector4(a.mV[VX] * b.mMatrix[VX][VX] + - a.mV[VY] * b.mMatrix[VY][VX] + - a.mV[VZ] * b.mMatrix[VZ][VX] + - a.mV[VW] * b.mMatrix[VW][VX], - - a.mV[VX] * b.mMatrix[VX][VY] + - a.mV[VY] * b.mMatrix[VY][VY] + - a.mV[VZ] * b.mMatrix[VZ][VY] + - a.mV[VW] * b.mMatrix[VW][VY], - - a.mV[VX] * b.mMatrix[VX][VZ] + - a.mV[VY] * b.mMatrix[VY][VZ] + - a.mV[VZ] * b.mMatrix[VZ][VZ] + - a.mV[VW] * b.mMatrix[VW][VZ], - - a.mV[VX] * b.mMatrix[VX][VW] + - a.mV[VY] * b.mMatrix[VY][VW] + - a.mV[VZ] * b.mMatrix[VZ][VW] + - a.mV[VW] * b.mMatrix[VW][VW]); -} - -LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b) -{ - // Rotates but does not translate - // Operate "to the left" on row-vector a - LLVector4 vec; - vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + - a.mV[VY] * b.mMatrix[VY][VX] + - a.mV[VZ] * b.mMatrix[VZ][VX]; - - vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + - a.mV[VY] * b.mMatrix[VY][VY] + - a.mV[VZ] * b.mMatrix[VZ][VY]; - - vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + - a.mV[VY] * b.mMatrix[VY][VZ] + - a.mV[VZ] * b.mMatrix[VZ][VZ]; - -// vec.mV[VW] = a.mV[VX] * b.mMatrix[VX][VW] + -// a.mV[VY] * b.mMatrix[VY][VW] + -// a.mV[VZ] * b.mMatrix[VZ][VW] + - vec.mV[VW] = a.mV[VW]; - return vec; -} - -LLVector3 rotate_vector(const LLVector3 &a, const LLMatrix4 &b) -{ - // Rotates but does not translate - // Operate "to the left" on row-vector a - LLVector3 vec; - vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + - a.mV[VY] * b.mMatrix[VY][VX] + - a.mV[VZ] * b.mMatrix[VZ][VX]; - - vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + - a.mV[VY] * b.mMatrix[VY][VY] + - a.mV[VZ] * b.mMatrix[VZ][VY]; - - vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + - a.mV[VY] * b.mMatrix[VY][VZ] + - a.mV[VZ] * b.mMatrix[VZ][VZ]; - return vec; -} - -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[j][i] != b.mMatrix[j][i]) - return false; - } - } - return true; -} - -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[j][i] != b.mMatrix[j][i]) - return true; - } - } - 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; - for (i = 0; i < NUM_VALUES_IN_MAT4; i++) - { - for (j = 0; j < NUM_VALUES_IN_MAT4; j++) - { - a.mMatrix[j][i] *= k; - } - } - return a; -} - -std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a) -{ - s << "{ " - << a.mMatrix[VX][VX] << ", " - << a.mMatrix[VX][VY] << ", " - << a.mMatrix[VX][VZ] << ", " - << a.mMatrix[VX][VW] - << "; " - << a.mMatrix[VY][VX] << ", " - << a.mMatrix[VY][VY] << ", " - << a.mMatrix[VY][VZ] << ", " - << a.mMatrix[VY][VW] - << "; " - << a.mMatrix[VZ][VX] << ", " - << a.mMatrix[VZ][VY] << ", " - << a.mMatrix[VZ][VZ] << ", " - << a.mMatrix[VZ][VW] - << "; " - << a.mMatrix[VW][VX] << ", " - << a.mMatrix[VW][VY] << ", " - << a.mMatrix[VW][VZ] << ", " - << a.mMatrix[VW][VW] - << " }"; - return s; -} - -LLSD LLMatrix4::getValue() const -{ - LLSD ret; - - ret[0] = mMatrix[0][0]; - ret[1] = mMatrix[0][1]; - ret[2] = mMatrix[0][2]; - ret[3] = mMatrix[0][3]; - - ret[4] = mMatrix[1][0]; - ret[5] = mMatrix[1][1]; - ret[6] = mMatrix[1][2]; - ret[7] = mMatrix[1][3]; - - ret[8] = mMatrix[2][0]; - ret[9] = mMatrix[2][1]; - ret[10] = mMatrix[2][2]; - ret[11] = mMatrix[2][3]; - - ret[12] = mMatrix[3][0]; - ret[13] = mMatrix[3][1]; - ret[14] = mMatrix[3][2]; - ret[15] = mMatrix[3][3]; - - return ret; -} - -void LLMatrix4::setValue(const LLSD& data) -{ - mMatrix[0][0] = (F32)data[0].asReal(); - mMatrix[0][1] = (F32)data[1].asReal(); - mMatrix[0][2] = (F32)data[2].asReal(); - mMatrix[0][3] = (F32)data[3].asReal(); - - mMatrix[1][0] = (F32)data[4].asReal(); - mMatrix[1][1] = (F32)data[5].asReal(); - mMatrix[1][2] = (F32)data[6].asReal(); - mMatrix[1][3] = (F32)data[7].asReal(); - - mMatrix[2][0] = (F32)data[8].asReal(); - mMatrix[2][1] = (F32)data[9].asReal(); - mMatrix[2][2] = (F32)data[10].asReal(); - mMatrix[2][3] = (F32)data[11].asReal(); - - mMatrix[3][0] = (F32)data[12].asReal(); - mMatrix[3][1] = (F32)data[13].asReal(); - mMatrix[3][2] = (F32)data[14].asReal(); - mMatrix[3][3] = (F32)data[15].asReal(); -} - - +/** + * @file m4math.cpp + * @brief LLMatrix4 class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +//#include "vmath.h" +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquaternion.h" +#include "llmatrix4a.h" + + +// LLMatrix4 + +// Constructors + + +LLMatrix4::LLMatrix4(const F32 *mat) +{ + mMatrix[0][0] = mat[0]; + mMatrix[0][1] = mat[1]; + mMatrix[0][2] = mat[2]; + mMatrix[0][3] = mat[3]; + + mMatrix[1][0] = mat[4]; + mMatrix[1][1] = mat[5]; + mMatrix[1][2] = mat[6]; + mMatrix[1][3] = mat[7]; + + mMatrix[2][0] = mat[8]; + mMatrix[2][1] = mat[9]; + mMatrix[2][2] = mat[10]; + mMatrix[2][3] = mat[11]; + + mMatrix[3][0] = mat[12]; + mMatrix[3][1] = mat[13]; + mMatrix[3][2] = mat[14]; + mMatrix[3][3] = mat[15]; +} + +LLMatrix4::LLMatrix4(const LLMatrix3 &mat, const LLVector4 &vec) +{ + mMatrix[0][0] = mat.mMatrix[0][0]; + mMatrix[0][1] = mat.mMatrix[0][1]; + mMatrix[0][2] = mat.mMatrix[0][2]; + mMatrix[0][3] = 0.f; + + mMatrix[1][0] = mat.mMatrix[1][0]; + mMatrix[1][1] = mat.mMatrix[1][1]; + mMatrix[1][2] = mat.mMatrix[1][2]; + mMatrix[1][3] = 0.f; + + mMatrix[2][0] = mat.mMatrix[2][0]; + mMatrix[2][1] = mat.mMatrix[2][1]; + mMatrix[2][2] = mat.mMatrix[2][2]; + mMatrix[2][3] = 0.f; + + mMatrix[3][0] = vec.mV[0]; + mMatrix[3][1] = vec.mV[1]; + mMatrix[3][2] = vec.mV[2]; + mMatrix[3][3] = 1.f; +} + +LLMatrix4::LLMatrix4(const LLMatrix3 &mat) +{ + mMatrix[0][0] = mat.mMatrix[0][0]; + mMatrix[0][1] = mat.mMatrix[0][1]; + mMatrix[0][2] = mat.mMatrix[0][2]; + mMatrix[0][3] = 0.f; + + mMatrix[1][0] = mat.mMatrix[1][0]; + mMatrix[1][1] = mat.mMatrix[1][1]; + mMatrix[1][2] = mat.mMatrix[1][2]; + mMatrix[1][3] = 0.f; + + mMatrix[2][0] = mat.mMatrix[2][0]; + mMatrix[2][1] = mat.mMatrix[2][1]; + mMatrix[2][2] = mat.mMatrix[2][2]; + mMatrix[2][3] = 0.f; + + mMatrix[3][0] = 0.f; + mMatrix[3][1] = 0.f; + mMatrix[3][2] = 0.f; + mMatrix[3][3] = 1.f; +} + +LLMatrix4::LLMatrix4(const LLQuaternion &q) +{ + *this = initRotation(q); +} + +LLMatrix4::LLMatrix4(const LLMatrix4a& mat) + : LLMatrix4(mat.getF32ptr()) +{ + +} + +LLMatrix4::LLMatrix4(const LLQuaternion &q, const LLVector4 &pos) +{ + *this = initRotTrans(q, pos); +} + +LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec, const LLVector4 &pos) +{ + initRotTrans(LLQuaternion(angle, vec), pos); +} + +LLMatrix4::LLMatrix4(const F32 angle, const LLVector4 &vec) +{ + initRotation(LLQuaternion(angle, vec)); + + mMatrix[3][0] = 0.f; + mMatrix[3][1] = 0.f; + mMatrix[3][2] = 0.f; + mMatrix[3][3] = 1.f; +} + +LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos) +{ + LLMatrix3 mat(roll, pitch, yaw); + initRotTrans(LLQuaternion(mat), pos); +} + +LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw) +{ + LLMatrix3 mat(roll, pitch, yaw); + initRotation(LLQuaternion(mat)); + + mMatrix[3][0] = 0.f; + mMatrix[3][1] = 0.f; + mMatrix[3][2] = 0.f; + mMatrix[3][3] = 1.f; +} + +LLMatrix4::~LLMatrix4(void) +{ +} + +// Clear and Assignment Functions + +const LLMatrix4& LLMatrix4::setZero() +{ + mMatrix[0][0] = 0.f; + mMatrix[0][1] = 0.f; + mMatrix[0][2] = 0.f; + mMatrix[0][3] = 0.f; + + mMatrix[1][0] = 0.f; + mMatrix[1][1] = 0.f; + mMatrix[1][2] = 0.f; + mMatrix[1][3] = 0.f; + + mMatrix[2][0] = 0.f; + mMatrix[2][1] = 0.f; + mMatrix[2][2] = 0.f; + mMatrix[2][3] = 0.f; + + mMatrix[3][0] = 0.f; + mMatrix[3][1] = 0.f; + mMatrix[3][2] = 0.f; + mMatrix[3][3] = 0.f; + return *this; +} + + +// various useful mMatrix functions + +const LLMatrix4& LLMatrix4::transpose() +{ + LLMatrix4 mat; + mat.mMatrix[0][0] = mMatrix[0][0]; + mat.mMatrix[1][0] = mMatrix[0][1]; + mat.mMatrix[2][0] = mMatrix[0][2]; + mat.mMatrix[3][0] = mMatrix[0][3]; + + mat.mMatrix[0][1] = mMatrix[1][0]; + mat.mMatrix[1][1] = mMatrix[1][1]; + mat.mMatrix[2][1] = mMatrix[1][2]; + mat.mMatrix[3][1] = mMatrix[1][3]; + + mat.mMatrix[0][2] = mMatrix[2][0]; + mat.mMatrix[1][2] = mMatrix[2][1]; + mat.mMatrix[2][2] = mMatrix[2][2]; + mat.mMatrix[3][2] = mMatrix[2][3]; + + mat.mMatrix[0][3] = mMatrix[3][0]; + mat.mMatrix[1][3] = mMatrix[3][1]; + mat.mMatrix[2][3] = mMatrix[3][2]; + mat.mMatrix[3][3] = mMatrix[3][3]; + + *this = mat; + return *this; +} + + +F32 LLMatrix4::determinant() const +{ + 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. +const LLMatrix4& LLMatrix4::invert(void) +{ + // transpose the rotation part + F32 temp; + temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp; + temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp; + temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp; + + // rotate the translation part by the new rotation + // (temporarily store in empty column of matrix) + U32 j; + for (j=0; j<3; j++) + { + mMatrix[j][VW] = mMatrix[VW][VX] * mMatrix[VX][j] + + mMatrix[VW][VY] * mMatrix[VY][j] + + mMatrix[VW][VZ] * mMatrix[VZ][j]; + } + + // negate and copy the temporary vector back to the tranlation row + mMatrix[VW][VX] = -mMatrix[VX][VW]; + mMatrix[VW][VY] = -mMatrix[VY][VW]; + mMatrix[VW][VZ] = -mMatrix[VZ][VW]; + + // zero the empty column again + mMatrix[VX][VW] = mMatrix[VY][VW] = mMatrix[VZ][VW] = 0.0f; + + return *this; +} + +// Convenience func for simplifying comparison-heavy code by +// intentionally stomping values in [-FLT_EPS,FLT_EPS] to 0.0f +// +void LLMatrix4::condition(void) +{ + U32 i; + U32 j; + for (i = 0; i < 3;i++) + for (j = 0; j < 3;j++) + mMatrix[i][j] = ((mMatrix[i][j] > -FLT_EPSILON) + && (mMatrix[i][j] < FLT_EPSILON)) ? 0.0f : mMatrix[i][j]; +} + +LLVector4 LLMatrix4::getFwdRow4() const +{ + return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]); +} + +LLVector4 LLMatrix4::getLeftRow4() const +{ + return LLVector4(mMatrix[VY][VX], mMatrix[VY][VY], mMatrix[VY][VZ], mMatrix[VY][VW]); +} + +LLVector4 LLMatrix4::getUpRow4() const +{ + return LLVector4(mMatrix[VZ][VX], mMatrix[VZ][VY], mMatrix[VZ][VZ], mMatrix[VZ][VW]); +} + +// SJB: This code is correct for a logicly stored (non-transposed) matrix; +// Our matrices are stored transposed, OpenGL style, so this generates the +// INVERSE quaternion (-x, -y, -z, w)! +// Because we use similar logic in LLQuaternion::getMatrix3, +// we are internally consistant so everything works OK :) +LLQuaternion LLMatrix4::quaternion() const +{ + LLQuaternion quat; + F32 tr, s, q[4]; + U32 i, j, k; + U32 nxt[3] = {1, 2, 0}; + + tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2]; + + // check the diagonal + if (tr > 0.f) + { + s = (F32)sqrt (tr + 1.f); + quat.mQ[VS] = s / 2.f; + s = 0.5f / s; + quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s; + quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s; + quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s; + } + else + { + // diagonal is negative + i = 0; + if (mMatrix[1][1] > mMatrix[0][0]) + i = 1; + if (mMatrix[2][2] > mMatrix[i][i]) + i = 2; + + j = nxt[i]; + k = nxt[j]; + + + s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f); + + q[i] = s * 0.5f; + + if (s != 0.f) + s = 0.5f / s; + + q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s; + q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s; + q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s; + + quat.setQuat(q); + } + return quat; +} + + + +void LLMatrix4::initRows(const LLVector4 &row0, + const LLVector4 &row1, + const LLVector4 &row2, + const LLVector4 &row3) +{ + mMatrix[0][0] = row0.mV[0]; + mMatrix[0][1] = row0.mV[1]; + mMatrix[0][2] = row0.mV[2]; + mMatrix[0][3] = row0.mV[3]; + + mMatrix[1][0] = row1.mV[0]; + mMatrix[1][1] = row1.mV[1]; + mMatrix[1][2] = row1.mV[2]; + mMatrix[1][3] = row1.mV[3]; + + mMatrix[2][0] = row2.mV[0]; + mMatrix[2][1] = row2.mV[1]; + mMatrix[2][2] = row2.mV[2]; + mMatrix[2][3] = row2.mV[3]; + + mMatrix[3][0] = row3.mV[0]; + mMatrix[3][1] = row3.mV[1]; + mMatrix[3][2] = row3.mV[2]; + mMatrix[3][3] = row3.mV[3]; +} + + +const LLMatrix4& LLMatrix4::initRotation(F32 angle, const LLVector4 &vec) +{ + LLMatrix3 mat(angle, vec); + return initMatrix(mat); +} + + +const LLMatrix4& LLMatrix4::initRotation(const F32 roll, const F32 pitch, const F32 yaw) +{ + LLMatrix3 mat(roll, pitch, yaw); + return initMatrix(mat); +} + + +const LLMatrix4& LLMatrix4::initRotation(const LLQuaternion &q) +{ + LLMatrix3 mat(q); + return initMatrix(mat); +} + + +const LLMatrix4& LLMatrix4::initRotTrans(const F32 angle, const LLVector3 &axis, const LLVector3&translation) +{ + LLMatrix3 mat(angle, axis); + initMatrix(mat); + setTranslation(translation); + return (*this); +} + +const LLMatrix4& LLMatrix4::initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &translation) +{ + LLMatrix3 mat(roll, pitch, yaw); + initMatrix(mat); + setTranslation(translation); + return (*this); +} + +/* +const LLMatrix4& LLMatrix4::initRotTrans(const LLVector4 &fwd, + const LLVector4 &left, + const LLVector4 &up, + const LLVector4 &translation) +{ + LLMatrix3 mat(fwd, left, up); + initMatrix(mat); + setTranslation(translation); + return (*this); +} +*/ + +const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector4 &translation) +{ + LLMatrix3 mat(q); + initMatrix(mat); + setTranslation(translation); + 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; + F32 xx, xy, xz, xw, yy, yz, yw, zz, zw; + + sx = scale.mV[0]; + sy = scale.mV[1]; + sz = scale.mV[2]; + + xx = q.mQ[VX] * q.mQ[VX]; + xy = q.mQ[VX] * q.mQ[VY]; + xz = q.mQ[VX] * q.mQ[VZ]; + xw = q.mQ[VX] * q.mQ[VW]; + + yy = q.mQ[VY] * q.mQ[VY]; + yz = q.mQ[VY] * q.mQ[VZ]; + yw = q.mQ[VY] * q.mQ[VW]; + + zz = q.mQ[VZ] * q.mQ[VZ]; + zw = q.mQ[VZ] * q.mQ[VW]; + + mMatrix[0][0] = (1.f - 2.f * ( yy + zz )) *sx; + mMatrix[0][1] = ( 2.f * ( xy + zw )) *sx; + mMatrix[0][2] = ( 2.f * ( xz - yw )) *sx; + + mMatrix[1][0] = ( 2.f * ( xy - zw )) *sy; + mMatrix[1][1] = (1.f - 2.f * ( xx + zz )) *sy; + mMatrix[1][2] = ( 2.f * ( yz + xw )) *sy; + + mMatrix[2][0] = ( 2.f * ( xz + yw )) *sz; + mMatrix[2][1] = ( 2.f * ( yz - xw )) *sz; + mMatrix[2][2] = (1.f - 2.f * ( xx + yy )) *sz; + + mMatrix[3][0] = pos.mV[0]; + mMatrix[3][1] = pos.mV[1]; + mMatrix[3][2] = pos.mV[2]; + mMatrix[3][3] = 1.0; + + // TODO -- should we set the translation portion to zero? + return (*this); +} + +const LLMatrix4& LLMatrix4::rotate(const F32 angle, const LLVector4 &vec) +{ + LLMatrix4 mat(angle, vec); + *this *= mat; + return *this; +} + +const LLMatrix4& LLMatrix4::rotate(const F32 roll, const F32 pitch, const F32 yaw) +{ + LLMatrix4 mat(roll, pitch, yaw); + *this *= mat; + return *this; +} + +const LLMatrix4& LLMatrix4::rotate(const LLQuaternion &q) +{ + LLMatrix4 mat(q); + *this *= mat; + return *this; +} + + +const LLMatrix4& LLMatrix4::translate(const LLVector3 &vec) +{ + mMatrix[3][0] += vec.mV[0]; + mMatrix[3][1] += vec.mV[1]; + mMatrix[3][2] += vec.mV[2]; + return (*this); +} + + +void LLMatrix4::setFwdRow(const LLVector3 &row) +{ + mMatrix[VX][VX] = row.mV[VX]; + mMatrix[VX][VY] = row.mV[VY]; + mMatrix[VX][VZ] = row.mV[VZ]; +} + +void LLMatrix4::setLeftRow(const LLVector3 &row) +{ + mMatrix[VY][VX] = row.mV[VX]; + mMatrix[VY][VY] = row.mV[VY]; + mMatrix[VY][VZ] = row.mV[VZ]; +} + +void LLMatrix4::setUpRow(const LLVector3 &row) +{ + mMatrix[VZ][VX] = row.mV[VX]; + mMatrix[VZ][VY] = row.mV[VY]; + mMatrix[VZ][VZ] = row.mV[VZ]; +} + + +void LLMatrix4::setFwdCol(const LLVector3 &col) +{ + mMatrix[VX][VX] = col.mV[VX]; + mMatrix[VY][VX] = col.mV[VY]; + mMatrix[VZ][VX] = col.mV[VZ]; +} + +void LLMatrix4::setLeftCol(const LLVector3 &col) +{ + mMatrix[VX][VY] = col.mV[VX]; + mMatrix[VY][VY] = col.mV[VY]; + mMatrix[VZ][VY] = col.mV[VZ]; +} + +void LLMatrix4::setUpCol(const LLVector3 &col) +{ + mMatrix[VX][VZ] = col.mV[VX]; + mMatrix[VY][VZ] = col.mV[VY]; + mMatrix[VZ][VZ] = col.mV[VZ]; +} + + +const LLMatrix4& LLMatrix4::setTranslation(const F32 tx, const F32 ty, const F32 tz) +{ + mMatrix[VW][VX] = tx; + mMatrix[VW][VY] = ty; + mMatrix[VW][VZ] = tz; + return (*this); +} + +const LLMatrix4& LLMatrix4::setTranslation(const LLVector3 &translation) +{ + mMatrix[VW][VX] = translation.mV[VX]; + mMatrix[VW][VY] = translation.mV[VY]; + mMatrix[VW][VZ] = translation.mV[VZ]; + return (*this); +} + +const LLMatrix4& LLMatrix4::setTranslation(const LLVector4 &translation) +{ + mMatrix[VW][VX] = translation.mV[VX]; + mMatrix[VW][VY] = translation.mV[VY]; + mMatrix[VW][VZ] = translation.mV[VZ]; + return (*this); +} + +// LLMatrix3 Extraction and Setting +LLMatrix3 LLMatrix4::getMat3() const +{ + LLMatrix3 retmat; + + retmat.mMatrix[0][0] = mMatrix[0][0]; + retmat.mMatrix[0][1] = mMatrix[0][1]; + retmat.mMatrix[0][2] = mMatrix[0][2]; + + retmat.mMatrix[1][0] = mMatrix[1][0]; + retmat.mMatrix[1][1] = mMatrix[1][1]; + retmat.mMatrix[1][2] = mMatrix[1][2]; + + retmat.mMatrix[2][0] = mMatrix[2][0]; + retmat.mMatrix[2][1] = mMatrix[2][1]; + retmat.mMatrix[2][2] = mMatrix[2][2]; + + return retmat; +} + +const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat) +{ + mMatrix[0][0] = mat.mMatrix[0][0]; + mMatrix[0][1] = mat.mMatrix[0][1]; + mMatrix[0][2] = mat.mMatrix[0][2]; + mMatrix[0][3] = 0.f; + + mMatrix[1][0] = mat.mMatrix[1][0]; + mMatrix[1][1] = mat.mMatrix[1][1]; + mMatrix[1][2] = mat.mMatrix[1][2]; + mMatrix[1][3] = 0.f; + + mMatrix[2][0] = mat.mMatrix[2][0]; + mMatrix[2][1] = mat.mMatrix[2][1]; + mMatrix[2][2] = mat.mMatrix[2][2]; + mMatrix[2][3] = 0.f; + + mMatrix[3][0] = 0.f; + mMatrix[3][1] = 0.f; + mMatrix[3][2] = 0.f; + mMatrix[3][3] = 1.f; + return (*this); +} + +const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 &translation) +{ + mMatrix[0][0] = mat.mMatrix[0][0]; + mMatrix[0][1] = mat.mMatrix[0][1]; + mMatrix[0][2] = mat.mMatrix[0][2]; + mMatrix[0][3] = 0.f; + + mMatrix[1][0] = mat.mMatrix[1][0]; + mMatrix[1][1] = mat.mMatrix[1][1]; + mMatrix[1][2] = mat.mMatrix[1][2]; + mMatrix[1][3] = 0.f; + + mMatrix[2][0] = mat.mMatrix[2][0]; + mMatrix[2][1] = mat.mMatrix[2][1]; + mMatrix[2][2] = mat.mMatrix[2][2]; + mMatrix[2][3] = 0.f; + + mMatrix[3][0] = translation.mV[0]; + mMatrix[3][1] = translation.mV[1]; + mMatrix[3][2] = translation.mV[2]; + mMatrix[3][3] = 1.f; + return (*this); +} + +// LLMatrix4 Operators + +LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b) +{ + // Operate "to the left" on row-vector a + return LLVector4(a.mV[VX] * b.mMatrix[VX][VX] + + a.mV[VY] * b.mMatrix[VY][VX] + + a.mV[VZ] * b.mMatrix[VZ][VX] + + a.mV[VW] * b.mMatrix[VW][VX], + + a.mV[VX] * b.mMatrix[VX][VY] + + a.mV[VY] * b.mMatrix[VY][VY] + + a.mV[VZ] * b.mMatrix[VZ][VY] + + a.mV[VW] * b.mMatrix[VW][VY], + + a.mV[VX] * b.mMatrix[VX][VZ] + + a.mV[VY] * b.mMatrix[VY][VZ] + + a.mV[VZ] * b.mMatrix[VZ][VZ] + + a.mV[VW] * b.mMatrix[VW][VZ], + + a.mV[VX] * b.mMatrix[VX][VW] + + a.mV[VY] * b.mMatrix[VY][VW] + + a.mV[VZ] * b.mMatrix[VZ][VW] + + a.mV[VW] * b.mMatrix[VW][VW]); +} + +LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b) +{ + // Rotates but does not translate + // Operate "to the left" on row-vector a + LLVector4 vec; + vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + + a.mV[VY] * b.mMatrix[VY][VX] + + a.mV[VZ] * b.mMatrix[VZ][VX]; + + vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + + a.mV[VY] * b.mMatrix[VY][VY] + + a.mV[VZ] * b.mMatrix[VZ][VY]; + + vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + + a.mV[VY] * b.mMatrix[VY][VZ] + + a.mV[VZ] * b.mMatrix[VZ][VZ]; + +// vec.mV[VW] = a.mV[VX] * b.mMatrix[VX][VW] + +// a.mV[VY] * b.mMatrix[VY][VW] + +// a.mV[VZ] * b.mMatrix[VZ][VW] + + vec.mV[VW] = a.mV[VW]; + return vec; +} + +LLVector3 rotate_vector(const LLVector3 &a, const LLMatrix4 &b) +{ + // Rotates but does not translate + // Operate "to the left" on row-vector a + LLVector3 vec; + vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + + a.mV[VY] * b.mMatrix[VY][VX] + + a.mV[VZ] * b.mMatrix[VZ][VX]; + + vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + + a.mV[VY] * b.mMatrix[VY][VY] + + a.mV[VZ] * b.mMatrix[VZ][VY]; + + vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + + a.mV[VY] * b.mMatrix[VY][VZ] + + a.mV[VZ] * b.mMatrix[VZ][VZ]; + return vec; +} + +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[j][i] != b.mMatrix[j][i]) + return false; + } + } + return true; +} + +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[j][i] != b.mMatrix[j][i]) + return true; + } + } + 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; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + a.mMatrix[j][i] *= k; + } + } + return a; +} + +std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a) +{ + s << "{ " + << a.mMatrix[VX][VX] << ", " + << a.mMatrix[VX][VY] << ", " + << a.mMatrix[VX][VZ] << ", " + << a.mMatrix[VX][VW] + << "; " + << a.mMatrix[VY][VX] << ", " + << a.mMatrix[VY][VY] << ", " + << a.mMatrix[VY][VZ] << ", " + << a.mMatrix[VY][VW] + << "; " + << a.mMatrix[VZ][VX] << ", " + << a.mMatrix[VZ][VY] << ", " + << a.mMatrix[VZ][VZ] << ", " + << a.mMatrix[VZ][VW] + << "; " + << a.mMatrix[VW][VX] << ", " + << a.mMatrix[VW][VY] << ", " + << a.mMatrix[VW][VZ] << ", " + << a.mMatrix[VW][VW] + << " }"; + return s; +} + +LLSD LLMatrix4::getValue() const +{ + LLSD ret; + + ret[0] = mMatrix[0][0]; + ret[1] = mMatrix[0][1]; + ret[2] = mMatrix[0][2]; + ret[3] = mMatrix[0][3]; + + ret[4] = mMatrix[1][0]; + ret[5] = mMatrix[1][1]; + ret[6] = mMatrix[1][2]; + ret[7] = mMatrix[1][3]; + + ret[8] = mMatrix[2][0]; + ret[9] = mMatrix[2][1]; + ret[10] = mMatrix[2][2]; + ret[11] = mMatrix[2][3]; + + ret[12] = mMatrix[3][0]; + ret[13] = mMatrix[3][1]; + ret[14] = mMatrix[3][2]; + ret[15] = mMatrix[3][3]; + + return ret; +} + +void LLMatrix4::setValue(const LLSD& data) +{ + mMatrix[0][0] = (F32)data[0].asReal(); + mMatrix[0][1] = (F32)data[1].asReal(); + mMatrix[0][2] = (F32)data[2].asReal(); + mMatrix[0][3] = (F32)data[3].asReal(); + + mMatrix[1][0] = (F32)data[4].asReal(); + mMatrix[1][1] = (F32)data[5].asReal(); + mMatrix[1][2] = (F32)data[6].asReal(); + mMatrix[1][3] = (F32)data[7].asReal(); + + mMatrix[2][0] = (F32)data[8].asReal(); + mMatrix[2][1] = (F32)data[9].asReal(); + mMatrix[2][2] = (F32)data[10].asReal(); + mMatrix[2][3] = (F32)data[11].asReal(); + + mMatrix[3][0] = (F32)data[12].asReal(); + mMatrix[3][1] = (F32)data[13].asReal(); + mMatrix[3][2] = (F32)data[14].asReal(); + mMatrix[3][3] = (F32)data[15].asReal(); +} + + diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index 6bdb1280ba..893bf1fc70 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -1,1269 +1,1269 @@ -/** - * @file raytrace.cpp - * @brief Functions called by box object scripts. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "math.h" -//#include "vmath.h" -#include "v3math.h" -#include "llquaternion.h" -#include "m3math.h" -#include "raytrace.h" - - -bool line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, - LLVector3 &intersection) -{ - F32 N = line_direction * plane_normal; - if (0.0f == N) - { - // line is perpendicular to plane normal - // so it is either entirely on plane, or not on plane at all - return false; - } - // Ax + By, + Cz + D = 0 - // D = - (plane_point * plane_normal) - // N = line_direction * plane_normal - // intersection = line_point - ((D + plane_normal * line_point) / N) * line_direction - intersection = line_point - ((plane_normal * line_point - plane_point * plane_normal) / N) * line_direction; - return true; -} - - -bool ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, - LLVector3 &intersection) -{ - F32 N = ray_direction * plane_normal; - if (0.0f == N) - { - // ray is perpendicular to plane normal - // so it is either entirely on plane, or not on plane at all - return false; - } - // Ax + By, + Cz + D = 0 - // D = - (plane_point * plane_normal) - // N = ray_direction * plane_normal - // intersection = ray_point - ((D + plane_normal * ray_point) / N) * ray_direction - F32 alpha = -(plane_normal * ray_point - plane_point * plane_normal) / N; - if (alpha < 0.0f) - { - // ray points away from plane - return false; - } - intersection = ray_point + alpha * ray_direction; - return true; -} - - -bool ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, - LLVector3 &intersection) -{ - if (ray_plane(ray_point, ray_direction, circle_center, plane_normal, intersection)) - { - if (circle_radius >= (intersection - circle_center).magVec()) - { - return true; - } - } - return false; -} - - -bool ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 side_01 = point_1 - point_0; - LLVector3 side_12 = point_2 - point_1; - - intersection_normal = side_01 % side_12; - intersection_normal.normVec(); - - if (ray_plane(ray_point, ray_direction, point_0, intersection_normal, intersection)) - { - LLVector3 side_20 = point_0 - point_2; - if (intersection_normal * (side_01 % (intersection - point_0)) >= 0.0f && - intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f && - intersection_normal * (side_20 % (intersection - point_2)) >= 0.0f) - { - return true; - } - } - return false; -} - - -// assumes a parallelogram -bool ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 side_01 = point_1 - point_0; - LLVector3 side_12 = point_2 - point_1; - - intersection_normal = side_01 % side_12; - intersection_normal.normVec(); - - if (ray_plane(ray_point, ray_direction, point_0, intersection_normal, intersection)) - { - LLVector3 point_3 = point_0 + (side_12); - LLVector3 side_23 = point_3 - point_2; - LLVector3 side_30 = point_0 - point_3; - if (intersection_normal * (side_01 % (intersection - point_0)) >= 0.0f && - intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f && - intersection_normal * (side_23 % (intersection - point_2)) >= 0.0f && - intersection_normal * (side_30 % (intersection - point_3)) >= 0.0f) - { - return true; - } - } - return false; -} - - -bool ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &sphere_center, F32 sphere_radius, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_to_sphere = sphere_center - ray_point; - F32 dot = ray_to_sphere * ray_direction; - - LLVector3 closest_approach = dot * ray_direction - ray_to_sphere; - - F32 shortest_distance = closest_approach.magVecSquared(); - F32 radius_squared = sphere_radius * sphere_radius; - if (shortest_distance > radius_squared) - { - return false; - } - - F32 half_chord = (F32) sqrt(radius_squared - shortest_distance); - closest_approach = sphere_center + closest_approach; // closest_approach now in absolute coordinates - intersection = closest_approach + half_chord * ray_direction; - dot = ray_direction * (intersection - ray_point); - if (dot < 0.0f) - { - // ray shoots away from sphere and is not inside it - return false; - } - - shortest_distance = ray_direction * ((closest_approach - half_chord * ray_direction) - ray_point); - if (shortest_distance > 0.0f) - { - // ray enters sphere - intersection = intersection - (2.0f * half_chord) * ray_direction; - } - else - { - // do nothing - // ray starts inside sphere and intersects as it leaves the sphere - } - - intersection_normal = intersection - sphere_center; - if (sphere_radius > 0.0f) - { - intersection_normal *= 1.0f / sphere_radius; - } - else - { - intersection_normal.setVec(0.0f, 0.0f, 0.0f); - } - - return true; -} - - -bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - // calculate the centers of the cylinder caps in the absolute frame - LLVector3 cyl_top(0.0f, 0.0f, 0.5f * cyl_scale.mV[VZ]); - LLVector3 cyl_bottom(0.0f, 0.0f, -cyl_top.mV[VZ]); - cyl_top = (cyl_top * cyl_rotation) + cyl_center; - cyl_bottom = (cyl_bottom * cyl_rotation) + cyl_center; - - // we only handle cylinders with circular cross-sections at the moment - F32 cyl_radius = 0.5f * llmax(cyl_scale.mV[VX], cyl_scale.mV[VY]); // HACK until scaled cylinders are supported - - // This implementation is based on the intcyl() function from Graphics_Gems_IV, page 361 - LLVector3 cyl_axis; // axis direction (bottom toward top) - LLVector3 ray_to_cyl; // ray_point to cyl_top - F32 shortest_distance; // shortest distance from ray to axis - F32 cyl_length; - LLVector3 shortest_direction; - LLVector3 temp_vector; - - cyl_axis = cyl_bottom - cyl_top; - cyl_length = cyl_axis.normVec(); - ray_to_cyl = ray_point - cyl_bottom; - shortest_direction = ray_direction % cyl_axis; - shortest_distance = shortest_direction.normVec(); // recycle shortest_distance - - // check for ray parallel to cylinder axis - if (0.0f == shortest_distance) - { - // ray is parallel to cylinder axis - temp_vector = ray_to_cyl - (ray_to_cyl * cyl_axis) * cyl_axis; - shortest_distance = temp_vector.magVec(); - if (shortest_distance <= cyl_radius) - { - shortest_distance = ray_to_cyl * cyl_axis; - F32 dot = ray_direction * cyl_axis; - - if (shortest_distance > 0.0) - { - if (dot > 0.0f) - { - // ray points away from cylinder bottom - return false; - } - // ray hit bottom of cylinder from outside - intersection = ray_point - shortest_distance * cyl_axis; - intersection_normal = cyl_axis; - - } - else if (shortest_distance > -cyl_length) - { - // ray starts inside cylinder - if (dot < 0.0f) - { - // ray hit top from inside - intersection = ray_point - (cyl_length + shortest_distance) * cyl_axis; - intersection_normal = -cyl_axis; - } - else - { - // ray hit bottom from inside - intersection = ray_point - shortest_distance * cyl_axis; - intersection_normal = cyl_axis; - } - } - else - { - if (dot < 0.0f) - { - // ray points away from cylinder bottom - return false; - } - // ray hit top from outside - intersection = ray_point - (shortest_distance + cyl_length) * cyl_axis; - intersection_normal = -cyl_axis; - } - return true; - } - return false; - } - - // check for intersection with infinite cylinder - shortest_distance = (F32) fabs(ray_to_cyl * shortest_direction); - if (shortest_distance <= cyl_radius) - { - F32 dist_to_closest_point; // dist from ray_point to closest_point - F32 half_chord_length; // half length of intersection chord - F32 in, out; // distances to entering/exiting points - temp_vector = ray_to_cyl % cyl_axis; - dist_to_closest_point = - (temp_vector * shortest_direction); - temp_vector = shortest_direction % cyl_axis; - temp_vector.normVec(); - half_chord_length = (F32) fabs( sqrt(cyl_radius*cyl_radius - shortest_distance * shortest_distance) / - (ray_direction * temp_vector) ); - - out = dist_to_closest_point + half_chord_length; // dist to exiting point - if (out < 0.0f) - { - // cylinder is behind the ray, so we return false - return false; - } - - in = dist_to_closest_point - half_chord_length; // dist to entering point - if (in < 0.0f) - { - // ray_point is inside the cylinder - // so we store the exiting intersection - intersection = ray_point + out * ray_direction; - shortest_distance = out; - } - else - { - // ray hit cylinder from outside - // so we store the entering intersection - intersection = ray_point + in * ray_direction; - shortest_distance = in; - } - - // calculate the normal at intersection - if (0.0f == cyl_radius) - { - intersection_normal.setVec(0.0f, 0.0f, 0.0f); - } - else - { - temp_vector = intersection - cyl_bottom; - intersection_normal = temp_vector - (temp_vector * cyl_axis) * cyl_axis; - intersection_normal.normVec(); - } - - // check for intersection with end caps - // calculate intersection of ray and top plane - if (line_plane(ray_point, ray_direction, cyl_top, -cyl_axis, temp_vector)) // NOTE side-effect: changing temp_vector - { - shortest_distance = (temp_vector - ray_point).magVec(); - if ( (ray_direction * cyl_axis) > 0.0f) - { - // ray potentially enters the cylinder at top - if (shortest_distance > out) - { - // ray missed the finite cylinder - return false; - } - if (shortest_distance > in) - { - // ray intersects cylinder at top plane - intersection = temp_vector; - intersection_normal = -cyl_axis; - return true; - } - } - else - { - // ray potentially exits the cylinder at top - if (shortest_distance < in) - { - // missed the finite cylinder - return false; - } - } - - // calculate intersection of ray and bottom plane - line_plane(ray_point, ray_direction, cyl_bottom, cyl_axis, temp_vector); // NOTE side-effect: changing temp_vector - shortest_distance = (temp_vector - ray_point).magVec(); - if ( (ray_direction * cyl_axis) < 0.0) - { - // ray potentially enters the cylinder at bottom - if (shortest_distance > out) - { - // ray missed the finite cylinder - return false; - } - if (shortest_distance > in) - { - // ray intersects cylinder at bottom plane - intersection = temp_vector; - intersection_normal = cyl_axis; - return true; - } - } - else - { - // ray potentially exits the cylinder at bottom - if (shortest_distance < in) - { - // ray missed the finite cylinder - return false; - } - } - - } - else - { - // ray is parallel to end cap planes - temp_vector = cyl_bottom - ray_point; - shortest_distance = temp_vector * cyl_axis; - if (shortest_distance < 0.0f || shortest_distance > cyl_length) - { - // ray missed finite cylinder - return false; - } - } - - return true; - } - - return false; -} - - -U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - - // Need to rotate into box frame - LLQuaternion into_box_frame(box_rotation); // rotates things from box frame to absolute - into_box_frame.conjQuat(); // now rotates things into box frame - LLVector3 line_point = (ray_point - box_center) * into_box_frame; - LLVector3 line_direction = ray_direction * into_box_frame; - - // Suppose we have a plane: Ax + By + Cz + D = 0 - // then, assuming [A, B, C] is a unit vector: - // - // plane_normal = [A, B, C] - // D = - (plane_normal * plane_point) - // - // Suppose we have a line: X = line_point + alpha * line_direction - // - // the intersection of the plane and line determines alpha - // - // alpha = - (D + plane_normal * line_point) / (plane_normal * line_direction) - - LLVector3 line_plane_intersection; - - F32 pointX = line_point.mV[VX]; - F32 pointY = line_point.mV[VY]; - F32 pointZ = line_point.mV[VZ]; - - F32 dirX = line_direction.mV[VX]; - F32 dirY = line_direction.mV[VY]; - F32 dirZ = line_direction.mV[VZ]; - - // we'll be using the half-scales of the box - F32 boxX = 0.5f * box_scale.mV[VX]; - F32 boxY = 0.5f * box_scale.mV[VY]; - F32 boxZ = 0.5f * box_scale.mV[VZ]; - - // check to see if line_point is OUTSIDE the box - if (pointX < -boxX || - pointX > boxX || - pointY < -boxY || - pointY > boxY || - pointZ < -boxZ || - pointZ > boxZ) - { - // -------------- point is OUTSIDE the box ---------------- - - // front - if (pointX > 0.0f && dirX < 0.0f) - { - // plane_normal = [ 1, 0, 0] - // plane_normal*line_point = pointX - // plane_normal*line_direction = dirX - // D = -boxX - // alpha = - (-boxX + pointX) / dirX - line_plane_intersection = line_point - ((pointX - boxX) / dirX) * line_direction; - if (line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(1.0f, 0.0f, 0.0f) * box_rotation; - return FRONT_SIDE; - } - } - - // back - if (pointX < 0.0f && dirX > 0.0f) - { - // plane_normal = [ -1, 0, 0] - // plane_normal*line_point = -pX - // plane_normal*line_direction = -direction.mV[VX] - // D = -bX - // alpha = - (-bX - pX) / (-dirX) - line_plane_intersection = line_point - ((boxX + pointX)/ dirX) * line_direction; - if (line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(-1.0f, 0.0f, 0.0f) * box_rotation; - return BACK_SIDE; - } - } - - // left - if (pointY > 0.0f && dirY < 0.0f) - { - // plane_normal = [0, 1, 0] - // plane_normal*line_point = pointY - // plane_normal*line_direction = dirY - // D = -boxY - // alpha = - (-boxY + pointY) / dirY - line_plane_intersection = line_point + ((boxY - pointY)/dirY) * line_direction; - - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, 1.0f, 0.0f) * box_rotation; - return LEFT_SIDE; - } - } - - // right - if (pointY < 0.0f && dirY > 0.0f) - { - // plane_normal = [0, -1, 0] - // plane_normal*line_point = -pointY - // plane_normal*line_direction = -dirY - // D = -boxY - // alpha = - (-boxY - pointY) / (-dirY) - line_plane_intersection = line_point - ((boxY + pointY)/dirY) * line_direction; - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, -1.0f, 0.0f) * box_rotation; - return RIGHT_SIDE; - } - } - - // top - if (pointZ > 0.0f && dirZ < 0.0f) - { - // plane_normal = [0, 0, 1] - // plane_normal*line_point = pointZ - // plane_normal*line_direction = dirZ - // D = -boxZ - // alpha = - (-boxZ + pointZ) / dirZ - line_plane_intersection = line_point - ((pointZ - boxZ)/dirZ) * line_direction; - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, 0.0f, 1.0f) * box_rotation; - return TOP_SIDE; - } - } - - // bottom - if (pointZ < 0.0f && dirZ > 0.0f) - { - // plane_normal = [0, 0, -1] - // plane_normal*line_point = -pointZ - // plane_normal*line_direction = -dirZ - // D = -boxZ - // alpha = - (-boxZ - pointZ) / (-dirZ) - line_plane_intersection = line_point - ((boxZ + pointZ)/dirZ) * line_direction; - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, 0.0f, -1.0f) * box_rotation; - return BOTTOM_SIDE; - } - } - return NO_SIDE; - } - - // -------------- point is INSIDE the box ---------------- - - // front - if (dirX > 0.0f) - { - // plane_normal = [ 1, 0, 0] - // plane_normal*line_point = pointX - // plane_normal*line_direction = dirX - // D = -boxX - // alpha = - (-boxX + pointX) / dirX - line_plane_intersection = line_point - ((pointX - boxX) / dirX) * line_direction; - if (line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(1.0f, 0.0f, 0.0f) * box_rotation; - return FRONT_SIDE; - } - } - - // back - if (dirX < 0.0f) - { - // plane_normal = [ -1, 0, 0] - // plane_normal*line_point = -pX - // plane_normal*line_direction = -direction.mV[VX] - // D = -bX - // alpha = - (-bX - pX) / (-dirX) - line_plane_intersection = line_point - ((boxX + pointX)/ dirX) * line_direction; - if (line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(-1.0f, 0.0f, 0.0f) * box_rotation; - return BACK_SIDE; - } - } - - // left - if (dirY > 0.0f) - { - // plane_normal = [0, 1, 0] - // plane_normal*line_point = pointY - // plane_normal*line_direction = dirY - // D = -boxY - // alpha = - (-boxY + pointY) / dirY - line_plane_intersection = line_point + ((boxY - pointY)/dirY) * line_direction; - - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, 1.0f, 0.0f) * box_rotation; - return LEFT_SIDE; - } - } - - // right - if (dirY < 0.0f) - { - // plane_normal = [0, -1, 0] - // plane_normal*line_point = -pointY - // plane_normal*line_direction = -dirY - // D = -boxY - // alpha = - (-boxY - pointY) / (-dirY) - line_plane_intersection = line_point - ((boxY + pointY)/dirY) * line_direction; - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VZ] < boxZ && - line_plane_intersection.mV[VZ] > -boxZ ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, -1.0f, 0.0f) * box_rotation; - return RIGHT_SIDE; - } - } - - // top - if (dirZ > 0.0f) - { - // plane_normal = [0, 0, 1] - // plane_normal*line_point = pointZ - // plane_normal*line_direction = dirZ - // D = -boxZ - // alpha = - (-boxZ + pointZ) / dirZ - line_plane_intersection = line_point - ((pointZ - boxZ)/dirZ) * line_direction; - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, 0.0f, 1.0f) * box_rotation; - return TOP_SIDE; - } - } - - // bottom - if (dirZ < 0.0f) - { - // plane_normal = [0, 0, -1] - // plane_normal*line_point = -pointZ - // plane_normal*line_direction = -dirZ - // D = -boxZ - // alpha = - (-boxZ - pointZ) / (-dirZ) - line_plane_intersection = line_point - ((boxZ + pointZ)/dirZ) * line_direction; - if (line_plane_intersection.mV[VX] < boxX && - line_plane_intersection.mV[VX] > -boxX && - line_plane_intersection.mV[VY] < boxY && - line_plane_intersection.mV[VY] > -boxY ) - { - intersection = (line_plane_intersection * box_rotation) + box_center; - intersection_normal = LLVector3(0.0f, 0.0f, -1.0f) * box_rotation; - return BOTTOM_SIDE; - } - } - - // should never get here unless line instersects at tangent point on edge or corner - // however such cases will be EXTREMELY rare - return NO_SIDE; -} - - -bool ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - // (0) Z - // /| \ . - // (1)| \ /|\ _.Y - // | \ \ | /| - // | |\ \ | / - // | | \(0)\ | / - // | | \ \ |/ - // | | \ \ (*)----> X - // |(3)---\---(2) - // |/ \ / - // (4)-------(5) - - // need to calculate the points of the prism so we can run ray tests with each face - F32 x = prism_scale.mV[VX]; - F32 y = prism_scale.mV[VY]; - F32 z = prism_scale.mV[VZ]; - - F32 tx = x * 2.0f / 3.0f; - F32 ty = y * 0.5f; - F32 tz = z * 2.0f / 3.0f; - - LLVector3 point0(tx-x, ty, tz); - LLVector3 point1(tx-x, -ty, tz); - LLVector3 point2(tx, ty, tz-z); - LLVector3 point3(tx-x, ty, tz-z); - LLVector3 point4(tx-x, -ty, tz-z); - LLVector3 point5(tx, -ty, tz-z); - - // transform these points into absolute frame - point0 = (point0 * prism_rotation) + prism_center; - point1 = (point1 * prism_rotation) + prism_center; - point2 = (point2 * prism_rotation) + prism_center; - point3 = (point3 * prism_rotation) + prism_center; - point4 = (point4 * prism_rotation) + prism_center; - point5 = (point5 * prism_rotation) + prism_center; - - // test ray intersection for each face - bool b_hit = false; - LLVector3 face_intersection, face_normal; - F32 distance_squared = 0.0f; - F32 temp; - - // face 0 - if (ray_direction * ( (point0 - point2) % (point5 - point2)) < 0.0f && - ray_quadrangle(ray_point, ray_direction, point5, point2, point0, intersection, intersection_normal)) - { - distance_squared = (ray_point - intersection).magVecSquared(); - b_hit = true; - } - - // face 1 - if (ray_direction * ( (point0 - point3) % (point2 - point3)) < 0.0f && - ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 2 - if (ray_direction * ( (point1 - point4) % (point3 - point4)) < 0.0f && - ray_quadrangle(ray_point, ray_direction, point3, point4, point1, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 3 - if (ray_direction * ( (point5 - point4) % (point1 - point4)) < 0.0f && - ray_triangle(ray_point, ray_direction, point1, point4, point5, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 4 - if (ray_direction * ( (point4 - point5) % (point2 - point5)) < 0.0f && - ray_quadrangle(ray_point, ray_direction, point2, point5, point4, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - return b_hit; -} - - -bool ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - F32 a = 0.5f * F_SQRT3; // height of unit triangle - F32 b = 1.0f / F_SQRT3; // distance of center of unit triangle to each point - F32 c = F_SQRT2 / F_SQRT3; // height of unit tetrahedron - F32 d = 0.5f * F_SQRT3 / F_SQRT2; // distance of center of tetrahedron to each point - - // if we want the tetrahedron to have unit height (c = 1.0) then we need to divide - // each constant by hieght of a unit tetrahedron - F32 oo_c = 1.0f / c; - a = a * oo_c; - b = b * oo_c; - c = 1.0f; - d = d * oo_c; - F32 e = 0.5f * oo_c; - - LLVector3 point0( 0.0f, 0.0f, t_scale.mV[VZ] * d); - LLVector3 point1(t_scale.mV[VX] * b, 0.0f, t_scale.mV[VZ] * (d-c)); - LLVector3 point2(t_scale.mV[VX] * (b-a), e * t_scale.mV[VY], t_scale.mV[VZ] * (d-c)); - LLVector3 point3(t_scale.mV[VX] * (b-a), -e * t_scale.mV[VY], t_scale.mV[VZ] * (d-c)); - - // transform these points into absolute frame - point0 = (point0 * t_rotation) + t_center; - point1 = (point1 * t_rotation) + t_center; - point2 = (point2 * t_rotation) + t_center; - point3 = (point3 * t_rotation) + t_center; - - // test ray intersection for each face - bool b_hit = false; - LLVector3 face_intersection, face_normal; - F32 distance_squared = 1.0e12f; - F32 temp; - - // face 0 - if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f && - ray_triangle(ray_point, ray_direction, point1, point2, point0, intersection, intersection_normal)) - { - distance_squared = (ray_point - intersection).magVecSquared(); - b_hit = true; - } - - // face 1 - if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f && - ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 2 - if (ray_direction * ( (point1 - point3) % (point0 - point3)) < 0.0f && - ray_triangle(ray_point, ray_direction, point3, point1, point0, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 3 - if (ray_direction * ( (point2 - point3) % (point1 - point3)) < 0.0f && - ray_triangle(ray_point, ray_direction, point3, point2, point1, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - return b_hit; -} - - -bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - // center of mass of pyramid is located 1/4 its height from the base - F32 x = 0.5f * p_scale.mV[VX]; - F32 y = 0.5f * p_scale.mV[VY]; - F32 z = 0.25f * p_scale.mV[VZ]; - - LLVector3 point0(0.0f, 0.0f, p_scale.mV[VZ] - z); - LLVector3 point1( x, y, -z); - LLVector3 point2(-x, y, -z); - LLVector3 point3(-x, -y, -z); - LLVector3 point4( x, -y, -z); - - // transform these points into absolute frame - point0 = (point0 * p_rotation) + p_center; - point1 = (point1 * p_rotation) + p_center; - point2 = (point2 * p_rotation) + p_center; - point3 = (point3 * p_rotation) + p_center; - point4 = (point4 * p_rotation) + p_center; - - // test ray intersection for each face - bool b_hit = false; - LLVector3 face_intersection, face_normal; - F32 distance_squared = 1.0e12f; - F32 temp; - - // face 0 - if (ray_direction * ( (point1 - point4) % (point0 - point4)) < 0.0f && - ray_triangle(ray_point, ray_direction, point4, point1, point0, intersection, intersection_normal)) - { - distance_squared = (ray_point - intersection).magVecSquared(); - b_hit = true; - } - - // face 1 - if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f && - ray_triangle(ray_point, ray_direction, point1, point2, point0, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 2 - if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f && - ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 3 - if (ray_direction * ( (point4 - point3) % (point0 - point3)) < 0.0f && - ray_triangle(ray_point, ray_direction, point3, point4, point0, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - distance_squared = temp; - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - distance_squared = (ray_point - face_intersection).magVecSquared(); - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - // face 4 - if (ray_direction * ( (point3 - point4) % (point2 - point4)) < 0.0f && - ray_quadrangle(ray_point, ray_direction, point4, point3, point2, face_intersection, face_normal)) - { - if (b_hit) - { - temp = (ray_point - face_intersection).magVecSquared(); - if (temp < distance_squared) - { - intersection = face_intersection; - intersection_normal = face_normal; - } - } - else - { - intersection = face_intersection; - intersection_normal = face_normal; - b_hit = true; - } - } - - return b_hit; -} - - -bool linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, - LLVector3 &intersection) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_circle(point_a, ray_direction, circle_center, plane_normal, circle_radius, intersection)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -bool linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_triangle(point_a, ray_direction, point_0, point_1, point_2, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -bool linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_quadrangle(point_a, ray_direction, point_0, point_1, point_2, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -bool linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &sphere_center, F32 sphere_radius, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_sphere(point_a, ray_direction, sphere_center, sphere_radius, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_cylinder(point_a, ray_direction, cyl_center, cyl_scale, cyl_rotation, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 direction = point_b - point_a; - if (direction.isNull()) - { - return NO_SIDE; - } - - F32 segment_length = direction.normVec(); - U32 box_side = ray_box(point_a, direction, box_center, box_scale, box_rotation, intersection, intersection_normal); - if (NO_SIDE == box_side || segment_length < (intersection - point_a).magVec()) - { - return NO_SIDE; - } - - return box_side; -} - - -bool linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_prism(point_a, ray_direction, prism_center, prism_scale, prism_rotation, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -bool linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_tetrahedron(point_a, ray_direction, t_center, t_scale, t_rotation, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} - - -bool linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal) -{ - LLVector3 ray_direction = point_b - point_a; - F32 segment_length = ray_direction.normVec(); - - if (ray_pyramid(point_a, ray_direction, p_center, p_scale, p_rotation, intersection, intersection_normal)) - { - if (segment_length >= (point_a - intersection).magVec()) - { - return true; - } - } - return false; -} +/** + * @file raytrace.cpp + * @brief Functions called by box object scripts. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "math.h" +//#include "vmath.h" +#include "v3math.h" +#include "llquaternion.h" +#include "m3math.h" +#include "raytrace.h" + + +bool line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, + LLVector3 &intersection) +{ + F32 N = line_direction * plane_normal; + if (0.0f == N) + { + // line is perpendicular to plane normal + // so it is either entirely on plane, or not on plane at all + return false; + } + // Ax + By, + Cz + D = 0 + // D = - (plane_point * plane_normal) + // N = line_direction * plane_normal + // intersection = line_point - ((D + plane_normal * line_point) / N) * line_direction + intersection = line_point - ((plane_normal * line_point - plane_point * plane_normal) / N) * line_direction; + return true; +} + + +bool ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, + LLVector3 &intersection) +{ + F32 N = ray_direction * plane_normal; + if (0.0f == N) + { + // ray is perpendicular to plane normal + // so it is either entirely on plane, or not on plane at all + return false; + } + // Ax + By, + Cz + D = 0 + // D = - (plane_point * plane_normal) + // N = ray_direction * plane_normal + // intersection = ray_point - ((D + plane_normal * ray_point) / N) * ray_direction + F32 alpha = -(plane_normal * ray_point - plane_point * plane_normal) / N; + if (alpha < 0.0f) + { + // ray points away from plane + return false; + } + intersection = ray_point + alpha * ray_direction; + return true; +} + + +bool ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, + LLVector3 &intersection) +{ + if (ray_plane(ray_point, ray_direction, circle_center, plane_normal, intersection)) + { + if (circle_radius >= (intersection - circle_center).magVec()) + { + return true; + } + } + return false; +} + + +bool ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 side_01 = point_1 - point_0; + LLVector3 side_12 = point_2 - point_1; + + intersection_normal = side_01 % side_12; + intersection_normal.normVec(); + + if (ray_plane(ray_point, ray_direction, point_0, intersection_normal, intersection)) + { + LLVector3 side_20 = point_0 - point_2; + if (intersection_normal * (side_01 % (intersection - point_0)) >= 0.0f && + intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f && + intersection_normal * (side_20 % (intersection - point_2)) >= 0.0f) + { + return true; + } + } + return false; +} + + +// assumes a parallelogram +bool ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 side_01 = point_1 - point_0; + LLVector3 side_12 = point_2 - point_1; + + intersection_normal = side_01 % side_12; + intersection_normal.normVec(); + + if (ray_plane(ray_point, ray_direction, point_0, intersection_normal, intersection)) + { + LLVector3 point_3 = point_0 + (side_12); + LLVector3 side_23 = point_3 - point_2; + LLVector3 side_30 = point_0 - point_3; + if (intersection_normal * (side_01 % (intersection - point_0)) >= 0.0f && + intersection_normal * (side_12 % (intersection - point_1)) >= 0.0f && + intersection_normal * (side_23 % (intersection - point_2)) >= 0.0f && + intersection_normal * (side_30 % (intersection - point_3)) >= 0.0f) + { + return true; + } + } + return false; +} + + +bool ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &sphere_center, F32 sphere_radius, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_to_sphere = sphere_center - ray_point; + F32 dot = ray_to_sphere * ray_direction; + + LLVector3 closest_approach = dot * ray_direction - ray_to_sphere; + + F32 shortest_distance = closest_approach.magVecSquared(); + F32 radius_squared = sphere_radius * sphere_radius; + if (shortest_distance > radius_squared) + { + return false; + } + + F32 half_chord = (F32) sqrt(radius_squared - shortest_distance); + closest_approach = sphere_center + closest_approach; // closest_approach now in absolute coordinates + intersection = closest_approach + half_chord * ray_direction; + dot = ray_direction * (intersection - ray_point); + if (dot < 0.0f) + { + // ray shoots away from sphere and is not inside it + return false; + } + + shortest_distance = ray_direction * ((closest_approach - half_chord * ray_direction) - ray_point); + if (shortest_distance > 0.0f) + { + // ray enters sphere + intersection = intersection - (2.0f * half_chord) * ray_direction; + } + else + { + // do nothing + // ray starts inside sphere and intersects as it leaves the sphere + } + + intersection_normal = intersection - sphere_center; + if (sphere_radius > 0.0f) + { + intersection_normal *= 1.0f / sphere_radius; + } + else + { + intersection_normal.setVec(0.0f, 0.0f, 0.0f); + } + + return true; +} + + +bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + // calculate the centers of the cylinder caps in the absolute frame + LLVector3 cyl_top(0.0f, 0.0f, 0.5f * cyl_scale.mV[VZ]); + LLVector3 cyl_bottom(0.0f, 0.0f, -cyl_top.mV[VZ]); + cyl_top = (cyl_top * cyl_rotation) + cyl_center; + cyl_bottom = (cyl_bottom * cyl_rotation) + cyl_center; + + // we only handle cylinders with circular cross-sections at the moment + F32 cyl_radius = 0.5f * llmax(cyl_scale.mV[VX], cyl_scale.mV[VY]); // HACK until scaled cylinders are supported + + // This implementation is based on the intcyl() function from Graphics_Gems_IV, page 361 + LLVector3 cyl_axis; // axis direction (bottom toward top) + LLVector3 ray_to_cyl; // ray_point to cyl_top + F32 shortest_distance; // shortest distance from ray to axis + F32 cyl_length; + LLVector3 shortest_direction; + LLVector3 temp_vector; + + cyl_axis = cyl_bottom - cyl_top; + cyl_length = cyl_axis.normVec(); + ray_to_cyl = ray_point - cyl_bottom; + shortest_direction = ray_direction % cyl_axis; + shortest_distance = shortest_direction.normVec(); // recycle shortest_distance + + // check for ray parallel to cylinder axis + if (0.0f == shortest_distance) + { + // ray is parallel to cylinder axis + temp_vector = ray_to_cyl - (ray_to_cyl * cyl_axis) * cyl_axis; + shortest_distance = temp_vector.magVec(); + if (shortest_distance <= cyl_radius) + { + shortest_distance = ray_to_cyl * cyl_axis; + F32 dot = ray_direction * cyl_axis; + + if (shortest_distance > 0.0) + { + if (dot > 0.0f) + { + // ray points away from cylinder bottom + return false; + } + // ray hit bottom of cylinder from outside + intersection = ray_point - shortest_distance * cyl_axis; + intersection_normal = cyl_axis; + + } + else if (shortest_distance > -cyl_length) + { + // ray starts inside cylinder + if (dot < 0.0f) + { + // ray hit top from inside + intersection = ray_point - (cyl_length + shortest_distance) * cyl_axis; + intersection_normal = -cyl_axis; + } + else + { + // ray hit bottom from inside + intersection = ray_point - shortest_distance * cyl_axis; + intersection_normal = cyl_axis; + } + } + else + { + if (dot < 0.0f) + { + // ray points away from cylinder bottom + return false; + } + // ray hit top from outside + intersection = ray_point - (shortest_distance + cyl_length) * cyl_axis; + intersection_normal = -cyl_axis; + } + return true; + } + return false; + } + + // check for intersection with infinite cylinder + shortest_distance = (F32) fabs(ray_to_cyl * shortest_direction); + if (shortest_distance <= cyl_radius) + { + F32 dist_to_closest_point; // dist from ray_point to closest_point + F32 half_chord_length; // half length of intersection chord + F32 in, out; // distances to entering/exiting points + temp_vector = ray_to_cyl % cyl_axis; + dist_to_closest_point = - (temp_vector * shortest_direction); + temp_vector = shortest_direction % cyl_axis; + temp_vector.normVec(); + half_chord_length = (F32) fabs( sqrt(cyl_radius*cyl_radius - shortest_distance * shortest_distance) / + (ray_direction * temp_vector) ); + + out = dist_to_closest_point + half_chord_length; // dist to exiting point + if (out < 0.0f) + { + // cylinder is behind the ray, so we return false + return false; + } + + in = dist_to_closest_point - half_chord_length; // dist to entering point + if (in < 0.0f) + { + // ray_point is inside the cylinder + // so we store the exiting intersection + intersection = ray_point + out * ray_direction; + shortest_distance = out; + } + else + { + // ray hit cylinder from outside + // so we store the entering intersection + intersection = ray_point + in * ray_direction; + shortest_distance = in; + } + + // calculate the normal at intersection + if (0.0f == cyl_radius) + { + intersection_normal.setVec(0.0f, 0.0f, 0.0f); + } + else + { + temp_vector = intersection - cyl_bottom; + intersection_normal = temp_vector - (temp_vector * cyl_axis) * cyl_axis; + intersection_normal.normVec(); + } + + // check for intersection with end caps + // calculate intersection of ray and top plane + if (line_plane(ray_point, ray_direction, cyl_top, -cyl_axis, temp_vector)) // NOTE side-effect: changing temp_vector + { + shortest_distance = (temp_vector - ray_point).magVec(); + if ( (ray_direction * cyl_axis) > 0.0f) + { + // ray potentially enters the cylinder at top + if (shortest_distance > out) + { + // ray missed the finite cylinder + return false; + } + if (shortest_distance > in) + { + // ray intersects cylinder at top plane + intersection = temp_vector; + intersection_normal = -cyl_axis; + return true; + } + } + else + { + // ray potentially exits the cylinder at top + if (shortest_distance < in) + { + // missed the finite cylinder + return false; + } + } + + // calculate intersection of ray and bottom plane + line_plane(ray_point, ray_direction, cyl_bottom, cyl_axis, temp_vector); // NOTE side-effect: changing temp_vector + shortest_distance = (temp_vector - ray_point).magVec(); + if ( (ray_direction * cyl_axis) < 0.0) + { + // ray potentially enters the cylinder at bottom + if (shortest_distance > out) + { + // ray missed the finite cylinder + return false; + } + if (shortest_distance > in) + { + // ray intersects cylinder at bottom plane + intersection = temp_vector; + intersection_normal = cyl_axis; + return true; + } + } + else + { + // ray potentially exits the cylinder at bottom + if (shortest_distance < in) + { + // ray missed the finite cylinder + return false; + } + } + + } + else + { + // ray is parallel to end cap planes + temp_vector = cyl_bottom - ray_point; + shortest_distance = temp_vector * cyl_axis; + if (shortest_distance < 0.0f || shortest_distance > cyl_length) + { + // ray missed finite cylinder + return false; + } + } + + return true; + } + + return false; +} + + +U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + + // Need to rotate into box frame + LLQuaternion into_box_frame(box_rotation); // rotates things from box frame to absolute + into_box_frame.conjQuat(); // now rotates things into box frame + LLVector3 line_point = (ray_point - box_center) * into_box_frame; + LLVector3 line_direction = ray_direction * into_box_frame; + + // Suppose we have a plane: Ax + By + Cz + D = 0 + // then, assuming [A, B, C] is a unit vector: + // + // plane_normal = [A, B, C] + // D = - (plane_normal * plane_point) + // + // Suppose we have a line: X = line_point + alpha * line_direction + // + // the intersection of the plane and line determines alpha + // + // alpha = - (D + plane_normal * line_point) / (plane_normal * line_direction) + + LLVector3 line_plane_intersection; + + F32 pointX = line_point.mV[VX]; + F32 pointY = line_point.mV[VY]; + F32 pointZ = line_point.mV[VZ]; + + F32 dirX = line_direction.mV[VX]; + F32 dirY = line_direction.mV[VY]; + F32 dirZ = line_direction.mV[VZ]; + + // we'll be using the half-scales of the box + F32 boxX = 0.5f * box_scale.mV[VX]; + F32 boxY = 0.5f * box_scale.mV[VY]; + F32 boxZ = 0.5f * box_scale.mV[VZ]; + + // check to see if line_point is OUTSIDE the box + if (pointX < -boxX || + pointX > boxX || + pointY < -boxY || + pointY > boxY || + pointZ < -boxZ || + pointZ > boxZ) + { + // -------------- point is OUTSIDE the box ---------------- + + // front + if (pointX > 0.0f && dirX < 0.0f) + { + // plane_normal = [ 1, 0, 0] + // plane_normal*line_point = pointX + // plane_normal*line_direction = dirX + // D = -boxX + // alpha = - (-boxX + pointX) / dirX + line_plane_intersection = line_point - ((pointX - boxX) / dirX) * line_direction; + if (line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(1.0f, 0.0f, 0.0f) * box_rotation; + return FRONT_SIDE; + } + } + + // back + if (pointX < 0.0f && dirX > 0.0f) + { + // plane_normal = [ -1, 0, 0] + // plane_normal*line_point = -pX + // plane_normal*line_direction = -direction.mV[VX] + // D = -bX + // alpha = - (-bX - pX) / (-dirX) + line_plane_intersection = line_point - ((boxX + pointX)/ dirX) * line_direction; + if (line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(-1.0f, 0.0f, 0.0f) * box_rotation; + return BACK_SIDE; + } + } + + // left + if (pointY > 0.0f && dirY < 0.0f) + { + // plane_normal = [0, 1, 0] + // plane_normal*line_point = pointY + // plane_normal*line_direction = dirY + // D = -boxY + // alpha = - (-boxY + pointY) / dirY + line_plane_intersection = line_point + ((boxY - pointY)/dirY) * line_direction; + + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, 1.0f, 0.0f) * box_rotation; + return LEFT_SIDE; + } + } + + // right + if (pointY < 0.0f && dirY > 0.0f) + { + // plane_normal = [0, -1, 0] + // plane_normal*line_point = -pointY + // plane_normal*line_direction = -dirY + // D = -boxY + // alpha = - (-boxY - pointY) / (-dirY) + line_plane_intersection = line_point - ((boxY + pointY)/dirY) * line_direction; + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, -1.0f, 0.0f) * box_rotation; + return RIGHT_SIDE; + } + } + + // top + if (pointZ > 0.0f && dirZ < 0.0f) + { + // plane_normal = [0, 0, 1] + // plane_normal*line_point = pointZ + // plane_normal*line_direction = dirZ + // D = -boxZ + // alpha = - (-boxZ + pointZ) / dirZ + line_plane_intersection = line_point - ((pointZ - boxZ)/dirZ) * line_direction; + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, 0.0f, 1.0f) * box_rotation; + return TOP_SIDE; + } + } + + // bottom + if (pointZ < 0.0f && dirZ > 0.0f) + { + // plane_normal = [0, 0, -1] + // plane_normal*line_point = -pointZ + // plane_normal*line_direction = -dirZ + // D = -boxZ + // alpha = - (-boxZ - pointZ) / (-dirZ) + line_plane_intersection = line_point - ((boxZ + pointZ)/dirZ) * line_direction; + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, 0.0f, -1.0f) * box_rotation; + return BOTTOM_SIDE; + } + } + return NO_SIDE; + } + + // -------------- point is INSIDE the box ---------------- + + // front + if (dirX > 0.0f) + { + // plane_normal = [ 1, 0, 0] + // plane_normal*line_point = pointX + // plane_normal*line_direction = dirX + // D = -boxX + // alpha = - (-boxX + pointX) / dirX + line_plane_intersection = line_point - ((pointX - boxX) / dirX) * line_direction; + if (line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(1.0f, 0.0f, 0.0f) * box_rotation; + return FRONT_SIDE; + } + } + + // back + if (dirX < 0.0f) + { + // plane_normal = [ -1, 0, 0] + // plane_normal*line_point = -pX + // plane_normal*line_direction = -direction.mV[VX] + // D = -bX + // alpha = - (-bX - pX) / (-dirX) + line_plane_intersection = line_point - ((boxX + pointX)/ dirX) * line_direction; + if (line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(-1.0f, 0.0f, 0.0f) * box_rotation; + return BACK_SIDE; + } + } + + // left + if (dirY > 0.0f) + { + // plane_normal = [0, 1, 0] + // plane_normal*line_point = pointY + // plane_normal*line_direction = dirY + // D = -boxY + // alpha = - (-boxY + pointY) / dirY + line_plane_intersection = line_point + ((boxY - pointY)/dirY) * line_direction; + + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, 1.0f, 0.0f) * box_rotation; + return LEFT_SIDE; + } + } + + // right + if (dirY < 0.0f) + { + // plane_normal = [0, -1, 0] + // plane_normal*line_point = -pointY + // plane_normal*line_direction = -dirY + // D = -boxY + // alpha = - (-boxY - pointY) / (-dirY) + line_plane_intersection = line_point - ((boxY + pointY)/dirY) * line_direction; + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VZ] < boxZ && + line_plane_intersection.mV[VZ] > -boxZ ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, -1.0f, 0.0f) * box_rotation; + return RIGHT_SIDE; + } + } + + // top + if (dirZ > 0.0f) + { + // plane_normal = [0, 0, 1] + // plane_normal*line_point = pointZ + // plane_normal*line_direction = dirZ + // D = -boxZ + // alpha = - (-boxZ + pointZ) / dirZ + line_plane_intersection = line_point - ((pointZ - boxZ)/dirZ) * line_direction; + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, 0.0f, 1.0f) * box_rotation; + return TOP_SIDE; + } + } + + // bottom + if (dirZ < 0.0f) + { + // plane_normal = [0, 0, -1] + // plane_normal*line_point = -pointZ + // plane_normal*line_direction = -dirZ + // D = -boxZ + // alpha = - (-boxZ - pointZ) / (-dirZ) + line_plane_intersection = line_point - ((boxZ + pointZ)/dirZ) * line_direction; + if (line_plane_intersection.mV[VX] < boxX && + line_plane_intersection.mV[VX] > -boxX && + line_plane_intersection.mV[VY] < boxY && + line_plane_intersection.mV[VY] > -boxY ) + { + intersection = (line_plane_intersection * box_rotation) + box_center; + intersection_normal = LLVector3(0.0f, 0.0f, -1.0f) * box_rotation; + return BOTTOM_SIDE; + } + } + + // should never get here unless line instersects at tangent point on edge or corner + // however such cases will be EXTREMELY rare + return NO_SIDE; +} + + +bool ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + // (0) Z + // /| \ . + // (1)| \ /|\ _.Y + // | \ \ | /| + // | |\ \ | / + // | | \(0)\ | / + // | | \ \ |/ + // | | \ \ (*)----> X + // |(3)---\---(2) + // |/ \ / + // (4)-------(5) + + // need to calculate the points of the prism so we can run ray tests with each face + F32 x = prism_scale.mV[VX]; + F32 y = prism_scale.mV[VY]; + F32 z = prism_scale.mV[VZ]; + + F32 tx = x * 2.0f / 3.0f; + F32 ty = y * 0.5f; + F32 tz = z * 2.0f / 3.0f; + + LLVector3 point0(tx-x, ty, tz); + LLVector3 point1(tx-x, -ty, tz); + LLVector3 point2(tx, ty, tz-z); + LLVector3 point3(tx-x, ty, tz-z); + LLVector3 point4(tx-x, -ty, tz-z); + LLVector3 point5(tx, -ty, tz-z); + + // transform these points into absolute frame + point0 = (point0 * prism_rotation) + prism_center; + point1 = (point1 * prism_rotation) + prism_center; + point2 = (point2 * prism_rotation) + prism_center; + point3 = (point3 * prism_rotation) + prism_center; + point4 = (point4 * prism_rotation) + prism_center; + point5 = (point5 * prism_rotation) + prism_center; + + // test ray intersection for each face + bool b_hit = false; + LLVector3 face_intersection, face_normal; + F32 distance_squared = 0.0f; + F32 temp; + + // face 0 + if (ray_direction * ( (point0 - point2) % (point5 - point2)) < 0.0f && + ray_quadrangle(ray_point, ray_direction, point5, point2, point0, intersection, intersection_normal)) + { + distance_squared = (ray_point - intersection).magVecSquared(); + b_hit = true; + } + + // face 1 + if (ray_direction * ( (point0 - point3) % (point2 - point3)) < 0.0f && + ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 2 + if (ray_direction * ( (point1 - point4) % (point3 - point4)) < 0.0f && + ray_quadrangle(ray_point, ray_direction, point3, point4, point1, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 3 + if (ray_direction * ( (point5 - point4) % (point1 - point4)) < 0.0f && + ray_triangle(ray_point, ray_direction, point1, point4, point5, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 4 + if (ray_direction * ( (point4 - point5) % (point2 - point5)) < 0.0f && + ray_quadrangle(ray_point, ray_direction, point2, point5, point4, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + return b_hit; +} + + +bool ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + F32 a = 0.5f * F_SQRT3; // height of unit triangle + F32 b = 1.0f / F_SQRT3; // distance of center of unit triangle to each point + F32 c = F_SQRT2 / F_SQRT3; // height of unit tetrahedron + F32 d = 0.5f * F_SQRT3 / F_SQRT2; // distance of center of tetrahedron to each point + + // if we want the tetrahedron to have unit height (c = 1.0) then we need to divide + // each constant by hieght of a unit tetrahedron + F32 oo_c = 1.0f / c; + a = a * oo_c; + b = b * oo_c; + c = 1.0f; + d = d * oo_c; + F32 e = 0.5f * oo_c; + + LLVector3 point0( 0.0f, 0.0f, t_scale.mV[VZ] * d); + LLVector3 point1(t_scale.mV[VX] * b, 0.0f, t_scale.mV[VZ] * (d-c)); + LLVector3 point2(t_scale.mV[VX] * (b-a), e * t_scale.mV[VY], t_scale.mV[VZ] * (d-c)); + LLVector3 point3(t_scale.mV[VX] * (b-a), -e * t_scale.mV[VY], t_scale.mV[VZ] * (d-c)); + + // transform these points into absolute frame + point0 = (point0 * t_rotation) + t_center; + point1 = (point1 * t_rotation) + t_center; + point2 = (point2 * t_rotation) + t_center; + point3 = (point3 * t_rotation) + t_center; + + // test ray intersection for each face + bool b_hit = false; + LLVector3 face_intersection, face_normal; + F32 distance_squared = 1.0e12f; + F32 temp; + + // face 0 + if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f && + ray_triangle(ray_point, ray_direction, point1, point2, point0, intersection, intersection_normal)) + { + distance_squared = (ray_point - intersection).magVecSquared(); + b_hit = true; + } + + // face 1 + if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f && + ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 2 + if (ray_direction * ( (point1 - point3) % (point0 - point3)) < 0.0f && + ray_triangle(ray_point, ray_direction, point3, point1, point0, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 3 + if (ray_direction * ( (point2 - point3) % (point1 - point3)) < 0.0f && + ray_triangle(ray_point, ray_direction, point3, point2, point1, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + return b_hit; +} + + +bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + // center of mass of pyramid is located 1/4 its height from the base + F32 x = 0.5f * p_scale.mV[VX]; + F32 y = 0.5f * p_scale.mV[VY]; + F32 z = 0.25f * p_scale.mV[VZ]; + + LLVector3 point0(0.0f, 0.0f, p_scale.mV[VZ] - z); + LLVector3 point1( x, y, -z); + LLVector3 point2(-x, y, -z); + LLVector3 point3(-x, -y, -z); + LLVector3 point4( x, -y, -z); + + // transform these points into absolute frame + point0 = (point0 * p_rotation) + p_center; + point1 = (point1 * p_rotation) + p_center; + point2 = (point2 * p_rotation) + p_center; + point3 = (point3 * p_rotation) + p_center; + point4 = (point4 * p_rotation) + p_center; + + // test ray intersection for each face + bool b_hit = false; + LLVector3 face_intersection, face_normal; + F32 distance_squared = 1.0e12f; + F32 temp; + + // face 0 + if (ray_direction * ( (point1 - point4) % (point0 - point4)) < 0.0f && + ray_triangle(ray_point, ray_direction, point4, point1, point0, intersection, intersection_normal)) + { + distance_squared = (ray_point - intersection).magVecSquared(); + b_hit = true; + } + + // face 1 + if (ray_direction * ( (point2 - point1) % (point0 - point1)) < 0.0f && + ray_triangle(ray_point, ray_direction, point1, point2, point0, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 2 + if (ray_direction * ( (point3 - point2) % (point0 - point2)) < 0.0f && + ray_triangle(ray_point, ray_direction, point2, point3, point0, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 3 + if (ray_direction * ( (point4 - point3) % (point0 - point3)) < 0.0f && + ray_triangle(ray_point, ray_direction, point3, point4, point0, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + distance_squared = temp; + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + distance_squared = (ray_point - face_intersection).magVecSquared(); + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + // face 4 + if (ray_direction * ( (point3 - point4) % (point2 - point4)) < 0.0f && + ray_quadrangle(ray_point, ray_direction, point4, point3, point2, face_intersection, face_normal)) + { + if (b_hit) + { + temp = (ray_point - face_intersection).magVecSquared(); + if (temp < distance_squared) + { + intersection = face_intersection; + intersection_normal = face_normal; + } + } + else + { + intersection = face_intersection; + intersection_normal = face_normal; + b_hit = true; + } + } + + return b_hit; +} + + +bool linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, + LLVector3 &intersection) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_circle(point_a, ray_direction, circle_center, plane_normal, circle_radius, intersection)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +bool linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_triangle(point_a, ray_direction, point_0, point_1, point_2, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +bool linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_quadrangle(point_a, ray_direction, point_0, point_1, point_2, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +bool linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &sphere_center, F32 sphere_radius, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_sphere(point_a, ray_direction, sphere_center, sphere_radius, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_cylinder(point_a, ray_direction, cyl_center, cyl_scale, cyl_rotation, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 direction = point_b - point_a; + if (direction.isNull()) + { + return NO_SIDE; + } + + F32 segment_length = direction.normVec(); + U32 box_side = ray_box(point_a, direction, box_center, box_scale, box_rotation, intersection, intersection_normal); + if (NO_SIDE == box_side || segment_length < (intersection - point_a).magVec()) + { + return NO_SIDE; + } + + return box_side; +} + + +bool linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_prism(point_a, ray_direction, prism_center, prism_scale, prism_rotation, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +bool linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_tetrahedron(point_a, ray_direction, t_center, t_scale, t_rotation, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} + + +bool linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal) +{ + LLVector3 ray_direction = point_b - point_a; + F32 segment_length = ray_direction.normVec(); + + if (ray_pyramid(point_a, ray_direction, p_center, p_scale, p_rotation, intersection, intersection_normal)) + { + if (segment_length >= (point_a - intersection).magVec()) + { + return true; + } + } + return false; +} diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index 8892347f9b..b55f29aef6 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -1,229 +1,229 @@ -/** - * @file raytrace.h - * @brief Ray intersection tests for primitives. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_RAYTRACE_H -#define LL_RAYTRACE_H - -class LLVector3; -class LLQuaternion; - -// All functions produce results in the same reference frame as the arguments. -// -// Any arguments of the form "foo_direction" or "foo_normal" are assumed to -// be normalized, or normalized vectors are stored in them. -// -// Vector arguments of the form "shape_scale" represent the scale of the -// object along the three axes. -// -// All functions return the expected true or false, unless otherwise noted. -// When false is returned, any resulting values that might have been stored -// are undefined. -// -// Rays are defined by a "ray_point" and a "ray_direction" (unit). -// -// Lines are defined by a "line_point" and a "line_direction" (unit). -// -// Line segements are defined by "point_a" and "point_b", and for intersection -// purposes are assumed to point from "point_a" to "point_b". -// -// A ray is different from a line in that it starts at a point and extends -// in only one direction. -// -// Intersection normals always point outside the object, normal to the object's -// surface at the point of intersection. -// -// Object rotations passed as quaternions are expected to rotate from the -// object's local frame to the absolute frame. So, if "foo" is a vector in -// the object's local frame, then "foo * object_rotation" is in the absolute -// frame. - - -// returns true if line is not parallel to plane. -bool line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, - LLVector3 &intersection); - - -// returns true if line is not parallel to plane. -bool ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &plane_point, const LLVector3 plane_normal, - LLVector3 &intersection); - - -bool ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, - LLVector3 &intersection); - -// point_0 through point_2 define the plane_normal via the right-hand rule: -// circle from point_0 to point_2 with fingers ==> thumb points in direction of normal -bool ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -// point_0 is the lower-left corner, point_1 is the lower-right, point_2 is the upper-right -// right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right -// ==> thumb points in direction of normal -// assumes a parallelogram, so point_3 is determined by the other points -bool ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &sphere_center, F32 sphere_radius, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -// finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom", -// and by the cylinder radius "cyl_radius" -bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -// this function doesn't just return a bool because the return is currently -// used to decide how to break up boxes that have been hit by shots... -// a hack that will probably be changed later -// -// returns a number representing the side of the box that was hit by the ray, -// or NO_SIDE if intersection test failed. -U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -/* TODO -bool ray_ellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_cone(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &cone_tip, const LLVector3 &cone_bottom, - const LLVector3 &cone_scale, const LLQuaternion &cone_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); -*/ - - -bool ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - - -/* TODO -bool ray_hemiellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation, - const LLVector3 &e_cut_normal, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_hemisphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &sphere_center, F32 sphere_radius, const LLVector3 &sphere_cut_normal, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_hemicylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &cyl_top, const LLVector3 &cyl_bottom, F32 cyl_radius, - const LLVector3 &cyl_cut_normal, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool ray_hemicone(const LLVector3 &ray_point, const LLVector3 &ray_direction, - const LLVector3 &cone_tip, const LLVector3 &cone_bottom, - const LLVector3 &cone_scale, const LLVector3 &cyl_cut_normal, - LLVector3 &intersection, LLVector3 &intersection_normal); -*/ - - -bool linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, - LLVector3 &intersection); - -// point_0 through point_2 define the plane_normal via the right-hand rule: -// circle from point_0 to point_2 with fingers ==> thumb points in direction of normal -bool linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -// point_0 is the lower-left corner, point_1 is the lower-right, point_2 is the upper-right -// right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right -// ==> thumb points in direction of normal -// assumes a parallelogram, so point_3 is determined by the other points -bool linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &sphere_center, F32 sphere_radius, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -// finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom", -// and by the cylinder radius "cyl_radius" -bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -// this function doesn't just return a bool because the return is currently -// used to decide how to break up boxes that have been hit by shots... -// a hack that will probably be changed later -// -// returns a number representing the side of the box that was hit by the ray, -// or NO_SIDE if intersection test failed. -U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); - - -bool linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, - const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, - LLVector3 &intersection, LLVector3 &intersection_normal); -#endif +/** + * @file raytrace.h + * @brief Ray intersection tests for primitives. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_RAYTRACE_H +#define LL_RAYTRACE_H + +class LLVector3; +class LLQuaternion; + +// All functions produce results in the same reference frame as the arguments. +// +// Any arguments of the form "foo_direction" or "foo_normal" are assumed to +// be normalized, or normalized vectors are stored in them. +// +// Vector arguments of the form "shape_scale" represent the scale of the +// object along the three axes. +// +// All functions return the expected true or false, unless otherwise noted. +// When false is returned, any resulting values that might have been stored +// are undefined. +// +// Rays are defined by a "ray_point" and a "ray_direction" (unit). +// +// Lines are defined by a "line_point" and a "line_direction" (unit). +// +// Line segements are defined by "point_a" and "point_b", and for intersection +// purposes are assumed to point from "point_a" to "point_b". +// +// A ray is different from a line in that it starts at a point and extends +// in only one direction. +// +// Intersection normals always point outside the object, normal to the object's +// surface at the point of intersection. +// +// Object rotations passed as quaternions are expected to rotate from the +// object's local frame to the absolute frame. So, if "foo" is a vector in +// the object's local frame, then "foo * object_rotation" is in the absolute +// frame. + + +// returns true if line is not parallel to plane. +bool line_plane(const LLVector3 &line_point, const LLVector3 &line_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, + LLVector3 &intersection); + + +// returns true if line is not parallel to plane. +bool ray_plane(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &plane_point, const LLVector3 plane_normal, + LLVector3 &intersection); + + +bool ray_circle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, + LLVector3 &intersection); + +// point_0 through point_2 define the plane_normal via the right-hand rule: +// circle from point_0 to point_2 with fingers ==> thumb points in direction of normal +bool ray_triangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +// point_0 is the lower-left corner, point_1 is the lower-right, point_2 is the upper-right +// right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right +// ==> thumb points in direction of normal +// assumes a parallelogram, so point_3 is determined by the other points +bool ray_quadrangle(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_sphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &sphere_center, F32 sphere_radius, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +// finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom", +// and by the cylinder radius "cyl_radius" +bool ray_cylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +// this function doesn't just return a bool because the return is currently +// used to decide how to break up boxes that have been hit by shots... +// a hack that will probably be changed later +// +// returns a number representing the side of the box that was hit by the ray, +// or NO_SIDE if intersection test failed. +U32 ray_box(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +/* TODO +bool ray_ellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_cone(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &cone_tip, const LLVector3 &cone_bottom, + const LLVector3 &cone_scale, const LLQuaternion &cone_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); +*/ + + +bool ray_prism(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_tetrahedron(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_pyramid(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + + +/* TODO +bool ray_hemiellipsoid(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &e_center, const LLVector3 &e_scale, const LLQuaternion &e_rotation, + const LLVector3 &e_cut_normal, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_hemisphere(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &sphere_center, F32 sphere_radius, const LLVector3 &sphere_cut_normal, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_hemicylinder(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &cyl_top, const LLVector3 &cyl_bottom, F32 cyl_radius, + const LLVector3 &cyl_cut_normal, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool ray_hemicone(const LLVector3 &ray_point, const LLVector3 &ray_direction, + const LLVector3 &cone_tip, const LLVector3 &cone_bottom, + const LLVector3 &cone_scale, const LLVector3 &cyl_cut_normal, + LLVector3 &intersection, LLVector3 &intersection_normal); +*/ + + +bool linesegment_circle(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &circle_center, const LLVector3 plane_normal, F32 circle_radius, + LLVector3 &intersection); + +// point_0 through point_2 define the plane_normal via the right-hand rule: +// circle from point_0 to point_2 with fingers ==> thumb points in direction of normal +bool linesegment_triangle(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +// point_0 is the lower-left corner, point_1 is the lower-right, point_2 is the upper-right +// right-hand-rule... curl fingers from lower-left toward lower-right then toward upper-right +// ==> thumb points in direction of normal +// assumes a parallelogram, so point_3 is determined by the other points +bool linesegment_quadrangle(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &point_0, const LLVector3 &point_1, const LLVector3 &point_2, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool linesegment_sphere(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &sphere_center, F32 sphere_radius, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +// finite right cylinder is defined by end centers: "cyl_top", "cyl_bottom", +// and by the cylinder radius "cyl_radius" +bool linesegment_cylinder(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &cyl_center, const LLVector3 &cyl_scale, const LLQuaternion &cyl_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +// this function doesn't just return a bool because the return is currently +// used to decide how to break up boxes that have been hit by shots... +// a hack that will probably be changed later +// +// returns a number representing the side of the box that was hit by the ray, +// or NO_SIDE if intersection test failed. +U32 linesegment_box(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &box_center, const LLVector3 &box_scale, const LLQuaternion &box_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool linesegment_prism(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &prism_center, const LLVector3 &prism_scale, const LLQuaternion &prism_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool linesegment_tetrahedron(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &t_center, const LLVector3 &t_scale, const LLQuaternion &t_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); + + +bool linesegment_pyramid(const LLVector3 &point_a, const LLVector3 &point_b, + const LLVector3 &p_center, const LLVector3 &p_scale, const LLQuaternion &p_rotation, + LLVector3 &intersection, LLVector3 &intersection_normal); +#endif diff --git a/indra/llmath/tests/llbbox_test.cpp b/indra/llmath/tests/llbbox_test.cpp index 0847420a3e..bd6bd9e4b0 100644 --- a/indra/llmath/tests/llbbox_test.cpp +++ b/indra/llmath/tests/llbbox_test.cpp @@ -1,367 +1,367 @@ -/** - * @file llbbox_test.cpp - * @author Martin Reddy - * @date 2009-06-25 - * @brief Test for llbbox.cpp. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "../test/lltut.h" - -#include "../llbbox.h" - - -#define ANGLE (3.14159265f / 2.0f) -#define APPROX_EQUAL(a, b) (dist_vec_squared((a),(b)) < 1e-10) - -namespace tut -{ - struct LLBBoxData - { - }; - - typedef test_group factory; - typedef factory::object object; -} - -namespace -{ - tut::factory llbbox_test_factory("LLBBox"); -} - -namespace tut -{ - template<> template<> - void object::test<1>() - { - // - // test the default constructor - // - - LLBBox bbox1; - - ensure_equals("Default bbox min", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - ensure_equals("Default bbox max", bbox1.getMaxLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - ensure_equals("Default bbox pos agent", bbox1.getPositionAgent(), LLVector3(0.0f, 0.0f, 0.0f)); - ensure_equals("Default bbox rotation", bbox1.getRotation(), LLQuaternion(0.0f, 0.0f, 0.0f, 1.0f)); - } - - template<> template<> - void object::test<2>() - { - // - // test the non-default constructor - // - - LLBBox bbox2(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), - LLVector3(2.0f, 3.0f, 4.0f), LLVector3(4.0f, 5.0f, 6.0f)); - - ensure_equals("Custom bbox min", bbox2.getMinLocal(), LLVector3(2.0f, 3.0f, 4.0f)); - ensure_equals("Custom bbox max", bbox2.getMaxLocal(), LLVector3(4.0f, 5.0f, 6.0f)); - ensure_equals("Custom bbox pos agent", bbox2.getPositionAgent(), LLVector3(1.0f, 2.0f, 3.0f)); - ensure_equals("Custom bbox rotation", bbox2.getRotation(), LLQuaternion(0.0f, 0.0f, 0.0f, 1.0f)); - } - - template<> template<> - void object::test<3>() - { - // - // test the setMinLocal() method - // - LLBBox bbox2; - bbox2.setMinLocal(LLVector3(3.0f, 3.0f, 3.0f)); - ensure_equals("Custom bbox min (2)", bbox2.getMinLocal(), LLVector3(3.0f, 3.0f, 3.0f)); - } - - template<> template<> - void object::test<4>() - { - // - // test the setMaxLocal() method - // - LLBBox bbox2; - bbox2.setMaxLocal(LLVector3(5.0f, 5.0f, 5.0f)); - ensure_equals("Custom bbox max (2)", bbox2.getMaxLocal(), LLVector3(5.0f, 5.0f, 5.0f)); - } - - template<> template<> - void object::test<5>() - { - // - // test the getCenterLocal() method - // - - ensure_equals("Default bbox local center", LLBBox().getCenterLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - - LLBBox bbox1(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), - LLVector3(2.0f, 4.0f, 6.0f), LLVector3(4.0f, 6.0f, 8.0f)); - - ensure_equals("Custom bbox center local", bbox1.getCenterLocal(), LLVector3(3.0f, 5.0f, 7.0f)); - - LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(0.0f, 0.0f, 1.0f)), - LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); - - ensure_equals("Custom bbox center local with rot", bbox2.getCenterLocal(), LLVector3(3.0f, 3.0f, 3.0f)); - } - - template<> template<> - void object::test<6>() - { - // - // test the getCenterAgent() - // - - ensure_equals("Default bbox agent center", LLBBox().getCenterAgent(), LLVector3(0.0f, 0.0f, 0.0f)); - - LLBBox bbox1(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), - LLVector3(2.0f, 4.0f, 6.0f), LLVector3(4.0f, 6.0f, 8.0f)); - - ensure_equals("Custom bbox center agent", bbox1.getCenterAgent(), LLVector3(4.0f, 7.0f, 10.0f)); - - LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(0.0f, 0.0f, 1.0f)), - LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); - - ensure("Custom bbox center agent with rot", APPROX_EQUAL(bbox2.getCenterAgent(), LLVector3(-2.0f, 4.0f, 4.0f))); - } - - template<> template<> - void object::test<7>() - { - // - // test the getExtentLocal() method - // - - ensure_equals("Default bbox local extent", LLBBox().getExtentLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - - LLBBox bbox1(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), - LLVector3(2.0f, 4.0f, 6.0f), LLVector3(4.0f, 6.0f, 8.0f)); - - ensure_equals("Custom bbox extent local", bbox1.getExtentLocal(), LLVector3(2.0f, 2.0f, 2.0f)); - - LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(0.0f, 0.0f, 1.0f)), - LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); - - ensure_equals("Custom bbox extent local with rot", bbox1.getExtentLocal(), LLVector3(2.0f, 2.0f, 2.0f)); - } - - template<> template<> - void object::test<8>() - { - // - // test the addPointLocal() method - // - - LLBBox bbox1; - bbox1.addPointLocal(LLVector3(1.0f, 1.0f, 1.0f)); - bbox1.addPointLocal(LLVector3(3.0f, 3.0f, 3.0f)); - - ensure_equals("addPointLocal center local (1)", bbox1.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); - ensure_equals("addPointLocal center agent (1)", bbox1.getCenterAgent(), LLVector3(2.0f, 2.0f, 2.0f)); - ensure_equals("addPointLocal min (1)", bbox1.getMinLocal(), LLVector3(1.0f, 1.0f, 1.0f)); - ensure_equals("addPointLocal max (1)", bbox1.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); - - bbox1.addPointLocal(LLVector3(0.0f, 0.0f, 0.0f)); - bbox1.addPointLocal(LLVector3(1.0f, 1.0f, 1.0f)); - bbox1.addPointLocal(LLVector3(2.0f, 2.0f, 2.0f)); - - ensure_equals("addPointLocal center local (2)", bbox1.getCenterLocal(), LLVector3(1.5f, 1.5f, 1.5f)); - ensure_equals("addPointLocal min (2)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - ensure_equals("addPointLocal max (2)", bbox1.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); - } - - template<> template<> - void object::test<9>() - { - // - // test the addBBoxLocal() method - // - - LLBBox bbox1; - bbox1.addBBoxLocal(LLBBox(LLVector3(), LLQuaternion(), - LLVector3(0.0f, 0.0f, 0.0f), LLVector3(3.0f, 3.0f, 3.0f))); - - ensure_equals("addPointLocal center local (3)", bbox1.getCenterLocal(), LLVector3(1.5f, 1.5f, 1.5f)); - ensure_equals("addPointLocal min (3)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - ensure_equals("addPointLocal max (3)", bbox1.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); - - bbox1.addBBoxLocal(LLBBox(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(5.0f, 5.0f, 5.0f), LLVector3(10.0f, 10.0f, 10.0f))); - - ensure_equals("addPointLocal center local (4)", bbox1.getCenterLocal(), LLVector3(5.0f, 5.0f, 5.0f)); - ensure_equals("addPointLocal center agent (4)", bbox1.getCenterAgent(), LLVector3(5.0f, 5.0f, 5.0f)); - ensure_equals("addPointLocal min (4)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - ensure_equals("addPointLocal max (4)", bbox1.getMaxLocal(), LLVector3(10.0f, 10.0f, 10.0f)); - } - - template<> template<> - void object::test<10>() - { - // - // test the addPointAgent() method - // - - LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(1.0, 0.0, 0.0, 1.0), - LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); - - bbox1.addPointAgent(LLVector3(1.0f, 1.0f, 1.0f)); - bbox1.addPointAgent(LLVector3(3.0f, 3.0f, 3.0f)); - - ensure_equals("addPointAgent center local (1)", bbox1.getCenterLocal(), LLVector3(2.0f, 2.0f, -2.0f)); - ensure_equals("addPointAgent center agent (1)", bbox1.getCenterAgent(), LLVector3(3.0f, 3.0f, 7.0f)); - ensure_equals("addPointAgent min (1)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, -4.0f)); - ensure_equals("addPointAgent max (1)", bbox1.getMaxLocal(), LLVector3(4.0f, 4.0f, 0.0f)); - } - - template<> template<> - void object::test<11>() - { - // - // test the addBBoxAgent() method - // - - LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(1.0, 0.0, 0.0, 1.0), - LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); - - bbox1.addPointAgent(LLVector3(1.0f, 1.0f, 1.0f)); - bbox1.addPointAgent(LLVector3(3.0f, 3.0f, 3.0f)); - - bbox1.addBBoxLocal(LLBBox(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(5.0f, 5.0f, 5.0f), LLVector3(10.0f, 10.0f, 10.0f))); - - ensure_equals("addPointAgent center local (2)", bbox1.getCenterLocal(), LLVector3(5.0f, 5.0f, 3.0f)); - ensure_equals("addPointAgent center agent (2)", bbox1.getCenterAgent(), LLVector3(6.0f, -10.0f, 8.0f)); - ensure_equals("addPointAgent min (2)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, -4.0f)); - ensure_equals("addPointAgent max (2)", bbox1.getMaxLocal(), LLVector3(10.0f, 10.0f, 10.0f)); - } - - template<> template<> - void object::test<12>() - { - // - // test the expand() method - // - - LLBBox bbox1; - bbox1.expand(0.0); - - ensure_equals("Zero-expanded Default BBox center", bbox1.getCenterLocal(), LLVector3(0.0f, 0.0f, 0.0f)); - - LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); - bbox2.expand(0.0); - - ensure_equals("Zero-expanded center local", bbox2.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); - ensure_equals("Zero-expanded center agent", bbox2.getCenterAgent(), LLVector3(3.0f, 3.0f, 3.0f)); - ensure_equals("Zero-expanded min", bbox2.getMinLocal(), LLVector3(1.0f, 1.0f, 1.0f)); - ensure_equals("Zero-expanded max", bbox2.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); - - bbox2.expand(0.5); - - ensure_equals("Positive-expanded center", bbox2.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); - ensure_equals("Positive-expanded min", bbox2.getMinLocal(), LLVector3(0.5f, 0.5f, 0.5f)); - ensure_equals("Positive-expanded max", bbox2.getMaxLocal(), LLVector3(3.5f, 3.5f, 3.5f)); - - bbox2.expand(-1.0); - - ensure_equals("Negative-expanded center", bbox2.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); - ensure_equals("Negative-expanded min", bbox2.getMinLocal(), LLVector3(1.5f, 1.5f, 1.5f)); - ensure_equals("Negative-expanded max", bbox2.getMaxLocal(), LLVector3(2.5f, 2.5f, 2.5f)); - } - - template<> template<> - void object::test<13>() - { - // - // test the localToAgent() method - // - - LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); - - ensure_equals("localToAgent(1,2,3)", bbox1.localToAgent(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(2.0f, 3.0f, 4.0f)); - - LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(1.0f, 0.0f, 0.0f)), - LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); - - ensure("localToAgent(1,2,3) rot", APPROX_EQUAL(bbox2.localToAgent(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(2.0f, -2.0f, 3.0f))); - } - - template<> template<> - void object::test<14>() - { - // - // test the agentToLocal() method - // - - LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); - - ensure_equals("agentToLocal(1,2,3)", bbox1.agentToLocal(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(0.0f, 1.0f, 2.0f)); - ensure_equals("agentToLocal(localToAgent)", bbox1.agentToLocal(bbox1.localToAgent(LLVector3(1.0f, 2.0f, 3.0f))), - LLVector3(1.0f, 2.0f, 3.0f)); - - LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(1.0f, 0.0f, 0.0f)), - LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); - - ensure("agentToLocal(1,2,3) rot", APPROX_EQUAL(bbox2.agentToLocal(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(0.0f, 2.0f, -1.0f))); - ensure("agentToLocal(localToAgent) rot", APPROX_EQUAL(bbox2.agentToLocal(bbox2.localToAgent(LLVector3(1.0f, 2.0f, 3.0f))), - LLVector3(1.0f, 2.0f, 3.0f))); - } - - template<> template<> - void object::test<15>() - { - // - // test the containsPointLocal() method - // - - LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); - - ensure("containsPointLocal(0,0,0)", bbox1.containsPointLocal(LLVector3(0.0f, 0.0f, 0.0f)) == false); - ensure("containsPointLocal(1,2,3)", bbox1.containsPointLocal(LLVector3(1.0f, 2.0f, 3.0f)) == true); - ensure("containsPointLocal(0.999,2,3)", bbox1.containsPointLocal(LLVector3(0.999f, 2.0f, 3.0f)) == false); - ensure("containsPointLocal(3,4,5)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.0f)) == true); - ensure("containsPointLocal(3,4,5.001)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.001f)) == false); - } - - template<> template<> - void object::test<16>() - { - // - // test the containsPointAgent() method - // - - LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), - LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); - - ensure("containsPointAgent(0,0,0)", bbox1.containsPointAgent(LLVector3(0.0f, 0.0f, 0.0f)) == false); - ensure("containsPointAgent(2,3,4)", bbox1.containsPointAgent(LLVector3(2.0f, 3.0f, 4.0f)) == true); - ensure("containsPointAgent(2,2.999,4)", bbox1.containsPointAgent(LLVector3(2.0f, 2.999f, 4.0f)) == false); - ensure("containsPointAgent(4,5,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.0f, 6.0f)) == true); - ensure("containsPointAgent(4,5.001,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.001f, 6.0f)) == false); - } -} - +/** + * @file llbbox_test.cpp + * @author Martin Reddy + * @date 2009-06-25 + * @brief Test for llbbox.cpp. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "../test/lltut.h" + +#include "../llbbox.h" + + +#define ANGLE (3.14159265f / 2.0f) +#define APPROX_EQUAL(a, b) (dist_vec_squared((a),(b)) < 1e-10) + +namespace tut +{ + struct LLBBoxData + { + }; + + typedef test_group factory; + typedef factory::object object; +} + +namespace +{ + tut::factory llbbox_test_factory("LLBBox"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + // + // test the default constructor + // + + LLBBox bbox1; + + ensure_equals("Default bbox min", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("Default bbox max", bbox1.getMaxLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("Default bbox pos agent", bbox1.getPositionAgent(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("Default bbox rotation", bbox1.getRotation(), LLQuaternion(0.0f, 0.0f, 0.0f, 1.0f)); + } + + template<> template<> + void object::test<2>() + { + // + // test the non-default constructor + // + + LLBBox bbox2(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), + LLVector3(2.0f, 3.0f, 4.0f), LLVector3(4.0f, 5.0f, 6.0f)); + + ensure_equals("Custom bbox min", bbox2.getMinLocal(), LLVector3(2.0f, 3.0f, 4.0f)); + ensure_equals("Custom bbox max", bbox2.getMaxLocal(), LLVector3(4.0f, 5.0f, 6.0f)); + ensure_equals("Custom bbox pos agent", bbox2.getPositionAgent(), LLVector3(1.0f, 2.0f, 3.0f)); + ensure_equals("Custom bbox rotation", bbox2.getRotation(), LLQuaternion(0.0f, 0.0f, 0.0f, 1.0f)); + } + + template<> template<> + void object::test<3>() + { + // + // test the setMinLocal() method + // + LLBBox bbox2; + bbox2.setMinLocal(LLVector3(3.0f, 3.0f, 3.0f)); + ensure_equals("Custom bbox min (2)", bbox2.getMinLocal(), LLVector3(3.0f, 3.0f, 3.0f)); + } + + template<> template<> + void object::test<4>() + { + // + // test the setMaxLocal() method + // + LLBBox bbox2; + bbox2.setMaxLocal(LLVector3(5.0f, 5.0f, 5.0f)); + ensure_equals("Custom bbox max (2)", bbox2.getMaxLocal(), LLVector3(5.0f, 5.0f, 5.0f)); + } + + template<> template<> + void object::test<5>() + { + // + // test the getCenterLocal() method + // + + ensure_equals("Default bbox local center", LLBBox().getCenterLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBox bbox1(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), + LLVector3(2.0f, 4.0f, 6.0f), LLVector3(4.0f, 6.0f, 8.0f)); + + ensure_equals("Custom bbox center local", bbox1.getCenterLocal(), LLVector3(3.0f, 5.0f, 7.0f)); + + LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(0.0f, 0.0f, 1.0f)), + LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); + + ensure_equals("Custom bbox center local with rot", bbox2.getCenterLocal(), LLVector3(3.0f, 3.0f, 3.0f)); + } + + template<> template<> + void object::test<6>() + { + // + // test the getCenterAgent() + // + + ensure_equals("Default bbox agent center", LLBBox().getCenterAgent(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBox bbox1(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), + LLVector3(2.0f, 4.0f, 6.0f), LLVector3(4.0f, 6.0f, 8.0f)); + + ensure_equals("Custom bbox center agent", bbox1.getCenterAgent(), LLVector3(4.0f, 7.0f, 10.0f)); + + LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(0.0f, 0.0f, 1.0f)), + LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); + + ensure("Custom bbox center agent with rot", APPROX_EQUAL(bbox2.getCenterAgent(), LLVector3(-2.0f, 4.0f, 4.0f))); + } + + template<> template<> + void object::test<7>() + { + // + // test the getExtentLocal() method + // + + ensure_equals("Default bbox local extent", LLBBox().getExtentLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBox bbox1(LLVector3(1.0f, 2.0f, 3.0f), LLQuaternion(), + LLVector3(2.0f, 4.0f, 6.0f), LLVector3(4.0f, 6.0f, 8.0f)); + + ensure_equals("Custom bbox extent local", bbox1.getExtentLocal(), LLVector3(2.0f, 2.0f, 2.0f)); + + LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(0.0f, 0.0f, 1.0f)), + LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); + + ensure_equals("Custom bbox extent local with rot", bbox1.getExtentLocal(), LLVector3(2.0f, 2.0f, 2.0f)); + } + + template<> template<> + void object::test<8>() + { + // + // test the addPointLocal() method + // + + LLBBox bbox1; + bbox1.addPointLocal(LLVector3(1.0f, 1.0f, 1.0f)); + bbox1.addPointLocal(LLVector3(3.0f, 3.0f, 3.0f)); + + ensure_equals("addPointLocal center local (1)", bbox1.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); + ensure_equals("addPointLocal center agent (1)", bbox1.getCenterAgent(), LLVector3(2.0f, 2.0f, 2.0f)); + ensure_equals("addPointLocal min (1)", bbox1.getMinLocal(), LLVector3(1.0f, 1.0f, 1.0f)); + ensure_equals("addPointLocal max (1)", bbox1.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); + + bbox1.addPointLocal(LLVector3(0.0f, 0.0f, 0.0f)); + bbox1.addPointLocal(LLVector3(1.0f, 1.0f, 1.0f)); + bbox1.addPointLocal(LLVector3(2.0f, 2.0f, 2.0f)); + + ensure_equals("addPointLocal center local (2)", bbox1.getCenterLocal(), LLVector3(1.5f, 1.5f, 1.5f)); + ensure_equals("addPointLocal min (2)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("addPointLocal max (2)", bbox1.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); + } + + template<> template<> + void object::test<9>() + { + // + // test the addBBoxLocal() method + // + + LLBBox bbox1; + bbox1.addBBoxLocal(LLBBox(LLVector3(), LLQuaternion(), + LLVector3(0.0f, 0.0f, 0.0f), LLVector3(3.0f, 3.0f, 3.0f))); + + ensure_equals("addPointLocal center local (3)", bbox1.getCenterLocal(), LLVector3(1.5f, 1.5f, 1.5f)); + ensure_equals("addPointLocal min (3)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("addPointLocal max (3)", bbox1.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); + + bbox1.addBBoxLocal(LLBBox(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(5.0f, 5.0f, 5.0f), LLVector3(10.0f, 10.0f, 10.0f))); + + ensure_equals("addPointLocal center local (4)", bbox1.getCenterLocal(), LLVector3(5.0f, 5.0f, 5.0f)); + ensure_equals("addPointLocal center agent (4)", bbox1.getCenterAgent(), LLVector3(5.0f, 5.0f, 5.0f)); + ensure_equals("addPointLocal min (4)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("addPointLocal max (4)", bbox1.getMaxLocal(), LLVector3(10.0f, 10.0f, 10.0f)); + } + + template<> template<> + void object::test<10>() + { + // + // test the addPointAgent() method + // + + LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(1.0, 0.0, 0.0, 1.0), + LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); + + bbox1.addPointAgent(LLVector3(1.0f, 1.0f, 1.0f)); + bbox1.addPointAgent(LLVector3(3.0f, 3.0f, 3.0f)); + + ensure_equals("addPointAgent center local (1)", bbox1.getCenterLocal(), LLVector3(2.0f, 2.0f, -2.0f)); + ensure_equals("addPointAgent center agent (1)", bbox1.getCenterAgent(), LLVector3(3.0f, 3.0f, 7.0f)); + ensure_equals("addPointAgent min (1)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, -4.0f)); + ensure_equals("addPointAgent max (1)", bbox1.getMaxLocal(), LLVector3(4.0f, 4.0f, 0.0f)); + } + + template<> template<> + void object::test<11>() + { + // + // test the addBBoxAgent() method + // + + LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(1.0, 0.0, 0.0, 1.0), + LLVector3(2.0f, 2.0f, 2.0f), LLVector3(4.0f, 4.0f, 4.0f)); + + bbox1.addPointAgent(LLVector3(1.0f, 1.0f, 1.0f)); + bbox1.addPointAgent(LLVector3(3.0f, 3.0f, 3.0f)); + + bbox1.addBBoxLocal(LLBBox(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(5.0f, 5.0f, 5.0f), LLVector3(10.0f, 10.0f, 10.0f))); + + ensure_equals("addPointAgent center local (2)", bbox1.getCenterLocal(), LLVector3(5.0f, 5.0f, 3.0f)); + ensure_equals("addPointAgent center agent (2)", bbox1.getCenterAgent(), LLVector3(6.0f, -10.0f, 8.0f)); + ensure_equals("addPointAgent min (2)", bbox1.getMinLocal(), LLVector3(0.0f, 0.0f, -4.0f)); + ensure_equals("addPointAgent max (2)", bbox1.getMaxLocal(), LLVector3(10.0f, 10.0f, 10.0f)); + } + + template<> template<> + void object::test<12>() + { + // + // test the expand() method + // + + LLBBox bbox1; + bbox1.expand(0.0); + + ensure_equals("Zero-expanded Default BBox center", bbox1.getCenterLocal(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); + bbox2.expand(0.0); + + ensure_equals("Zero-expanded center local", bbox2.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); + ensure_equals("Zero-expanded center agent", bbox2.getCenterAgent(), LLVector3(3.0f, 3.0f, 3.0f)); + ensure_equals("Zero-expanded min", bbox2.getMinLocal(), LLVector3(1.0f, 1.0f, 1.0f)); + ensure_equals("Zero-expanded max", bbox2.getMaxLocal(), LLVector3(3.0f, 3.0f, 3.0f)); + + bbox2.expand(0.5); + + ensure_equals("Positive-expanded center", bbox2.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); + ensure_equals("Positive-expanded min", bbox2.getMinLocal(), LLVector3(0.5f, 0.5f, 0.5f)); + ensure_equals("Positive-expanded max", bbox2.getMaxLocal(), LLVector3(3.5f, 3.5f, 3.5f)); + + bbox2.expand(-1.0); + + ensure_equals("Negative-expanded center", bbox2.getCenterLocal(), LLVector3(2.0f, 2.0f, 2.0f)); + ensure_equals("Negative-expanded min", bbox2.getMinLocal(), LLVector3(1.5f, 1.5f, 1.5f)); + ensure_equals("Negative-expanded max", bbox2.getMaxLocal(), LLVector3(2.5f, 2.5f, 2.5f)); + } + + template<> template<> + void object::test<13>() + { + // + // test the localToAgent() method + // + + LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); + + ensure_equals("localToAgent(1,2,3)", bbox1.localToAgent(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(2.0f, 3.0f, 4.0f)); + + LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(1.0f, 0.0f, 0.0f)), + LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); + + ensure("localToAgent(1,2,3) rot", APPROX_EQUAL(bbox2.localToAgent(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(2.0f, -2.0f, 3.0f))); + } + + template<> template<> + void object::test<14>() + { + // + // test the agentToLocal() method + // + + LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); + + ensure_equals("agentToLocal(1,2,3)", bbox1.agentToLocal(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(0.0f, 1.0f, 2.0f)); + ensure_equals("agentToLocal(localToAgent)", bbox1.agentToLocal(bbox1.localToAgent(LLVector3(1.0f, 2.0f, 3.0f))), + LLVector3(1.0f, 2.0f, 3.0f)); + + LLBBox bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(ANGLE, LLVector3(1.0f, 0.0f, 0.0f)), + LLVector3(1.0f, 1.0f, 1.0f), LLVector3(3.0f, 3.0f, 3.0f)); + + ensure("agentToLocal(1,2,3) rot", APPROX_EQUAL(bbox2.agentToLocal(LLVector3(1.0f, 2.0f, 3.0f)), LLVector3(0.0f, 2.0f, -1.0f))); + ensure("agentToLocal(localToAgent) rot", APPROX_EQUAL(bbox2.agentToLocal(bbox2.localToAgent(LLVector3(1.0f, 2.0f, 3.0f))), + LLVector3(1.0f, 2.0f, 3.0f))); + } + + template<> template<> + void object::test<15>() + { + // + // test the containsPointLocal() method + // + + LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); + + ensure("containsPointLocal(0,0,0)", bbox1.containsPointLocal(LLVector3(0.0f, 0.0f, 0.0f)) == false); + ensure("containsPointLocal(1,2,3)", bbox1.containsPointLocal(LLVector3(1.0f, 2.0f, 3.0f)) == true); + ensure("containsPointLocal(0.999,2,3)", bbox1.containsPointLocal(LLVector3(0.999f, 2.0f, 3.0f)) == false); + ensure("containsPointLocal(3,4,5)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.0f)) == true); + ensure("containsPointLocal(3,4,5.001)", bbox1.containsPointLocal(LLVector3(3.0f, 4.0f, 5.001f)) == false); + } + + template<> template<> + void object::test<16>() + { + // + // test the containsPointAgent() method + // + + LLBBox bbox1(LLVector3(1.0f, 1.0f, 1.0f), LLQuaternion(), + LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); + + ensure("containsPointAgent(0,0,0)", bbox1.containsPointAgent(LLVector3(0.0f, 0.0f, 0.0f)) == false); + ensure("containsPointAgent(2,3,4)", bbox1.containsPointAgent(LLVector3(2.0f, 3.0f, 4.0f)) == true); + ensure("containsPointAgent(2,2.999,4)", bbox1.containsPointAgent(LLVector3(2.0f, 2.999f, 4.0f)) == false); + ensure("containsPointAgent(4,5,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.0f, 6.0f)) == true); + ensure("containsPointAgent(4,5.001,6)", bbox1.containsPointAgent(LLVector3(4.0f, 5.001f, 6.0f)) == false); + } +} + diff --git a/indra/llmath/tests/llrect_test.cpp b/indra/llmath/tests/llrect_test.cpp index 5e3104e293..0fd5602d4a 100644 --- a/indra/llmath/tests/llrect_test.cpp +++ b/indra/llmath/tests/llrect_test.cpp @@ -1,526 +1,526 @@ -/** - * @file llrect_test.cpp - * @author Martin Reddy - * @date 2009-06-25 - * @brief Test for llrect.cpp. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" -#include "../llrect.h" - -namespace tut -{ - struct LLRectData - { - }; - - typedef test_group factory; - typedef factory::object object; -} - -namespace -{ - tut::factory llrect_test_factory("LLRect"); -} - -namespace tut -{ - template<> template<> - void object::test<1>() - { - // - // test the LLRect default constructor - // - - LLSD zero; - zero.append(0); zero.append(0); zero.append(0); zero.append(0); - - // default constructor - LLRect rect1; - ensure_equals("Empty rect", rect1.getValue(), zero); - ensure_equals("Empty rect left", rect1.mLeft, 0); - ensure_equals("Empty rect top", rect1.mTop, 0); - ensure_equals("Empty rect right", rect1.mRight, 0); - ensure_equals("Empty rect bottom", rect1.mBottom, 0); - ensure_equals("Empty rect width", rect1.getWidth(), 0); - ensure_equals("Empty rect height", rect1.getHeight(), 0); - ensure_equals("Empty rect centerx", rect1.getCenterX(), 0); - ensure_equals("Empty rect centery", rect1.getCenterY(), 0); - } - - template<> template<> - void object::test<2>() - { - // - // test the LLRectf default constructor - // - - LLSD zerof; - zerof.append(0.0f); zerof.append(0.0f); zerof.append(0.0f); zerof.append(0.0f); - - LLRectf rect2; - ensure_equals("Empty rectf", rect2.getValue(), zerof); - ensure_equals("Empty rectf left", rect2.mLeft, 0.0f); - ensure_equals("Empty rectf top", rect2.mTop, 0.0f); - ensure_equals("Empty rectf right", rect2.mRight, 0.0f); - ensure_equals("Empty rectf bottom", rect2.mBottom, 0.0f); - ensure_equals("Empty rectf width", rect2.getWidth(), 0.0f); - ensure_equals("Empty rectf height", rect2.getHeight(), 0.0f); - ensure_equals("Empty rectf centerx", rect2.getCenterX(), 0.0f); - ensure_equals("Empty rectf centery", rect2.getCenterY(), 0.0f); - } - - template<> template<> - void object::test<3>() - { - // - // test the LLRect constructor from another LLRect - // - - LLRect rect3(LLRect(1, 6, 7, 2)); - ensure_equals("Default rect left", rect3.mLeft, 1); - ensure_equals("Default rect top", rect3.mTop, 6); - ensure_equals("Default rect right", rect3.mRight, 7); - ensure_equals("Default rect bottom", rect3.mBottom, 2); - ensure_equals("Default rect width", rect3.getWidth(), 6); - ensure_equals("Default rect height", rect3.getHeight(), 4); - ensure_equals("Default rect centerx", rect3.getCenterX(), 4); - ensure_equals("Default rect centery", rect3.getCenterY(), 4); - } - - template<> template<> - void object::test<4>() - { - // - // test the LLRectf four-float constructor - // - - LLRectf rect4(1.0f, 5.0f, 6.0f, 2.0f); - ensure_equals("Default rectf left", rect4.mLeft, 1.0f); - ensure_equals("Default rectf top", rect4.mTop, 5.0f); - ensure_equals("Default rectf right", rect4.mRight, 6.0f); - ensure_equals("Default rectf bottom", rect4.mBottom, 2.0f); - ensure_equals("Default rectf width", rect4.getWidth(), 5.0f); - ensure_equals("Default rectf height", rect4.getHeight(), 3.0f); - ensure_equals("Default rectf centerx", rect4.getCenterX(), 3.5f); - ensure_equals("Default rectf centery", rect4.getCenterY(), 3.5f); - } - - template<> template<> - void object::test<5>() - { - // - // test the LLRectf LLSD constructor - // - - LLSD array; - array.append(-1.0f); array.append(0.0f); array.append(0.0f); array.append(-1.0f); - LLRectf rect5(array); - ensure_equals("LLSD rectf left", rect5.mLeft, -1.0f); - ensure_equals("LLSD rectf top", rect5.mTop, 0.0f); - ensure_equals("LLSD rectf right", rect5.mRight, 0.0f); - ensure_equals("LLSD rectf bottom", rect5.mBottom, -1.0f); - ensure_equals("LLSD rectf width", rect5.getWidth(), 1.0f); - ensure_equals("LLSD rectf height", rect5.getHeight(), 1.0f); - ensure_equals("LLSD rectf centerx", rect5.getCenterX(), -0.5f); - ensure_equals("LLSD rectf centery", rect5.getCenterY(), -0.5f); - } - - template<> template<> - void object::test<6>() - { - // - // test directly setting the member variables for dimensions - // - - LLRectf rectf; - - rectf.mLeft = -1.0f; - rectf.mTop = 1.0f; - rectf.mRight = 1.0f; - rectf.mBottom = -1.0f; - ensure_equals("Member-set rectf left", rectf.mLeft, -1.0f); - ensure_equals("Member-set rectf top", rectf.mTop, 1.0f); - ensure_equals("Member-set rectf right", rectf.mRight, 1.0f); - ensure_equals("Member-set rectf bottom", rectf.mBottom, -1.0f); - ensure_equals("Member-set rectf width", rectf.getWidth(), 2.0f); - ensure_equals("Member-set rectf height", rectf.getHeight(), 2.0f); - ensure_equals("Member-set rectf centerx", rectf.getCenterX(), 0.0f); - ensure_equals("Member-set rectf centery", rectf.getCenterY(), 0.0f); - } - - template<> template<> - void object::test<7>() - { - // - // test the setValue() method - // - - LLRectf rectf; - - LLSD array; - array.append(-1.0f); array.append(0.0f); array.append(0.0f); array.append(-1.0f); - rectf.setValue(array); - ensure_equals("setValue() rectf left", rectf.mLeft, -1.0f); - ensure_equals("setValue() rectf top", rectf.mTop, 0.0f); - ensure_equals("setValue() rectf right", rectf.mRight, 0.0f); - ensure_equals("setValue() rectf bottom", rectf.mBottom, -1.0f); - ensure_equals("setValue() rectf width", rectf.getWidth(), 1.0f); - ensure_equals("setValue() rectf height", rectf.getHeight(), 1.0f); - ensure_equals("setValue() rectf centerx", rectf.getCenterX(), -0.5f); - ensure_equals("setValue() rectf centery", rectf.getCenterY(), -0.5f); - } - - template<> template<> - void object::test<8>() - { - // - // test the set() method - // - - LLRect rect; - - rect.set(10, 90, 70, 10); - ensure_equals("set() rectf left", rect.mLeft, 10); - ensure_equals("set() rectf top", rect.mTop, 90); - ensure_equals("set() rectf right", rect.mRight, 70); - ensure_equals("set() rectf bottom", rect.mBottom, 10); - ensure_equals("set() rectf width", rect.getWidth(), 60); - ensure_equals("set() rectf height", rect.getHeight(), 80); - ensure_equals("set() rectf centerx", rect.getCenterX(), 40); - ensure_equals("set() rectf centery", rect.getCenterY(), 50); - } - - template<> template<> - void object::test<9>() - { - // - // test the setOriginAndSize() method - // - - LLRectf rectf; - - rectf.setOriginAndSize(0.0f, 0.0f, 2.0f, 1.0f); - ensure_equals("setOriginAndSize() rectf left", rectf.mLeft, 0.0f); - ensure_equals("setOriginAndSize() rectf top", rectf.mTop, 1.0f); - ensure_equals("setOriginAndSize() rectf right", rectf.mRight, 2.0f); - ensure_equals("setOriginAndSize() rectf bottom", rectf.mBottom, 0.0f); - ensure_equals("setOriginAndSize() rectf width", rectf.getWidth(), 2.0f); - ensure_equals("setOriginAndSize() rectf height", rectf.getHeight(), 1.0f); - ensure_equals("setOriginAndSize() rectf centerx", rectf.getCenterX(), 1.0f); - ensure_equals("setOriginAndSize() rectf centery", rectf.getCenterY(), 0.5f); - } - - template<> template<> - void object::test<10>() - { - // - // test the setLeftTopAndSize() method - // - - LLRectf rectf; - - rectf.setLeftTopAndSize(0.0f, 0.0f, 2.0f, 1.0f); - ensure_equals("setLeftTopAndSize() rectf left", rectf.mLeft, 0.0f); - ensure_equals("setLeftTopAndSize() rectf top", rectf.mTop, 0.0f); - ensure_equals("setLeftTopAndSize() rectf right", rectf.mRight, 2.0f); - ensure_equals("setLeftTopAndSize() rectf bottom", rectf.mBottom, -1.0f); - ensure_equals("setLeftTopAndSize() rectf width", rectf.getWidth(), 2.0f); - ensure_equals("setLeftTopAndSize() rectf height", rectf.getHeight(), 1.0f); - ensure_equals("setLeftTopAndSize() rectf centerx", rectf.getCenterX(), 1.0f); - ensure_equals("setLeftTopAndSize() rectf centery", rectf.getCenterY(), -0.5f); - } - - template<> template<> - void object::test<11>() - { - // - // test the setCenterAndSize() method - // - - LLRectf rectf; - - rectf.setCenterAndSize(0.0f, 0.0f, 2.0f, 1.0f); - ensure_equals("setCenterAndSize() rectf left", rectf.mLeft, -1.0f); - ensure_equals("setCenterAndSize() rectf top", rectf.mTop, 0.5f); - ensure_equals("setCenterAndSize() rectf right", rectf.mRight, 1.0f); - ensure_equals("setCenterAndSize() rectf bottom", rectf.mBottom, -0.5f); - ensure_equals("setCenterAndSize() rectf width", rectf.getWidth(), 2.0f); - ensure_equals("setCenterAndSize() rectf height", rectf.getHeight(), 1.0f); - ensure_equals("setCenterAndSize() rectf centerx", rectf.getCenterX(), 0.0f); - ensure_equals("setCenterAndSize() rectf centery", rectf.getCenterY(), 0.0f); - } - - template<> template<> - void object::test<12>() - { - // - // test the validity checking method - // - - LLRectf rectf; - - rectf.set(-1.0f, 1.0f, 1.0f, -1.0f); - ensure("BBox is valid", rectf.isValid()); - - rectf.mLeft = 2.0f; - ensure("BBox is not valid", ! rectf.isValid()); - - rectf.makeValid(); - ensure("BBox forced valid", rectf.isValid()); - - rectf.set(-1.0f, -1.0f, -1.0f, -1.0f); - ensure("BBox(0,0,0,0) is valid", rectf.isValid()); - } - - template<> template<> - void object::test<13>() - { - // - // test the null checking methods - // - - LLRectf rectf; - - rectf.set(-1.0f, 1.0f, 1.0f, -1.0f); - ensure("BBox is not Null", ! rectf.isEmpty()); - ensure("BBox notNull", rectf.notEmpty()); - - rectf.mLeft = 2.0f; - rectf.makeValid(); - ensure("BBox is now Null", rectf.isEmpty()); - - rectf.set(-1.0f, -1.0f, -1.0f, -1.0f); - ensure("BBox(0,0,0,0) is Null", rectf.isEmpty()); - } - - template<> template<> - void object::test<14>() - { - // - // test the (in)equality operators - // - - LLRectf rect1, rect2; - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(-1.0f, 0.9f, 1.0f, -1.0f); - - ensure("rect1 == rect2 (false)", ! (rect1 == rect2)); - ensure("rect1 != rect2 (true)", rect1 != rect2); - - ensure("rect1 == rect1 (true)", rect1 == rect1); - ensure("rect1 != rect1 (false)", ! (rect1 != rect1)); - } - - template<> template<> - void object::test<15>() - { - // - // test the copy constructor - // - - LLRectf rect1, rect2(rect1); - - ensure("rect1 == rect2 (true)", rect1 == rect2); - ensure("rect1 != rect2 (false)", ! (rect1 != rect2)); - } - - template<> template<> - void object::test<16>() - { - // - // test the translate() method - // - - LLRectf rect1(-1.0f, 1.0f, 1.0f, -1.0f); - LLRectf rect2(rect1); - - rect1.translate(0.0f, 0.0f); - - ensure("translate(0, 0)", rect1 == rect2); - - rect1.translate(100.0f, 100.0f); - rect1.translate(-100.0f, -100.0f); - - ensure("translate(100, 100) + translate(-100, -100)", rect1 == rect2); - - rect1.translate(10.0f, 0.0f); - rect2.set(9.0f, 1.0f, 11.0f, -1.0f); - ensure("translate(10, 0)", rect1 == rect2); - - rect1.translate(0.0f, 10.0f); - rect2.set(9.0f, 11.0f, 11.0f, 9.0f); - ensure("translate(0, 10)", rect1 == rect2); - - rect1.translate(-10.0f, -10.0f); - rect2.set(-1.0f, 1.0f, 1.0f, -1.0f); - ensure("translate(-10, -10)", rect1 == rect2); - } - - template<> template<> - void object::test<17>() - { - // - // test the stretch() method - // - - LLRectf rect1(-1.0f, 1.0f, 1.0f, -1.0f); - LLRectf rect2(rect1); - - rect1.stretch(0.0f); - ensure("stretch(0)", rect1 == rect2); - - rect1.stretch(0.0f, 0.0f); - ensure("stretch(0, 0)", rect1 == rect2); - - rect1.stretch(10.0f); - rect1.stretch(-10.0f); - ensure("stretch(10) + stretch(-10)", rect1 == rect2); - - rect1.stretch(2.0f, 1.0f); - rect2.set(-3.0f, 2.0f, 3.0f, -2.0f); - ensure("stretch(2, 1)", rect1 == rect2); - } - - - template<> template<> - void object::test<18>() - { - // - // test the unionWith() method - // - - LLRectf rect1, rect2, rect3; - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect3 = rect1; - rect3.unionWith(rect2); - ensure_equals("union with self", rect3, rect1); - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(-2.0f, 2.0f, 0.0f, 0.0f); - rect3 = rect1; - rect3.unionWith(rect2); - ensure_equals("union - overlap", rect3, LLRectf(-2.0f, 2.0f, 1.0f, -1.0f)); - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(5.0f, 10.0f, 10.0f, 5.0f); - rect3 = rect1; - rect3.unionWith(rect2); - ensure_equals("union - no overlap", rect3, LLRectf(-1.0f, 10.0f, 10.0f, -1.0f)); - } - - template<> template<> - void object::test<19>() - { - // - // test the intersectWith() methods - // - - LLRectf rect1, rect2, rect3; - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect3 = rect1; - rect3.intersectWith(rect2); - ensure_equals("intersect with self", rect3, rect1); - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(-2.0f, 2.0f, 0.0f, 0.0f); - rect3 = rect1; - rect3.intersectWith(rect2); - ensure_equals("intersect - overlap", rect3, LLRectf(-1.0f, 1.0f, 0.0f, 0.0f)); - - rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); - rect2.set(5.0f, 10.0f, 10.0f, 5.0f); - rect3 = rect1; - rect3.intersectWith(rect2); - ensure("intersect - no overlap", rect3.isEmpty()); - } - - template<> template<> - void object::test<20>() - { - // - // test the pointInRect() method - // - - LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); - - ensure("(0,0) not in rect", rect.pointInRect(0.0f, 0.0f) == false); - ensure("(2,2) in rect", rect.pointInRect(2.0f, 2.0f) == true); - ensure("(1,1) in rect", rect.pointInRect(1.0f, 1.0f) == true); - ensure("(3,3) not in rect", rect.pointInRect(3.0f, 3.0f) == false); - ensure("(2.999,2.999) in rect", rect.pointInRect(2.999f, 2.999f) == true); - ensure("(2.999,3.0) not in rect", rect.pointInRect(2.999f, 3.0f) == false); - ensure("(3.0,2.999) not in rect", rect.pointInRect(3.0f, 2.999f) == false); - } - - template<> template<> - void object::test<21>() - { - // - // test the localPointInRect() method - // - - LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); - - ensure("(0,0) in local rect", rect.localPointInRect(0.0f, 0.0f) == true); - ensure("(-0.0001,-0.0001) not in local rect", rect.localPointInRect(-0.0001f, -0.001f) == false); - ensure("(1,1) in local rect", rect.localPointInRect(1.0f, 1.0f) == true); - ensure("(2,2) not in local rect", rect.localPointInRect(2.0f, 2.0f) == false); - ensure("(1.999,1.999) in local rect", rect.localPointInRect(1.999f, 1.999f) == true); - ensure("(1.999,2.0) not in local rect", rect.localPointInRect(1.999f, 2.0f) == false); - ensure("(2.0,1.999) not in local rect", rect.localPointInRect(2.0f, 1.999f) == false); - } - - template<> template<> - void object::test<22>() - { - // - // test the clampPointToRect() method - // - - LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); - F32 x, y; - - x = 2.0f; y = 2.0f; - rect.clampPointToRect(x, y); - ensure_equals("clamp x-coord within rect", x, 2.0f); - ensure_equals("clamp y-coord within rect", y, 2.0f); - - x = -100.0f; y = 100.0f; - rect.clampPointToRect(x, y); - ensure_equals("clamp x-coord outside rect", x, 1.0f); - ensure_equals("clamp y-coord outside rect", y, 3.0f); - - x = 3.0f; y = 1.0f; - rect.clampPointToRect(x, y); - ensure_equals("clamp x-coord edge rect", x, 3.0f); - ensure_equals("clamp y-coord edge rect", y, 1.0f); - } -} +/** + * @file llrect_test.cpp + * @author Martin Reddy + * @date 2009-06-25 + * @brief Test for llrect.cpp. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" +#include "../llrect.h" + +namespace tut +{ + struct LLRectData + { + }; + + typedef test_group factory; + typedef factory::object object; +} + +namespace +{ + tut::factory llrect_test_factory("LLRect"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + // + // test the LLRect default constructor + // + + LLSD zero; + zero.append(0); zero.append(0); zero.append(0); zero.append(0); + + // default constructor + LLRect rect1; + ensure_equals("Empty rect", rect1.getValue(), zero); + ensure_equals("Empty rect left", rect1.mLeft, 0); + ensure_equals("Empty rect top", rect1.mTop, 0); + ensure_equals("Empty rect right", rect1.mRight, 0); + ensure_equals("Empty rect bottom", rect1.mBottom, 0); + ensure_equals("Empty rect width", rect1.getWidth(), 0); + ensure_equals("Empty rect height", rect1.getHeight(), 0); + ensure_equals("Empty rect centerx", rect1.getCenterX(), 0); + ensure_equals("Empty rect centery", rect1.getCenterY(), 0); + } + + template<> template<> + void object::test<2>() + { + // + // test the LLRectf default constructor + // + + LLSD zerof; + zerof.append(0.0f); zerof.append(0.0f); zerof.append(0.0f); zerof.append(0.0f); + + LLRectf rect2; + ensure_equals("Empty rectf", rect2.getValue(), zerof); + ensure_equals("Empty rectf left", rect2.mLeft, 0.0f); + ensure_equals("Empty rectf top", rect2.mTop, 0.0f); + ensure_equals("Empty rectf right", rect2.mRight, 0.0f); + ensure_equals("Empty rectf bottom", rect2.mBottom, 0.0f); + ensure_equals("Empty rectf width", rect2.getWidth(), 0.0f); + ensure_equals("Empty rectf height", rect2.getHeight(), 0.0f); + ensure_equals("Empty rectf centerx", rect2.getCenterX(), 0.0f); + ensure_equals("Empty rectf centery", rect2.getCenterY(), 0.0f); + } + + template<> template<> + void object::test<3>() + { + // + // test the LLRect constructor from another LLRect + // + + LLRect rect3(LLRect(1, 6, 7, 2)); + ensure_equals("Default rect left", rect3.mLeft, 1); + ensure_equals("Default rect top", rect3.mTop, 6); + ensure_equals("Default rect right", rect3.mRight, 7); + ensure_equals("Default rect bottom", rect3.mBottom, 2); + ensure_equals("Default rect width", rect3.getWidth(), 6); + ensure_equals("Default rect height", rect3.getHeight(), 4); + ensure_equals("Default rect centerx", rect3.getCenterX(), 4); + ensure_equals("Default rect centery", rect3.getCenterY(), 4); + } + + template<> template<> + void object::test<4>() + { + // + // test the LLRectf four-float constructor + // + + LLRectf rect4(1.0f, 5.0f, 6.0f, 2.0f); + ensure_equals("Default rectf left", rect4.mLeft, 1.0f); + ensure_equals("Default rectf top", rect4.mTop, 5.0f); + ensure_equals("Default rectf right", rect4.mRight, 6.0f); + ensure_equals("Default rectf bottom", rect4.mBottom, 2.0f); + ensure_equals("Default rectf width", rect4.getWidth(), 5.0f); + ensure_equals("Default rectf height", rect4.getHeight(), 3.0f); + ensure_equals("Default rectf centerx", rect4.getCenterX(), 3.5f); + ensure_equals("Default rectf centery", rect4.getCenterY(), 3.5f); + } + + template<> template<> + void object::test<5>() + { + // + // test the LLRectf LLSD constructor + // + + LLSD array; + array.append(-1.0f); array.append(0.0f); array.append(0.0f); array.append(-1.0f); + LLRectf rect5(array); + ensure_equals("LLSD rectf left", rect5.mLeft, -1.0f); + ensure_equals("LLSD rectf top", rect5.mTop, 0.0f); + ensure_equals("LLSD rectf right", rect5.mRight, 0.0f); + ensure_equals("LLSD rectf bottom", rect5.mBottom, -1.0f); + ensure_equals("LLSD rectf width", rect5.getWidth(), 1.0f); + ensure_equals("LLSD rectf height", rect5.getHeight(), 1.0f); + ensure_equals("LLSD rectf centerx", rect5.getCenterX(), -0.5f); + ensure_equals("LLSD rectf centery", rect5.getCenterY(), -0.5f); + } + + template<> template<> + void object::test<6>() + { + // + // test directly setting the member variables for dimensions + // + + LLRectf rectf; + + rectf.mLeft = -1.0f; + rectf.mTop = 1.0f; + rectf.mRight = 1.0f; + rectf.mBottom = -1.0f; + ensure_equals("Member-set rectf left", rectf.mLeft, -1.0f); + ensure_equals("Member-set rectf top", rectf.mTop, 1.0f); + ensure_equals("Member-set rectf right", rectf.mRight, 1.0f); + ensure_equals("Member-set rectf bottom", rectf.mBottom, -1.0f); + ensure_equals("Member-set rectf width", rectf.getWidth(), 2.0f); + ensure_equals("Member-set rectf height", rectf.getHeight(), 2.0f); + ensure_equals("Member-set rectf centerx", rectf.getCenterX(), 0.0f); + ensure_equals("Member-set rectf centery", rectf.getCenterY(), 0.0f); + } + + template<> template<> + void object::test<7>() + { + // + // test the setValue() method + // + + LLRectf rectf; + + LLSD array; + array.append(-1.0f); array.append(0.0f); array.append(0.0f); array.append(-1.0f); + rectf.setValue(array); + ensure_equals("setValue() rectf left", rectf.mLeft, -1.0f); + ensure_equals("setValue() rectf top", rectf.mTop, 0.0f); + ensure_equals("setValue() rectf right", rectf.mRight, 0.0f); + ensure_equals("setValue() rectf bottom", rectf.mBottom, -1.0f); + ensure_equals("setValue() rectf width", rectf.getWidth(), 1.0f); + ensure_equals("setValue() rectf height", rectf.getHeight(), 1.0f); + ensure_equals("setValue() rectf centerx", rectf.getCenterX(), -0.5f); + ensure_equals("setValue() rectf centery", rectf.getCenterY(), -0.5f); + } + + template<> template<> + void object::test<8>() + { + // + // test the set() method + // + + LLRect rect; + + rect.set(10, 90, 70, 10); + ensure_equals("set() rectf left", rect.mLeft, 10); + ensure_equals("set() rectf top", rect.mTop, 90); + ensure_equals("set() rectf right", rect.mRight, 70); + ensure_equals("set() rectf bottom", rect.mBottom, 10); + ensure_equals("set() rectf width", rect.getWidth(), 60); + ensure_equals("set() rectf height", rect.getHeight(), 80); + ensure_equals("set() rectf centerx", rect.getCenterX(), 40); + ensure_equals("set() rectf centery", rect.getCenterY(), 50); + } + + template<> template<> + void object::test<9>() + { + // + // test the setOriginAndSize() method + // + + LLRectf rectf; + + rectf.setOriginAndSize(0.0f, 0.0f, 2.0f, 1.0f); + ensure_equals("setOriginAndSize() rectf left", rectf.mLeft, 0.0f); + ensure_equals("setOriginAndSize() rectf top", rectf.mTop, 1.0f); + ensure_equals("setOriginAndSize() rectf right", rectf.mRight, 2.0f); + ensure_equals("setOriginAndSize() rectf bottom", rectf.mBottom, 0.0f); + ensure_equals("setOriginAndSize() rectf width", rectf.getWidth(), 2.0f); + ensure_equals("setOriginAndSize() rectf height", rectf.getHeight(), 1.0f); + ensure_equals("setOriginAndSize() rectf centerx", rectf.getCenterX(), 1.0f); + ensure_equals("setOriginAndSize() rectf centery", rectf.getCenterY(), 0.5f); + } + + template<> template<> + void object::test<10>() + { + // + // test the setLeftTopAndSize() method + // + + LLRectf rectf; + + rectf.setLeftTopAndSize(0.0f, 0.0f, 2.0f, 1.0f); + ensure_equals("setLeftTopAndSize() rectf left", rectf.mLeft, 0.0f); + ensure_equals("setLeftTopAndSize() rectf top", rectf.mTop, 0.0f); + ensure_equals("setLeftTopAndSize() rectf right", rectf.mRight, 2.0f); + ensure_equals("setLeftTopAndSize() rectf bottom", rectf.mBottom, -1.0f); + ensure_equals("setLeftTopAndSize() rectf width", rectf.getWidth(), 2.0f); + ensure_equals("setLeftTopAndSize() rectf height", rectf.getHeight(), 1.0f); + ensure_equals("setLeftTopAndSize() rectf centerx", rectf.getCenterX(), 1.0f); + ensure_equals("setLeftTopAndSize() rectf centery", rectf.getCenterY(), -0.5f); + } + + template<> template<> + void object::test<11>() + { + // + // test the setCenterAndSize() method + // + + LLRectf rectf; + + rectf.setCenterAndSize(0.0f, 0.0f, 2.0f, 1.0f); + ensure_equals("setCenterAndSize() rectf left", rectf.mLeft, -1.0f); + ensure_equals("setCenterAndSize() rectf top", rectf.mTop, 0.5f); + ensure_equals("setCenterAndSize() rectf right", rectf.mRight, 1.0f); + ensure_equals("setCenterAndSize() rectf bottom", rectf.mBottom, -0.5f); + ensure_equals("setCenterAndSize() rectf width", rectf.getWidth(), 2.0f); + ensure_equals("setCenterAndSize() rectf height", rectf.getHeight(), 1.0f); + ensure_equals("setCenterAndSize() rectf centerx", rectf.getCenterX(), 0.0f); + ensure_equals("setCenterAndSize() rectf centery", rectf.getCenterY(), 0.0f); + } + + template<> template<> + void object::test<12>() + { + // + // test the validity checking method + // + + LLRectf rectf; + + rectf.set(-1.0f, 1.0f, 1.0f, -1.0f); + ensure("BBox is valid", rectf.isValid()); + + rectf.mLeft = 2.0f; + ensure("BBox is not valid", ! rectf.isValid()); + + rectf.makeValid(); + ensure("BBox forced valid", rectf.isValid()); + + rectf.set(-1.0f, -1.0f, -1.0f, -1.0f); + ensure("BBox(0,0,0,0) is valid", rectf.isValid()); + } + + template<> template<> + void object::test<13>() + { + // + // test the null checking methods + // + + LLRectf rectf; + + rectf.set(-1.0f, 1.0f, 1.0f, -1.0f); + ensure("BBox is not Null", ! rectf.isEmpty()); + ensure("BBox notNull", rectf.notEmpty()); + + rectf.mLeft = 2.0f; + rectf.makeValid(); + ensure("BBox is now Null", rectf.isEmpty()); + + rectf.set(-1.0f, -1.0f, -1.0f, -1.0f); + ensure("BBox(0,0,0,0) is Null", rectf.isEmpty()); + } + + template<> template<> + void object::test<14>() + { + // + // test the (in)equality operators + // + + LLRectf rect1, rect2; + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(-1.0f, 0.9f, 1.0f, -1.0f); + + ensure("rect1 == rect2 (false)", ! (rect1 == rect2)); + ensure("rect1 != rect2 (true)", rect1 != rect2); + + ensure("rect1 == rect1 (true)", rect1 == rect1); + ensure("rect1 != rect1 (false)", ! (rect1 != rect1)); + } + + template<> template<> + void object::test<15>() + { + // + // test the copy constructor + // + + LLRectf rect1, rect2(rect1); + + ensure("rect1 == rect2 (true)", rect1 == rect2); + ensure("rect1 != rect2 (false)", ! (rect1 != rect2)); + } + + template<> template<> + void object::test<16>() + { + // + // test the translate() method + // + + LLRectf rect1(-1.0f, 1.0f, 1.0f, -1.0f); + LLRectf rect2(rect1); + + rect1.translate(0.0f, 0.0f); + + ensure("translate(0, 0)", rect1 == rect2); + + rect1.translate(100.0f, 100.0f); + rect1.translate(-100.0f, -100.0f); + + ensure("translate(100, 100) + translate(-100, -100)", rect1 == rect2); + + rect1.translate(10.0f, 0.0f); + rect2.set(9.0f, 1.0f, 11.0f, -1.0f); + ensure("translate(10, 0)", rect1 == rect2); + + rect1.translate(0.0f, 10.0f); + rect2.set(9.0f, 11.0f, 11.0f, 9.0f); + ensure("translate(0, 10)", rect1 == rect2); + + rect1.translate(-10.0f, -10.0f); + rect2.set(-1.0f, 1.0f, 1.0f, -1.0f); + ensure("translate(-10, -10)", rect1 == rect2); + } + + template<> template<> + void object::test<17>() + { + // + // test the stretch() method + // + + LLRectf rect1(-1.0f, 1.0f, 1.0f, -1.0f); + LLRectf rect2(rect1); + + rect1.stretch(0.0f); + ensure("stretch(0)", rect1 == rect2); + + rect1.stretch(0.0f, 0.0f); + ensure("stretch(0, 0)", rect1 == rect2); + + rect1.stretch(10.0f); + rect1.stretch(-10.0f); + ensure("stretch(10) + stretch(-10)", rect1 == rect2); + + rect1.stretch(2.0f, 1.0f); + rect2.set(-3.0f, 2.0f, 3.0f, -2.0f); + ensure("stretch(2, 1)", rect1 == rect2); + } + + + template<> template<> + void object::test<18>() + { + // + // test the unionWith() method + // + + LLRectf rect1, rect2, rect3; + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect3 = rect1; + rect3.unionWith(rect2); + ensure_equals("union with self", rect3, rect1); + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(-2.0f, 2.0f, 0.0f, 0.0f); + rect3 = rect1; + rect3.unionWith(rect2); + ensure_equals("union - overlap", rect3, LLRectf(-2.0f, 2.0f, 1.0f, -1.0f)); + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(5.0f, 10.0f, 10.0f, 5.0f); + rect3 = rect1; + rect3.unionWith(rect2); + ensure_equals("union - no overlap", rect3, LLRectf(-1.0f, 10.0f, 10.0f, -1.0f)); + } + + template<> template<> + void object::test<19>() + { + // + // test the intersectWith() methods + // + + LLRectf rect1, rect2, rect3; + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect3 = rect1; + rect3.intersectWith(rect2); + ensure_equals("intersect with self", rect3, rect1); + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(-2.0f, 2.0f, 0.0f, 0.0f); + rect3 = rect1; + rect3.intersectWith(rect2); + ensure_equals("intersect - overlap", rect3, LLRectf(-1.0f, 1.0f, 0.0f, 0.0f)); + + rect1.set(-1.0f, 1.0f, 1.0f, -1.0f); + rect2.set(5.0f, 10.0f, 10.0f, 5.0f); + rect3 = rect1; + rect3.intersectWith(rect2); + ensure("intersect - no overlap", rect3.isEmpty()); + } + + template<> template<> + void object::test<20>() + { + // + // test the pointInRect() method + // + + LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); + + ensure("(0,0) not in rect", rect.pointInRect(0.0f, 0.0f) == false); + ensure("(2,2) in rect", rect.pointInRect(2.0f, 2.0f) == true); + ensure("(1,1) in rect", rect.pointInRect(1.0f, 1.0f) == true); + ensure("(3,3) not in rect", rect.pointInRect(3.0f, 3.0f) == false); + ensure("(2.999,2.999) in rect", rect.pointInRect(2.999f, 2.999f) == true); + ensure("(2.999,3.0) not in rect", rect.pointInRect(2.999f, 3.0f) == false); + ensure("(3.0,2.999) not in rect", rect.pointInRect(3.0f, 2.999f) == false); + } + + template<> template<> + void object::test<21>() + { + // + // test the localPointInRect() method + // + + LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); + + ensure("(0,0) in local rect", rect.localPointInRect(0.0f, 0.0f) == true); + ensure("(-0.0001,-0.0001) not in local rect", rect.localPointInRect(-0.0001f, -0.001f) == false); + ensure("(1,1) in local rect", rect.localPointInRect(1.0f, 1.0f) == true); + ensure("(2,2) not in local rect", rect.localPointInRect(2.0f, 2.0f) == false); + ensure("(1.999,1.999) in local rect", rect.localPointInRect(1.999f, 1.999f) == true); + ensure("(1.999,2.0) not in local rect", rect.localPointInRect(1.999f, 2.0f) == false); + ensure("(2.0,1.999) not in local rect", rect.localPointInRect(2.0f, 1.999f) == false); + } + + template<> template<> + void object::test<22>() + { + // + // test the clampPointToRect() method + // + + LLRectf rect(1.0f, 3.0f, 3.0f, 1.0f); + F32 x, y; + + x = 2.0f; y = 2.0f; + rect.clampPointToRect(x, y); + ensure_equals("clamp x-coord within rect", x, 2.0f); + ensure_equals("clamp y-coord within rect", y, 2.0f); + + x = -100.0f; y = 100.0f; + rect.clampPointToRect(x, y); + ensure_equals("clamp x-coord outside rect", x, 1.0f); + ensure_equals("clamp y-coord outside rect", y, 3.0f); + + x = 3.0f; y = 1.0f; + rect.clampPointToRect(x, y); + ensure_equals("clamp x-coord edge rect", x, 3.0f); + ensure_equals("clamp y-coord edge rect", y, 1.0f); + } +} diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp index 63d35bee96..ff0899e975 100644 --- a/indra/llmath/tests/mathmisc_test.cpp +++ b/indra/llmath/tests/mathmisc_test.cpp @@ -1,723 +1,723 @@ -/** - * @file math.cpp - * @author Phoenix - * @date 2005-09-26 - * @brief Tests for the llmath library. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" - -#include "llcrc.h" -#include "llrand.h" -#include "lluuid.h" - -#include "../llline.h" -#include "../llmath.h" -#include "../llsphere.h" -#include "../v3math.h" - -namespace tut -{ - struct math_data - { - }; - typedef test_group math_test; - typedef math_test::object math_object; - tut::math_test tm("BasicLindenMath"); - - template<> template<> - void math_object::test<1>() - { - S32 val = 89543; - val = llabs(val); - ensure("integer absolute value 1", (89543 == val)); - val = -500; - val = llabs(val); - ensure("integer absolute value 2", (500 == val)); - } - - template<> template<> - void math_object::test<2>() - { - F32 val = -2583.4f; - val = llabs(val); - ensure("float absolute value 1", (2583.4f == val)); - val = 430903.f; - val = llabs(val); - ensure("float absolute value 2", (430903.f == val)); - } - - template<> template<> - void math_object::test<3>() - { - F64 val = 387439393.987329839; - val = llabs(val); - ensure("double absolute value 1", (387439393.987329839 == val)); - val = -8937843.9394878; - val = llabs(val); - ensure("double absolute value 2", (8937843.9394878 == val)); - } - - template<> template<> - void math_object::test<4>() - { - F32 val = 430903.9f; - S32 val1 = lltrunc(val); - ensure("float truncate value 1", (430903 == val1)); - val = -2303.9f; - val1 = lltrunc(val); - ensure("float truncate value 2", (-2303 == val1)); - } - - template<> template<> - void math_object::test<5>() - { - F64 val = 387439393.987329839 ; - S32 val1 = lltrunc(val); - ensure("float truncate value 1", (387439393 == val1)); - val = -387439393.987329839; - val1 = lltrunc(val); - ensure("float truncate value 2", (-387439393 == val1)); - } - - template<> template<> - void math_object::test<6>() - { - F32 val = 430903.2f; - S32 val1 = llfloor(val); - ensure("float llfloor value 1", (430903 == val1)); - val = -430903.9f; - val1 = llfloor(val); - ensure("float llfloor value 2", (-430904 == val1)); - } - - template<> template<> - void math_object::test<7>() - { - F32 val = 430903.2f; - S32 val1 = llceil(val); - ensure("float llceil value 1", (430904 == val1)); - val = -430903.9f; - val1 = llceil(val); - ensure("float llceil value 2", (-430903 == val1)); - } - - template<> template<> - void math_object::test<8>() - { - F32 val = 430903.2f; - S32 val1 = ll_round(val); - ensure("float ll_round value 1", (430903 == val1)); - val = -430903.9f; - val1 = ll_round(val); - ensure("float ll_round value 2", (-430904 == val1)); - } - - template<> template<> - void math_object::test<9>() - { - F32 val = 430905.2654f, nearest = 100.f; - val = ll_round(val, nearest); - ensure("float ll_round value 1", (430900 == val)); - val = -430905.2654f, nearest = 10.f; - val = ll_round(val, nearest); - ensure("float ll_round value 1", (-430910 == val)); - } - - template<> template<> - void math_object::test<10>() - { - F64 val = 430905.2654, nearest = 100.0; - val = ll_round(val, nearest); - ensure("double ll_round value 1", (430900 == val)); - val = -430905.2654, nearest = 10.0; - val = ll_round(val, nearest); - ensure("double ll_round value 1", (-430910.00000 == val)); - } - - template<> template<> - void math_object::test<11>() - { - const F32 F_PI = 3.1415926535897932384626433832795f; - F32 angle = 3506.f; - angle = llsimple_angle(angle); - ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); - angle = -431.f; - angle = llsimple_angle(angle); - ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); - } -} - -namespace tut -{ - struct uuid_data - { - LLUUID id; - }; - typedef test_group uuid_test; - typedef uuid_test::object uuid_object; - tut::uuid_test tu("LLUUID"); - - template<> template<> - void uuid_object::test<1>() - { - ensure("uuid null", id.isNull()); - id.generate(); - ensure("generate not null", id.notNull()); - id.setNull(); - ensure("set null", id.isNull()); - } - - template<> template<> - void uuid_object::test<2>() - { - id.generate(); - LLUUID a(id); - ensure_equals("copy equal", id, a); - a.generate(); - ensure_not_equals("generate not equal", id, a); - a = id; - ensure_equals("assignment equal", id, a); - } - - template<> template<> - void uuid_object::test<3>() - { - id.generate(); - LLUUID copy(id); - LLUUID mask; - mask.generate(); - copy ^= mask; - ensure_not_equals("mask not equal", id, copy); - copy ^= mask; - ensure_equals("mask back", id, copy); - } - - template<> template<> - void uuid_object::test<4>() - { - id.generate(); - std::string id_str = id.asString(); - LLUUID copy(id_str.c_str()); - ensure_equals("string serialization", id, copy); - } - -} - -namespace tut -{ - struct crc_data - { - }; - typedef test_group crc_test; - typedef crc_test::object crc_object; - tut::crc_test tc("LLCrc"); - - template<> template<> - void crc_object::test<1>() - { - /* Test buffer update and individual char update */ - const char TEST_BUFFER[] = "hello &#$)$&Nd0"; - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1); - char* rh = (char*)TEST_BUFFER; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - ensure_equals("crc update 1", c1.getCRC(), c2.getCRC()); - } - - template<> template<> - void crc_object::test<2>() - { - /* Test mixing of buffer and individual char update */ - const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$"; - const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds"; - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1); - char* rh = (char*)TEST_BUFFER2; - while(*rh != '\0') - { - c1.update(*rh); - ++rh; - } - - rh = (char*)TEST_BUFFER1; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1); - - ensure_equals("crc update 2", c1.getCRC(), c2.getCRC()); - } -} - -namespace tut -{ - struct sphere_data - { - }; - typedef test_group sphere_test; - typedef sphere_test::object sphere_object; - tut::sphere_test tsphere("LLSphere"); - - template<> template<> - void sphere_object::test<1>() - { - // test LLSphere::contains() and ::overlaps() - S32 number_of_tests = 10; - for (S32 test = 0; test < number_of_tests; ++test) - { - LLVector3 first_center(1.f, 1.f, 1.f); - F32 first_radius = 3.f; - LLSphere first_sphere( first_center, first_radius ); - - F32 half_millimeter = 0.0005f; - LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); - direction.normalize(); - - F32 distance = ll_frand(first_radius - 2.f * half_millimeter); - LLVector3 second_center = first_center + distance * direction; - F32 second_radius = first_radius - distance - half_millimeter; - LLSphere second_sphere( second_center, second_radius ); - ensure("first sphere should contain the second", first_sphere.contains(second_sphere)); - ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); - - distance = first_radius + ll_frand(first_radius); - second_center = first_center + distance * direction; - second_radius = distance - first_radius + half_millimeter; - second_sphere.set( second_center, second_radius ); - ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); - ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); - - distance = first_radius + ll_frand(first_radius) + half_millimeter; - second_center = first_center + distance * direction; - second_radius = distance - first_radius - half_millimeter; - second_sphere.set( second_center, second_radius ); - ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); - ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere)); - } - } - - template<> template<> - void sphere_object::test<2>() - { - skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only."); - - // test LLSphere::getBoundingSphere() - S32 number_of_tests = 100; - S32 number_of_spheres = 10; - F32 sphere_center_range = 32.f; - F32 sphere_radius_range = 5.f; - - for (S32 test = 0; test < number_of_tests; ++test) - { - // gegnerate a bunch of random sphere - std::vector< LLSphere > sphere_list; - for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count) - { - LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); - direction.normalize(); - F32 distance = ll_frand(sphere_center_range); - LLVector3 center = distance * direction; - F32 radius = ll_frand(sphere_radius_range); - LLSphere sphere( center, radius ); - sphere_list.push_back(sphere); - } - - // compute the bounding sphere - LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list); - - // make sure all spheres are inside the bounding sphere - { - std::vector< LLSphere >::const_iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr)); - } - } - - // TODO -- improve LLSphere::getBoundingSphere() to the point where - // we can reduce the 'expansion' in the two tests below to about - // 2 mm or less - - F32 expansion = 0.005f; - // move all spheres out a little bit - // and count how many are NOT contained - { - std::vector< LLVector3 > uncontained_directions; - std::vector< LLSphere >::iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); - direction.normalize(); - - sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction ); - if (! bounding_sphere.contains( *sphere_itr ) ) - { - uncontained_directions.push_back(direction); - } - } - ensure("when moving spheres out there should be at least two uncontained spheres", - uncontained_directions.size() > 1); - - /* TODO -- when the bounding sphere algorithm is improved we can open up this test - * at the moment it occasionally fails when the sphere collection is tight and small - * (2 meters or less) - if (2 == uncontained_directions.size() ) - { - // if there were only two uncontained spheres then - // the two directions should be nearly opposite - F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; - ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); - } - */ - } - - // compute the new bounding sphere - bounding_sphere = LLSphere::getBoundingSphere(sphere_list); - - // increase the size of all spheres a little bit - // and count how many are NOT contained - { - std::vector< LLVector3 > uncontained_directions; - std::vector< LLSphere >::iterator sphere_itr; - for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) - { - LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); - direction.normalize(); - - sphere_itr->setRadius( sphere_itr->getRadius() + expansion ); - if (! bounding_sphere.contains( *sphere_itr ) ) - { - uncontained_directions.push_back(direction); - } - } - ensure("when boosting sphere radii there should be at least two uncontained spheres", - uncontained_directions.size() > 1); - - /* TODO -- when the bounding sphere algorithm is improved we can open up this test - * at the moment it occasionally fails when the sphere collection is tight and small - * (2 meters or less) - if (2 == uncontained_directions.size() ) - { - // if there were only two uncontained spheres then - // the two directions should be nearly opposite - F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; - ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); - } - */ - } - } - } -} - -namespace tut -{ - F32 SMALL_RADIUS = 1.0f; - F32 MEDIUM_RADIUS = 5.0f; - F32 LARGE_RADIUS = 10.0f; - - struct line_data - { - }; - typedef test_group line_test; - typedef line_test::object line_object; - tut::line_test tline("LLLine"); - - template<> template<> - void line_object::test<1>() - { - // this is a test for LLLine::intersects(point) which returns true - // if the line passes within some tolerance of point - - // these tests will have some floating point error, - // so we need to specify how much error is ok - F32 allowable_relative_error = 0.00001f; - S32 number_of_tests = 100; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate some random point to be on the line - LLVector3 point_on_line( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_line.normalize(); - point_on_line *= ll_frand(LARGE_RADIUS); - - // generate some random point to "intersect" - LLVector3 random_direction ( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - random_direction.normalize(); - - LLVector3 random_offset( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - random_offset.normalize(); - random_offset *= ll_frand(SMALL_RADIUS); - - LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction - + random_offset; - - // compute the axis of approach (a unit vector between the points) - LLVector3 axis_of_approach = point - point_on_line; - axis_of_approach.normalize(); - - // compute the direction of the the first line (perp to axis_of_approach) - LLVector3 first_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - first_dir.normalize(); - F32 dot = first_dir * axis_of_approach; - first_dir -= dot * axis_of_approach; // subtract component parallel to axis - first_dir.normalize(); - - // construct the line - LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir; - LLLine line(another_point_on_line, point_on_line); - - // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS - F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS; - test_radius += (LARGE_RADIUS * allowable_relative_error); - ensure("line should pass near intersection point", line.intersects(point, test_radius)); - - test_radius = allowable_relative_error * (point - point_on_line).length(); - ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius)); - } - } - - template<> template<> - void line_object::test<2>() - { - /* - These tests fail intermittently on all platforms - see DEV-16600 - Commenting this out until dev has time to investigate. - - // this is a test for LLLine::nearestApproach(LLLIne) method - // which computes the point on a line nearest another line - - // these tests will have some floating point error, - // so we need to specify how much error is ok - // TODO -- make nearestApproach() algorithm more accurate so - // we can tighten the allowable_error. Most tests are tighter - // than one milimeter, however when doing randomized testing - // you can walk into inaccurate cases. - F32 allowable_relative_error = 0.001f; - S32 number_of_tests = 100; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate two points to be our known nearest approaches - LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - some_point.normalize(); - some_point *= ll_frand(LARGE_RADIUS); - - LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - another_point.normalize(); - another_point *= ll_frand(LARGE_RADIUS); - - // compute the axis of approach (a unit vector between the points) - LLVector3 axis_of_approach = another_point - some_point; - axis_of_approach.normalize(); - - // compute the direction of the the first line (perp to axis_of_approach) - LLVector3 first_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - F32 dot = first_dir * axis_of_approach; - first_dir -= dot * axis_of_approach; // subtract component parallel to axis - first_dir.normalize(); // normalize - - // compute the direction of the the second line - LLVector3 second_dir( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - dot = second_dir * axis_of_approach; - second_dir -= dot * axis_of_approach; - second_dir.normalize(); - - // make sure the lines aren't too parallel, - dot = fabsf(first_dir * second_dir); - if (dot > 0.99f) - { - // skip this test, we're not interested in testing - // the intractible cases - continue; - } - - // construct the lines - LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir; - LLLine first_line(first_point, some_point); - - LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir; - LLLine second_line(second_point, another_point); - - // compute the points of nearest approach - LLVector3 some_computed_point = first_line.nearestApproach(second_line); - LLVector3 another_computed_point = second_line.nearestApproach(first_line); - - // compute the error - F32 first_error = (some_point - some_computed_point).length(); - F32 scale = llmax((some_point - another_point).length(), some_point.length()); - scale = llmax(scale, another_point.length()); - scale = llmax(scale, 1.f); - F32 first_relative_error = first_error / scale; - - F32 second_error = (another_point - another_computed_point).length(); - F32 second_relative_error = second_error / scale; - - //if (first_relative_error > allowable_relative_error) - //{ - // std::cout << "first_error = " << first_error - // << " first_relative_error = " << first_relative_error - // << " scale = " << scale - // << " dir_dot = " << (first_dir * second_dir) - // << std::endl; - //} - //if (second_relative_error > allowable_relative_error) - //{ - // std::cout << "second_error = " << second_error - // << " second_relative_error = " << second_relative_error - // << " scale = " << scale - // << " dist = " << (some_point - another_point).length() - // << " dir_dot = " << (first_dir * second_dir) - // << std::endl; - //} - - // test that the errors are small - - ensure("first line should accurately compute its closest approach", - first_relative_error <= allowable_relative_error); - ensure("second line should accurately compute its closest approach", - second_relative_error <= allowable_relative_error); - } - */ - } - - F32 ALMOST_PARALLEL = 0.99f; - template<> template<> - void line_object::test<3>() - { - // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method - - // first some known tests - LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f)); - LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f)); - LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f)); - - LLLine x_line; - LLLine y_line; - LLLine z_line; - - bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane); - bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane); - bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane); - - ensure("xy and zx planes should intersect", x_success); - ensure("yz and xy planes should intersect", y_success); - ensure("zx and yz planes should intersect", z_success); - - LLVector3 direction = x_line.getDirection(); - ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f - && 0.f == direction.mV[VY] - && 0.f == direction.mV[VZ] ); - direction = y_line.getDirection(); - ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] - && fabs(direction.mV[VY]) == 1.f - && 0.f == direction.mV[VZ] ); - direction = z_line.getDirection(); - ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] - && 0.f == direction.mV[VY] - && fabs(direction.mV[VZ]) == 1.f ); - - // next some random tests - F32 allowable_relative_error = 0.0001f; - S32 number_of_tests = 20; - for (S32 test = 0; test < number_of_tests; ++test) - { - // generate the known line - LLVector3 some_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - some_point.normalize(); - some_point *= ll_frand(LARGE_RADIUS); - LLVector3 another_point( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - another_point.normalize(); - another_point *= ll_frand(LARGE_RADIUS); - LLLine known_intersection(some_point, another_point); - - // compute a plane that intersect the line - LLVector3 point_on_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_plane.normalize(); - point_on_plane *= ll_frand(LARGE_RADIUS); - LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); - plane_normal.normalize(); - LLLine first_plane(point_on_plane, point_on_plane + plane_normal); - - // compute a different plane that intersect the line - LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f, - ll_frand(2.f) - 1.f); - point_on_different_plane.normalize(); - point_on_different_plane *= ll_frand(LARGE_RADIUS); - LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); - different_plane_normal.normalize(); - LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal); - - if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL) - { - // the two planes are approximately parallel, so we won't test this case - continue; - } - - LLLine measured_intersection; - bool success = LLLine::getIntersectionBetweenTwoPlanes( - measured_intersection, - first_plane, - second_plane); - - ensure("plane intersection should succeed", success); - - F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); - ensure("measured intersection should be parallel to known intersection", - dot > ALMOST_PARALLEL); - - ensure("measured intersection should pass near known point", - measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); - } - } -} - +/** + * @file math.cpp + * @author Phoenix + * @date 2005-09-26 + * @brief Tests for the llmath library. + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" + +#include "llcrc.h" +#include "llrand.h" +#include "lluuid.h" + +#include "../llline.h" +#include "../llmath.h" +#include "../llsphere.h" +#include "../v3math.h" + +namespace tut +{ + struct math_data + { + }; + typedef test_group math_test; + typedef math_test::object math_object; + tut::math_test tm("BasicLindenMath"); + + template<> template<> + void math_object::test<1>() + { + S32 val = 89543; + val = llabs(val); + ensure("integer absolute value 1", (89543 == val)); + val = -500; + val = llabs(val); + ensure("integer absolute value 2", (500 == val)); + } + + template<> template<> + void math_object::test<2>() + { + F32 val = -2583.4f; + val = llabs(val); + ensure("float absolute value 1", (2583.4f == val)); + val = 430903.f; + val = llabs(val); + ensure("float absolute value 2", (430903.f == val)); + } + + template<> template<> + void math_object::test<3>() + { + F64 val = 387439393.987329839; + val = llabs(val); + ensure("double absolute value 1", (387439393.987329839 == val)); + val = -8937843.9394878; + val = llabs(val); + ensure("double absolute value 2", (8937843.9394878 == val)); + } + + template<> template<> + void math_object::test<4>() + { + F32 val = 430903.9f; + S32 val1 = lltrunc(val); + ensure("float truncate value 1", (430903 == val1)); + val = -2303.9f; + val1 = lltrunc(val); + ensure("float truncate value 2", (-2303 == val1)); + } + + template<> template<> + void math_object::test<5>() + { + F64 val = 387439393.987329839 ; + S32 val1 = lltrunc(val); + ensure("float truncate value 1", (387439393 == val1)); + val = -387439393.987329839; + val1 = lltrunc(val); + ensure("float truncate value 2", (-387439393 == val1)); + } + + template<> template<> + void math_object::test<6>() + { + F32 val = 430903.2f; + S32 val1 = llfloor(val); + ensure("float llfloor value 1", (430903 == val1)); + val = -430903.9f; + val1 = llfloor(val); + ensure("float llfloor value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<7>() + { + F32 val = 430903.2f; + S32 val1 = llceil(val); + ensure("float llceil value 1", (430904 == val1)); + val = -430903.9f; + val1 = llceil(val); + ensure("float llceil value 2", (-430903 == val1)); + } + + template<> template<> + void math_object::test<8>() + { + F32 val = 430903.2f; + S32 val1 = ll_round(val); + ensure("float ll_round value 1", (430903 == val1)); + val = -430903.9f; + val1 = ll_round(val); + ensure("float ll_round value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<9>() + { + F32 val = 430905.2654f, nearest = 100.f; + val = ll_round(val, nearest); + ensure("float ll_round value 1", (430900 == val)); + val = -430905.2654f, nearest = 10.f; + val = ll_round(val, nearest); + ensure("float ll_round value 1", (-430910 == val)); + } + + template<> template<> + void math_object::test<10>() + { + F64 val = 430905.2654, nearest = 100.0; + val = ll_round(val, nearest); + ensure("double ll_round value 1", (430900 == val)); + val = -430905.2654, nearest = 10.0; + val = ll_round(val, nearest); + ensure("double ll_round value 1", (-430910.00000 == val)); + } + + template<> template<> + void math_object::test<11>() + { + const F32 F_PI = 3.1415926535897932384626433832795f; + F32 angle = 3506.f; + angle = llsimple_angle(angle); + ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); + angle = -431.f; + angle = llsimple_angle(angle); + ensure("llsimple_angle value 1", (angle <=F_PI && angle >= -F_PI)); + } +} + +namespace tut +{ + struct uuid_data + { + LLUUID id; + }; + typedef test_group uuid_test; + typedef uuid_test::object uuid_object; + tut::uuid_test tu("LLUUID"); + + template<> template<> + void uuid_object::test<1>() + { + ensure("uuid null", id.isNull()); + id.generate(); + ensure("generate not null", id.notNull()); + id.setNull(); + ensure("set null", id.isNull()); + } + + template<> template<> + void uuid_object::test<2>() + { + id.generate(); + LLUUID a(id); + ensure_equals("copy equal", id, a); + a.generate(); + ensure_not_equals("generate not equal", id, a); + a = id; + ensure_equals("assignment equal", id, a); + } + + template<> template<> + void uuid_object::test<3>() + { + id.generate(); + LLUUID copy(id); + LLUUID mask; + mask.generate(); + copy ^= mask; + ensure_not_equals("mask not equal", id, copy); + copy ^= mask; + ensure_equals("mask back", id, copy); + } + + template<> template<> + void uuid_object::test<4>() + { + id.generate(); + std::string id_str = id.asString(); + LLUUID copy(id_str.c_str()); + ensure_equals("string serialization", id, copy); + } + +} + +namespace tut +{ + struct crc_data + { + }; + typedef test_group crc_test; + typedef crc_test::object crc_object; + tut::crc_test tc("LLCrc"); + + template<> template<> + void crc_object::test<1>() + { + /* Test buffer update and individual char update */ + const char TEST_BUFFER[] = "hello &#$)$&Nd0"; + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER, sizeof(TEST_BUFFER) - 1); + char* rh = (char*)TEST_BUFFER; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + ensure_equals("crc update 1", c1.getCRC(), c2.getCRC()); + } + + template<> template<> + void crc_object::test<2>() + { + /* Test mixing of buffer and individual char update */ + const char TEST_BUFFER1[] = "Split Buffer one $^%$%#@$"; + const char TEST_BUFFER2[] = "Split Buffer two )(8723#5dsds"; + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER1, sizeof(TEST_BUFFER1) - 1); + char* rh = (char*)TEST_BUFFER2; + while(*rh != '\0') + { + c1.update(*rh); + ++rh; + } + + rh = (char*)TEST_BUFFER1; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + c2.update((U8*)TEST_BUFFER2, sizeof(TEST_BUFFER2) - 1); + + ensure_equals("crc update 2", c1.getCRC(), c2.getCRC()); + } +} + +namespace tut +{ + struct sphere_data + { + }; + typedef test_group sphere_test; + typedef sphere_test::object sphere_object; + tut::sphere_test tsphere("LLSphere"); + + template<> template<> + void sphere_object::test<1>() + { + // test LLSphere::contains() and ::overlaps() + S32 number_of_tests = 10; + for (S32 test = 0; test < number_of_tests; ++test) + { + LLVector3 first_center(1.f, 1.f, 1.f); + F32 first_radius = 3.f; + LLSphere first_sphere( first_center, first_radius ); + + F32 half_millimeter = 0.0005f; + LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); + direction.normalize(); + + F32 distance = ll_frand(first_radius - 2.f * half_millimeter); + LLVector3 second_center = first_center + distance * direction; + F32 second_radius = first_radius - distance - half_millimeter; + LLSphere second_sphere( second_center, second_radius ); + ensure("first sphere should contain the second", first_sphere.contains(second_sphere)); + ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); + + distance = first_radius + ll_frand(first_radius); + second_center = first_center + distance * direction; + second_radius = distance - first_radius + half_millimeter; + second_sphere.set( second_center, second_radius ); + ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); + ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere)); + + distance = first_radius + ll_frand(first_radius) + half_millimeter; + second_center = first_center + distance * direction; + second_radius = distance - first_radius - half_millimeter; + second_sphere.set( second_center, second_radius ); + ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere)); + ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere)); + } + } + + template<> template<> + void sphere_object::test<2>() + { + skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only."); + + // test LLSphere::getBoundingSphere() + S32 number_of_tests = 100; + S32 number_of_spheres = 10; + F32 sphere_center_range = 32.f; + F32 sphere_radius_range = 5.f; + + for (S32 test = 0; test < number_of_tests; ++test) + { + // gegnerate a bunch of random sphere + std::vector< LLSphere > sphere_list; + for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count) + { + LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); + direction.normalize(); + F32 distance = ll_frand(sphere_center_range); + LLVector3 center = distance * direction; + F32 radius = ll_frand(sphere_radius_range); + LLSphere sphere( center, radius ); + sphere_list.push_back(sphere); + } + + // compute the bounding sphere + LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list); + + // make sure all spheres are inside the bounding sphere + { + std::vector< LLSphere >::const_iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr)); + } + } + + // TODO -- improve LLSphere::getBoundingSphere() to the point where + // we can reduce the 'expansion' in the two tests below to about + // 2 mm or less + + F32 expansion = 0.005f; + // move all spheres out a little bit + // and count how many are NOT contained + { + std::vector< LLVector3 > uncontained_directions; + std::vector< LLSphere >::iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); + direction.normalize(); + + sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction ); + if (! bounding_sphere.contains( *sphere_itr ) ) + { + uncontained_directions.push_back(direction); + } + } + ensure("when moving spheres out there should be at least two uncontained spheres", + uncontained_directions.size() > 1); + + /* TODO -- when the bounding sphere algorithm is improved we can open up this test + * at the moment it occasionally fails when the sphere collection is tight and small + * (2 meters or less) + if (2 == uncontained_directions.size() ) + { + // if there were only two uncontained spheres then + // the two directions should be nearly opposite + F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; + ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); + } + */ + } + + // compute the new bounding sphere + bounding_sphere = LLSphere::getBoundingSphere(sphere_list); + + // increase the size of all spheres a little bit + // and count how many are NOT contained + { + std::vector< LLVector3 > uncontained_directions; + std::vector< LLSphere >::iterator sphere_itr; + for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) + { + LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter(); + direction.normalize(); + + sphere_itr->setRadius( sphere_itr->getRadius() + expansion ); + if (! bounding_sphere.contains( *sphere_itr ) ) + { + uncontained_directions.push_back(direction); + } + } + ensure("when boosting sphere radii there should be at least two uncontained spheres", + uncontained_directions.size() > 1); + + /* TODO -- when the bounding sphere algorithm is improved we can open up this test + * at the moment it occasionally fails when the sphere collection is tight and small + * (2 meters or less) + if (2 == uncontained_directions.size() ) + { + // if there were only two uncontained spheres then + // the two directions should be nearly opposite + F32 dir_dot = uncontained_directions[0] * uncontained_directions[1]; + ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f); + } + */ + } + } + } +} + +namespace tut +{ + F32 SMALL_RADIUS = 1.0f; + F32 MEDIUM_RADIUS = 5.0f; + F32 LARGE_RADIUS = 10.0f; + + struct line_data + { + }; + typedef test_group line_test; + typedef line_test::object line_object; + tut::line_test tline("LLLine"); + + template<> template<> + void line_object::test<1>() + { + // this is a test for LLLine::intersects(point) which returns true + // if the line passes within some tolerance of point + + // these tests will have some floating point error, + // so we need to specify how much error is ok + F32 allowable_relative_error = 0.00001f; + S32 number_of_tests = 100; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate some random point to be on the line + LLVector3 point_on_line( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_line.normalize(); + point_on_line *= ll_frand(LARGE_RADIUS); + + // generate some random point to "intersect" + LLVector3 random_direction ( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + random_direction.normalize(); + + LLVector3 random_offset( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + random_offset.normalize(); + random_offset *= ll_frand(SMALL_RADIUS); + + LLVector3 point = point_on_line + MEDIUM_RADIUS * random_direction + + random_offset; + + // compute the axis of approach (a unit vector between the points) + LLVector3 axis_of_approach = point - point_on_line; + axis_of_approach.normalize(); + + // compute the direction of the the first line (perp to axis_of_approach) + LLVector3 first_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + first_dir.normalize(); + F32 dot = first_dir * axis_of_approach; + first_dir -= dot * axis_of_approach; // subtract component parallel to axis + first_dir.normalize(); + + // construct the line + LLVector3 another_point_on_line = point_on_line + ll_frand(LARGE_RADIUS) * first_dir; + LLLine line(another_point_on_line, point_on_line); + + // test that the intersection point is within MEDIUM_RADIUS + SMALL_RADIUS + F32 test_radius = MEDIUM_RADIUS + SMALL_RADIUS; + test_radius += (LARGE_RADIUS * allowable_relative_error); + ensure("line should pass near intersection point", line.intersects(point, test_radius)); + + test_radius = allowable_relative_error * (point - point_on_line).length(); + ensure("line should intersect point used to define it", line.intersects(point_on_line, test_radius)); + } + } + + template<> template<> + void line_object::test<2>() + { + /* + These tests fail intermittently on all platforms - see DEV-16600 + Commenting this out until dev has time to investigate. + + // this is a test for LLLine::nearestApproach(LLLIne) method + // which computes the point on a line nearest another line + + // these tests will have some floating point error, + // so we need to specify how much error is ok + // TODO -- make nearestApproach() algorithm more accurate so + // we can tighten the allowable_error. Most tests are tighter + // than one milimeter, however when doing randomized testing + // you can walk into inaccurate cases. + F32 allowable_relative_error = 0.001f; + S32 number_of_tests = 100; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate two points to be our known nearest approaches + LLVector3 some_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + some_point.normalize(); + some_point *= ll_frand(LARGE_RADIUS); + + LLVector3 another_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + another_point.normalize(); + another_point *= ll_frand(LARGE_RADIUS); + + // compute the axis of approach (a unit vector between the points) + LLVector3 axis_of_approach = another_point - some_point; + axis_of_approach.normalize(); + + // compute the direction of the the first line (perp to axis_of_approach) + LLVector3 first_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + F32 dot = first_dir * axis_of_approach; + first_dir -= dot * axis_of_approach; // subtract component parallel to axis + first_dir.normalize(); // normalize + + // compute the direction of the the second line + LLVector3 second_dir( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + dot = second_dir * axis_of_approach; + second_dir -= dot * axis_of_approach; + second_dir.normalize(); + + // make sure the lines aren't too parallel, + dot = fabsf(first_dir * second_dir); + if (dot > 0.99f) + { + // skip this test, we're not interested in testing + // the intractible cases + continue; + } + + // construct the lines + LLVector3 first_point = some_point + ll_frand(LARGE_RADIUS) * first_dir; + LLLine first_line(first_point, some_point); + + LLVector3 second_point = another_point + ll_frand(LARGE_RADIUS) * second_dir; + LLLine second_line(second_point, another_point); + + // compute the points of nearest approach + LLVector3 some_computed_point = first_line.nearestApproach(second_line); + LLVector3 another_computed_point = second_line.nearestApproach(first_line); + + // compute the error + F32 first_error = (some_point - some_computed_point).length(); + F32 scale = llmax((some_point - another_point).length(), some_point.length()); + scale = llmax(scale, another_point.length()); + scale = llmax(scale, 1.f); + F32 first_relative_error = first_error / scale; + + F32 second_error = (another_point - another_computed_point).length(); + F32 second_relative_error = second_error / scale; + + //if (first_relative_error > allowable_relative_error) + //{ + // std::cout << "first_error = " << first_error + // << " first_relative_error = " << first_relative_error + // << " scale = " << scale + // << " dir_dot = " << (first_dir * second_dir) + // << std::endl; + //} + //if (second_relative_error > allowable_relative_error) + //{ + // std::cout << "second_error = " << second_error + // << " second_relative_error = " << second_relative_error + // << " scale = " << scale + // << " dist = " << (some_point - another_point).length() + // << " dir_dot = " << (first_dir * second_dir) + // << std::endl; + //} + + // test that the errors are small + + ensure("first line should accurately compute its closest approach", + first_relative_error <= allowable_relative_error); + ensure("second line should accurately compute its closest approach", + second_relative_error <= allowable_relative_error); + } + */ + } + + F32 ALMOST_PARALLEL = 0.99f; + template<> template<> + void line_object::test<3>() + { + // this is a test for LLLine::getIntersectionBetweenTwoPlanes() method + + // first some known tests + LLLine xy_plane(LLVector3(0.f, 0.f, 2.f), LLVector3(0.f, 0.f, 3.f)); + LLLine yz_plane(LLVector3(2.f, 0.f, 0.f), LLVector3(3.f, 0.f, 0.f)); + LLLine zx_plane(LLVector3(0.f, 2.f, 0.f), LLVector3(0.f, 3.f, 0.f)); + + LLLine x_line; + LLLine y_line; + LLLine z_line; + + bool x_success = LLLine::getIntersectionBetweenTwoPlanes(x_line, xy_plane, zx_plane); + bool y_success = LLLine::getIntersectionBetweenTwoPlanes(y_line, yz_plane, xy_plane); + bool z_success = LLLine::getIntersectionBetweenTwoPlanes(z_line, zx_plane, yz_plane); + + ensure("xy and zx planes should intersect", x_success); + ensure("yz and xy planes should intersect", y_success); + ensure("zx and yz planes should intersect", z_success); + + LLVector3 direction = x_line.getDirection(); + ensure("x_line should be parallel to x_axis", fabs(direction.mV[VX]) == 1.f + && 0.f == direction.mV[VY] + && 0.f == direction.mV[VZ] ); + direction = y_line.getDirection(); + ensure("y_line should be parallel to y_axis", 0.f == direction.mV[VX] + && fabs(direction.mV[VY]) == 1.f + && 0.f == direction.mV[VZ] ); + direction = z_line.getDirection(); + ensure("z_line should be parallel to z_axis", 0.f == direction.mV[VX] + && 0.f == direction.mV[VY] + && fabs(direction.mV[VZ]) == 1.f ); + + // next some random tests + F32 allowable_relative_error = 0.0001f; + S32 number_of_tests = 20; + for (S32 test = 0; test < number_of_tests; ++test) + { + // generate the known line + LLVector3 some_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + some_point.normalize(); + some_point *= ll_frand(LARGE_RADIUS); + LLVector3 another_point( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + another_point.normalize(); + another_point *= ll_frand(LARGE_RADIUS); + LLLine known_intersection(some_point, another_point); + + // compute a plane that intersect the line + LLVector3 point_on_plane( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_plane.normalize(); + point_on_plane *= ll_frand(LARGE_RADIUS); + LLVector3 plane_normal = (point_on_plane - some_point) % known_intersection.getDirection(); + plane_normal.normalize(); + LLLine first_plane(point_on_plane, point_on_plane + plane_normal); + + // compute a different plane that intersect the line + LLVector3 point_on_different_plane( ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f, + ll_frand(2.f) - 1.f); + point_on_different_plane.normalize(); + point_on_different_plane *= ll_frand(LARGE_RADIUS); + LLVector3 different_plane_normal = (point_on_different_plane - another_point) % known_intersection.getDirection(); + different_plane_normal.normalize(); + LLLine second_plane(point_on_different_plane, point_on_different_plane + different_plane_normal); + + if (fabs(plane_normal * different_plane_normal) > ALMOST_PARALLEL) + { + // the two planes are approximately parallel, so we won't test this case + continue; + } + + LLLine measured_intersection; + bool success = LLLine::getIntersectionBetweenTwoPlanes( + measured_intersection, + first_plane, + second_plane); + + ensure("plane intersection should succeed", success); + + F32 dot = fabs(known_intersection.getDirection() * measured_intersection.getDirection()); + ensure("measured intersection should be parallel to known intersection", + dot > ALMOST_PARALLEL); + + ensure("measured intersection should pass near known point", + measured_intersection.intersects(some_point, LARGE_RADIUS * allowable_relative_error)); + } + } +} + diff --git a/indra/llmath/tests/v2math_test.cpp b/indra/llmath/tests/v2math_test.cpp index 229edc56f5..860e3ef672 100644 --- a/indra/llmath/tests/v2math_test.cpp +++ b/indra/llmath/tests/v2math_test.cpp @@ -1,448 +1,448 @@ -/** - * @file v2math_test.cpp - * @author Adroit - * @date 2007-02 - * @brief v2math test cases. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" - -#include "../v2math.h" - - -namespace tut -{ - struct v2math_data - { - }; - typedef test_group v2math_test; - typedef v2math_test::object v2math_object; - tut::v2math_test v2math_testcase("v2math_h"); - - template<> template<> - void v2math_object::test<1>() - { - LLVector2 vec2; - ensure("LLVector2:Fail to initialize ", (0.f == vec2.mV[VX] && 0.f == vec2.mV[VY])); - - F32 x =2.0f, y = 3.2f ; - LLVector2 vec3(x,y); - ensure("LLVector2(F32 x, F32 y):Fail to initialize ", (x == vec3.mV[VX]) && (y == vec3.mV[VY])); - - const F32 vec[2] = {3.2f, 4.5f}; - LLVector2 vec4(vec); - ensure("LLVector2(const F32 *vec):Fail to initialize ", (vec[0] == vec4.mV[VX]) && (vec[1] == vec4.mV[VY])); - - vec4.clearVec(); - ensure("clearVec():Fail to clean the values ", (0.f == vec4.mV[VX] && 0.f == vec4.mV[VY])); - - vec3.zeroVec(); - ensure("zeroVec():Fail to fill the zero ", (0.f == vec3.mV[VX] && 0.f == vec3.mV[VY])); - } - - template<> template<> - void v2math_object::test<2>() - { - F32 x = 123.356f, y = 2387.453f; - LLVector2 vec2,vec3; - vec2.setVec(x, y); - ensure("1:setVec: Fail ", (x == vec2.mV[VX]) && (y == vec2.mV[VY])); - - vec3.setVec(vec2); - ensure("2:setVec: Fail " ,(vec2 == vec3)); - - vec3.zeroVec(); - const F32 vec[2] = {3.24653f, 457653.4f}; - vec3.setVec(vec); - ensure("3:setVec: Fail ", (vec[0] == vec3.mV[VX]) && (vec[1] == vec3.mV[VY])); - } - - template<> template<> - void v2math_object::test<3>() - { - F32 x = 2.2345f, y = 3.5678f ; - LLVector2 vec2(x,y); - ensure("magVecSquared:Fail ", is_approx_equal(vec2.magVecSquared(), (x*x + y*y))); - ensure("magVec:Fail ", is_approx_equal(vec2.magVec(), (F32) sqrt(x*x + y*y))); - } - - template<> template<> - void v2math_object::test<4>() - { - F32 x =-2.0f, y = -3.0f ; - LLVector2 vec2(x,y); - ensure_equals("abs():Fail", vec2.abs(), true); - ensure("abs() x", is_approx_equal(vec2.mV[VX], 2.f)); - ensure("abs() y", is_approx_equal(vec2.mV[VY], 3.f)); - - ensure("isNull():Fail ", false == vec2.isNull()); //Returns true if vector has a _very_small_ length - - x =.00000001f, y = .000001001f; - vec2.setVec(x, y); - ensure("isNull(): Fail ", true == vec2.isNull()); - } - - template<> template<> - void v2math_object::test<5>() - { - F32 x =1.f, y = 2.f; - LLVector2 vec2(x, y), vec3; - vec3 = vec3.scaleVec(vec2); - ensure("scaleVec: Fail ", vec3.mV[VX] == 0. && vec3.mV[VY] == 0.); - ensure("isExactlyZero(): Fail", true == vec3.isExactlyZero()); - - vec3.setVec(2.f, 1.f); - vec3 = vec3.scaleVec(vec2); - ensure("scaleVec: Fail ", (2.f == vec3.mV[VX]) && (2.f == vec3.mV[VY])); - ensure("isExactlyZero():Fail", false == vec3.isExactlyZero()); - } - - template<> template<> - void v2math_object::test<6>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3(x2, y2), vec4; - vec4 = vec2 + vec3 ; - val1 = x1+x2; - val2 = y1+y2; - ensure("1:operator+ failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); - - vec2.clearVec(); - vec3.clearVec(); - x1 = -.235f, y1 = -24.32f, x2 = -2.3f, y2 = 1.f; - vec2.setVec(x1, y1); - vec3.setVec(x2, y2); - vec4 = vec2 + vec3; - val1 = x1+x2; - val2 = y1+y2; - ensure("2:operator+ failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); - } - - template<> template<> - void v2math_object::test<7>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3(x2, y2), vec4; - vec4 = vec2 - vec3 ; - val1 = x1-x2; - val2 = y1-y2; - ensure("1:operator- failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); - - vec2.clearVec(); - vec3.clearVec(); - vec4.clearVec(); - x1 = -.235f, y1 = -24.32f, x2 = -2.3f, y2 = 1.f; - vec2.setVec(x1, y1); - vec3.setVec(x2, y2); - vec4 = vec2 - vec3; - val1 = x1-x2; - val2 = y1-y2; - ensure("2:operator- failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); - } - - template<> template<> - void v2math_object::test<8>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3(x2, y2); - val1 = vec2 * vec3; - val2 = x1*x2 + y1*y2; - ensure("1:operator* failed",(val1 == val2)); - - vec3.clearVec(); - F32 mulVal = 4.332f; - vec3 = vec2 * mulVal; - val1 = x1*mulVal; - val2 = y1*mulVal; - ensure("2:operator* failed",(val1 == vec3.mV[VX]) && (val2 == vec3.mV[VY])); - - vec3.clearVec(); - vec3 = mulVal * vec2; - ensure("3:operator* failed",(val1 == vec3.mV[VX]) && (val2 == vec3.mV[VY])); - } - - template<> template<> - void v2math_object::test<9>() - { - F32 x1 =1.f, y1 = 2.f, div = 3.2f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3; - vec3 = vec2 / div; - val1 = x1 / div; - val2 = y1 / div; - ensure("1:operator/ failed", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY])); - - vec3.clearVec(); - x1 = -.235f, y1 = -24.32f, div = -2.2f; - vec2.setVec(x1, y1); - vec3 = vec2 / div; - val1 = x1 / div; - val2 = y1 / div; - ensure("2:operator/ failed", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY])); - } - - template<> template<> - void v2math_object::test<10>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3(x2, y2), vec4; - vec4 = vec2 % vec3; - val1 = x1*y2 - x2*y1; - val2 = y1*x2 - y2*x1; - ensure("1:operator% failed",(val1 == vec4.mV[VX]) && (val2 == vec4.mV[VY])); - - vec2.clearVec(); - vec3.clearVec(); - vec4.clearVec(); - x1 = -.235f, y1 = -24.32f, x2 = -2.3f, y2 = 1.f; - vec2.setVec(x1, y1); - vec3.setVec(x2, y2); - vec4 = vec2 % vec3; - val1 = x1*y2 - x2*y1; - val2 = y1*x2 - y2*x1; - ensure("2:operator% failed",(val1 == vec4.mV[VX]) && (val2 == vec4.mV[VY])); - } - template<> template<> - void v2math_object::test<11>() - { - F32 x1 =1.f, y1 = 2.f; - LLVector2 vec2(x1, y1), vec3(x1, y1); - ensure("1:operator== failed",(vec2 == vec3)); - - vec2.clearVec(); - vec3.clearVec(); - x1 = -.235f, y1 = -24.32f; - vec2.setVec(x1, y1); - vec3.setVec(vec2); - ensure("2:operator== failed",(vec2 == vec3)); - } - - template<> template<> - void v2math_object::test<12>() - { - F32 x1 = 1.f, y1 = 2.f,x2 = 2.332f, y2 = -1.23f; - LLVector2 vec2(x1, y1), vec3(x2, y2); - ensure("1:operator!= failed",(vec2 != vec3)); - - vec2.clearVec(); - vec3.clearVec(); - vec2.setVec(x1, y1); - vec3.setVec(vec2); - ensure("2:operator!= failed", (false == (vec2 != vec3))); - } - template<> template<> - void v2math_object::test<13>() - { - F32 x1 = 1.f, y1 = 2.f,x2 = 2.332f, y2 = -1.23f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3(x2, y2); - vec2 +=vec3; - val1 = x1+x2; - val2 = y1+y2; - ensure("1:operator+= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); - - vec2.setVec(x1, y1); - vec2 -=vec3; - val1 = x1-x2; - val2 = y1-y2; - ensure("2:operator-= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); - - vec2.clearVec(); - vec3.clearVec(); - x1 = -21.000466f, y1 = 2.98382f,x2 = 0.332f, y2 = -01.23f; - vec2.setVec(x1, y1); - vec3.setVec(x2, y2); - vec2 +=vec3; - val1 = x1+x2; - val2 = y1+y2; - ensure("3:operator+= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); - - vec2.setVec(x1, y1); - vec2 -=vec3; - val1 = x1-x2; - val2 = y1-y2; - ensure("4:operator-= failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY])); - } - - template<> template<> - void v2math_object::test<14>() - { - F32 x1 =1.f, y1 = 2.f; - F32 val1, val2, mulVal = 4.332f; - LLVector2 vec2(x1, y1); - vec2 /=mulVal; - val1 = x1 / mulVal; - val2 = y1 / mulVal; - ensure("1:operator/= failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY])); - - vec2.clearVec(); - x1 = .213f, y1 = -2.34f, mulVal = -.23f; - vec2.setVec(x1, y1); - vec2 /=mulVal; - val1 = x1 / mulVal; - val2 = y1 / mulVal; - ensure("2:operator/= failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY])); - } - - template<> template<> - void v2math_object::test<15>() - { - F32 x1 =1.f, y1 = 2.f; - F32 val1, val2, mulVal = 4.332f; - LLVector2 vec2(x1, y1); - vec2 *=mulVal; - val1 = x1*mulVal; - val2 = y1*mulVal; - ensure("1:operator*= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); - - vec2.clearVec(); - x1 = .213f, y1 = -2.34f, mulVal = -.23f; - vec2.setVec(x1, y1); - vec2 *=mulVal; - val1 = x1*mulVal; - val2 = y1*mulVal; - ensure("2:operator*= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); - } - - template<> template<> - void v2math_object::test<16>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; - F32 val1, val2; - LLVector2 vec2(x1, y1), vec3(x2, y2); - vec2 %= vec3; - val1 = x1*y2 - x2*y1; - val2 = y1*x2 - y2*x1; - ensure("1:operator%= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); - } - - template<> template<> - void v2math_object::test<17>() - { - F32 x1 =1.f, y1 = 2.f; - LLVector2 vec2(x1, y1),vec3; - vec3 = -vec2; - ensure("1:operator- failed",(-vec3 == vec2)); - } - - template<> template<> - void v2math_object::test<18>() - { - F32 x1 =1.f, y1 = 2.f; - std::ostringstream stream1, stream2; - LLVector2 vec2(x1, y1),vec3; - stream1 << vec2; - vec3.setVec(x1, y1); - stream2 << vec3; - ensure("1:operator << failed",(stream1.str() == stream2.str())); - } - - template<> template<> - void v2math_object::test<19>() - { - F32 x1 =1.0f, y1 = 2.0f, x2 = -.32f, y2 = .2234f; - LLVector2 vec2(x1, y1),vec3(x2, y2); - ensure("1:operator < failed",(vec3 < vec2)); - - x1 = 1.0f, y1 = 2.0f, x2 = 1.0f, y2 = 3.2234f; - vec2.setVec(x1, y1); - vec3.setVec(x2, y2); - ensure("2:operator < failed", (false == (vec3 < vec2))); - } - - template<> template<> - void v2math_object::test<20>() - { - F32 x1 =1.0f, y1 = 2.0f; - LLVector2 vec2(x1, y1); - ensure("1:operator [] failed",( x1 == vec2[0])); - ensure("2:operator [] failed",( y1 == vec2[1])); - - vec2.clearVec(); - x1 = 23.0f, y1 = -.2361f; - vec2.setVec(x1, y1); - F32 ref1 = vec2[0]; - ensure("3:operator [] failed", ( ref1 == x1)); - F32 ref2 = vec2[1]; - ensure("4:operator [] failed", ( ref2 == y1)); - } - - template<> template<> - void v2math_object::test<21>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -.32f, y2 = .2234f; - F32 val1, val2; - LLVector2 vec2(x1, y1),vec3(x2, y2); - val1 = dist_vec_squared2D(vec2, vec3); - val2 = (x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2); - ensure_equals("dist_vec_squared2D values are not equal",val2, val1); - - val1 = dist_vec_squared(vec2, vec3); - ensure_equals("dist_vec_squared values are not equal",val2, val1); - - val1 = dist_vec(vec2, vec3); - val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2)); - ensure_equals("dist_vec values are not equal",val2, val1); - } - - template<> template<> - void v2math_object::test<22>() - { - F32 x1 =1.f, y1 = 2.f, x2 = -.32f, y2 = .2234f,fVal = .0121f; - F32 val1, val2; - LLVector2 vec2(x1, y1),vec3(x2, y2); - LLVector2 vec4 = lerp(vec2, vec3, fVal); - val1 = x1 + (x2 - x1) * fVal; - val2 = y1 + (y2 - y1) * fVal; - ensure("lerp values are not equal", ((val1 == vec4.mV[VX]) && (val2 == vec4.mV[VY]))); - } - - template<> template<> - void v2math_object::test<23>() - { - F32 x1 =1.f, y1 = 2.f; - F32 val1, val2; - LLVector2 vec2(x1, y1); - - F32 vecMag = vec2.normVec(); - F32 mag = (F32) sqrt(x1*x1 + y1*y1); - - F32 oomag = 1.f / mag; - val1 = x1 * oomag; - val2 = y1 * oomag; - - ensure("normVec failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY]) && is_approx_equal(vecMag, mag)); - - x1 =.00000001f, y1 = 0.f; - - vec2.setVec(x1, y1); - vecMag = vec2.normVec(); - ensure("normVec failed should be 0.", 0. == vec2.mV[VX] && 0. == vec2.mV[VY] && vecMag == 0.); - } -} +/** + * @file v2math_test.cpp + * @author Adroit + * @date 2007-02 + * @brief v2math test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" + +#include "../v2math.h" + + +namespace tut +{ + struct v2math_data + { + }; + typedef test_group v2math_test; + typedef v2math_test::object v2math_object; + tut::v2math_test v2math_testcase("v2math_h"); + + template<> template<> + void v2math_object::test<1>() + { + LLVector2 vec2; + ensure("LLVector2:Fail to initialize ", (0.f == vec2.mV[VX] && 0.f == vec2.mV[VY])); + + F32 x =2.0f, y = 3.2f ; + LLVector2 vec3(x,y); + ensure("LLVector2(F32 x, F32 y):Fail to initialize ", (x == vec3.mV[VX]) && (y == vec3.mV[VY])); + + const F32 vec[2] = {3.2f, 4.5f}; + LLVector2 vec4(vec); + ensure("LLVector2(const F32 *vec):Fail to initialize ", (vec[0] == vec4.mV[VX]) && (vec[1] == vec4.mV[VY])); + + vec4.clearVec(); + ensure("clearVec():Fail to clean the values ", (0.f == vec4.mV[VX] && 0.f == vec4.mV[VY])); + + vec3.zeroVec(); + ensure("zeroVec():Fail to fill the zero ", (0.f == vec3.mV[VX] && 0.f == vec3.mV[VY])); + } + + template<> template<> + void v2math_object::test<2>() + { + F32 x = 123.356f, y = 2387.453f; + LLVector2 vec2,vec3; + vec2.setVec(x, y); + ensure("1:setVec: Fail ", (x == vec2.mV[VX]) && (y == vec2.mV[VY])); + + vec3.setVec(vec2); + ensure("2:setVec: Fail " ,(vec2 == vec3)); + + vec3.zeroVec(); + const F32 vec[2] = {3.24653f, 457653.4f}; + vec3.setVec(vec); + ensure("3:setVec: Fail ", (vec[0] == vec3.mV[VX]) && (vec[1] == vec3.mV[VY])); + } + + template<> template<> + void v2math_object::test<3>() + { + F32 x = 2.2345f, y = 3.5678f ; + LLVector2 vec2(x,y); + ensure("magVecSquared:Fail ", is_approx_equal(vec2.magVecSquared(), (x*x + y*y))); + ensure("magVec:Fail ", is_approx_equal(vec2.magVec(), (F32) sqrt(x*x + y*y))); + } + + template<> template<> + void v2math_object::test<4>() + { + F32 x =-2.0f, y = -3.0f ; + LLVector2 vec2(x,y); + ensure_equals("abs():Fail", vec2.abs(), true); + ensure("abs() x", is_approx_equal(vec2.mV[VX], 2.f)); + ensure("abs() y", is_approx_equal(vec2.mV[VY], 3.f)); + + ensure("isNull():Fail ", false == vec2.isNull()); //Returns true if vector has a _very_small_ length + + x =.00000001f, y = .000001001f; + vec2.setVec(x, y); + ensure("isNull(): Fail ", true == vec2.isNull()); + } + + template<> template<> + void v2math_object::test<5>() + { + F32 x =1.f, y = 2.f; + LLVector2 vec2(x, y), vec3; + vec3 = vec3.scaleVec(vec2); + ensure("scaleVec: Fail ", vec3.mV[VX] == 0. && vec3.mV[VY] == 0.); + ensure("isExactlyZero(): Fail", true == vec3.isExactlyZero()); + + vec3.setVec(2.f, 1.f); + vec3 = vec3.scaleVec(vec2); + ensure("scaleVec: Fail ", (2.f == vec3.mV[VX]) && (2.f == vec3.mV[VY])); + ensure("isExactlyZero():Fail", false == vec3.isExactlyZero()); + } + + template<> template<> + void v2math_object::test<6>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3(x2, y2), vec4; + vec4 = vec2 + vec3 ; + val1 = x1+x2; + val2 = y1+y2; + ensure("1:operator+ failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); + + vec2.clearVec(); + vec3.clearVec(); + x1 = -.235f, y1 = -24.32f, x2 = -2.3f, y2 = 1.f; + vec2.setVec(x1, y1); + vec3.setVec(x2, y2); + vec4 = vec2 + vec3; + val1 = x1+x2; + val2 = y1+y2; + ensure("2:operator+ failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); + } + + template<> template<> + void v2math_object::test<7>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3(x2, y2), vec4; + vec4 = vec2 - vec3 ; + val1 = x1-x2; + val2 = y1-y2; + ensure("1:operator- failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); + + vec2.clearVec(); + vec3.clearVec(); + vec4.clearVec(); + x1 = -.235f, y1 = -24.32f, x2 = -2.3f, y2 = 1.f; + vec2.setVec(x1, y1); + vec3.setVec(x2, y2); + vec4 = vec2 - vec3; + val1 = x1-x2; + val2 = y1-y2; + ensure("2:operator- failed",(val1 == vec4.mV[VX]) && ((val2 == vec4.mV[VY]))); + } + + template<> template<> + void v2math_object::test<8>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3(x2, y2); + val1 = vec2 * vec3; + val2 = x1*x2 + y1*y2; + ensure("1:operator* failed",(val1 == val2)); + + vec3.clearVec(); + F32 mulVal = 4.332f; + vec3 = vec2 * mulVal; + val1 = x1*mulVal; + val2 = y1*mulVal; + ensure("2:operator* failed",(val1 == vec3.mV[VX]) && (val2 == vec3.mV[VY])); + + vec3.clearVec(); + vec3 = mulVal * vec2; + ensure("3:operator* failed",(val1 == vec3.mV[VX]) && (val2 == vec3.mV[VY])); + } + + template<> template<> + void v2math_object::test<9>() + { + F32 x1 =1.f, y1 = 2.f, div = 3.2f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3; + vec3 = vec2 / div; + val1 = x1 / div; + val2 = y1 / div; + ensure("1:operator/ failed", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY])); + + vec3.clearVec(); + x1 = -.235f, y1 = -24.32f, div = -2.2f; + vec2.setVec(x1, y1); + vec3 = vec2 / div; + val1 = x1 / div; + val2 = y1 / div; + ensure("2:operator/ failed", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY])); + } + + template<> template<> + void v2math_object::test<10>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3(x2, y2), vec4; + vec4 = vec2 % vec3; + val1 = x1*y2 - x2*y1; + val2 = y1*x2 - y2*x1; + ensure("1:operator% failed",(val1 == vec4.mV[VX]) && (val2 == vec4.mV[VY])); + + vec2.clearVec(); + vec3.clearVec(); + vec4.clearVec(); + x1 = -.235f, y1 = -24.32f, x2 = -2.3f, y2 = 1.f; + vec2.setVec(x1, y1); + vec3.setVec(x2, y2); + vec4 = vec2 % vec3; + val1 = x1*y2 - x2*y1; + val2 = y1*x2 - y2*x1; + ensure("2:operator% failed",(val1 == vec4.mV[VX]) && (val2 == vec4.mV[VY])); + } + template<> template<> + void v2math_object::test<11>() + { + F32 x1 =1.f, y1 = 2.f; + LLVector2 vec2(x1, y1), vec3(x1, y1); + ensure("1:operator== failed",(vec2 == vec3)); + + vec2.clearVec(); + vec3.clearVec(); + x1 = -.235f, y1 = -24.32f; + vec2.setVec(x1, y1); + vec3.setVec(vec2); + ensure("2:operator== failed",(vec2 == vec3)); + } + + template<> template<> + void v2math_object::test<12>() + { + F32 x1 = 1.f, y1 = 2.f,x2 = 2.332f, y2 = -1.23f; + LLVector2 vec2(x1, y1), vec3(x2, y2); + ensure("1:operator!= failed",(vec2 != vec3)); + + vec2.clearVec(); + vec3.clearVec(); + vec2.setVec(x1, y1); + vec3.setVec(vec2); + ensure("2:operator!= failed", (false == (vec2 != vec3))); + } + template<> template<> + void v2math_object::test<13>() + { + F32 x1 = 1.f, y1 = 2.f,x2 = 2.332f, y2 = -1.23f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3(x2, y2); + vec2 +=vec3; + val1 = x1+x2; + val2 = y1+y2; + ensure("1:operator+= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); + + vec2.setVec(x1, y1); + vec2 -=vec3; + val1 = x1-x2; + val2 = y1-y2; + ensure("2:operator-= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); + + vec2.clearVec(); + vec3.clearVec(); + x1 = -21.000466f, y1 = 2.98382f,x2 = 0.332f, y2 = -01.23f; + vec2.setVec(x1, y1); + vec3.setVec(x2, y2); + vec2 +=vec3; + val1 = x1+x2; + val2 = y1+y2; + ensure("3:operator+= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); + + vec2.setVec(x1, y1); + vec2 -=vec3; + val1 = x1-x2; + val2 = y1-y2; + ensure("4:operator-= failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY])); + } + + template<> template<> + void v2math_object::test<14>() + { + F32 x1 =1.f, y1 = 2.f; + F32 val1, val2, mulVal = 4.332f; + LLVector2 vec2(x1, y1); + vec2 /=mulVal; + val1 = x1 / mulVal; + val2 = y1 / mulVal; + ensure("1:operator/= failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY])); + + vec2.clearVec(); + x1 = .213f, y1 = -2.34f, mulVal = -.23f; + vec2.setVec(x1, y1); + vec2 /=mulVal; + val1 = x1 / mulVal; + val2 = y1 / mulVal; + ensure("2:operator/= failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY])); + } + + template<> template<> + void v2math_object::test<15>() + { + F32 x1 =1.f, y1 = 2.f; + F32 val1, val2, mulVal = 4.332f; + LLVector2 vec2(x1, y1); + vec2 *=mulVal; + val1 = x1*mulVal; + val2 = y1*mulVal; + ensure("1:operator*= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); + + vec2.clearVec(); + x1 = .213f, y1 = -2.34f, mulVal = -.23f; + vec2.setVec(x1, y1); + vec2 *=mulVal; + val1 = x1*mulVal; + val2 = y1*mulVal; + ensure("2:operator*= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); + } + + template<> template<> + void v2math_object::test<16>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -2.3f, y2 = 1.11f; + F32 val1, val2; + LLVector2 vec2(x1, y1), vec3(x2, y2); + vec2 %= vec3; + val1 = x1*y2 - x2*y1; + val2 = y1*x2 - y2*x1; + ensure("1:operator%= failed",(val1 == vec2.mV[VX]) && (val2 == vec2.mV[VY])); + } + + template<> template<> + void v2math_object::test<17>() + { + F32 x1 =1.f, y1 = 2.f; + LLVector2 vec2(x1, y1),vec3; + vec3 = -vec2; + ensure("1:operator- failed",(-vec3 == vec2)); + } + + template<> template<> + void v2math_object::test<18>() + { + F32 x1 =1.f, y1 = 2.f; + std::ostringstream stream1, stream2; + LLVector2 vec2(x1, y1),vec3; + stream1 << vec2; + vec3.setVec(x1, y1); + stream2 << vec3; + ensure("1:operator << failed",(stream1.str() == stream2.str())); + } + + template<> template<> + void v2math_object::test<19>() + { + F32 x1 =1.0f, y1 = 2.0f, x2 = -.32f, y2 = .2234f; + LLVector2 vec2(x1, y1),vec3(x2, y2); + ensure("1:operator < failed",(vec3 < vec2)); + + x1 = 1.0f, y1 = 2.0f, x2 = 1.0f, y2 = 3.2234f; + vec2.setVec(x1, y1); + vec3.setVec(x2, y2); + ensure("2:operator < failed", (false == (vec3 < vec2))); + } + + template<> template<> + void v2math_object::test<20>() + { + F32 x1 =1.0f, y1 = 2.0f; + LLVector2 vec2(x1, y1); + ensure("1:operator [] failed",( x1 == vec2[0])); + ensure("2:operator [] failed",( y1 == vec2[1])); + + vec2.clearVec(); + x1 = 23.0f, y1 = -.2361f; + vec2.setVec(x1, y1); + F32 ref1 = vec2[0]; + ensure("3:operator [] failed", ( ref1 == x1)); + F32 ref2 = vec2[1]; + ensure("4:operator [] failed", ( ref2 == y1)); + } + + template<> template<> + void v2math_object::test<21>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -.32f, y2 = .2234f; + F32 val1, val2; + LLVector2 vec2(x1, y1),vec3(x2, y2); + val1 = dist_vec_squared2D(vec2, vec3); + val2 = (x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2); + ensure_equals("dist_vec_squared2D values are not equal",val2, val1); + + val1 = dist_vec_squared(vec2, vec3); + ensure_equals("dist_vec_squared values are not equal",val2, val1); + + val1 = dist_vec(vec2, vec3); + val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2)); + ensure_equals("dist_vec values are not equal",val2, val1); + } + + template<> template<> + void v2math_object::test<22>() + { + F32 x1 =1.f, y1 = 2.f, x2 = -.32f, y2 = .2234f,fVal = .0121f; + F32 val1, val2; + LLVector2 vec2(x1, y1),vec3(x2, y2); + LLVector2 vec4 = lerp(vec2, vec3, fVal); + val1 = x1 + (x2 - x1) * fVal; + val2 = y1 + (y2 - y1) * fVal; + ensure("lerp values are not equal", ((val1 == vec4.mV[VX]) && (val2 == vec4.mV[VY]))); + } + + template<> template<> + void v2math_object::test<23>() + { + F32 x1 =1.f, y1 = 2.f; + F32 val1, val2; + LLVector2 vec2(x1, y1); + + F32 vecMag = vec2.normVec(); + F32 mag = (F32) sqrt(x1*x1 + y1*y1); + + F32 oomag = 1.f / mag; + val1 = x1 * oomag; + val2 = y1 * oomag; + + ensure("normVec failed", is_approx_equal(val1, vec2.mV[VX]) && is_approx_equal(val2, vec2.mV[VY]) && is_approx_equal(vecMag, mag)); + + x1 =.00000001f, y1 = 0.f; + + vec2.setVec(x1, y1); + vecMag = vec2.normVec(); + ensure("normVec failed should be 0.", 0. == vec2.mV[VX] && 0. == vec2.mV[VY] && vecMag == 0.); + } +} diff --git a/indra/llmath/tests/v3color_test.cpp b/indra/llmath/tests/v3color_test.cpp index 11298bebd2..8897d48365 100644 --- a/indra/llmath/tests/v3color_test.cpp +++ b/indra/llmath/tests/v3color_test.cpp @@ -1,309 +1,309 @@ -/** - * @file v3color_test.cpp - * @author Adroit - * @date 2007-03 - * @brief v3color test cases. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" - -#include "../v3color.h" - - -namespace tut -{ - struct v3color_data - { - }; - typedef test_group v3color_test; - typedef v3color_test::object v3color_object; - tut::v3color_test v3color_testcase("v3color_h"); - - template<> template<> - void v3color_object::test<1>() - { - LLColor3 llcolor3; - ensure("1:LLColor3:Fail to default-initialize ", (0.0f == llcolor3.mV[0]) && (0.0f == llcolor3.mV[1]) && (0.0f == llcolor3.mV[2])); - F32 r = 2.0f, g = 3.2f, b = 1.f; - F32 v1,v2,v3; - LLColor3 llcolor3a(r,g,b); - ensure("2:LLColor3:Fail to initialize " ,(2.0f == llcolor3a.mV[0]) && (3.2f == llcolor3a.mV[1]) && (1.f == llcolor3a.mV[2])); - - const F32 vec[3] = {2.0f, 3.2f,1.f}; - LLColor3 llcolor3b(vec); - ensure("3:LLColor3:Fail to initialize " ,(2.0f == llcolor3b.mV[0]) && (3.2f == llcolor3b.mV[1]) && (1.f == llcolor3b.mV[2])); - const char* str = "561122"; - LLColor3 llcolor3c(str); - v1 = (F32)86.0f/255.0f; // 0x56 = 86 - v2 = (F32)17.0f/255.0f; // 0x11 = 17 - v3 = (F32)34.0f/255.f; // 0x22 = 34 - ensure("4:LLColor3:Fail to initialize " , is_approx_equal(v1, llcolor3c.mV[0]) && is_approx_equal(v2, llcolor3c.mV[1]) && is_approx_equal(v3, llcolor3c.mV[2])); - } - - template<> template<> - void v3color_object::test<2>() - { - LLColor3 llcolor3; - llcolor3.setToBlack(); - ensure("setToBlack:Fail to set black ", ((llcolor3.mV[0] == 0.f) && (llcolor3.mV[1] == 0.f) && (llcolor3.mV[2] == 0.f))); - llcolor3.setToWhite(); - ensure("setToWhite:Fail to set white ", ((llcolor3.mV[0] == 1.f) && (llcolor3.mV[1] == 1.f) && (llcolor3.mV[2] == 1.f))); - } - - template<> template<> - void v3color_object::test<3>() - { - F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; - LLColor3 llcolor3, llcolor3a; - llcolor3.setVec(r,g,b); - ensure("1:setVec(r,g,b) Fail ",((r == llcolor3.mV[0]) && (g == llcolor3.mV[1]) && (b == llcolor3.mV[2]))); - llcolor3a.setVec(llcolor3); - ensure_equals("2:setVec(LLColor3) Fail ", llcolor3,llcolor3a); - F32 vec[3] = {1.2324f, 2.45634f, .234563f}; - llcolor3.setToBlack(); - llcolor3.setVec(vec); - ensure("3:setVec(F32*) Fail ",((vec[0] == llcolor3.mV[0]) && (vec[1] == llcolor3.mV[1]) && (vec[2] == llcolor3.mV[2]))); - } - - template<> template<> - void v3color_object::test<4>() - { - F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; - LLColor3 llcolor3(r,g,b); - ensure("magVecSquared:Fail ", is_approx_equal(llcolor3.magVecSquared(), (r*r + g*g + b*b))); - ensure("magVec:Fail ", is_approx_equal(llcolor3.magVec(), (F32) sqrt(r*r + g*g + b*b))); - } - - template<> template<> - void v3color_object::test<5>() - { - F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; - F32 val1, val2,val3; - LLColor3 llcolor3(r,g,b); - F32 vecMag = llcolor3.normVec(); - F32 mag = (F32) sqrt(r*r + g*g + b*b); - F32 oomag = 1.f / mag; - val1 = r * oomag; - val2 = g * oomag; - val3 = b * oomag; - ensure("1:normVec failed ", (is_approx_equal(val1, llcolor3.mV[0]) && is_approx_equal(val2, llcolor3.mV[1]) && is_approx_equal(val3, llcolor3.mV[2]) && is_approx_equal(vecMag, mag))); - r = .000000000f, g = 0.f, b = 0.0f; - llcolor3.setVec(r,g,b); - vecMag = llcolor3.normVec(); - ensure("2:normVec failed should be 0. ", (0. == llcolor3.mV[0] && 0. == llcolor3.mV[1] && 0. == llcolor3.mV[2] && vecMag == 0.)); - } - - template<> template<> - void v3color_object::test<6>() - { - F32 r = 2.3436212f, g = -1231.f, b = .7849321232f; - std::ostringstream stream1, stream2; - LLColor3 llcolor3(r,g,b),llcolor3a; - stream1 << llcolor3; - llcolor3a.setVec(r,g,b); - stream2 << llcolor3a; - ensure("operator << failed ", (stream1.str() == stream2.str())); - } - - template<> template<> - void v3color_object::test<7>() - { - F32 r = 2.3436212f, g = -1231.f, b = .7849321232f; - LLColor3 llcolor3(r,g,b),llcolor3a; - llcolor3a = llcolor3; - ensure("operator == failed ", (llcolor3a == llcolor3)); - } - - template<> template<> - void v3color_object::test<8>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2),llcolor3b; - llcolor3b = llcolor3 + llcolor3a ; - ensure("1:operator+ failed",is_approx_equal(r1+r2 ,llcolor3b.mV[0]) && is_approx_equal(g1+g2,llcolor3b.mV[1])&& is_approx_equal(b1+b2,llcolor3b.mV[2])); - r1 = -.235f, g1 = -24.32f, b1 = 2.13f, r2 = -2.3f, g2 = 1.f, b2 = 34.21f; - llcolor3.setVec(r1,g1,b1); - llcolor3a.setVec(r2,g2,b2); - llcolor3b = llcolor3 + llcolor3a; - ensure("2:operator+ failed",is_approx_equal(r1+r2 ,llcolor3b.mV[0]) && is_approx_equal(g1+g2,llcolor3b.mV[1])&& is_approx_equal(b1+b2,llcolor3b.mV[2])); - } - - template<> template<> - void v3color_object::test<9>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2),llcolor3b; - llcolor3b = llcolor3 - llcolor3a ; - ensure("1:operator- failed",is_approx_equal(r1-r2 ,llcolor3b.mV[0]) && is_approx_equal(g1-g2,llcolor3b.mV[1])&& is_approx_equal(b1-b2,llcolor3b.mV[2])); - r1 = -.235f, g1 = -24.32f, b1 = 2.13f, r2 = -2.3f, g2 = 1.f, b2 = 34.21f; - llcolor3.setVec(r1,g1,b1); - llcolor3a.setVec(r2,g2,b2); - llcolor3b = llcolor3 - llcolor3a; - ensure("2:operator- failed",is_approx_equal(r1-r2 ,llcolor3b.mV[0]) && is_approx_equal(g1-g2,llcolor3b.mV[1])&& is_approx_equal(b1-b2,llcolor3b.mV[2])); - } - - template<> template<> - void v3color_object::test<10>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2),llcolor3b; - llcolor3b = llcolor3 * llcolor3a; - ensure("1:operator* failed",is_approx_equal(r1*r2 ,llcolor3b.mV[0]) && is_approx_equal(g1*g2,llcolor3b.mV[1])&& is_approx_equal(b1*b2,llcolor3b.mV[2])); - llcolor3a.setToBlack(); - F32 mulVal = 4.332f; - llcolor3a = llcolor3 * mulVal; - ensure("2:operator* failed",is_approx_equal(r1*mulVal ,llcolor3a.mV[0]) && is_approx_equal(g1*mulVal,llcolor3a.mV[1])&& is_approx_equal(b1*mulVal,llcolor3a.mV[2])); - llcolor3a.setToBlack(); - llcolor3a = mulVal * llcolor3; - ensure("3:operator* failed",is_approx_equal(r1*mulVal ,llcolor3a.mV[0]) && is_approx_equal(g1*mulVal,llcolor3a.mV[1])&& is_approx_equal(b1*mulVal,llcolor3a.mV[2])); - } - - template<> template<> - void v3color_object::test<11>() - { - F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; - LLColor3 llcolor3(r,g,b),llcolor3a; - llcolor3a = -llcolor3; - ensure("operator- failed ", (-llcolor3a == llcolor3)); - } - - template<> template<> - void v3color_object::test<12>() - { - F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; - LLColor3 llcolor3(r,g,b),llcolor3a(r,g,b); - ensure_equals("1:operator== failed",llcolor3a,llcolor3); - r = 13.3436212f, g = -11.f, b = .7849321232f; - llcolor3.setVec(r,g,b); - llcolor3a.setVec(r,g,b); - ensure_equals("2:operator== failed",llcolor3a,llcolor3); - } - - template<> template<> - void v3color_object::test<13>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); - ensure("1:operator!= failed",(llcolor3 != llcolor3a)); - llcolor3.setToBlack(); - llcolor3a.setVec(llcolor3); - ensure("2:operator!= failed", ( false == (llcolor3a != llcolor3))); - } - - template<> template<> - void v3color_object::test<14>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); - llcolor3a += llcolor3; - ensure("1:operator+= failed",is_approx_equal(r1+r2 ,llcolor3a.mV[0]) && is_approx_equal(g1+g2,llcolor3a.mV[1])&& is_approx_equal(b1+b2,llcolor3a.mV[2])); - llcolor3.setVec(r1,g1,b1); - llcolor3a.setVec(r2,g2,b2); - llcolor3a += llcolor3; - ensure("2:operator+= failed",is_approx_equal(r1+r2 ,llcolor3a.mV[0]) && is_approx_equal(g1+g2,llcolor3a.mV[1])&& is_approx_equal(b1+b2,llcolor3a.mV[2])); - } - - template<> template<> - void v3color_object::test<15>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); - llcolor3a -= llcolor3; - ensure("1:operator-= failed", is_approx_equal(r2-r1, llcolor3a.mV[0])); - ensure("2:operator-= failed", is_approx_equal(g2-g1, llcolor3a.mV[1])); - ensure("3:operator-= failed", is_approx_equal(b2-b1, llcolor3a.mV[2])); - llcolor3.setVec(r1,g1,b1); - llcolor3a.setVec(r2,g2,b2); - llcolor3a -= llcolor3; - ensure("4:operator-= failed", is_approx_equal(r2-r1, llcolor3a.mV[0])); - ensure("5:operator-= failed", is_approx_equal(g2-g1, llcolor3a.mV[1])); - ensure("6:operator-= failed", is_approx_equal(b2-b1, llcolor3a.mV[2])); - } - - template<> template<> - void v3color_object::test<16>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); - llcolor3a *= llcolor3; - ensure("1:operator*= failed",is_approx_equal(r1*r2 ,llcolor3a.mV[0]) && is_approx_equal(g1*g2,llcolor3a.mV[1])&& is_approx_equal(b1*b2,llcolor3a.mV[2])); - F32 mulVal = 4.332f; - llcolor3 *=mulVal; - ensure("2:operator*= failed",is_approx_equal(r1*mulVal ,llcolor3.mV[0]) && is_approx_equal(g1*mulVal,llcolor3.mV[1])&& is_approx_equal(b1*mulVal,llcolor3.mV[2])); - } - - template<> template<> - void v3color_object::test<17>() - { - F32 r = 2.3436212f, g = -1231.f, b = .7849321232f; - LLColor3 llcolor3(r,g,b); - llcolor3.clamp(); - ensure("1:clamp:Fail to clamp " ,(1.0f == llcolor3.mV[0]) && (0.f == llcolor3.mV[1]) && (b == llcolor3.mV[2])); - r = -2.3436212f, g = -1231.f, b = 67.7849321232f; - llcolor3.setVec(r,g,b); - llcolor3.clamp(); - ensure("2:clamp:Fail to clamp " ,(0.f == llcolor3.mV[0]) && (0.f == llcolor3.mV[1]) && (1.f == llcolor3.mV[2])); - } - - template<> template<> - void v3color_object::test<18>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - F32 val = 2.3f,val1,val2,val3; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); - val1 = r1 + (r2 - r1)* val; - val2 = g1 + (g2 - g1)* val; - val3 = b1 + (b2 - b1)* val; - LLColor3 llcolor3b = lerp(llcolor3,llcolor3a,val); - ensure("lerp failed ", ((val1 ==llcolor3b.mV[0])&& (val2 ==llcolor3b.mV[1]) && (val3 ==llcolor3b.mV[2]))); - } - - template<> template<> - void v3color_object::test<19>() - { - F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; - LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); - F32 val = distVec(llcolor3,llcolor3a); - ensure("distVec failed ", is_approx_equal((F32) sqrt((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val)); - - F32 val1 = distVec_squared(llcolor3,llcolor3a); - ensure("distVec_squared failed ", is_approx_equal(((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val1)); - } - - template<> template<> - void v3color_object::test<20>() - { - F32 r1 = 1.02223f, g1 = 22222.212f, b1 = 122222.00002f; - LLColor3 llcolor31(r1,g1,b1); - - LLSD sd = llcolor31.getValue(); - LLColor3 llcolor32; - llcolor32.setValue(sd); - ensure_equals("LLColor3::setValue/getValue failed", llcolor31, llcolor32); - - LLColor3 llcolor33(sd); - ensure_equals("LLColor3(LLSD) failed", llcolor31, llcolor33); - } -} +/** + * @file v3color_test.cpp + * @author Adroit + * @date 2007-03 + * @brief v3color test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" + +#include "../v3color.h" + + +namespace tut +{ + struct v3color_data + { + }; + typedef test_group v3color_test; + typedef v3color_test::object v3color_object; + tut::v3color_test v3color_testcase("v3color_h"); + + template<> template<> + void v3color_object::test<1>() + { + LLColor3 llcolor3; + ensure("1:LLColor3:Fail to default-initialize ", (0.0f == llcolor3.mV[0]) && (0.0f == llcolor3.mV[1]) && (0.0f == llcolor3.mV[2])); + F32 r = 2.0f, g = 3.2f, b = 1.f; + F32 v1,v2,v3; + LLColor3 llcolor3a(r,g,b); + ensure("2:LLColor3:Fail to initialize " ,(2.0f == llcolor3a.mV[0]) && (3.2f == llcolor3a.mV[1]) && (1.f == llcolor3a.mV[2])); + + const F32 vec[3] = {2.0f, 3.2f,1.f}; + LLColor3 llcolor3b(vec); + ensure("3:LLColor3:Fail to initialize " ,(2.0f == llcolor3b.mV[0]) && (3.2f == llcolor3b.mV[1]) && (1.f == llcolor3b.mV[2])); + const char* str = "561122"; + LLColor3 llcolor3c(str); + v1 = (F32)86.0f/255.0f; // 0x56 = 86 + v2 = (F32)17.0f/255.0f; // 0x11 = 17 + v3 = (F32)34.0f/255.f; // 0x22 = 34 + ensure("4:LLColor3:Fail to initialize " , is_approx_equal(v1, llcolor3c.mV[0]) && is_approx_equal(v2, llcolor3c.mV[1]) && is_approx_equal(v3, llcolor3c.mV[2])); + } + + template<> template<> + void v3color_object::test<2>() + { + LLColor3 llcolor3; + llcolor3.setToBlack(); + ensure("setToBlack:Fail to set black ", ((llcolor3.mV[0] == 0.f) && (llcolor3.mV[1] == 0.f) && (llcolor3.mV[2] == 0.f))); + llcolor3.setToWhite(); + ensure("setToWhite:Fail to set white ", ((llcolor3.mV[0] == 1.f) && (llcolor3.mV[1] == 1.f) && (llcolor3.mV[2] == 1.f))); + } + + template<> template<> + void v3color_object::test<3>() + { + F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; + LLColor3 llcolor3, llcolor3a; + llcolor3.setVec(r,g,b); + ensure("1:setVec(r,g,b) Fail ",((r == llcolor3.mV[0]) && (g == llcolor3.mV[1]) && (b == llcolor3.mV[2]))); + llcolor3a.setVec(llcolor3); + ensure_equals("2:setVec(LLColor3) Fail ", llcolor3,llcolor3a); + F32 vec[3] = {1.2324f, 2.45634f, .234563f}; + llcolor3.setToBlack(); + llcolor3.setVec(vec); + ensure("3:setVec(F32*) Fail ",((vec[0] == llcolor3.mV[0]) && (vec[1] == llcolor3.mV[1]) && (vec[2] == llcolor3.mV[2]))); + } + + template<> template<> + void v3color_object::test<4>() + { + F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; + LLColor3 llcolor3(r,g,b); + ensure("magVecSquared:Fail ", is_approx_equal(llcolor3.magVecSquared(), (r*r + g*g + b*b))); + ensure("magVec:Fail ", is_approx_equal(llcolor3.magVec(), (F32) sqrt(r*r + g*g + b*b))); + } + + template<> template<> + void v3color_object::test<5>() + { + F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; + F32 val1, val2,val3; + LLColor3 llcolor3(r,g,b); + F32 vecMag = llcolor3.normVec(); + F32 mag = (F32) sqrt(r*r + g*g + b*b); + F32 oomag = 1.f / mag; + val1 = r * oomag; + val2 = g * oomag; + val3 = b * oomag; + ensure("1:normVec failed ", (is_approx_equal(val1, llcolor3.mV[0]) && is_approx_equal(val2, llcolor3.mV[1]) && is_approx_equal(val3, llcolor3.mV[2]) && is_approx_equal(vecMag, mag))); + r = .000000000f, g = 0.f, b = 0.0f; + llcolor3.setVec(r,g,b); + vecMag = llcolor3.normVec(); + ensure("2:normVec failed should be 0. ", (0. == llcolor3.mV[0] && 0. == llcolor3.mV[1] && 0. == llcolor3.mV[2] && vecMag == 0.)); + } + + template<> template<> + void v3color_object::test<6>() + { + F32 r = 2.3436212f, g = -1231.f, b = .7849321232f; + std::ostringstream stream1, stream2; + LLColor3 llcolor3(r,g,b),llcolor3a; + stream1 << llcolor3; + llcolor3a.setVec(r,g,b); + stream2 << llcolor3a; + ensure("operator << failed ", (stream1.str() == stream2.str())); + } + + template<> template<> + void v3color_object::test<7>() + { + F32 r = 2.3436212f, g = -1231.f, b = .7849321232f; + LLColor3 llcolor3(r,g,b),llcolor3a; + llcolor3a = llcolor3; + ensure("operator == failed ", (llcolor3a == llcolor3)); + } + + template<> template<> + void v3color_object::test<8>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2),llcolor3b; + llcolor3b = llcolor3 + llcolor3a ; + ensure("1:operator+ failed",is_approx_equal(r1+r2 ,llcolor3b.mV[0]) && is_approx_equal(g1+g2,llcolor3b.mV[1])&& is_approx_equal(b1+b2,llcolor3b.mV[2])); + r1 = -.235f, g1 = -24.32f, b1 = 2.13f, r2 = -2.3f, g2 = 1.f, b2 = 34.21f; + llcolor3.setVec(r1,g1,b1); + llcolor3a.setVec(r2,g2,b2); + llcolor3b = llcolor3 + llcolor3a; + ensure("2:operator+ failed",is_approx_equal(r1+r2 ,llcolor3b.mV[0]) && is_approx_equal(g1+g2,llcolor3b.mV[1])&& is_approx_equal(b1+b2,llcolor3b.mV[2])); + } + + template<> template<> + void v3color_object::test<9>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2),llcolor3b; + llcolor3b = llcolor3 - llcolor3a ; + ensure("1:operator- failed",is_approx_equal(r1-r2 ,llcolor3b.mV[0]) && is_approx_equal(g1-g2,llcolor3b.mV[1])&& is_approx_equal(b1-b2,llcolor3b.mV[2])); + r1 = -.235f, g1 = -24.32f, b1 = 2.13f, r2 = -2.3f, g2 = 1.f, b2 = 34.21f; + llcolor3.setVec(r1,g1,b1); + llcolor3a.setVec(r2,g2,b2); + llcolor3b = llcolor3 - llcolor3a; + ensure("2:operator- failed",is_approx_equal(r1-r2 ,llcolor3b.mV[0]) && is_approx_equal(g1-g2,llcolor3b.mV[1])&& is_approx_equal(b1-b2,llcolor3b.mV[2])); + } + + template<> template<> + void v3color_object::test<10>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2),llcolor3b; + llcolor3b = llcolor3 * llcolor3a; + ensure("1:operator* failed",is_approx_equal(r1*r2 ,llcolor3b.mV[0]) && is_approx_equal(g1*g2,llcolor3b.mV[1])&& is_approx_equal(b1*b2,llcolor3b.mV[2])); + llcolor3a.setToBlack(); + F32 mulVal = 4.332f; + llcolor3a = llcolor3 * mulVal; + ensure("2:operator* failed",is_approx_equal(r1*mulVal ,llcolor3a.mV[0]) && is_approx_equal(g1*mulVal,llcolor3a.mV[1])&& is_approx_equal(b1*mulVal,llcolor3a.mV[2])); + llcolor3a.setToBlack(); + llcolor3a = mulVal * llcolor3; + ensure("3:operator* failed",is_approx_equal(r1*mulVal ,llcolor3a.mV[0]) && is_approx_equal(g1*mulVal,llcolor3a.mV[1])&& is_approx_equal(b1*mulVal,llcolor3a.mV[2])); + } + + template<> template<> + void v3color_object::test<11>() + { + F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; + LLColor3 llcolor3(r,g,b),llcolor3a; + llcolor3a = -llcolor3; + ensure("operator- failed ", (-llcolor3a == llcolor3)); + } + + template<> template<> + void v3color_object::test<12>() + { + F32 r = 2.3436212f, g = 1231.f, b = 4.7849321232f; + LLColor3 llcolor3(r,g,b),llcolor3a(r,g,b); + ensure_equals("1:operator== failed",llcolor3a,llcolor3); + r = 13.3436212f, g = -11.f, b = .7849321232f; + llcolor3.setVec(r,g,b); + llcolor3a.setVec(r,g,b); + ensure_equals("2:operator== failed",llcolor3a,llcolor3); + } + + template<> template<> + void v3color_object::test<13>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); + ensure("1:operator!= failed",(llcolor3 != llcolor3a)); + llcolor3.setToBlack(); + llcolor3a.setVec(llcolor3); + ensure("2:operator!= failed", ( false == (llcolor3a != llcolor3))); + } + + template<> template<> + void v3color_object::test<14>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); + llcolor3a += llcolor3; + ensure("1:operator+= failed",is_approx_equal(r1+r2 ,llcolor3a.mV[0]) && is_approx_equal(g1+g2,llcolor3a.mV[1])&& is_approx_equal(b1+b2,llcolor3a.mV[2])); + llcolor3.setVec(r1,g1,b1); + llcolor3a.setVec(r2,g2,b2); + llcolor3a += llcolor3; + ensure("2:operator+= failed",is_approx_equal(r1+r2 ,llcolor3a.mV[0]) && is_approx_equal(g1+g2,llcolor3a.mV[1])&& is_approx_equal(b1+b2,llcolor3a.mV[2])); + } + + template<> template<> + void v3color_object::test<15>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); + llcolor3a -= llcolor3; + ensure("1:operator-= failed", is_approx_equal(r2-r1, llcolor3a.mV[0])); + ensure("2:operator-= failed", is_approx_equal(g2-g1, llcolor3a.mV[1])); + ensure("3:operator-= failed", is_approx_equal(b2-b1, llcolor3a.mV[2])); + llcolor3.setVec(r1,g1,b1); + llcolor3a.setVec(r2,g2,b2); + llcolor3a -= llcolor3; + ensure("4:operator-= failed", is_approx_equal(r2-r1, llcolor3a.mV[0])); + ensure("5:operator-= failed", is_approx_equal(g2-g1, llcolor3a.mV[1])); + ensure("6:operator-= failed", is_approx_equal(b2-b1, llcolor3a.mV[2])); + } + + template<> template<> + void v3color_object::test<16>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); + llcolor3a *= llcolor3; + ensure("1:operator*= failed",is_approx_equal(r1*r2 ,llcolor3a.mV[0]) && is_approx_equal(g1*g2,llcolor3a.mV[1])&& is_approx_equal(b1*b2,llcolor3a.mV[2])); + F32 mulVal = 4.332f; + llcolor3 *=mulVal; + ensure("2:operator*= failed",is_approx_equal(r1*mulVal ,llcolor3.mV[0]) && is_approx_equal(g1*mulVal,llcolor3.mV[1])&& is_approx_equal(b1*mulVal,llcolor3.mV[2])); + } + + template<> template<> + void v3color_object::test<17>() + { + F32 r = 2.3436212f, g = -1231.f, b = .7849321232f; + LLColor3 llcolor3(r,g,b); + llcolor3.clamp(); + ensure("1:clamp:Fail to clamp " ,(1.0f == llcolor3.mV[0]) && (0.f == llcolor3.mV[1]) && (b == llcolor3.mV[2])); + r = -2.3436212f, g = -1231.f, b = 67.7849321232f; + llcolor3.setVec(r,g,b); + llcolor3.clamp(); + ensure("2:clamp:Fail to clamp " ,(0.f == llcolor3.mV[0]) && (0.f == llcolor3.mV[1]) && (1.f == llcolor3.mV[2])); + } + + template<> template<> + void v3color_object::test<18>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + F32 val = 2.3f,val1,val2,val3; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); + val1 = r1 + (r2 - r1)* val; + val2 = g1 + (g2 - g1)* val; + val3 = b1 + (b2 - b1)* val; + LLColor3 llcolor3b = lerp(llcolor3,llcolor3a,val); + ensure("lerp failed ", ((val1 ==llcolor3b.mV[0])&& (val2 ==llcolor3b.mV[1]) && (val3 ==llcolor3b.mV[2]))); + } + + template<> template<> + void v3color_object::test<19>() + { + F32 r1 =1.f, g1 = 2.f,b1 = 1.2f, r2 = -2.3f, g2 = 1.11f, b2 = 1234.234f; + LLColor3 llcolor3(r1,g1,b1),llcolor3a(r2,g2,b2); + F32 val = distVec(llcolor3,llcolor3a); + ensure("distVec failed ", is_approx_equal((F32) sqrt((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val)); + + F32 val1 = distVec_squared(llcolor3,llcolor3a); + ensure("distVec_squared failed ", is_approx_equal(((r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2)) ,val1)); + } + + template<> template<> + void v3color_object::test<20>() + { + F32 r1 = 1.02223f, g1 = 22222.212f, b1 = 122222.00002f; + LLColor3 llcolor31(r1,g1,b1); + + LLSD sd = llcolor31.getValue(); + LLColor3 llcolor32; + llcolor32.setValue(sd); + ensure_equals("LLColor3::setValue/getValue failed", llcolor31, llcolor32); + + LLColor3 llcolor33(sd); + ensure_equals("LLColor3(LLSD) failed", llcolor31, llcolor33); + } +} diff --git a/indra/llmath/tests/v3dmath_test.cpp b/indra/llmath/tests/v3dmath_test.cpp index fc9e7d9dc1..db08419012 100644 --- a/indra/llmath/tests/v3dmath_test.cpp +++ b/indra/llmath/tests/v3dmath_test.cpp @@ -1,531 +1,531 @@ -/** - * @file v3dmath_test.cpp - * @author Adroit - * @date 2007-03 - * @brief v3dmath test cases. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llsd.h" -#include "../test/lltut.h" - -#include "../m3math.h" -#include "../v4math.h" -#include "../v3dmath.h" -#include "../v3dmath.h" -#include "../llquaternion.h" - -namespace tut -{ - struct v3dmath_data - { - }; - typedef test_group v3dmath_test; - typedef v3dmath_test::object v3dmath_object; - tut::v3dmath_test v3dmath_testcase("v3dmath_h"); - - template<> template<> - void v3dmath_object::test<1>() - { - LLVector3d vec3D; - ensure("1:LLVector3d:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ]))); - F64 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3d vec3Da(x,y,z); - ensure("2:LLVector3d:Fail to initialize ", ((2.32f == vec3Da.mdV[VX]) && (1.212f == vec3Da.mdV[VY]) && (-.12f == vec3Da.mdV[VZ]))); - const F64 vec[3] = {1.2f ,3.2f, -4.2f}; - LLVector3d vec3Db(vec); - ensure("3:LLVector3d:Fail to initialize ", ((1.2f == vec3Db.mdV[VX]) && (3.2f == vec3Db.mdV[VY]) && (-4.2f == vec3Db.mdV[VZ]))); - LLVector3 vec3((F32)x,(F32)y,(F32)z); - LLVector3d vec3Dc(vec3); - ensure_equals("4:LLVector3d Fail to initialize",vec3Da,vec3Dc); - } - - template<> template<> - void v3dmath_object::test<2>() - { - S32 a = -235; - LLSD llsd(a); - LLVector3d vec3d(llsd); - LLSD sd = vec3d.getValue(); - LLVector3d vec3da(sd); - ensure("1:getValue:Fail ", (vec3d == vec3da)); - } - - template<> template<> - void v3dmath_object::test<3>() - { - F64 a = 232345521.411132; - LLSD llsd(a); - LLVector3d vec3d; - vec3d.setValue(llsd); - LLSD sd = vec3d.getValue(); - LLVector3d vec3da(sd); - ensure("1:setValue:Fail to initialize ", (vec3d == vec3da)); - } - - template<> template<> - void v3dmath_object::test<4>() - { - F64 a[3] = {222231.43222, 12345.2343, -434343.33222}; - LLSD llsd; - llsd[0] = a[0]; - llsd[1] = a[1]; - llsd[2] = a[2]; - LLVector3d vec3D; - vec3D = (LLVector3d)llsd; - ensure("1:operator=:Fail to initialize ", ((llsd[0].asReal()== vec3D.mdV[VX]) && (llsd[1].asReal() == vec3D.mdV[VY]) && (llsd[2].asReal() == vec3D.mdV[VZ]))); - } - - template<> template<> - void v3dmath_object::test<5>() - { - F64 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3d vec3D(x,y,z); - vec3D.clearVec(); - ensure("1:clearVec:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ]))); - vec3D.setVec(x,y,z); - ensure("2:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ]))); - vec3D.zeroVec(); - ensure("3:zeroVec:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ]))); - vec3D.clearVec(); - LLVector3 vec3((F32)x,(F32)y,(F32)z); - vec3D.setVec(vec3); - ensure("4:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ]))); - vec3D.clearVec(); - const F64 vec[3] = {x,y,z}; - vec3D.setVec(vec); - ensure("5:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ]))); - LLVector3d vec3Da; - vec3Da.setVec(vec3D); - ensure_equals("6:setVec: Fail to initialize", vec3D, vec3Da); - } - - template<> template<> - void v3dmath_object::test<6>() - { - F64 x = -2.32, y = 1.212, z = -.12; - LLVector3d vec3D(x,y,z); - vec3D.abs(); - ensure("1:abs:Fail ", ((-x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (-z == vec3D.mdV[VZ]))); - ensure("2:isNull():Fail ", (false == vec3D.isNull())); - vec3D.clearVec(); - x =.00000001, y = .000001001, z = .000001001; - vec3D.setVec(x,y,z); - ensure("3:isNull():Fail ", (true == vec3D.isNull())); - ensure("4:isExactlyZero():Fail ", (false == vec3D.isExactlyZero())); - x =.0000000, y = .00000000, z = .00000000; - vec3D.setVec(x,y,z); - ensure("5:isExactlyZero():Fail ", (true == vec3D.isExactlyZero())); - } - - template<> template<> - void v3dmath_object::test<7>() - { - F64 x = -2.32, y = 1.212, z = -.12; - LLVector3d vec3D(x,y,z); - - ensure("1:operator [] failed",( x == vec3D[0])); - ensure("2:operator [] failed",( y == vec3D[1])); - ensure("3:operator [] failed",( z == vec3D[2])); - vec3D.clearVec(); - x = 23.23, y = -.2361, z = 3.25; - vec3D.setVec(x,y,z); - F64 &ref1 = vec3D[0]; - ensure("4:operator [] failed",( ref1 == vec3D[0])); - F64 &ref2 = vec3D[1]; - ensure("5:operator [] failed",( ref2 == vec3D[1])); - F64 &ref3 = vec3D[2]; - ensure("6:operator [] failed",( ref3 == vec3D[2])); - } - - template<> template<> - void v3dmath_object::test<8>() - { - F32 x = 1.f, y = 2.f, z = -1.f; - LLVector4 vec4(x,y,z); - LLVector3d vec3D; - vec3D = vec4; - ensure("1:operator=:Fail to initialize ", ((vec4.mV[VX] == vec3D.mdV[VX]) && (vec4.mV[VY] == vec3D.mdV[VY]) && (vec4.mV[VZ] == vec3D.mdV[VZ]))); - } - - template<> template<> - void v3dmath_object::test<9>() - { - F64 x1 = 1.78787878, y1 = 232322.2121, z1 = -12121.121212; - F64 x2 = 1.2, y2 = 2.5, z2 = 1.; - LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2),vec3Db; - vec3Db = vec3Da+ vec3D; - ensure("1:operator+:Fail to initialize ", ((x1+x2 == vec3Db.mdV[VX]) && (y1+y2 == vec3Db.mdV[VY]) && (z1+z2 == vec3Db.mdV[VZ]))); - x1 = -2.45, y1 = 2.1, z1 = 3.0; - vec3D.clearVec(); - vec3Da.clearVec(); - vec3D.setVec(x1,y1,z1); - vec3Da += vec3D; - ensure_equals("2:operator+=: Fail to initialize", vec3Da,vec3D); - vec3Da += vec3D; - ensure("3:operator+=:Fail to initialize ", ((2*x1 == vec3Da.mdV[VX]) && (2*y1 == vec3Da.mdV[VY]) && (2*z1 == vec3Da.mdV[VZ]))); - } - - template<> template<> - void v3dmath_object::test<10>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - F64 x2 = 1.2, y2 = 2.5, z2 = 1.; - LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2),vec3Db; - vec3Db = vec3Da - vec3D; - ensure("1:operator-:Fail to initialize ", ((x2-x1 == vec3Db.mdV[VX]) && (y2-y1 == vec3Db.mdV[VY]) && (z2-z1 == vec3Db.mdV[VZ]))); - x1 = -2.45, y1 = 2.1, z1 = 3.0; - vec3D.clearVec(); - vec3Da.clearVec(); - vec3D.setVec(x1,y1,z1); - vec3Da -=vec3D; - ensure("2:operator-=:Fail to initialize ", ((2.45 == vec3Da.mdV[VX]) && (-2.1 == vec3Da.mdV[VY]) && (-3.0 == vec3Da.mdV[VZ]))); - vec3Da -= vec3D; - ensure("3:operator-=:Fail to initialize ", ((-2*x1 == vec3Da.mdV[VX]) && (-2*y1 == vec3Da.mdV[VY]) && (-2*z1 == vec3Da.mdV[VZ]))); - } - template<> template<> - void v3dmath_object::test<11>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - F64 x2 = 1.2, y2 = 2.5, z2 = 1.; - LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2); - F64 res = vec3D * vec3Da; - ensure_approximately_equals( - "1:operator* failed", - res, - (x1*x2 + y1*y2 + z1*z2), - 8); - vec3Da.clearVec(); - F64 mulVal = 4.2; - vec3Da = vec3D * mulVal; - ensure_approximately_equals( - "2a:operator* failed", - vec3Da.mdV[VX], - x1*mulVal, - 8); - ensure_approximately_equals( - "2b:operator* failed", - vec3Da.mdV[VY], - y1*mulVal, - 8); - ensure_approximately_equals( - "2c:operator* failed", - vec3Da.mdV[VZ], - z1*mulVal, - 8); - vec3Da.clearVec(); - vec3Da = mulVal * vec3D; - ensure_approximately_equals( - "3a:operator* failed", - vec3Da.mdV[VX], - x1*mulVal, - 8); - ensure_approximately_equals( - "3b:operator* failed", - vec3Da.mdV[VY], - y1*mulVal, - 8); - ensure_approximately_equals( - "3c:operator* failed", - vec3Da.mdV[VZ], - z1*mulVal, - 8); - vec3D *= mulVal; - ensure_approximately_equals( - "4a:operator*= failed", - vec3D.mdV[VX], - x1*mulVal, - 8); - ensure_approximately_equals( - "4b:operator*= failed", - vec3D.mdV[VY], - y1*mulVal, - 8); - ensure_approximately_equals( - "4c:operator*= failed", - vec3D.mdV[VZ], - z1*mulVal, - 8); - } - - template<> template<> - void v3dmath_object::test<12>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - F64 x2 = 1.2, y2 = 2.5, z2 = 1.; - F64 val1, val2, val3; - LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2), vec3Db; - vec3Db = vec3D % vec3Da; - val1 = y1*z2 - y2*z1; - val2 = z1*x2 -z2*x1; - val3 = x1*y2-x2*y1; - ensure("1:operator% failed",(val1 == vec3Db.mdV[VX]) && (val2 == vec3Db.mdV[VY]) && (val3 == vec3Db.mdV[VZ])); - vec3D %= vec3Da; - ensure("2:operator%= failed", - is_approx_equal(vec3D.mdV[VX],vec3Db.mdV[VX]) && - is_approx_equal(vec3D.mdV[VY],vec3Db.mdV[VY]) && - is_approx_equal(vec3D.mdV[VZ],vec3Db.mdV[VZ]) ); - } - - template<> template<> - void v3dmath_object::test<13>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1,div = 4.2; - F64 t = 1.f / div; - LLVector3d vec3D(x1,y1,z1), vec3Da; - vec3Da = vec3D/div; - ensure_approximately_equals( - "1a:operator/ failed", - vec3Da.mdV[VX], - x1*t, - 8); - ensure_approximately_equals( - "1b:operator/ failed", - vec3Da.mdV[VY], - y1*t, - 8); - ensure_approximately_equals( - "1c:operator/ failed", - vec3Da.mdV[VZ], - z1*t, - 8); - x1 = 1.23, y1 = 4., z1 = -2.32; - vec3D.clearVec(); - vec3Da.clearVec(); - vec3D.setVec(x1,y1,z1); - vec3Da = vec3D/div; - ensure_approximately_equals( - "2a:operator/ failed", - vec3Da.mdV[VX], - x1*t, - 8); - ensure_approximately_equals( - "2b:operator/ failed", - vec3Da.mdV[VY], - y1*t, - 8); - ensure_approximately_equals( - "2c:operator/ failed", - vec3Da.mdV[VZ], - z1*t, - 8); - vec3D /= div; - ensure_approximately_equals( - "3a:operator/= failed", - vec3D.mdV[VX], - x1*t, - 8); - ensure_approximately_equals( - "3b:operator/= failed", - vec3D.mdV[VY], - y1*t, - 8); - ensure_approximately_equals( - "3c:operator/= failed", - vec3D.mdV[VZ], - z1*t, - 8); - } - - template<> template<> - void v3dmath_object::test<14>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - LLVector3d vec3D(x1,y1,z1), vec3Da; - ensure("1:operator!= failed",(true == (vec3D !=vec3Da))); - vec3Da = vec3D; - ensure("2:operator== failed",(vec3D ==vec3Da)); - vec3D.clearVec(); - vec3Da.clearVec(); - x1 = .211, y1 = 21.111, z1 = 23.22; - vec3D.setVec(x1,y1,z1); - vec3Da.setVec(x1,y1,z1); - ensure("3:operator== failed",(vec3D ==vec3Da)); - ensure("4:operator!= failed",(false == (vec3D !=vec3Da))); - } - - template<> template<> - void v3dmath_object::test<15>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - LLVector3d vec3D(x1,y1,z1), vec3Da; - std::ostringstream stream1, stream2; - stream1 << vec3D; - vec3Da.setVec(x1,y1,z1); - stream2 << vec3Da; - ensure("1:operator << failed",(stream1.str() == stream2.str())); - } - - template<> template<> - void v3dmath_object::test<16>() - { - F64 x1 = 1.23, y1 = 2.0, z1 = 4.; - std::string buf("1.23 2. 4"); - LLVector3d vec3D, vec3Da(x1,y1,z1); - LLVector3d::parseVector3d(buf, &vec3D); - ensure_equals("1:parseVector3d: failed " , vec3D, vec3Da); - } - - template<> template<> - void v3dmath_object::test<17>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - LLVector3d vec3D(x1,y1,z1), vec3Da; - vec3Da = -vec3D; - ensure("1:operator- failed", (vec3D == - vec3Da)); - } - - template<> template<> - void v3dmath_object::test<18>() - { - F64 x = 1., y = 2., z = -1.1; - LLVector3d vec3D(x,y,z); - F64 res = (x*x + y*y + z*z) - vec3D.magVecSquared(); - ensure("1:magVecSquared:Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO))); - res = (F32) sqrt(x*x + y*y + z*z) - vec3D.magVec(); - ensure("2:magVec: Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO))); - } - - template<> template<> - void v3dmath_object::test<19>() - { - F64 x = 1., y = 2., z = -1.1; - LLVector3d vec3D(x,y,z); - F64 mag = vec3D.normVec(); - mag = 1.f/ mag; - ensure_approximately_equals( - "1a:normVec: Fail ", - vec3D.mdV[VX], - x * mag, - 8); - ensure_approximately_equals( - "1b:normVec: Fail ", - vec3D.mdV[VY], - y * mag, - 8); - ensure_approximately_equals( - "1c:normVec: Fail ", - vec3D.mdV[VZ], - z * mag, - 8); - x = 0.000000001, y = 0.000000001, z = 0.000000001; - vec3D.clearVec(); - vec3D.setVec(x,y,z); - mag = vec3D.normVec(); - ensure_approximately_equals( - "2a:normVec: Fail ", - vec3D.mdV[VX], - x * mag, - 8); - ensure_approximately_equals( - "2b:normVec: Fail ", - vec3D.mdV[VY], - y * mag, - 8); - ensure_approximately_equals( - "2c:normVec: Fail ", - vec3D.mdV[VZ], - z * mag, - 8); - } - - template<> template<> - void v3dmath_object::test<20>() - { - F64 x1 = 1111.232222; - F64 y1 = 2222222222.22; - F64 z1 = 422222222222.0; - std::string buf("1111.232222 2222222222.22 422222222222"); - LLVector3d vec3Da, vec3Db(x1,y1,z1); - LLVector3d::parseVector3d(buf, &vec3Da); - ensure_equals("1:parseVector3 failed", vec3Da, vec3Db); - } - - template<> template<> - void v3dmath_object::test<21>() - { - F64 x1 = 1., y1 = 2., z1 = -1.1; - F64 x2 = 1.2, y2 = 2.5, z2 = 1.; - F64 val = 2.3f,val1,val2,val3; - val1 = x1 + (x2 - x1)* val; - val2 = y1 + (y2 - y1)* val; - val3 = z1 + (z2 - z1)* val; - LLVector3d vec3Da(x1,y1,z1),vec3Db(x2,y2,z2); - LLVector3d vec3d = lerp(vec3Da,vec3Db,val); - ensure("1:lerp failed", ((val1 ==vec3d.mdV[VX])&& (val2 ==vec3d.mdV[VY]) && (val3 ==vec3d.mdV[VZ]))); - } - - template<> template<> - void v3dmath_object::test<22>() - { - F64 x = 2.32, y = 1.212, z = -.12; - F64 min = 0.0001, max = 3.0; - LLVector3d vec3d(x,y,z); - ensure("1:clamp:Fail ", (true == (vec3d.clamp(min, max)))); - x = 0.000001f, z = 5.3f; - vec3d.setVec(x,y,z); - ensure("2:clamp:Fail ", (true == (vec3d.clamp(min, max)))); - } - - template<> template<> - void v3dmath_object::test<23>() - { - F64 x = 10., y = 20., z = -15.; - F64 epsilon = .23425; - LLVector3d vec3Da(x,y,z), vec3Db(x,y,z); - ensure("1:are_parallel: Fail ", (true == are_parallel(vec3Da,vec3Db,epsilon))); - F64 x1 = -12., y1 = -20., z1 = -100.; - vec3Db.clearVec(); - vec3Db.setVec(x1,y1,z1); - ensure("2:are_parallel: Fail ", (false == are_parallel(vec3Da,vec3Db,epsilon))); - } - - template<> template<> - void v3dmath_object::test<24>() - { -#if LL_WINDOWS && _MSC_VER < 1400 - skip("This fails on VS2003!"); -#else - F64 x = 10., y = 20., z = -15.; - F64 angle1, angle2; - LLVector3d vec3Da(x,y,z), vec3Db(x,y,z); - angle1 = angle_between(vec3Da, vec3Db); - ensure("1:angle_between: Fail ", (0 == angle1)); - F64 x1 = -1., y1 = -20., z1 = -1.; - vec3Da.clearVec(); - vec3Da.setVec(x1,y1,z1); - angle2 = angle_between(vec3Da, vec3Db); - vec3Db.normVec(); - vec3Da.normVec(); - F64 angle = vec3Db*vec3Da; - angle = acos(angle); -#if LL_WINDOWS && _MSC_VER > 1900 - skip("This fails on VS2017!"); -#else - ensure("2:angle_between: Fail ", (angle == angle2)); -#endif - -#endif - } -} +/** + * @file v3dmath_test.cpp + * @author Adroit + * @date 2007-03 + * @brief v3dmath test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llsd.h" +#include "../test/lltut.h" + +#include "../m3math.h" +#include "../v4math.h" +#include "../v3dmath.h" +#include "../v3dmath.h" +#include "../llquaternion.h" + +namespace tut +{ + struct v3dmath_data + { + }; + typedef test_group v3dmath_test; + typedef v3dmath_test::object v3dmath_object; + tut::v3dmath_test v3dmath_testcase("v3dmath_h"); + + template<> template<> + void v3dmath_object::test<1>() + { + LLVector3d vec3D; + ensure("1:LLVector3d:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ]))); + F64 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3d vec3Da(x,y,z); + ensure("2:LLVector3d:Fail to initialize ", ((2.32f == vec3Da.mdV[VX]) && (1.212f == vec3Da.mdV[VY]) && (-.12f == vec3Da.mdV[VZ]))); + const F64 vec[3] = {1.2f ,3.2f, -4.2f}; + LLVector3d vec3Db(vec); + ensure("3:LLVector3d:Fail to initialize ", ((1.2f == vec3Db.mdV[VX]) && (3.2f == vec3Db.mdV[VY]) && (-4.2f == vec3Db.mdV[VZ]))); + LLVector3 vec3((F32)x,(F32)y,(F32)z); + LLVector3d vec3Dc(vec3); + ensure_equals("4:LLVector3d Fail to initialize",vec3Da,vec3Dc); + } + + template<> template<> + void v3dmath_object::test<2>() + { + S32 a = -235; + LLSD llsd(a); + LLVector3d vec3d(llsd); + LLSD sd = vec3d.getValue(); + LLVector3d vec3da(sd); + ensure("1:getValue:Fail ", (vec3d == vec3da)); + } + + template<> template<> + void v3dmath_object::test<3>() + { + F64 a = 232345521.411132; + LLSD llsd(a); + LLVector3d vec3d; + vec3d.setValue(llsd); + LLSD sd = vec3d.getValue(); + LLVector3d vec3da(sd); + ensure("1:setValue:Fail to initialize ", (vec3d == vec3da)); + } + + template<> template<> + void v3dmath_object::test<4>() + { + F64 a[3] = {222231.43222, 12345.2343, -434343.33222}; + LLSD llsd; + llsd[0] = a[0]; + llsd[1] = a[1]; + llsd[2] = a[2]; + LLVector3d vec3D; + vec3D = (LLVector3d)llsd; + ensure("1:operator=:Fail to initialize ", ((llsd[0].asReal()== vec3D.mdV[VX]) && (llsd[1].asReal() == vec3D.mdV[VY]) && (llsd[2].asReal() == vec3D.mdV[VZ]))); + } + + template<> template<> + void v3dmath_object::test<5>() + { + F64 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3d vec3D(x,y,z); + vec3D.clearVec(); + ensure("1:clearVec:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ]))); + vec3D.setVec(x,y,z); + ensure("2:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ]))); + vec3D.zeroVec(); + ensure("3:zeroVec:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ]))); + vec3D.clearVec(); + LLVector3 vec3((F32)x,(F32)y,(F32)z); + vec3D.setVec(vec3); + ensure("4:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ]))); + vec3D.clearVec(); + const F64 vec[3] = {x,y,z}; + vec3D.setVec(vec); + ensure("5:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ]))); + LLVector3d vec3Da; + vec3Da.setVec(vec3D); + ensure_equals("6:setVec: Fail to initialize", vec3D, vec3Da); + } + + template<> template<> + void v3dmath_object::test<6>() + { + F64 x = -2.32, y = 1.212, z = -.12; + LLVector3d vec3D(x,y,z); + vec3D.abs(); + ensure("1:abs:Fail ", ((-x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (-z == vec3D.mdV[VZ]))); + ensure("2:isNull():Fail ", (false == vec3D.isNull())); + vec3D.clearVec(); + x =.00000001, y = .000001001, z = .000001001; + vec3D.setVec(x,y,z); + ensure("3:isNull():Fail ", (true == vec3D.isNull())); + ensure("4:isExactlyZero():Fail ", (false == vec3D.isExactlyZero())); + x =.0000000, y = .00000000, z = .00000000; + vec3D.setVec(x,y,z); + ensure("5:isExactlyZero():Fail ", (true == vec3D.isExactlyZero())); + } + + template<> template<> + void v3dmath_object::test<7>() + { + F64 x = -2.32, y = 1.212, z = -.12; + LLVector3d vec3D(x,y,z); + + ensure("1:operator [] failed",( x == vec3D[0])); + ensure("2:operator [] failed",( y == vec3D[1])); + ensure("3:operator [] failed",( z == vec3D[2])); + vec3D.clearVec(); + x = 23.23, y = -.2361, z = 3.25; + vec3D.setVec(x,y,z); + F64 &ref1 = vec3D[0]; + ensure("4:operator [] failed",( ref1 == vec3D[0])); + F64 &ref2 = vec3D[1]; + ensure("5:operator [] failed",( ref2 == vec3D[1])); + F64 &ref3 = vec3D[2]; + ensure("6:operator [] failed",( ref3 == vec3D[2])); + } + + template<> template<> + void v3dmath_object::test<8>() + { + F32 x = 1.f, y = 2.f, z = -1.f; + LLVector4 vec4(x,y,z); + LLVector3d vec3D; + vec3D = vec4; + ensure("1:operator=:Fail to initialize ", ((vec4.mV[VX] == vec3D.mdV[VX]) && (vec4.mV[VY] == vec3D.mdV[VY]) && (vec4.mV[VZ] == vec3D.mdV[VZ]))); + } + + template<> template<> + void v3dmath_object::test<9>() + { + F64 x1 = 1.78787878, y1 = 232322.2121, z1 = -12121.121212; + F64 x2 = 1.2, y2 = 2.5, z2 = 1.; + LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2),vec3Db; + vec3Db = vec3Da+ vec3D; + ensure("1:operator+:Fail to initialize ", ((x1+x2 == vec3Db.mdV[VX]) && (y1+y2 == vec3Db.mdV[VY]) && (z1+z2 == vec3Db.mdV[VZ]))); + x1 = -2.45, y1 = 2.1, z1 = 3.0; + vec3D.clearVec(); + vec3Da.clearVec(); + vec3D.setVec(x1,y1,z1); + vec3Da += vec3D; + ensure_equals("2:operator+=: Fail to initialize", vec3Da,vec3D); + vec3Da += vec3D; + ensure("3:operator+=:Fail to initialize ", ((2*x1 == vec3Da.mdV[VX]) && (2*y1 == vec3Da.mdV[VY]) && (2*z1 == vec3Da.mdV[VZ]))); + } + + template<> template<> + void v3dmath_object::test<10>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + F64 x2 = 1.2, y2 = 2.5, z2 = 1.; + LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2),vec3Db; + vec3Db = vec3Da - vec3D; + ensure("1:operator-:Fail to initialize ", ((x2-x1 == vec3Db.mdV[VX]) && (y2-y1 == vec3Db.mdV[VY]) && (z2-z1 == vec3Db.mdV[VZ]))); + x1 = -2.45, y1 = 2.1, z1 = 3.0; + vec3D.clearVec(); + vec3Da.clearVec(); + vec3D.setVec(x1,y1,z1); + vec3Da -=vec3D; + ensure("2:operator-=:Fail to initialize ", ((2.45 == vec3Da.mdV[VX]) && (-2.1 == vec3Da.mdV[VY]) && (-3.0 == vec3Da.mdV[VZ]))); + vec3Da -= vec3D; + ensure("3:operator-=:Fail to initialize ", ((-2*x1 == vec3Da.mdV[VX]) && (-2*y1 == vec3Da.mdV[VY]) && (-2*z1 == vec3Da.mdV[VZ]))); + } + template<> template<> + void v3dmath_object::test<11>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + F64 x2 = 1.2, y2 = 2.5, z2 = 1.; + LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2); + F64 res = vec3D * vec3Da; + ensure_approximately_equals( + "1:operator* failed", + res, + (x1*x2 + y1*y2 + z1*z2), + 8); + vec3Da.clearVec(); + F64 mulVal = 4.2; + vec3Da = vec3D * mulVal; + ensure_approximately_equals( + "2a:operator* failed", + vec3Da.mdV[VX], + x1*mulVal, + 8); + ensure_approximately_equals( + "2b:operator* failed", + vec3Da.mdV[VY], + y1*mulVal, + 8); + ensure_approximately_equals( + "2c:operator* failed", + vec3Da.mdV[VZ], + z1*mulVal, + 8); + vec3Da.clearVec(); + vec3Da = mulVal * vec3D; + ensure_approximately_equals( + "3a:operator* failed", + vec3Da.mdV[VX], + x1*mulVal, + 8); + ensure_approximately_equals( + "3b:operator* failed", + vec3Da.mdV[VY], + y1*mulVal, + 8); + ensure_approximately_equals( + "3c:operator* failed", + vec3Da.mdV[VZ], + z1*mulVal, + 8); + vec3D *= mulVal; + ensure_approximately_equals( + "4a:operator*= failed", + vec3D.mdV[VX], + x1*mulVal, + 8); + ensure_approximately_equals( + "4b:operator*= failed", + vec3D.mdV[VY], + y1*mulVal, + 8); + ensure_approximately_equals( + "4c:operator*= failed", + vec3D.mdV[VZ], + z1*mulVal, + 8); + } + + template<> template<> + void v3dmath_object::test<12>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + F64 x2 = 1.2, y2 = 2.5, z2 = 1.; + F64 val1, val2, val3; + LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2), vec3Db; + vec3Db = vec3D % vec3Da; + val1 = y1*z2 - y2*z1; + val2 = z1*x2 -z2*x1; + val3 = x1*y2-x2*y1; + ensure("1:operator% failed",(val1 == vec3Db.mdV[VX]) && (val2 == vec3Db.mdV[VY]) && (val3 == vec3Db.mdV[VZ])); + vec3D %= vec3Da; + ensure("2:operator%= failed", + is_approx_equal(vec3D.mdV[VX],vec3Db.mdV[VX]) && + is_approx_equal(vec3D.mdV[VY],vec3Db.mdV[VY]) && + is_approx_equal(vec3D.mdV[VZ],vec3Db.mdV[VZ]) ); + } + + template<> template<> + void v3dmath_object::test<13>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1,div = 4.2; + F64 t = 1.f / div; + LLVector3d vec3D(x1,y1,z1), vec3Da; + vec3Da = vec3D/div; + ensure_approximately_equals( + "1a:operator/ failed", + vec3Da.mdV[VX], + x1*t, + 8); + ensure_approximately_equals( + "1b:operator/ failed", + vec3Da.mdV[VY], + y1*t, + 8); + ensure_approximately_equals( + "1c:operator/ failed", + vec3Da.mdV[VZ], + z1*t, + 8); + x1 = 1.23, y1 = 4., z1 = -2.32; + vec3D.clearVec(); + vec3Da.clearVec(); + vec3D.setVec(x1,y1,z1); + vec3Da = vec3D/div; + ensure_approximately_equals( + "2a:operator/ failed", + vec3Da.mdV[VX], + x1*t, + 8); + ensure_approximately_equals( + "2b:operator/ failed", + vec3Da.mdV[VY], + y1*t, + 8); + ensure_approximately_equals( + "2c:operator/ failed", + vec3Da.mdV[VZ], + z1*t, + 8); + vec3D /= div; + ensure_approximately_equals( + "3a:operator/= failed", + vec3D.mdV[VX], + x1*t, + 8); + ensure_approximately_equals( + "3b:operator/= failed", + vec3D.mdV[VY], + y1*t, + 8); + ensure_approximately_equals( + "3c:operator/= failed", + vec3D.mdV[VZ], + z1*t, + 8); + } + + template<> template<> + void v3dmath_object::test<14>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + LLVector3d vec3D(x1,y1,z1), vec3Da; + ensure("1:operator!= failed",(true == (vec3D !=vec3Da))); + vec3Da = vec3D; + ensure("2:operator== failed",(vec3D ==vec3Da)); + vec3D.clearVec(); + vec3Da.clearVec(); + x1 = .211, y1 = 21.111, z1 = 23.22; + vec3D.setVec(x1,y1,z1); + vec3Da.setVec(x1,y1,z1); + ensure("3:operator== failed",(vec3D ==vec3Da)); + ensure("4:operator!= failed",(false == (vec3D !=vec3Da))); + } + + template<> template<> + void v3dmath_object::test<15>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + LLVector3d vec3D(x1,y1,z1), vec3Da; + std::ostringstream stream1, stream2; + stream1 << vec3D; + vec3Da.setVec(x1,y1,z1); + stream2 << vec3Da; + ensure("1:operator << failed",(stream1.str() == stream2.str())); + } + + template<> template<> + void v3dmath_object::test<16>() + { + F64 x1 = 1.23, y1 = 2.0, z1 = 4.; + std::string buf("1.23 2. 4"); + LLVector3d vec3D, vec3Da(x1,y1,z1); + LLVector3d::parseVector3d(buf, &vec3D); + ensure_equals("1:parseVector3d: failed " , vec3D, vec3Da); + } + + template<> template<> + void v3dmath_object::test<17>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + LLVector3d vec3D(x1,y1,z1), vec3Da; + vec3Da = -vec3D; + ensure("1:operator- failed", (vec3D == - vec3Da)); + } + + template<> template<> + void v3dmath_object::test<18>() + { + F64 x = 1., y = 2., z = -1.1; + LLVector3d vec3D(x,y,z); + F64 res = (x*x + y*y + z*z) - vec3D.magVecSquared(); + ensure("1:magVecSquared:Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO))); + res = (F32) sqrt(x*x + y*y + z*z) - vec3D.magVec(); + ensure("2:magVec: Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO))); + } + + template<> template<> + void v3dmath_object::test<19>() + { + F64 x = 1., y = 2., z = -1.1; + LLVector3d vec3D(x,y,z); + F64 mag = vec3D.normVec(); + mag = 1.f/ mag; + ensure_approximately_equals( + "1a:normVec: Fail ", + vec3D.mdV[VX], + x * mag, + 8); + ensure_approximately_equals( + "1b:normVec: Fail ", + vec3D.mdV[VY], + y * mag, + 8); + ensure_approximately_equals( + "1c:normVec: Fail ", + vec3D.mdV[VZ], + z * mag, + 8); + x = 0.000000001, y = 0.000000001, z = 0.000000001; + vec3D.clearVec(); + vec3D.setVec(x,y,z); + mag = vec3D.normVec(); + ensure_approximately_equals( + "2a:normVec: Fail ", + vec3D.mdV[VX], + x * mag, + 8); + ensure_approximately_equals( + "2b:normVec: Fail ", + vec3D.mdV[VY], + y * mag, + 8); + ensure_approximately_equals( + "2c:normVec: Fail ", + vec3D.mdV[VZ], + z * mag, + 8); + } + + template<> template<> + void v3dmath_object::test<20>() + { + F64 x1 = 1111.232222; + F64 y1 = 2222222222.22; + F64 z1 = 422222222222.0; + std::string buf("1111.232222 2222222222.22 422222222222"); + LLVector3d vec3Da, vec3Db(x1,y1,z1); + LLVector3d::parseVector3d(buf, &vec3Da); + ensure_equals("1:parseVector3 failed", vec3Da, vec3Db); + } + + template<> template<> + void v3dmath_object::test<21>() + { + F64 x1 = 1., y1 = 2., z1 = -1.1; + F64 x2 = 1.2, y2 = 2.5, z2 = 1.; + F64 val = 2.3f,val1,val2,val3; + val1 = x1 + (x2 - x1)* val; + val2 = y1 + (y2 - y1)* val; + val3 = z1 + (z2 - z1)* val; + LLVector3d vec3Da(x1,y1,z1),vec3Db(x2,y2,z2); + LLVector3d vec3d = lerp(vec3Da,vec3Db,val); + ensure("1:lerp failed", ((val1 ==vec3d.mdV[VX])&& (val2 ==vec3d.mdV[VY]) && (val3 ==vec3d.mdV[VZ]))); + } + + template<> template<> + void v3dmath_object::test<22>() + { + F64 x = 2.32, y = 1.212, z = -.12; + F64 min = 0.0001, max = 3.0; + LLVector3d vec3d(x,y,z); + ensure("1:clamp:Fail ", (true == (vec3d.clamp(min, max)))); + x = 0.000001f, z = 5.3f; + vec3d.setVec(x,y,z); + ensure("2:clamp:Fail ", (true == (vec3d.clamp(min, max)))); + } + + template<> template<> + void v3dmath_object::test<23>() + { + F64 x = 10., y = 20., z = -15.; + F64 epsilon = .23425; + LLVector3d vec3Da(x,y,z), vec3Db(x,y,z); + ensure("1:are_parallel: Fail ", (true == are_parallel(vec3Da,vec3Db,epsilon))); + F64 x1 = -12., y1 = -20., z1 = -100.; + vec3Db.clearVec(); + vec3Db.setVec(x1,y1,z1); + ensure("2:are_parallel: Fail ", (false == are_parallel(vec3Da,vec3Db,epsilon))); + } + + template<> template<> + void v3dmath_object::test<24>() + { +#if LL_WINDOWS && _MSC_VER < 1400 + skip("This fails on VS2003!"); +#else + F64 x = 10., y = 20., z = -15.; + F64 angle1, angle2; + LLVector3d vec3Da(x,y,z), vec3Db(x,y,z); + angle1 = angle_between(vec3Da, vec3Db); + ensure("1:angle_between: Fail ", (0 == angle1)); + F64 x1 = -1., y1 = -20., z1 = -1.; + vec3Da.clearVec(); + vec3Da.setVec(x1,y1,z1); + angle2 = angle_between(vec3Da, vec3Db); + vec3Db.normVec(); + vec3Da.normVec(); + F64 angle = vec3Db*vec3Da; + angle = acos(angle); +#if LL_WINDOWS && _MSC_VER > 1900 + skip("This fails on VS2017!"); +#else + ensure("2:angle_between: Fail ", (angle == angle2)); +#endif + +#endif + } +} diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp index 93d9f4a006..6d95a9e5b7 100644 --- a/indra/llmath/tests/v3math_test.cpp +++ b/indra/llmath/tests/v3math_test.cpp @@ -1,585 +1,585 @@ -/** - * @file v3math_test.cpp - * @author Adroit - * @date 2007-02 - * @brief v3math test cases. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" -#include "llsd.h" - -#include "../v3dmath.h" -#include "../m3math.h" -#include "../v4math.h" -#include "../v3math.h" -#include "../llquaternion.h" -#include "../llquantize.h" - - -namespace tut -{ - struct v3math_data - { - }; - typedef test_group v3math_test; - typedef v3math_test::object v3math_object; - tut::v3math_test v3math_testcase("v3math_h"); - - template<> template<> - void v3math_object::test<1>() - { - LLVector3 vec3; - ensure("1:LLVector3:Fail to initialize ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); - F32 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3 vec3a(x,y,z); - ensure("2:LLVector3:Fail to initialize ", ((2.32f == vec3a.mV[VX]) && (1.212f == vec3a.mV[VY]) && (-.12f == vec3a.mV[VZ]))); - const F32 vec[3] = {1.2f ,3.2f, -4.2f}; - LLVector3 vec3b(vec); - ensure("3:LLVector3:Fail to initialize ", ((1.2f == vec3b.mV[VX]) && (3.2f == vec3b.mV[VY]) && (-4.2f == vec3b.mV[VZ]))); - } - - template<> template<> - void v3math_object::test<2>() - { - F32 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3 vec3(x,y,z); - LLVector3d vector3d(vec3); - LLVector3 vec3a(vector3d); - ensure("1:LLVector3:Fail to initialize ", vec3 == vec3a); - LLVector4 vector4(vec3); - LLVector3 vec3b(vector4); - ensure("2:LLVector3:Fail to initialize ", vec3 == vec3b); - } - - template<> template<> - void v3math_object::test<3>() - { - S32 a = 231; - LLSD llsd(a); - LLVector3 vec3(llsd); - LLSD sd = vec3.getValue(); - LLVector3 vec3a(sd); - ensure("1:LLVector3:Fail to initialize ", (vec3 == vec3a)); - } - - template<> template<> - void v3math_object::test<4>() - { - S32 a = 231; - LLSD llsd(a); - LLVector3 vec3(llsd),vec3a; - vec3a = vec3; - ensure("1:Operator= Fail to initialize " ,(vec3 == vec3a)); - } - - template<> template<> - void v3math_object::test<5>() - { - F32 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3 vec3(x,y,z); - ensure("1:isFinite= Fail to initialize ", (true == vec3.isFinite()));//need more test cases: - vec3.clearVec(); - ensure("2:clearVec:Fail to set values ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); - vec3.setVec(x,y,z); - ensure("3:setVec:Fail to set values ", ((2.32f == vec3.mV[VX]) && (1.212f == vec3.mV[VY]) && (-.12f == vec3.mV[VZ]))); - vec3.zeroVec(); - ensure("4:zeroVec:Fail to set values ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); - } - - template<> template<> - void v3math_object::test<6>() - { - F32 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3 vec3(x,y,z),vec3a; - vec3.abs(); - ensure("1:abs:Fail ", ((x == vec3.mV[VX]) && (y == vec3.mV[VY]) && (-z == vec3.mV[VZ]))); - vec3a.setVec(vec3); - ensure("2:setVec:Fail to initialize ", (vec3a == vec3)); - const F32 vec[3] = {1.2f ,3.2f, -4.2f}; - vec3.clearVec(); - vec3.setVec(vec); - ensure("3:setVec:Fail to initialize ", ((1.2f == vec3.mV[VX]) && (3.2f == vec3.mV[VY]) && (-4.2f == vec3.mV[VZ]))); - vec3a.clearVec(); - LLVector3d vector3d(vec3); - vec3a.setVec(vector3d); - ensure("4:setVec:Fail to initialize ", (vec3 == vec3a)); - LLVector4 vector4(vec3); - vec3a.clearVec(); - vec3a.setVec(vector4); - ensure("5:setVec:Fail to initialize ", (vec3 == vec3a)); - } - - template<> template<> - void v3math_object::test<7>() - { - F32 x = 2.32f, y = 3.212f, z = -.12f; - F32 min = 0.0001f, max = 3.0f; - LLVector3 vec3(x,y,z); - ensure("1:clamp:Fail ", true == vec3.clamp(min, max) && x == vec3.mV[VX] && max == vec3.mV[VY] && min == vec3.mV[VZ]); - x = 1.f, y = 2.2f, z = 2.8f; - vec3.setVec(x,y,z); - ensure("2:clamp:Fail ", false == vec3.clamp(min, max)); - } - - template<> template<> - void v3math_object::test<8>() - { - F32 x = 2.32f, y = 1.212f, z = -.12f; - LLVector3 vec3(x,y,z); - ensure("1:magVecSquared:Fail ", is_approx_equal(vec3.magVecSquared(), (x*x + y*y + z*z))); - ensure("2:magVec:Fail ", is_approx_equal(vec3.magVec(), (F32) sqrt(x*x + y*y + z*z))); - } - - template<> template<> - void v3math_object::test<9>() - { - F32 x =-2.0f, y = -3.0f, z = 1.23f ; - LLVector3 vec3(x,y,z); - ensure("1:abs():Fail ", (true == vec3.abs())); - ensure("2:isNull():Fail", (false == vec3.isNull())); //Returns true if vector has a _very_small_ length - x =.00000001f, y = .000001001f, z = .000001001f; - vec3.setVec(x,y,z); - ensure("3:isNull(): Fail ", (true == vec3.isNull())); - } - - template<> template<> - void v3math_object::test<10>() - { - F32 x =-2.0f, y = -3.0f, z = 1.f ; - LLVector3 vec3(x,y,z),vec3a; - ensure("1:isExactlyZero():Fail ", (true == vec3a.isExactlyZero())); - vec3a = vec3a.scaleVec(vec3); - ensure("2:scaleVec: Fail ", vec3a.mV[VX] == 0.f && vec3a.mV[VY] == 0.f && vec3a.mV[VZ] == 0.f); - vec3a.setVec(x,y,z); - vec3a = vec3a.scaleVec(vec3); - ensure("3:scaleVec: Fail ", ((4 == vec3a.mV[VX]) && (9 == vec3a.mV[VY]) &&(1 == vec3a.mV[VZ]))); - ensure("4:isExactlyZero():Fail ", (false == vec3.isExactlyZero())); - } - - template<> template<> - void v3math_object::test<11>() - { - F32 x =20.0f, y = 30.0f, z = 15.f ; - F32 angle = 100.f; - LLVector3 vec3(x,y,z),vec3a(1.f,2.f,3.f); - vec3a = vec3a.rotVec(angle, vec3); - LLVector3 vec3b(1.f,2.f,3.f); - vec3b = vec3b.rotVec(angle, vec3); - ensure_equals("rotVec():Fail" ,vec3b,vec3a); - } - - template<> template<> - void v3math_object::test<12>() - { - F32 x =-2.0f, y = -3.0f, z = 1.f ; - LLVector3 vec3(x,y,z); - ensure("1:operator [] failed",( x == vec3[0])); - ensure("2:operator [] failed",( y == vec3[1])); - ensure("3:operator [] failed",( z == vec3[2])); - - vec3.clearVec(); - x = 23.f, y = -.2361f, z = 3.25; - vec3.setVec(x,y,z); - F32 &ref1 = vec3[0]; - ensure("4:operator [] failed",( ref1 == vec3[0])); - F32 &ref2 = vec3[1]; - ensure("5:operator [] failed",( ref2 == vec3[1])); - F32 &ref3 = vec3[2]; - ensure("6:operator [] failed",( ref3 == vec3[2])); - } - - template<> template<> - void v3math_object::test<13>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; - F32 val1, val2, val3; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2), vec3b; - vec3b = vec3 + vec3a ; - val1 = x1+x2; - val2 = y1+y2; - val3 = z1+z2; - ensure("1:operator+ failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); - - vec3.clearVec(); - vec3a.clearVec(); - vec3b.clearVec(); - x1 = -.235f, y1 = -24.32f,z1 = 2.13f, x2 = -2.3f, y2 = 1.f, z2 = 34.21f; - vec3.setVec(x1,y1,z1); - vec3a.setVec(x2,y2,z2); - vec3b = vec3 + vec3a; - val1 = x1+x2; - val2 = y1+y2; - val3 = z1+z2; - ensure("2:operator+ failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); - } - - template<> template<> - void v3math_object::test<14>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; - F32 val1, val2, val3; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2), vec3b; - vec3b = vec3 - vec3a ; - val1 = x1-x2; - val2 = y1-y2; - val3 = z1-z2; - ensure("1:operator- failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); - - vec3.clearVec(); - vec3a.clearVec(); - vec3b.clearVec(); - x1 = -.235f, y1 = -24.32f,z1 = 2.13f, x2 = -2.3f, y2 = 1.f, z2 = 34.21f; - vec3.setVec(x1,y1,z1); - vec3a.setVec(x2,y2,z2); - vec3b = vec3 - vec3a; - val1 = x1-x2; - val2 = y1-y2; - val3 = z1-z2; - ensure("2:operator- failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); - } - - template<> template<> - void v3math_object::test<15>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; - F32 val1, val2, val3; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - val1 = vec3 * vec3a; - val2 = x1*x2 + y1*y2 + z1*z2; - ensure_equals("1:operator* failed",val1,val2); - - vec3a.clearVec(); - F32 mulVal = 4.332f; - vec3a = vec3 * mulVal; - val1 = x1*mulVal; - val2 = y1*mulVal; - val3 = z1*mulVal; - ensure("2:operator* failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); - vec3a.clearVec(); - vec3a = mulVal * vec3; - ensure("3:operator* failed ", (val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); - } - - template<> template<> - void v3math_object::test<16>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; - F32 val1, val2, val3; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2), vec3b; - vec3b = vec3 % vec3a ; - val1 = y1*z2 - y2*z1; - val2 = z1*x2 -z2*x1; - val3 = x1*y2-x2*y1; - ensure("1:operator% failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); - - vec3.clearVec(); - vec3a.clearVec(); - vec3b.clearVec(); - x1 =112.f, y1 = 22.3f,z1 = 1.2f, x2 = -2.3f, y2 = 341.11f, z2 = 1234.234f; - vec3.setVec(x1,y1,z1); - vec3a.setVec(x2,y2,z2); - vec3b = vec3 % vec3a ; - val1 = y1*z2 - y2*z1; - val2 = z1*x2 -z2*x1; - val3 = x1*y2-x2*y1; - ensure("2:operator% failed ", (val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); - } - - template<> template<> - void v3math_object::test<17>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, div = 3.2f; - F32 t = 1.f / div, val1, val2, val3; - LLVector3 vec3(x1,y1,z1), vec3a; - vec3a = vec3 / div; - val1 = x1 * t; - val2 = y1 * t; - val3 = z1 *t; - ensure("1:operator/ failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY]) && (val3 == vec3a.mV[VZ])); - - vec3a.clearVec(); - x1 = -.235f, y1 = -24.32f, z1 = .342f, div = -2.2f; - t = 1.f / div; - vec3.setVec(x1,y1,z1); - vec3a = vec3 / div; - val1 = x1 * t; - val2 = y1 * t; - val3 = z1 *t; - ensure("2:operator/ failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY]) && (val3 == vec3a.mV[VZ])); - } - - template<> template<> - void v3math_object::test<18>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f; - LLVector3 vec3(x1,y1,z1), vec3a(x1,y1,z1); - ensure("1:operator== failed",(vec3 == vec3a)); - - vec3a.clearVec(); - x1 = -.235f, y1 = -24.32f, z1 = .342f; - vec3.clearVec(); - vec3a.clearVec(); - vec3.setVec(x1,y1,z1); - vec3a.setVec(x1,y1,z1); - ensure("2:operator== failed ", (vec3 == vec3a)); - } - - template<> template<> - void v3math_object::test<19>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 =112.f, y2 = 2.234f,z2 = 11.2f;; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - ensure("1:operator!= failed",(vec3a != vec3)); - - vec3.clearVec(); - vec3.clearVec(); - vec3a.setVec(vec3); - ensure("2:operator!= failed", ( false == (vec3a != vec3))); - } - - template<> template<> - void v3math_object::test<20>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 =112.f, y2 = 2.2f,z2 = 11.2f;; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - vec3a += vec3; - F32 val1, val2, val3; - val1 = x1+x2; - val2 = y1+y2; - val3 = z1+z2; - ensure("1:operator+= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); - } - - template<> template<> - void v3math_object::test<21>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 =112.f, y2 = 2.2f,z2 = 11.2f;; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - vec3a -= vec3; - F32 val1, val2, val3; - val1 = x2-x1; - val2 = y2-y1; - val3 = z2-z1; - ensure("1:operator-= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); - } - - template<> template<> - void v3math_object::test<22>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; - F32 val1,val2,val3; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - vec3a *= vec3; - val1 = x1*x2; - val2 = y1*y2; - val3 = z1*z2; - ensure("1:operator*= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); - - F32 mulVal = 4.332f; - vec3 *=mulVal; - val1 = x1*mulVal; - val2 = y1*mulVal; - val3 = z1*mulVal; - ensure("2:operator*= failed ", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY]) && is_approx_equal(val3, vec3.mV[VZ])); - } - - template<> template<> - void v3math_object::test<23>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2),vec3b; - vec3b = vec3a % vec3; - vec3a %= vec3; - ensure_equals("1:operator%= failed",vec3a,vec3b); - } - - template<> template<> - void v3math_object::test<24>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, div = 3.2f; - F32 t = 1.f / div, val1, val2, val3; - LLVector3 vec3a(x1,y1,z1); - vec3a /= div; - val1 = x1 * t; - val2 = y1 * t; - val3 = z1 *t; - ensure("1:operator/= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY]) && (val3 == vec3a.mV[VZ])); - } - - template<> template<> - void v3math_object::test<25>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f; - LLVector3 vec3(x1,y1,z1), vec3a; - vec3a = -vec3; - ensure("1:operator- failed",(-vec3a == vec3)); - } - - template<> template<> - void v3math_object::test<26>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 1.2f; - std::ostringstream stream1, stream2; - LLVector3 vec3(x1,y1,z1), vec3a; - stream1 << vec3; - vec3a.setVec(x1,y1,z1); - stream2 << vec3a; - ensure("1:operator << failed",(stream1.str() == stream2.str())); - } - - template<> template<> - void v3math_object::test<27>() - { - F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.11f, z2 = 1234.234f; - LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); - ensure("1:operator< failed", (true == (vec3 < vec3a))); - x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 2.f, z2 = 1234.234f; - vec3.setVec(x1,y1,z1); - vec3a.setVec(x2,y2,z2); - ensure("2:operator< failed ", (true == (vec3 < vec3a))); - x1 =2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, - vec3.setVec(x1,y1,z1); - vec3a.setVec(x2,y2,z2); - ensure("3:operator< failed ", (false == (vec3 < vec3a))); - } - - template<> template<> - void v3math_object::test<28>() - { - F32 x1 =1.23f, y1 = 2.f,z1 = 4.f; - std::string buf("1.23 2. 4"); - LLVector3 vec3, vec3a(x1,y1,z1); - LLVector3::parseVector3(buf, &vec3); - ensure_equals("1:parseVector3 failed", vec3, vec3a); - } - - template<> template<> - void v3math_object::test<29>() - { - F32 x1 =1.f, y1 = 2.f,z1 = 4.f; - LLVector3 vec3(x1,y1,z1),vec3a,vec3b; - vec3a.setVec(1,1,1); - vec3a.scaleVec(vec3); - ensure_equals("1:scaleVec failed", vec3, vec3a); - vec3a.clearVec(); - vec3a.setVec(x1,y1,z1); - vec3a.scaleVec(vec3); - ensure("2:scaleVec failed", ((1.f ==vec3a.mV[VX])&& (4.f ==vec3a.mV[VY]) && (16.f ==vec3a.mV[VZ]))); - } - - template<> template<> - void v3math_object::test<30>() - { - F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.11f, z2 = 1234.234f; - F32 val = 2.3f,val1,val2,val3; - val1 = x1 + (x2 - x1)* val; - val2 = y1 + (y2 - y1)* val; - val3 = z1 + (z2 - z1)* val; - LLVector3 vec3(x1,y1,z1),vec3a(x2,y2,z2); - LLVector3 vec3b = lerp(vec3,vec3a,val); - ensure("1:lerp failed", ((val1 ==vec3b.mV[VX])&& (val2 ==vec3b.mV[VY]) && (val3 ==vec3b.mV[VZ]))); - } - - template<> template<> - void v3math_object::test<31>() - { - F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.f, z2 = 1.f; - F32 val1,val2; - LLVector3 vec3(x1,y1,z1),vec3a(x2,y2,z2); - val1 = dist_vec(vec3,vec3a); - val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); - ensure_equals("1:dist_vec: Fail ",val2, val1); - val1 = dist_vec_squared(vec3,vec3a); - val2 =((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); - ensure_equals("2:dist_vec_squared: Fail ",val2, val1); - val1 = dist_vec_squared2D(vec3, vec3a); - val2 =(x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2); - ensure_equals("3:dist_vec_squared2D: Fail ",val2, val1); - } - - template<> template<> - void v3math_object::test<32>() - { - F32 x =12.3524f, y = -342.f,z = 4.126341f; - LLVector3 vec3(x,y,z); - F32 mag = vec3.normVec(); - mag = 1.f/ mag; - F32 val1 = x* mag, val2 = y* mag, val3 = z* mag; - ensure("1:normVec: Fail ", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY]) && is_approx_equal(val3, vec3.mV[VZ])); - x = 0.000000001f, y = 0.f, z = 0.f; - vec3.clearVec(); - vec3.setVec(x,y,z); - mag = vec3.normVec(); - val1 = x* mag, val2 = y* mag, val3 = z* mag; - ensure("2:normVec: Fail ", (mag == 0.) && (0. == vec3.mV[VX]) && (0. == vec3.mV[VY])&& (0. == vec3.mV[VZ])); - } - - template<> template<> - void v3math_object::test<33>() - { - F32 x = -202.23412f, y = 123.2312f, z = -89.f; - LLVector3 vec(x,y,z); - vec.snap(2); - ensure("1:snap: Fail ", is_approx_equal(-202.23f, vec.mV[VX]) && is_approx_equal(123.23f, vec.mV[VY]) && is_approx_equal(-89.f, vec.mV[VZ])); - } - - template<> template<> - void v3math_object::test<34>() - { - F32 x = 10.f, y = 20.f, z = -15.f; - F32 x1, y1, z1; - F32 lowerxy = 0.f, upperxy = 1.0f, lowerz = -1.0f, upperz = 1.f; - LLVector3 vec3(x,y,z); - vec3.quantize16(lowerxy,upperxy,lowerz,upperz); - x1 = U16_to_F32(F32_to_U16(x, lowerxy, upperxy), lowerxy, upperxy); - y1 = U16_to_F32(F32_to_U16(y, lowerxy, upperxy), lowerxy, upperxy); - z1 = U16_to_F32(F32_to_U16(z, lowerz, upperz), lowerz, upperz); - ensure("1:quantize16: Fail ", is_approx_equal(x1, vec3.mV[VX]) && is_approx_equal(y1, vec3.mV[VY]) && is_approx_equal(z1, vec3.mV[VZ])); - LLVector3 vec3a(x,y,z); - vec3a.quantize8(lowerxy,upperxy,lowerz,upperz); - x1 = U8_to_F32(F32_to_U8(x, lowerxy, upperxy), lowerxy, upperxy); - y1 = U8_to_F32(F32_to_U8(y, lowerxy, upperxy), lowerxy, upperxy); - z1 = U8_to_F32(F32_to_U8(z, lowerz, upperz), lowerz, upperz); - ensure("2:quantize8: Fail ", is_approx_equal(x1, vec3a.mV[VX]) && is_approx_equal(y1, vec3a.mV[VY]) && is_approx_equal(z1, vec3a.mV[VZ])); - } - - template<> template<> - void v3math_object::test<35>() - { - LLSD sd = LLSD::emptyArray(); - sd[0] = 1.f; - - LLVector3 parsed_1(sd); - ensure("1:LLSD parse: Fail ", is_approx_equal(parsed_1.mV[VX], 1.f) && is_approx_equal(parsed_1.mV[VY], 0.f) && is_approx_equal(parsed_1.mV[VZ], 0.f)); - - sd[1] = 2.f; - LLVector3 parsed_2(sd); - ensure("2:LLSD parse: Fail ", is_approx_equal(parsed_2.mV[VX], 1.f) && is_approx_equal(parsed_2.mV[VY], 2.f) && is_approx_equal(parsed_2.mV[VZ], 0.f)); - - sd[2] = 3.f; - LLVector3 parsed_3(sd); - ensure("3:LLSD parse: Fail ", is_approx_equal(parsed_3.mV[VX], 1.f) && is_approx_equal(parsed_3.mV[VY], 2.f) && is_approx_equal(parsed_3.mV[VZ], 3.f)); - } -} +/** + * @file v3math_test.cpp + * @author Adroit + * @date 2007-02 + * @brief v3math test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" +#include "llsd.h" + +#include "../v3dmath.h" +#include "../m3math.h" +#include "../v4math.h" +#include "../v3math.h" +#include "../llquaternion.h" +#include "../llquantize.h" + + +namespace tut +{ + struct v3math_data + { + }; + typedef test_group v3math_test; + typedef v3math_test::object v3math_object; + tut::v3math_test v3math_testcase("v3math_h"); + + template<> template<> + void v3math_object::test<1>() + { + LLVector3 vec3; + ensure("1:LLVector3:Fail to initialize ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); + F32 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3 vec3a(x,y,z); + ensure("2:LLVector3:Fail to initialize ", ((2.32f == vec3a.mV[VX]) && (1.212f == vec3a.mV[VY]) && (-.12f == vec3a.mV[VZ]))); + const F32 vec[3] = {1.2f ,3.2f, -4.2f}; + LLVector3 vec3b(vec); + ensure("3:LLVector3:Fail to initialize ", ((1.2f == vec3b.mV[VX]) && (3.2f == vec3b.mV[VY]) && (-4.2f == vec3b.mV[VZ]))); + } + + template<> template<> + void v3math_object::test<2>() + { + F32 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3 vec3(x,y,z); + LLVector3d vector3d(vec3); + LLVector3 vec3a(vector3d); + ensure("1:LLVector3:Fail to initialize ", vec3 == vec3a); + LLVector4 vector4(vec3); + LLVector3 vec3b(vector4); + ensure("2:LLVector3:Fail to initialize ", vec3 == vec3b); + } + + template<> template<> + void v3math_object::test<3>() + { + S32 a = 231; + LLSD llsd(a); + LLVector3 vec3(llsd); + LLSD sd = vec3.getValue(); + LLVector3 vec3a(sd); + ensure("1:LLVector3:Fail to initialize ", (vec3 == vec3a)); + } + + template<> template<> + void v3math_object::test<4>() + { + S32 a = 231; + LLSD llsd(a); + LLVector3 vec3(llsd),vec3a; + vec3a = vec3; + ensure("1:Operator= Fail to initialize " ,(vec3 == vec3a)); + } + + template<> template<> + void v3math_object::test<5>() + { + F32 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3 vec3(x,y,z); + ensure("1:isFinite= Fail to initialize ", (true == vec3.isFinite()));//need more test cases: + vec3.clearVec(); + ensure("2:clearVec:Fail to set values ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); + vec3.setVec(x,y,z); + ensure("3:setVec:Fail to set values ", ((2.32f == vec3.mV[VX]) && (1.212f == vec3.mV[VY]) && (-.12f == vec3.mV[VZ]))); + vec3.zeroVec(); + ensure("4:zeroVec:Fail to set values ", ((0.f == vec3.mV[VX]) && (0.f == vec3.mV[VY]) && (0.f == vec3.mV[VZ]))); + } + + template<> template<> + void v3math_object::test<6>() + { + F32 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3 vec3(x,y,z),vec3a; + vec3.abs(); + ensure("1:abs:Fail ", ((x == vec3.mV[VX]) && (y == vec3.mV[VY]) && (-z == vec3.mV[VZ]))); + vec3a.setVec(vec3); + ensure("2:setVec:Fail to initialize ", (vec3a == vec3)); + const F32 vec[3] = {1.2f ,3.2f, -4.2f}; + vec3.clearVec(); + vec3.setVec(vec); + ensure("3:setVec:Fail to initialize ", ((1.2f == vec3.mV[VX]) && (3.2f == vec3.mV[VY]) && (-4.2f == vec3.mV[VZ]))); + vec3a.clearVec(); + LLVector3d vector3d(vec3); + vec3a.setVec(vector3d); + ensure("4:setVec:Fail to initialize ", (vec3 == vec3a)); + LLVector4 vector4(vec3); + vec3a.clearVec(); + vec3a.setVec(vector4); + ensure("5:setVec:Fail to initialize ", (vec3 == vec3a)); + } + + template<> template<> + void v3math_object::test<7>() + { + F32 x = 2.32f, y = 3.212f, z = -.12f; + F32 min = 0.0001f, max = 3.0f; + LLVector3 vec3(x,y,z); + ensure("1:clamp:Fail ", true == vec3.clamp(min, max) && x == vec3.mV[VX] && max == vec3.mV[VY] && min == vec3.mV[VZ]); + x = 1.f, y = 2.2f, z = 2.8f; + vec3.setVec(x,y,z); + ensure("2:clamp:Fail ", false == vec3.clamp(min, max)); + } + + template<> template<> + void v3math_object::test<8>() + { + F32 x = 2.32f, y = 1.212f, z = -.12f; + LLVector3 vec3(x,y,z); + ensure("1:magVecSquared:Fail ", is_approx_equal(vec3.magVecSquared(), (x*x + y*y + z*z))); + ensure("2:magVec:Fail ", is_approx_equal(vec3.magVec(), (F32) sqrt(x*x + y*y + z*z))); + } + + template<> template<> + void v3math_object::test<9>() + { + F32 x =-2.0f, y = -3.0f, z = 1.23f ; + LLVector3 vec3(x,y,z); + ensure("1:abs():Fail ", (true == vec3.abs())); + ensure("2:isNull():Fail", (false == vec3.isNull())); //Returns true if vector has a _very_small_ length + x =.00000001f, y = .000001001f, z = .000001001f; + vec3.setVec(x,y,z); + ensure("3:isNull(): Fail ", (true == vec3.isNull())); + } + + template<> template<> + void v3math_object::test<10>() + { + F32 x =-2.0f, y = -3.0f, z = 1.f ; + LLVector3 vec3(x,y,z),vec3a; + ensure("1:isExactlyZero():Fail ", (true == vec3a.isExactlyZero())); + vec3a = vec3a.scaleVec(vec3); + ensure("2:scaleVec: Fail ", vec3a.mV[VX] == 0.f && vec3a.mV[VY] == 0.f && vec3a.mV[VZ] == 0.f); + vec3a.setVec(x,y,z); + vec3a = vec3a.scaleVec(vec3); + ensure("3:scaleVec: Fail ", ((4 == vec3a.mV[VX]) && (9 == vec3a.mV[VY]) &&(1 == vec3a.mV[VZ]))); + ensure("4:isExactlyZero():Fail ", (false == vec3.isExactlyZero())); + } + + template<> template<> + void v3math_object::test<11>() + { + F32 x =20.0f, y = 30.0f, z = 15.f ; + F32 angle = 100.f; + LLVector3 vec3(x,y,z),vec3a(1.f,2.f,3.f); + vec3a = vec3a.rotVec(angle, vec3); + LLVector3 vec3b(1.f,2.f,3.f); + vec3b = vec3b.rotVec(angle, vec3); + ensure_equals("rotVec():Fail" ,vec3b,vec3a); + } + + template<> template<> + void v3math_object::test<12>() + { + F32 x =-2.0f, y = -3.0f, z = 1.f ; + LLVector3 vec3(x,y,z); + ensure("1:operator [] failed",( x == vec3[0])); + ensure("2:operator [] failed",( y == vec3[1])); + ensure("3:operator [] failed",( z == vec3[2])); + + vec3.clearVec(); + x = 23.f, y = -.2361f, z = 3.25; + vec3.setVec(x,y,z); + F32 &ref1 = vec3[0]; + ensure("4:operator [] failed",( ref1 == vec3[0])); + F32 &ref2 = vec3[1]; + ensure("5:operator [] failed",( ref2 == vec3[1])); + F32 &ref3 = vec3[2]; + ensure("6:operator [] failed",( ref3 == vec3[2])); + } + + template<> template<> + void v3math_object::test<13>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; + F32 val1, val2, val3; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2), vec3b; + vec3b = vec3 + vec3a ; + val1 = x1+x2; + val2 = y1+y2; + val3 = z1+z2; + ensure("1:operator+ failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); + + vec3.clearVec(); + vec3a.clearVec(); + vec3b.clearVec(); + x1 = -.235f, y1 = -24.32f,z1 = 2.13f, x2 = -2.3f, y2 = 1.f, z2 = 34.21f; + vec3.setVec(x1,y1,z1); + vec3a.setVec(x2,y2,z2); + vec3b = vec3 + vec3a; + val1 = x1+x2; + val2 = y1+y2; + val3 = z1+z2; + ensure("2:operator+ failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); + } + + template<> template<> + void v3math_object::test<14>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; + F32 val1, val2, val3; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2), vec3b; + vec3b = vec3 - vec3a ; + val1 = x1-x2; + val2 = y1-y2; + val3 = z1-z2; + ensure("1:operator- failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); + + vec3.clearVec(); + vec3a.clearVec(); + vec3b.clearVec(); + x1 = -.235f, y1 = -24.32f,z1 = 2.13f, x2 = -2.3f, y2 = 1.f, z2 = 34.21f; + vec3.setVec(x1,y1,z1); + vec3a.setVec(x2,y2,z2); + vec3b = vec3 - vec3a; + val1 = x1-x2; + val2 = y1-y2; + val3 = z1-z2; + ensure("2:operator- failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); + } + + template<> template<> + void v3math_object::test<15>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; + F32 val1, val2, val3; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); + val1 = vec3 * vec3a; + val2 = x1*x2 + y1*y2 + z1*z2; + ensure_equals("1:operator* failed",val1,val2); + + vec3a.clearVec(); + F32 mulVal = 4.332f; + vec3a = vec3 * mulVal; + val1 = x1*mulVal; + val2 = y1*mulVal; + val3 = z1*mulVal; + ensure("2:operator* failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); + vec3a.clearVec(); + vec3a = mulVal * vec3; + ensure("3:operator* failed ", (val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); + } + + template<> template<> + void v3math_object::test<16>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; + F32 val1, val2, val3; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2), vec3b; + vec3b = vec3 % vec3a ; + val1 = y1*z2 - y2*z1; + val2 = z1*x2 -z2*x1; + val3 = x1*y2-x2*y1; + ensure("1:operator% failed",(val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); + + vec3.clearVec(); + vec3a.clearVec(); + vec3b.clearVec(); + x1 =112.f, y1 = 22.3f,z1 = 1.2f, x2 = -2.3f, y2 = 341.11f, z2 = 1234.234f; + vec3.setVec(x1,y1,z1); + vec3a.setVec(x2,y2,z2); + vec3b = vec3 % vec3a ; + val1 = y1*z2 - y2*z1; + val2 = z1*x2 -z2*x1; + val3 = x1*y2-x2*y1; + ensure("2:operator% failed ", (val1 == vec3b.mV[VX]) && (val2 == vec3b.mV[VY]) && (val3 == vec3b.mV[VZ])); + } + + template<> template<> + void v3math_object::test<17>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, div = 3.2f; + F32 t = 1.f / div, val1, val2, val3; + LLVector3 vec3(x1,y1,z1), vec3a; + vec3a = vec3 / div; + val1 = x1 * t; + val2 = y1 * t; + val3 = z1 *t; + ensure("1:operator/ failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY]) && (val3 == vec3a.mV[VZ])); + + vec3a.clearVec(); + x1 = -.235f, y1 = -24.32f, z1 = .342f, div = -2.2f; + t = 1.f / div; + vec3.setVec(x1,y1,z1); + vec3a = vec3 / div; + val1 = x1 * t; + val2 = y1 * t; + val3 = z1 *t; + ensure("2:operator/ failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY]) && (val3 == vec3a.mV[VZ])); + } + + template<> template<> + void v3math_object::test<18>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f; + LLVector3 vec3(x1,y1,z1), vec3a(x1,y1,z1); + ensure("1:operator== failed",(vec3 == vec3a)); + + vec3a.clearVec(); + x1 = -.235f, y1 = -24.32f, z1 = .342f; + vec3.clearVec(); + vec3a.clearVec(); + vec3.setVec(x1,y1,z1); + vec3a.setVec(x1,y1,z1); + ensure("2:operator== failed ", (vec3 == vec3a)); + } + + template<> template<> + void v3math_object::test<19>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 =112.f, y2 = 2.234f,z2 = 11.2f;; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); + ensure("1:operator!= failed",(vec3a != vec3)); + + vec3.clearVec(); + vec3.clearVec(); + vec3a.setVec(vec3); + ensure("2:operator!= failed", ( false == (vec3a != vec3))); + } + + template<> template<> + void v3math_object::test<20>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 =112.f, y2 = 2.2f,z2 = 11.2f;; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); + vec3a += vec3; + F32 val1, val2, val3; + val1 = x1+x2; + val2 = y1+y2; + val3 = z1+z2; + ensure("1:operator+= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); + } + + template<> template<> + void v3math_object::test<21>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 =112.f, y2 = 2.2f,z2 = 11.2f;; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); + vec3a -= vec3; + F32 val1, val2, val3; + val1 = x2-x1; + val2 = y2-y1; + val3 = z2-z1; + ensure("1:operator-= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); + } + + template<> template<> + void v3math_object::test<22>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; + F32 val1,val2,val3; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); + vec3a *= vec3; + val1 = x1*x2; + val2 = y1*y2; + val3 = z1*z2; + ensure("1:operator*= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY])&& (val3 == vec3a.mV[VZ])); + + F32 mulVal = 4.332f; + vec3 *=mulVal; + val1 = x1*mulVal; + val2 = y1*mulVal; + val3 = z1*mulVal; + ensure("2:operator*= failed ", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY]) && is_approx_equal(val3, vec3.mV[VZ])); + } + + template<> template<> + void v3math_object::test<23>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, x2 = -2.3f, y2 = 1.11f, z2 = 1234.234f; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2),vec3b; + vec3b = vec3a % vec3; + vec3a %= vec3; + ensure_equals("1:operator%= failed",vec3a,vec3b); + } + + template<> template<> + void v3math_object::test<24>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f, div = 3.2f; + F32 t = 1.f / div, val1, val2, val3; + LLVector3 vec3a(x1,y1,z1); + vec3a /= div; + val1 = x1 * t; + val2 = y1 * t; + val3 = z1 *t; + ensure("1:operator/= failed",(val1 == vec3a.mV[VX]) && (val2 == vec3a.mV[VY]) && (val3 == vec3a.mV[VZ])); + } + + template<> template<> + void v3math_object::test<25>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f; + LLVector3 vec3(x1,y1,z1), vec3a; + vec3a = -vec3; + ensure("1:operator- failed",(-vec3a == vec3)); + } + + template<> template<> + void v3math_object::test<26>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 1.2f; + std::ostringstream stream1, stream2; + LLVector3 vec3(x1,y1,z1), vec3a; + stream1 << vec3; + vec3a.setVec(x1,y1,z1); + stream2 << vec3a; + ensure("1:operator << failed",(stream1.str() == stream2.str())); + } + + template<> template<> + void v3math_object::test<27>() + { + F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.11f, z2 = 1234.234f; + LLVector3 vec3(x1,y1,z1), vec3a(x2,y2,z2); + ensure("1:operator< failed", (true == (vec3 < vec3a))); + x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 2.f, z2 = 1234.234f; + vec3.setVec(x1,y1,z1); + vec3a.setVec(x2,y2,z2); + ensure("2:operator< failed ", (true == (vec3 < vec3a))); + x1 =2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, + vec3.setVec(x1,y1,z1); + vec3a.setVec(x2,y2,z2); + ensure("3:operator< failed ", (false == (vec3 < vec3a))); + } + + template<> template<> + void v3math_object::test<28>() + { + F32 x1 =1.23f, y1 = 2.f,z1 = 4.f; + std::string buf("1.23 2. 4"); + LLVector3 vec3, vec3a(x1,y1,z1); + LLVector3::parseVector3(buf, &vec3); + ensure_equals("1:parseVector3 failed", vec3, vec3a); + } + + template<> template<> + void v3math_object::test<29>() + { + F32 x1 =1.f, y1 = 2.f,z1 = 4.f; + LLVector3 vec3(x1,y1,z1),vec3a,vec3b; + vec3a.setVec(1,1,1); + vec3a.scaleVec(vec3); + ensure_equals("1:scaleVec failed", vec3, vec3a); + vec3a.clearVec(); + vec3a.setVec(x1,y1,z1); + vec3a.scaleVec(vec3); + ensure("2:scaleVec failed", ((1.f ==vec3a.mV[VX])&& (4.f ==vec3a.mV[VY]) && (16.f ==vec3a.mV[VZ]))); + } + + template<> template<> + void v3math_object::test<30>() + { + F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.11f, z2 = 1234.234f; + F32 val = 2.3f,val1,val2,val3; + val1 = x1 + (x2 - x1)* val; + val2 = y1 + (y2 - y1)* val; + val3 = z1 + (z2 - z1)* val; + LLVector3 vec3(x1,y1,z1),vec3a(x2,y2,z2); + LLVector3 vec3b = lerp(vec3,vec3a,val); + ensure("1:lerp failed", ((val1 ==vec3b.mV[VX])&& (val2 ==vec3b.mV[VY]) && (val3 ==vec3b.mV[VZ]))); + } + + template<> template<> + void v3math_object::test<31>() + { + F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.f, z2 = 1.f; + F32 val1,val2; + LLVector3 vec3(x1,y1,z1),vec3a(x2,y2,z2); + val1 = dist_vec(vec3,vec3a); + val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); + ensure_equals("1:dist_vec: Fail ",val2, val1); + val1 = dist_vec_squared(vec3,vec3a); + val2 =((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); + ensure_equals("2:dist_vec_squared: Fail ",val2, val1); + val1 = dist_vec_squared2D(vec3, vec3a); + val2 =(x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2); + ensure_equals("3:dist_vec_squared2D: Fail ",val2, val1); + } + + template<> template<> + void v3math_object::test<32>() + { + F32 x =12.3524f, y = -342.f,z = 4.126341f; + LLVector3 vec3(x,y,z); + F32 mag = vec3.normVec(); + mag = 1.f/ mag; + F32 val1 = x* mag, val2 = y* mag, val3 = z* mag; + ensure("1:normVec: Fail ", is_approx_equal(val1, vec3.mV[VX]) && is_approx_equal(val2, vec3.mV[VY]) && is_approx_equal(val3, vec3.mV[VZ])); + x = 0.000000001f, y = 0.f, z = 0.f; + vec3.clearVec(); + vec3.setVec(x,y,z); + mag = vec3.normVec(); + val1 = x* mag, val2 = y* mag, val3 = z* mag; + ensure("2:normVec: Fail ", (mag == 0.) && (0. == vec3.mV[VX]) && (0. == vec3.mV[VY])&& (0. == vec3.mV[VZ])); + } + + template<> template<> + void v3math_object::test<33>() + { + F32 x = -202.23412f, y = 123.2312f, z = -89.f; + LLVector3 vec(x,y,z); + vec.snap(2); + ensure("1:snap: Fail ", is_approx_equal(-202.23f, vec.mV[VX]) && is_approx_equal(123.23f, vec.mV[VY]) && is_approx_equal(-89.f, vec.mV[VZ])); + } + + template<> template<> + void v3math_object::test<34>() + { + F32 x = 10.f, y = 20.f, z = -15.f; + F32 x1, y1, z1; + F32 lowerxy = 0.f, upperxy = 1.0f, lowerz = -1.0f, upperz = 1.f; + LLVector3 vec3(x,y,z); + vec3.quantize16(lowerxy,upperxy,lowerz,upperz); + x1 = U16_to_F32(F32_to_U16(x, lowerxy, upperxy), lowerxy, upperxy); + y1 = U16_to_F32(F32_to_U16(y, lowerxy, upperxy), lowerxy, upperxy); + z1 = U16_to_F32(F32_to_U16(z, lowerz, upperz), lowerz, upperz); + ensure("1:quantize16: Fail ", is_approx_equal(x1, vec3.mV[VX]) && is_approx_equal(y1, vec3.mV[VY]) && is_approx_equal(z1, vec3.mV[VZ])); + LLVector3 vec3a(x,y,z); + vec3a.quantize8(lowerxy,upperxy,lowerz,upperz); + x1 = U8_to_F32(F32_to_U8(x, lowerxy, upperxy), lowerxy, upperxy); + y1 = U8_to_F32(F32_to_U8(y, lowerxy, upperxy), lowerxy, upperxy); + z1 = U8_to_F32(F32_to_U8(z, lowerz, upperz), lowerz, upperz); + ensure("2:quantize8: Fail ", is_approx_equal(x1, vec3a.mV[VX]) && is_approx_equal(y1, vec3a.mV[VY]) && is_approx_equal(z1, vec3a.mV[VZ])); + } + + template<> template<> + void v3math_object::test<35>() + { + LLSD sd = LLSD::emptyArray(); + sd[0] = 1.f; + + LLVector3 parsed_1(sd); + ensure("1:LLSD parse: Fail ", is_approx_equal(parsed_1.mV[VX], 1.f) && is_approx_equal(parsed_1.mV[VY], 0.f) && is_approx_equal(parsed_1.mV[VZ], 0.f)); + + sd[1] = 2.f; + LLVector3 parsed_2(sd); + ensure("2:LLSD parse: Fail ", is_approx_equal(parsed_2.mV[VX], 1.f) && is_approx_equal(parsed_2.mV[VY], 2.f) && is_approx_equal(parsed_2.mV[VZ], 0.f)); + + sd[2] = 3.f; + LLVector3 parsed_3(sd); + ensure("3:LLSD parse: Fail ", is_approx_equal(parsed_3.mV[VX], 1.f) && is_approx_equal(parsed_3.mV[VY], 2.f) && is_approx_equal(parsed_3.mV[VZ], 3.f)); + } +} diff --git a/indra/llmath/tests/v4coloru_test.cpp b/indra/llmath/tests/v4coloru_test.cpp index b9968d0cd0..55cef0fea1 100644 --- a/indra/llmath/tests/v4coloru_test.cpp +++ b/indra/llmath/tests/v4coloru_test.cpp @@ -1,336 +1,336 @@ -/** - * @file v4coloru_test.cpp - * @author Adroit - * @date 2007-03 - * @brief v4coloru test cases. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#include "linden_common.h" -#include "../test/lltut.h" - -#include "llsd.h" - -#include "../v4coloru.h" - - -namespace tut -{ - struct v4coloru_data - { - }; - typedef test_group v4coloru_test; - typedef v4coloru_test::object v4coloru_object; - tut::v4coloru_test v4coloru_testcase("v4coloru_h"); - - template<> template<> - void v4coloru_object::test<1>() - { - LLColor4U llcolor4u; - ensure("1:LLColor4u:Fail to initialize ", ((0 == llcolor4u.mV[VX]) && (0 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); - - U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; - LLColor4U llcolor4u1(r,g,b); - ensure("2:LLColor4u:Fail to initialize ", ((r == llcolor4u1.mV[VX]) && (g == llcolor4u1.mV[VY]) && (b == llcolor4u1.mV[VZ])&& (255 == llcolor4u1.mV[VW]))); - - LLColor4U llcolor4u2(r,g,b,a); - ensure("3:LLColor4u:Fail to initialize ", ((r == llcolor4u2.mV[VX]) && (g == llcolor4u2.mV[VY]) && (b == llcolor4u2.mV[VZ])&& (a == llcolor4u2.mV[VW]))); - - const U8 vec[4] = {0x12,0xFF,0xAF,0x23}; - LLColor4U llcolor4u3(vec); - ensure("4:LLColor4u:Fail to initialize ", ((vec[0] == llcolor4u3.mV[VX]) && (vec[1] == llcolor4u3.mV[VY]) && (vec[2] == llcolor4u3.mV[VZ])&& (vec[3] == llcolor4u3.mV[VW]))); - - LLSD sd = llcolor4u3.getValue(); - LLColor4U llcolor4u4(sd); - ensure_equals("5:LLColor4u (LLSD) Failed ", llcolor4u4, llcolor4u3); - } - - template<> template<> - void v4coloru_object::test<2>() - { - LLColor4U llcolor4ua(1, 2, 3, 4); - LLSD sd = llcolor4ua.getValue(); - LLColor4U llcolor4u; - llcolor4u.setValue(sd); - ensure_equals("setValue(LLSD)/getValue Failed ", llcolor4u, llcolor4ua); - } - - template<> template<> - void v4coloru_object::test<3>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; - LLColor4U llcolor4u(r,g,b,a); - llcolor4u.setToBlack(); - ensure("setToBlack:Fail to set black ", ((0 == llcolor4u.mV[VX]) && (0 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); - - llcolor4u.setToWhite(); - ensure("setToWhite:Fail to white ", ((255 == llcolor4u.mV[VX]) && (255 == llcolor4u.mV[VY]) && (255 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); - } - - template<> template<> - void v4coloru_object::test<4>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; - LLColor4U llcolor4ua(r,g,b,a); - LLSD sd = llcolor4ua.getValue(); - LLColor4U llcolor4u = (LLColor4U)sd; - ensure_equals("Operator=(LLSD) Failed ", llcolor4u, llcolor4ua); - } - - template<> template<> - void v4coloru_object::test<5>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; - LLColor4U llcolor4u; - llcolor4u.setVec(r,g,b,a); - ensure("1:setVec:Fail to set the values ", ((r == llcolor4u.mV[VX]) && (g == llcolor4u.mV[VY]) && (b == llcolor4u.mV[VZ])&& (a == llcolor4u.mV[VW]))); - - llcolor4u.setToBlack(); - llcolor4u.setVec(r,g,b); - ensure("2:setVec:Fail to set the values ", ((r == llcolor4u.mV[VX]) && (g == llcolor4u.mV[VY]) && (b == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); - - LLColor4U llcolor4u1; - llcolor4u1.setVec(llcolor4u); - ensure_equals("3:setVec:Fail to set the values ", llcolor4u1,llcolor4u); - - const U8 vec[4] = {0x12,0xFF,0xAF,0x23}; - LLColor4U llcolor4u2; - llcolor4u2.setVec(vec); - ensure("4:setVec:Fail to set the values ", ((vec[0] == llcolor4u2.mV[VX]) && (vec[1] == llcolor4u2.mV[VY]) && (vec[2] == llcolor4u2.mV[VZ])&& (vec[3] == llcolor4u2.mV[VW]))); - } - - template<> template<> - void v4coloru_object::test<6>() - { - U8 alpha = 0x12; - LLColor4U llcolor4u; - llcolor4u.setAlpha(alpha); - ensure("setAlpha:Fail to set alpha value ", (alpha == llcolor4u.mV[VW])); - } - - template<> template<> - void v4coloru_object::test<7>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF; - LLColor4U llcolor4u(r,g,b); - ensure("magVecSquared:Fail ", is_approx_equal(llcolor4u.magVecSquared(), (F32)(r*r + g*g + b*b))); - ensure("magVec:Fail ", is_approx_equal(llcolor4u.magVec(), (F32) sqrt((F32) (r*r + g*g + b*b)))); - } - - template<> template<> - void v4coloru_object::test<8>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF; - std::ostringstream stream1, stream2; - LLColor4U llcolor4u1(r,g,b),llcolor4u2; - stream1 << llcolor4u1; - llcolor4u2.setVec(r,g,b); - stream2 << llcolor4u2; - ensure("operator << failed ", (stream1.str() == stream2.str())); - } - - template<> template<> - void v4coloru_object::test<9>() - { - U8 r1 = 0x12, g1 = 0xFF, b1 = 0xAF; - U8 r2 = 0x1C, g2 = 0x9A, b2 = 0x1B; - LLColor4U llcolor4u1(r1,g1,b1), llcolor4u2(r2,g2,b2),llcolor4u3; - llcolor4u3 = llcolor4u1 + llcolor4u2; - ensure_equals( - "1a.operator+:Fail to Add the values ", - llcolor4u3.mV[VX], - (U8)(r1+r2)); - ensure_equals( - "1b.operator+:Fail to Add the values ", - llcolor4u3.mV[VY], - (U8)(g1+g2)); - ensure_equals( - "1c.operator+:Fail to Add the values ", - llcolor4u3.mV[VZ], - (U8)(b1+b2)); - - llcolor4u2 += llcolor4u1; - ensure_equals( - "2a.operator+=:Fail to Add the values ", - llcolor4u2.mV[VX], - (U8)(r1+r2)); - ensure_equals( - "2b.operator+=:Fail to Add the values ", - llcolor4u2.mV[VY], - (U8)(g1+g2)); - ensure_equals( - "2c.operator+=:Fail to Add the values ", - llcolor4u2.mV[VZ], - (U8)(b1+b2)); - } - - template<> template<> - void v4coloru_object::test<10>() - { - U8 r1 = 0x12, g1 = 0xFF, b1 = 0xAF; - U8 r2 = 0x1C, g2 = 0x9A, b2 = 0x1B; - LLColor4U llcolor4u1(r1,g1,b1), llcolor4u2(r2,g2,b2),llcolor4u3; - llcolor4u3 = llcolor4u1 - llcolor4u2; - ensure_equals( - "1a. operator-:Fail to Add the values ", - llcolor4u3.mV[VX], - (U8)(r1-r2)); - ensure_equals( - "1b. operator-:Fail to Add the values ", - llcolor4u3.mV[VY], - (U8)(g1-g2)); - ensure_equals( - "1c. operator-:Fail to Add the values ", - llcolor4u3.mV[VZ], - (U8)(b1-b2)); - - llcolor4u1 -= llcolor4u2; - ensure_equals( - "2a. operator-=:Fail to Add the values ", - llcolor4u1.mV[VX], - (U8)(r1-r2)); - ensure_equals( - "2b. operator-=:Fail to Add the values ", - llcolor4u1.mV[VY], - (U8)(g1-g2)); - ensure_equals( - "2c. operator-=:Fail to Add the values ", - llcolor4u1.mV[VZ], - (U8)(b1-b2)); - } - - template<> template<> - void v4coloru_object::test<11>() - { - U8 r1 = 0x12, g1 = 0xFF, b1 = 0xAF; - U8 r2 = 0x1C, g2 = 0x9A, b2 = 0x1B; - LLColor4U llcolor4u1(r1,g1,b1), llcolor4u2(r2,g2,b2),llcolor4u3; - llcolor4u3 = llcolor4u1 * llcolor4u2; - ensure_equals( - "1a. operator*:Fail to multiply the values", - llcolor4u3.mV[VX], - (U8)(r1*r2)); - ensure_equals( - "1b. operator*:Fail to multiply the values", - llcolor4u3.mV[VY], - (U8)(g1*g2)); - ensure_equals( - "1c. operator*:Fail to multiply the values", - llcolor4u3.mV[VZ], - (U8)(b1*b2)); - - U8 mulVal = 123; - llcolor4u1 *= mulVal; - ensure_equals( - "2a. operator*=:Fail to multiply the values", - llcolor4u1.mV[VX], - (U8)(r1*mulVal)); - ensure_equals( - "2b. operator*=:Fail to multiply the values", - llcolor4u1.mV[VY], - (U8)(g1*mulVal)); - ensure_equals( - "2c. operator*=:Fail to multiply the values", - llcolor4u1.mV[VZ], - (U8)(b1*mulVal)); - } - - template<> template<> - void v4coloru_object::test<12>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF; - LLColor4U llcolor4u(r,g,b),llcolor4u1; - llcolor4u1 = llcolor4u; - ensure("operator== failed to ensure the equality ", (llcolor4u1 == llcolor4u)); - llcolor4u1.setToBlack(); - ensure("operator!= failed to ensure the equality ", (llcolor4u1 != llcolor4u)); - } - - template<> template<> - void v4coloru_object::test<13>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF, a = 12; - LLColor4U llcolor4u(r,g,b,a); - U8 modVal = 45; - llcolor4u %= modVal; - ensure_equals("operator%=:Fail ", llcolor4u.mV[VW], (U8)(a * modVal)); - } - - template<> template<> - void v4coloru_object::test<14>() - { - U8 r = 0x12, g = 0xFF, b = 0xAF, a = 12; - LLColor4U llcolor4u1(r,g,b,a); - std::string color("12, 23, 132, 50"); - LLColor4U::parseColor4U(color, &llcolor4u1); - ensure("parseColor4U() failed to parse the color value ", ((12 == llcolor4u1.mV[VX]) && (23 == llcolor4u1.mV[VY]) && (132 == llcolor4u1.mV[VZ])&& (50 == llcolor4u1.mV[VW]))); - - color = "12, 23, 132"; - ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); - - color = "12"; - ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); - } - - template<> template<> - void v4coloru_object::test<15>() - { - U8 r = 12, g = 123, b = 3, a = 2; - LLColor4U llcolor4u(r,g,b,a),llcolor4u1; - const F32 fVal = 3.f; - llcolor4u1 = llcolor4u.multAll(fVal); - ensure("multAll:Fail to multiply ", (((U8)ll_round(r * fVal) == llcolor4u1.mV[VX]) && (U8)ll_round(g * fVal) == llcolor4u1.mV[VY] - && ((U8)ll_round(b * fVal) == llcolor4u1.mV[VZ])&& ((U8)ll_round(a * fVal) == llcolor4u1.mV[VW]))); - } - - template<> template<> - void v4coloru_object::test<16>() - { - U8 r1 = 12, g1 = 123, b1 = 3, a1 = 2; - U8 r2 = 23, g2 = 230, b2 = 124, a2 = 255; - LLColor4U llcolor4u(r1,g1,b1,a1),llcolor4u1(r2,g2,b2,a2); - llcolor4u1 = llcolor4u1.addClampMax(llcolor4u); - ensure("1:addClampMax():Fail to add the value ", ((r1+r2 == llcolor4u1.mV[VX]) && (255 == llcolor4u1.mV[VY]) && (b1+b2 == llcolor4u1.mV[VZ])&& (255 == llcolor4u1.mV[VW]))); - - r1 = 132, g1 = 3, b1 = 3, a1 = 2; - r2 = 123, g2 = 230, b2 = 154, a2 = 25; - LLColor4U llcolor4u2(r1,g1,b1,a1),llcolor4u3(r2,g2,b2,a2); - llcolor4u3 = llcolor4u3.addClampMax(llcolor4u2); - ensure("2:addClampMax():Fail to add the value ", ((255 == llcolor4u3.mV[VX]) && (g1+g2 == llcolor4u3.mV[VY]) && (b1+b2 == llcolor4u3.mV[VZ])&& (a1+a2 == llcolor4u3.mV[VW]))); - } - - template<> template<> - void v4coloru_object::test<17>() - { - F32 r = 23.f, g = 12.32f, b = -12.3f; - LLColor3 color3(r,g,b); - LLColor4U llcolor4u; - llcolor4u.setVecScaleClamp(color3); - const S32 MAX_COLOR = 255; - F32 color_scale_factor = MAX_COLOR/r; - S32 r2 = ll_round(r * color_scale_factor); - S32 g2 = ll_round(g * color_scale_factor); - ensure("setVecScaleClamp():Fail to add the value ", ((r2 == llcolor4u.mV[VX]) && (g2 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); - } -} +/** + * @file v4coloru_test.cpp + * @author Adroit + * @date 2007-03 + * @brief v4coloru test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "linden_common.h" +#include "../test/lltut.h" + +#include "llsd.h" + +#include "../v4coloru.h" + + +namespace tut +{ + struct v4coloru_data + { + }; + typedef test_group v4coloru_test; + typedef v4coloru_test::object v4coloru_object; + tut::v4coloru_test v4coloru_testcase("v4coloru_h"); + + template<> template<> + void v4coloru_object::test<1>() + { + LLColor4U llcolor4u; + ensure("1:LLColor4u:Fail to initialize ", ((0 == llcolor4u.mV[VX]) && (0 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + + U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; + LLColor4U llcolor4u1(r,g,b); + ensure("2:LLColor4u:Fail to initialize ", ((r == llcolor4u1.mV[VX]) && (g == llcolor4u1.mV[VY]) && (b == llcolor4u1.mV[VZ])&& (255 == llcolor4u1.mV[VW]))); + + LLColor4U llcolor4u2(r,g,b,a); + ensure("3:LLColor4u:Fail to initialize ", ((r == llcolor4u2.mV[VX]) && (g == llcolor4u2.mV[VY]) && (b == llcolor4u2.mV[VZ])&& (a == llcolor4u2.mV[VW]))); + + const U8 vec[4] = {0x12,0xFF,0xAF,0x23}; + LLColor4U llcolor4u3(vec); + ensure("4:LLColor4u:Fail to initialize ", ((vec[0] == llcolor4u3.mV[VX]) && (vec[1] == llcolor4u3.mV[VY]) && (vec[2] == llcolor4u3.mV[VZ])&& (vec[3] == llcolor4u3.mV[VW]))); + + LLSD sd = llcolor4u3.getValue(); + LLColor4U llcolor4u4(sd); + ensure_equals("5:LLColor4u (LLSD) Failed ", llcolor4u4, llcolor4u3); + } + + template<> template<> + void v4coloru_object::test<2>() + { + LLColor4U llcolor4ua(1, 2, 3, 4); + LLSD sd = llcolor4ua.getValue(); + LLColor4U llcolor4u; + llcolor4u.setValue(sd); + ensure_equals("setValue(LLSD)/getValue Failed ", llcolor4u, llcolor4ua); + } + + template<> template<> + void v4coloru_object::test<3>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; + LLColor4U llcolor4u(r,g,b,a); + llcolor4u.setToBlack(); + ensure("setToBlack:Fail to set black ", ((0 == llcolor4u.mV[VX]) && (0 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + + llcolor4u.setToWhite(); + ensure("setToWhite:Fail to white ", ((255 == llcolor4u.mV[VX]) && (255 == llcolor4u.mV[VY]) && (255 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + } + + template<> template<> + void v4coloru_object::test<4>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; + LLColor4U llcolor4ua(r,g,b,a); + LLSD sd = llcolor4ua.getValue(); + LLColor4U llcolor4u = (LLColor4U)sd; + ensure_equals("Operator=(LLSD) Failed ", llcolor4u, llcolor4ua); + } + + template<> template<> + void v4coloru_object::test<5>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; + LLColor4U llcolor4u; + llcolor4u.setVec(r,g,b,a); + ensure("1:setVec:Fail to set the values ", ((r == llcolor4u.mV[VX]) && (g == llcolor4u.mV[VY]) && (b == llcolor4u.mV[VZ])&& (a == llcolor4u.mV[VW]))); + + llcolor4u.setToBlack(); + llcolor4u.setVec(r,g,b); + ensure("2:setVec:Fail to set the values ", ((r == llcolor4u.mV[VX]) && (g == llcolor4u.mV[VY]) && (b == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + + LLColor4U llcolor4u1; + llcolor4u1.setVec(llcolor4u); + ensure_equals("3:setVec:Fail to set the values ", llcolor4u1,llcolor4u); + + const U8 vec[4] = {0x12,0xFF,0xAF,0x23}; + LLColor4U llcolor4u2; + llcolor4u2.setVec(vec); + ensure("4:setVec:Fail to set the values ", ((vec[0] == llcolor4u2.mV[VX]) && (vec[1] == llcolor4u2.mV[VY]) && (vec[2] == llcolor4u2.mV[VZ])&& (vec[3] == llcolor4u2.mV[VW]))); + } + + template<> template<> + void v4coloru_object::test<6>() + { + U8 alpha = 0x12; + LLColor4U llcolor4u; + llcolor4u.setAlpha(alpha); + ensure("setAlpha:Fail to set alpha value ", (alpha == llcolor4u.mV[VW])); + } + + template<> template<> + void v4coloru_object::test<7>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF; + LLColor4U llcolor4u(r,g,b); + ensure("magVecSquared:Fail ", is_approx_equal(llcolor4u.magVecSquared(), (F32)(r*r + g*g + b*b))); + ensure("magVec:Fail ", is_approx_equal(llcolor4u.magVec(), (F32) sqrt((F32) (r*r + g*g + b*b)))); + } + + template<> template<> + void v4coloru_object::test<8>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF; + std::ostringstream stream1, stream2; + LLColor4U llcolor4u1(r,g,b),llcolor4u2; + stream1 << llcolor4u1; + llcolor4u2.setVec(r,g,b); + stream2 << llcolor4u2; + ensure("operator << failed ", (stream1.str() == stream2.str())); + } + + template<> template<> + void v4coloru_object::test<9>() + { + U8 r1 = 0x12, g1 = 0xFF, b1 = 0xAF; + U8 r2 = 0x1C, g2 = 0x9A, b2 = 0x1B; + LLColor4U llcolor4u1(r1,g1,b1), llcolor4u2(r2,g2,b2),llcolor4u3; + llcolor4u3 = llcolor4u1 + llcolor4u2; + ensure_equals( + "1a.operator+:Fail to Add the values ", + llcolor4u3.mV[VX], + (U8)(r1+r2)); + ensure_equals( + "1b.operator+:Fail to Add the values ", + llcolor4u3.mV[VY], + (U8)(g1+g2)); + ensure_equals( + "1c.operator+:Fail to Add the values ", + llcolor4u3.mV[VZ], + (U8)(b1+b2)); + + llcolor4u2 += llcolor4u1; + ensure_equals( + "2a.operator+=:Fail to Add the values ", + llcolor4u2.mV[VX], + (U8)(r1+r2)); + ensure_equals( + "2b.operator+=:Fail to Add the values ", + llcolor4u2.mV[VY], + (U8)(g1+g2)); + ensure_equals( + "2c.operator+=:Fail to Add the values ", + llcolor4u2.mV[VZ], + (U8)(b1+b2)); + } + + template<> template<> + void v4coloru_object::test<10>() + { + U8 r1 = 0x12, g1 = 0xFF, b1 = 0xAF; + U8 r2 = 0x1C, g2 = 0x9A, b2 = 0x1B; + LLColor4U llcolor4u1(r1,g1,b1), llcolor4u2(r2,g2,b2),llcolor4u3; + llcolor4u3 = llcolor4u1 - llcolor4u2; + ensure_equals( + "1a. operator-:Fail to Add the values ", + llcolor4u3.mV[VX], + (U8)(r1-r2)); + ensure_equals( + "1b. operator-:Fail to Add the values ", + llcolor4u3.mV[VY], + (U8)(g1-g2)); + ensure_equals( + "1c. operator-:Fail to Add the values ", + llcolor4u3.mV[VZ], + (U8)(b1-b2)); + + llcolor4u1 -= llcolor4u2; + ensure_equals( + "2a. operator-=:Fail to Add the values ", + llcolor4u1.mV[VX], + (U8)(r1-r2)); + ensure_equals( + "2b. operator-=:Fail to Add the values ", + llcolor4u1.mV[VY], + (U8)(g1-g2)); + ensure_equals( + "2c. operator-=:Fail to Add the values ", + llcolor4u1.mV[VZ], + (U8)(b1-b2)); + } + + template<> template<> + void v4coloru_object::test<11>() + { + U8 r1 = 0x12, g1 = 0xFF, b1 = 0xAF; + U8 r2 = 0x1C, g2 = 0x9A, b2 = 0x1B; + LLColor4U llcolor4u1(r1,g1,b1), llcolor4u2(r2,g2,b2),llcolor4u3; + llcolor4u3 = llcolor4u1 * llcolor4u2; + ensure_equals( + "1a. operator*:Fail to multiply the values", + llcolor4u3.mV[VX], + (U8)(r1*r2)); + ensure_equals( + "1b. operator*:Fail to multiply the values", + llcolor4u3.mV[VY], + (U8)(g1*g2)); + ensure_equals( + "1c. operator*:Fail to multiply the values", + llcolor4u3.mV[VZ], + (U8)(b1*b2)); + + U8 mulVal = 123; + llcolor4u1 *= mulVal; + ensure_equals( + "2a. operator*=:Fail to multiply the values", + llcolor4u1.mV[VX], + (U8)(r1*mulVal)); + ensure_equals( + "2b. operator*=:Fail to multiply the values", + llcolor4u1.mV[VY], + (U8)(g1*mulVal)); + ensure_equals( + "2c. operator*=:Fail to multiply the values", + llcolor4u1.mV[VZ], + (U8)(b1*mulVal)); + } + + template<> template<> + void v4coloru_object::test<12>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF; + LLColor4U llcolor4u(r,g,b),llcolor4u1; + llcolor4u1 = llcolor4u; + ensure("operator== failed to ensure the equality ", (llcolor4u1 == llcolor4u)); + llcolor4u1.setToBlack(); + ensure("operator!= failed to ensure the equality ", (llcolor4u1 != llcolor4u)); + } + + template<> template<> + void v4coloru_object::test<13>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF, a = 12; + LLColor4U llcolor4u(r,g,b,a); + U8 modVal = 45; + llcolor4u %= modVal; + ensure_equals("operator%=:Fail ", llcolor4u.mV[VW], (U8)(a * modVal)); + } + + template<> template<> + void v4coloru_object::test<14>() + { + U8 r = 0x12, g = 0xFF, b = 0xAF, a = 12; + LLColor4U llcolor4u1(r,g,b,a); + std::string color("12, 23, 132, 50"); + LLColor4U::parseColor4U(color, &llcolor4u1); + ensure("parseColor4U() failed to parse the color value ", ((12 == llcolor4u1.mV[VX]) && (23 == llcolor4u1.mV[VY]) && (132 == llcolor4u1.mV[VZ])&& (50 == llcolor4u1.mV[VW]))); + + color = "12, 23, 132"; + ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); + + color = "12"; + ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); + } + + template<> template<> + void v4coloru_object::test<15>() + { + U8 r = 12, g = 123, b = 3, a = 2; + LLColor4U llcolor4u(r,g,b,a),llcolor4u1; + const F32 fVal = 3.f; + llcolor4u1 = llcolor4u.multAll(fVal); + ensure("multAll:Fail to multiply ", (((U8)ll_round(r * fVal) == llcolor4u1.mV[VX]) && (U8)ll_round(g * fVal) == llcolor4u1.mV[VY] + && ((U8)ll_round(b * fVal) == llcolor4u1.mV[VZ])&& ((U8)ll_round(a * fVal) == llcolor4u1.mV[VW]))); + } + + template<> template<> + void v4coloru_object::test<16>() + { + U8 r1 = 12, g1 = 123, b1 = 3, a1 = 2; + U8 r2 = 23, g2 = 230, b2 = 124, a2 = 255; + LLColor4U llcolor4u(r1,g1,b1,a1),llcolor4u1(r2,g2,b2,a2); + llcolor4u1 = llcolor4u1.addClampMax(llcolor4u); + ensure("1:addClampMax():Fail to add the value ", ((r1+r2 == llcolor4u1.mV[VX]) && (255 == llcolor4u1.mV[VY]) && (b1+b2 == llcolor4u1.mV[VZ])&& (255 == llcolor4u1.mV[VW]))); + + r1 = 132, g1 = 3, b1 = 3, a1 = 2; + r2 = 123, g2 = 230, b2 = 154, a2 = 25; + LLColor4U llcolor4u2(r1,g1,b1,a1),llcolor4u3(r2,g2,b2,a2); + llcolor4u3 = llcolor4u3.addClampMax(llcolor4u2); + ensure("2:addClampMax():Fail to add the value ", ((255 == llcolor4u3.mV[VX]) && (g1+g2 == llcolor4u3.mV[VY]) && (b1+b2 == llcolor4u3.mV[VZ])&& (a1+a2 == llcolor4u3.mV[VW]))); + } + + template<> template<> + void v4coloru_object::test<17>() + { + F32 r = 23.f, g = 12.32f, b = -12.3f; + LLColor3 color3(r,g,b); + LLColor4U llcolor4u; + llcolor4u.setVecScaleClamp(color3); + const S32 MAX_COLOR = 255; + F32 color_scale_factor = MAX_COLOR/r; + S32 r2 = ll_round(r * color_scale_factor); + S32 g2 = ll_round(g * color_scale_factor); + ensure("setVecScaleClamp():Fail to add the value ", ((r2 == llcolor4u.mV[VX]) && (g2 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + } +} diff --git a/indra/llmath/tests/v4math_test.cpp b/indra/llmath/tests/v4math_test.cpp index 5e443663de..236585f13b 100644 --- a/indra/llmath/tests/v4math_test.cpp +++ b/indra/llmath/tests/v4math_test.cpp @@ -1,383 +1,383 @@ -/** - * @file v4math_test.cpp - * @author Adroit - * @date 2007-03 - * @brief v4math test cases. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" -#include "llsd.h" - -#include "../m4math.h" -#include "../v4math.h" -#include "../llquaternion.h" - -namespace tut -{ - struct v4math_data - { - }; - typedef test_group v4math_test; - typedef v4math_test::object v4math_object; - tut::v4math_test v4math_testcase("v4math_h"); - - template<> template<> - void v4math_object::test<1>() - { - LLVector4 vec4; - ensure("1:LLVector4:Fail to initialize " ,((0 == vec4.mV[VX]) && (0 == vec4.mV[VY]) && (0 == vec4.mV[VZ])&& (1.0f == vec4.mV[VW]))); - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - LLVector4 vec4a(x,y,z); - ensure("2:LLVector4:Fail to initialize " ,((x == vec4a.mV[VX]) && (y == vec4a.mV[VY]) && (z == vec4a.mV[VZ])&& (1.0f == vec4a.mV[VW]))); - LLVector4 vec4b(x,y,z,w); - ensure("3:LLVector4:Fail to initialize " ,((x == vec4b.mV[VX]) && (y == vec4b.mV[VY]) && (z == vec4b.mV[VZ])&& (w == vec4b.mV[VW]))); - const F32 vec[4] = {.112f ,23.2f, -4.2f, -.0001f}; - LLVector4 vec4c(vec); - ensure("4:LLVector4:Fail to initialize " ,((vec[0] == vec4c.mV[VX]) && (vec[1] == vec4c.mV[VY]) && (vec[2] == vec4c.mV[VZ])&& (vec[3] == vec4c.mV[VW]))); - LLVector3 vec3(-2.23f,1.01f,42.3f); - LLVector4 vec4d(vec3); - ensure("5:LLVector4:Fail to initialize " ,((vec3.mV[VX] == vec4d.mV[VX]) && (vec3.mV[VY] == vec4d.mV[VY]) && (vec3.mV[VZ] == vec4d.mV[VZ])&& (1.f == vec4d.mV[VW]))); - F32 w1 = -.234f; - LLVector4 vec4e(vec3,w1); - ensure("6:LLVector4:Fail to initialize " ,((vec3.mV[VX] == vec4e.mV[VX]) && (vec3.mV[VY] == vec4e.mV[VY]) && (vec3.mV[VZ] == vec4e.mV[VZ])&& (w1 == vec4e.mV[VW]))); - } - - template<> template<> - void v4math_object::test<2>() - { - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - LLVector4 vec4; - vec4.setVec(x,y,z); - ensure("1:setVec:Fail to initialize " ,((x == vec4.mV[VX]) && (y == vec4.mV[VY]) && (z == vec4.mV[VZ])&& (1.0f == vec4.mV[VW]))); - vec4.clearVec(); - ensure("2:clearVec:Fail " ,((0 == vec4.mV[VX]) && (0 == vec4.mV[VY]) && (0 == vec4.mV[VZ])&& (1.0f == vec4.mV[VW]))); - vec4.setVec(x,y,z,w); - ensure("3:setVec:Fail to initialize " ,((x == vec4.mV[VX]) && (y == vec4.mV[VY]) && (z == vec4.mV[VZ])&& (w == vec4.mV[VW]))); - vec4.zeroVec(); - ensure("4:zeroVec:Fail " ,((0 == vec4.mV[VX]) && (0 == vec4.mV[VY]) && (0 == vec4.mV[VZ])&& (0 == vec4.mV[VW]))); - LLVector3 vec3(-2.23f,1.01f,42.3f); - vec4.clearVec(); - vec4.setVec(vec3); - ensure("5:setVec:Fail to initialize " ,((vec3.mV[VX] == vec4.mV[VX]) && (vec3.mV[VY] == vec4.mV[VY]) && (vec3.mV[VZ] == vec4.mV[VZ])&& (1.f == vec4.mV[VW]))); - F32 w1 = -.234f; - vec4.zeroVec(); - vec4.setVec(vec3,w1); - ensure("6:setVec:Fail to initialize " ,((vec3.mV[VX] == vec4.mV[VX]) && (vec3.mV[VY] == vec4.mV[VY]) && (vec3.mV[VZ] == vec4.mV[VZ])&& (w1 == vec4.mV[VW]))); - const F32 vec[4] = {.112f ,23.2f, -4.2f, -.0001f}; - LLVector4 vec4a; - vec4a.setVec(vec); - ensure("7:setVec:Fail to initialize " ,((vec[0] == vec4a.mV[VX]) && (vec[1] == vec4a.mV[VY]) && (vec[2] == vec4a.mV[VZ])&& (vec[3] == vec4a.mV[VW]))); - } - - template<> template<> - void v4math_object::test<3>() - { - F32 x = 10.f, y = -2.3f, z = -.023f; - LLVector4 vec4(x,y,z); - ensure("magVec:Fail ", is_approx_equal(vec4.magVec(), (F32) sqrt(x*x + y*y + z*z))); - ensure("magVecSquared:Fail ", is_approx_equal(vec4.magVecSquared(), (x*x + y*y + z*z))); - } - - template<> template<> - void v4math_object::test<4>() - { - F32 x = 10.f, y = -2.3f, z = -.023f; - LLVector4 vec4(x,y,z); - F32 mag = vec4.normVec(); - mag = 1.f/ mag; - ensure("1:normVec: Fail " ,is_approx_equal(mag*x,vec4.mV[VX]) && is_approx_equal(mag*y, vec4.mV[VY])&& is_approx_equal(mag*z, vec4.mV[VZ])); - x = 0.000000001f, y = 0.000000001f, z = 0.000000001f; - vec4.clearVec(); - vec4.setVec(x,y,z); - mag = vec4.normVec(); - ensure("2:normVec: Fail " ,is_approx_equal(mag*x,vec4.mV[VX]) && is_approx_equal(mag*y, vec4.mV[VY])&& is_approx_equal(mag*z, vec4.mV[VZ])); - } - - template<> template<> - void v4math_object::test<5>() - { - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - LLVector4 vec4(x,y,z,w); - vec4.abs(); - ensure("abs:Fail " ,((x == vec4.mV[VX]) && (-y == vec4.mV[VY]) && (-z == vec4.mV[VZ])&& (-w == vec4.mV[VW]))); - vec4.clearVec(); - ensure("isExactlyClear:Fail " ,(true == vec4.isExactlyClear())); - vec4.zeroVec(); - ensure("isExactlyZero:Fail " ,(true == vec4.isExactlyZero())); - } - - template<> template<> - void v4math_object::test<6>() - { - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - LLVector4 vec4(x,y,z,w),vec4a; - vec4a = vec4.scaleVec(vec4); - ensure("scaleVec:Fail " ,(is_approx_equal(x*x, vec4a.mV[VX]) && is_approx_equal(y*y, vec4a.mV[VY]) && is_approx_equal(z*z, vec4a.mV[VZ])&& is_approx_equal(w*w, vec4a.mV[VW]))); - } - - template<> template<> - void v4math_object::test<7>() - { - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - LLVector4 vec4(x,y,z,w); - ensure("1:operator [] failed " ,( x == vec4[0])); - ensure("2:operator [] failed " ,( y == vec4[1])); - ensure("3:operator [] failed " ,( z == vec4[2])); - ensure("4:operator [] failed " ,( w == vec4[3])); - x = 23.f, y = -.2361f, z = 3.25; - vec4.setVec(x,y,z); - F32 &ref1 = vec4[0]; - ensure("5:operator [] failed " ,( ref1 == vec4[0])); - F32 &ref2 = vec4[1]; - ensure("6:operator [] failed " ,( ref2 == vec4[1])); - F32 &ref3 = vec4[2]; - ensure("7:operator [] failed " ,( ref3 == vec4[2])); - F32 &ref4 = vec4[3]; - ensure("8:operator [] failed " ,( ref4 == vec4[3])); - } - - template<> template<> - void v4math_object::test<8>() - { - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - const F32 val[16] = { - 1.f, 2.f, 3.f, 0.f, - .34f, .1f, -.5f, 0.f, - 2.f, 1.23f, 1.234f, 0.f, - .89f, 0.f, 0.f, 0.f - }; - LLMatrix4 mat(val); - LLVector4 vec4(x,y,z,w),vec4a; - vec4.rotVec(mat); - vec4a.setVec(x,y,z,w); - vec4a.rotVec(mat); - ensure_equals("1:rotVec: Fail " ,vec4a, vec4); - F32 a = 2.32f, b = -23.2f, c = -34.1112f, d = 1.010112f; - LLQuaternion q(a,b,c,d); - LLVector4 vec4b(a,b,c,d),vec4c; - vec4b.rotVec(q); - vec4c.setVec(a, b, c, d); - vec4c.rotVec(q); - ensure_equals("2:rotVec: Fail " ,vec4b, vec4c); - } - - template<> template<> - void v4math_object::test<9>() - { - F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; - LLVector4 vec4(x,y,z,w),vec4a;; - std::ostringstream stream1, stream2; - stream1 << vec4; - vec4a.setVec(x,y,z,w); - stream2 << vec4a; - ensure("operator << failed",(stream1.str() == stream2.str())); - } - - template<> template<> - void v4math_object::test<10>() - { - F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f, w1 = .23f; - F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f, w2 = 1.3f; - LLVector4 vec4(x1,y1,z1,w1),vec4a(x2,y2,z2,w2),vec4b; - vec4b = vec4a + vec4; - ensure("1:operator+:Fail to initialize " ,(is_approx_equal(x1+x2,vec4b.mV[VX]) && is_approx_equal(y1+y2,vec4b.mV[VY]) && is_approx_equal(z1+z2,vec4b.mV[VZ]))); - x1 = -2.45f, y1 = 2.1f, z1 = 3.0f; - vec4.clearVec(); - vec4a.clearVec(); - vec4.setVec(x1,y1,z1); - vec4a +=vec4; - ensure_equals("2:operator+=: Fail to initialize", vec4a,vec4); - vec4a += vec4; - ensure("3:operator+=:Fail to initialize " ,(is_approx_equal(2*x1,vec4a.mV[VX]) && is_approx_equal(2*y1,vec4a.mV[VY]) && is_approx_equal(2*z1,vec4a.mV[VZ]))); - } - template<> template<> - void v4math_object::test<11>() - { - F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f, w1 = .23f; - F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f, w2 = 1.3f; - LLVector4 vec4(x1,y1,z1,w1),vec4a(x2,y2,z2,w2),vec4b; - vec4b = vec4a - vec4; - ensure("1:operator-:Fail to initialize " ,(is_approx_equal(x2-x1,vec4b.mV[VX]) && is_approx_equal(y2-y1,vec4b.mV[VY]) && is_approx_equal(z2-z1,vec4b.mV[VZ]))); - x1 = -2.45f, y1 = 2.1f, z1 = 3.0f; - vec4.clearVec(); - vec4a.clearVec(); - vec4.setVec(x1,y1,z1); - vec4a -=vec4; - ensure_equals("2:operator-=: Fail to initialize" , vec4a,-vec4); - vec4a -=vec4; - ensure("3:operator-=:Fail to initialize " ,(is_approx_equal(-2*x1,vec4a.mV[VX]) && is_approx_equal(-2*y1,vec4a.mV[VY]) && is_approx_equal(-2*z1,vec4a.mV[VZ]))); - } - - template<> template<> - void v4math_object::test<12>() - { - F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f; - F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f; - LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2); - F32 res = vec4 * vec4a; - ensure("1:operator* failed " ,is_approx_equal(res, x1*x2 + y1*y2 + z1*z2)); - vec4a.clearVec(); - F32 mulVal = 4.2f; - vec4a = vec4 * mulVal; - ensure("2:operator* failed " ,is_approx_equal(x1*mulVal,vec4a.mV[VX]) && is_approx_equal(y1*mulVal, vec4a.mV[VY])&& is_approx_equal(z1*mulVal, vec4a.mV[VZ])); - vec4a.clearVec(); - vec4a = mulVal * vec4 ; - ensure("3:operator* failed " ,is_approx_equal(x1*mulVal, vec4a.mV[VX]) && is_approx_equal(y1*mulVal, vec4a.mV[VY])&& is_approx_equal(z1*mulVal, vec4a.mV[VZ])); - vec4 *= mulVal; - ensure("4:operator*= failed " ,is_approx_equal(x1*mulVal, vec4.mV[VX]) && is_approx_equal(y1*mulVal, vec4.mV[VY])&& is_approx_equal(z1*mulVal, vec4.mV[VZ])); - } - - template<> template<> - void v4math_object::test<13>() - { - F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f; - F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f; - LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2),vec4b; - vec4b = vec4 % vec4a; - ensure("1:operator% failed " ,is_approx_equal(y1*z2 - y2*z1, vec4b.mV[VX]) && is_approx_equal(z1*x2 -z2*x1, vec4b.mV[VY]) && is_approx_equal(x1*y2-x2*y1, vec4b.mV[VZ])); - vec4 %= vec4a; - ensure_equals("operator%= failed " ,vec4,vec4b); - } - - template<> template<> - void v4math_object::test<14>() - { - F32 x = 1.f, y = 2.f, z = -1.1f,div = 4.2f; - F32 t = 1.f / div; - LLVector4 vec4(x,y,z), vec4a; - vec4a = vec4/div; - ensure("1:operator/ failed " ,is_approx_equal(x*t, vec4a.mV[VX]) && is_approx_equal(y*t, vec4a.mV[VY])&& is_approx_equal(z*t, vec4a.mV[VZ])); - x = 1.23f, y = 4.f, z = -2.32f; - vec4.clearVec(); - vec4a.clearVec(); - vec4.setVec(x,y,z); - vec4a = vec4/div; - ensure("2:operator/ failed " ,is_approx_equal(x*t, vec4a.mV[VX]) && is_approx_equal(y*t, vec4a.mV[VY])&& is_approx_equal(z*t, vec4a.mV[VZ])); - vec4 /= div; - ensure("3:operator/ failed " ,is_approx_equal(x*t, vec4.mV[VX]) && is_approx_equal(y*t, vec4.mV[VY])&& is_approx_equal(z*t, vec4.mV[VZ])); - } - - template<> template<> - void v4math_object::test<15>() - { - F32 x = 1.f, y = 2.f, z = -1.1f; - LLVector4 vec4(x,y,z), vec4a; - ensure("operator!= failed " ,(vec4 != vec4a)); - vec4a = vec4; - ensure("operator== failed " ,(vec4 ==vec4a)); - } - - template<> template<> - void v4math_object::test<16>() - { - F32 x = 1.f, y = 2.f, z = -1.1f; - LLVector4 vec4(x,y,z), vec4a; - vec4a = - vec4; - ensure("operator- failed " , (vec4 == - vec4a)); - } - - template<> template<> - void v4math_object::test<17>() - { - F32 x = 1.f, y = 2.f, z = -1.1f,epsilon = .23425f; - LLVector4 vec4(x,y,z), vec4a(x,y,z); - ensure("1:are_parallel: Fail " ,(true == are_parallel(vec4a,vec4,epsilon))); - x = 21.f, y = 12.f, z = -123.1f; - vec4a.clearVec(); - vec4a.setVec(x,y,z); - ensure("2:are_parallel: Fail " ,(false == are_parallel(vec4a,vec4,epsilon))); - } - - template<> template<> - void v4math_object::test<18>() - { - F32 x = 1.f, y = 2.f, z = -1.1f; - F32 angle1, angle2; - LLVector4 vec4(x,y,z), vec4a(x,y,z); - angle1 = angle_between(vec4, vec4a); - vec4.normVec(); - vec4a.normVec(); - angle2 = acos(vec4 * vec4a); - ensure_approximately_equals("1:angle_between: Fail " ,angle1,angle2,8); - F32 x1 = 21.f, y1 = 2.23f, z1 = -1.1f; - LLVector4 vec4b(x,y,z), vec4c(x1,y1,z1); - angle1 = angle_between(vec4b, vec4c); - vec4b.normVec(); - vec4c.normVec(); - angle2 = acos(vec4b * vec4c); - ensure_approximately_equals("2:angle_between: Fail " ,angle1,angle2,8); - } - - template<> template<> - void v4math_object::test<19>() - { - F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.f, z2 = 1.f; - F32 val1,val2; - LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2); - val1 = dist_vec(vec4,vec4a); - val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); - ensure_equals("dist_vec: Fail ",val2, val1); - val1 = dist_vec_squared(vec4,vec4a); - val2 =((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); - ensure_equals("dist_vec_squared: Fail ",val2, val1); - } - - template<> template<> - void v4math_object::test<20>() - { - F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, w1 = -.23f, x2 = 1.3f, y2 = 1.f, z2 = 1.f,w2 = .12f; - F32 val = 2.3f,val1,val2,val3,val4; - LLVector4 vec4(x1,y1,z1,w1),vec4a(x2,y2,z2,w2); - val1 = x1 + (x2 - x1)* val; - val2 = y1 + (y2 - y1)* val; - val3 = z1 + (z2 - z1)* val; - val4 = w1 + (w2 - w1)* val; - LLVector4 vec4b = lerp(vec4,vec4a,val); - LLVector4 check(val1, val2, val3, val4); - ensure_equals("lerp failed", check, vec4b); - } - - template<> template<> - void v4math_object::test<21>() - { - F32 x = 1.f, y = 2.f, z = -1.1f; - LLVector4 vec4(x,y,z); - LLVector3 vec3 = vec4to3(vec4); - ensure("vec4to3 failed", ((x == vec3.mV[VX])&& (y == vec3.mV[VY]) && (z == vec3.mV[VZ]))); - LLVector4 vec4a = vec3to4(vec3); - ensure_equals("vec3to4 failed",vec4a,vec4); - } - - template<> template<> - void v4math_object::test<22>() - { - F32 x = 1.f, y = 2.f, z = -1.1f; - LLVector4 vec4(x,y,z); - LLSD llsd = vec4.getValue(); - LLVector3 vec3(llsd); - LLVector4 vec4a = vec3to4(vec3); - ensure_equals("getValue failed",vec4a,vec4); - } -} +/** + * @file v4math_test.cpp + * @author Adroit + * @date 2007-03 + * @brief v4math test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" +#include "llsd.h" + +#include "../m4math.h" +#include "../v4math.h" +#include "../llquaternion.h" + +namespace tut +{ + struct v4math_data + { + }; + typedef test_group v4math_test; + typedef v4math_test::object v4math_object; + tut::v4math_test v4math_testcase("v4math_h"); + + template<> template<> + void v4math_object::test<1>() + { + LLVector4 vec4; + ensure("1:LLVector4:Fail to initialize " ,((0 == vec4.mV[VX]) && (0 == vec4.mV[VY]) && (0 == vec4.mV[VZ])&& (1.0f == vec4.mV[VW]))); + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + LLVector4 vec4a(x,y,z); + ensure("2:LLVector4:Fail to initialize " ,((x == vec4a.mV[VX]) && (y == vec4a.mV[VY]) && (z == vec4a.mV[VZ])&& (1.0f == vec4a.mV[VW]))); + LLVector4 vec4b(x,y,z,w); + ensure("3:LLVector4:Fail to initialize " ,((x == vec4b.mV[VX]) && (y == vec4b.mV[VY]) && (z == vec4b.mV[VZ])&& (w == vec4b.mV[VW]))); + const F32 vec[4] = {.112f ,23.2f, -4.2f, -.0001f}; + LLVector4 vec4c(vec); + ensure("4:LLVector4:Fail to initialize " ,((vec[0] == vec4c.mV[VX]) && (vec[1] == vec4c.mV[VY]) && (vec[2] == vec4c.mV[VZ])&& (vec[3] == vec4c.mV[VW]))); + LLVector3 vec3(-2.23f,1.01f,42.3f); + LLVector4 vec4d(vec3); + ensure("5:LLVector4:Fail to initialize " ,((vec3.mV[VX] == vec4d.mV[VX]) && (vec3.mV[VY] == vec4d.mV[VY]) && (vec3.mV[VZ] == vec4d.mV[VZ])&& (1.f == vec4d.mV[VW]))); + F32 w1 = -.234f; + LLVector4 vec4e(vec3,w1); + ensure("6:LLVector4:Fail to initialize " ,((vec3.mV[VX] == vec4e.mV[VX]) && (vec3.mV[VY] == vec4e.mV[VY]) && (vec3.mV[VZ] == vec4e.mV[VZ])&& (w1 == vec4e.mV[VW]))); + } + + template<> template<> + void v4math_object::test<2>() + { + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + LLVector4 vec4; + vec4.setVec(x,y,z); + ensure("1:setVec:Fail to initialize " ,((x == vec4.mV[VX]) && (y == vec4.mV[VY]) && (z == vec4.mV[VZ])&& (1.0f == vec4.mV[VW]))); + vec4.clearVec(); + ensure("2:clearVec:Fail " ,((0 == vec4.mV[VX]) && (0 == vec4.mV[VY]) && (0 == vec4.mV[VZ])&& (1.0f == vec4.mV[VW]))); + vec4.setVec(x,y,z,w); + ensure("3:setVec:Fail to initialize " ,((x == vec4.mV[VX]) && (y == vec4.mV[VY]) && (z == vec4.mV[VZ])&& (w == vec4.mV[VW]))); + vec4.zeroVec(); + ensure("4:zeroVec:Fail " ,((0 == vec4.mV[VX]) && (0 == vec4.mV[VY]) && (0 == vec4.mV[VZ])&& (0 == vec4.mV[VW]))); + LLVector3 vec3(-2.23f,1.01f,42.3f); + vec4.clearVec(); + vec4.setVec(vec3); + ensure("5:setVec:Fail to initialize " ,((vec3.mV[VX] == vec4.mV[VX]) && (vec3.mV[VY] == vec4.mV[VY]) && (vec3.mV[VZ] == vec4.mV[VZ])&& (1.f == vec4.mV[VW]))); + F32 w1 = -.234f; + vec4.zeroVec(); + vec4.setVec(vec3,w1); + ensure("6:setVec:Fail to initialize " ,((vec3.mV[VX] == vec4.mV[VX]) && (vec3.mV[VY] == vec4.mV[VY]) && (vec3.mV[VZ] == vec4.mV[VZ])&& (w1 == vec4.mV[VW]))); + const F32 vec[4] = {.112f ,23.2f, -4.2f, -.0001f}; + LLVector4 vec4a; + vec4a.setVec(vec); + ensure("7:setVec:Fail to initialize " ,((vec[0] == vec4a.mV[VX]) && (vec[1] == vec4a.mV[VY]) && (vec[2] == vec4a.mV[VZ])&& (vec[3] == vec4a.mV[VW]))); + } + + template<> template<> + void v4math_object::test<3>() + { + F32 x = 10.f, y = -2.3f, z = -.023f; + LLVector4 vec4(x,y,z); + ensure("magVec:Fail ", is_approx_equal(vec4.magVec(), (F32) sqrt(x*x + y*y + z*z))); + ensure("magVecSquared:Fail ", is_approx_equal(vec4.magVecSquared(), (x*x + y*y + z*z))); + } + + template<> template<> + void v4math_object::test<4>() + { + F32 x = 10.f, y = -2.3f, z = -.023f; + LLVector4 vec4(x,y,z); + F32 mag = vec4.normVec(); + mag = 1.f/ mag; + ensure("1:normVec: Fail " ,is_approx_equal(mag*x,vec4.mV[VX]) && is_approx_equal(mag*y, vec4.mV[VY])&& is_approx_equal(mag*z, vec4.mV[VZ])); + x = 0.000000001f, y = 0.000000001f, z = 0.000000001f; + vec4.clearVec(); + vec4.setVec(x,y,z); + mag = vec4.normVec(); + ensure("2:normVec: Fail " ,is_approx_equal(mag*x,vec4.mV[VX]) && is_approx_equal(mag*y, vec4.mV[VY])&& is_approx_equal(mag*z, vec4.mV[VZ])); + } + + template<> template<> + void v4math_object::test<5>() + { + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + LLVector4 vec4(x,y,z,w); + vec4.abs(); + ensure("abs:Fail " ,((x == vec4.mV[VX]) && (-y == vec4.mV[VY]) && (-z == vec4.mV[VZ])&& (-w == vec4.mV[VW]))); + vec4.clearVec(); + ensure("isExactlyClear:Fail " ,(true == vec4.isExactlyClear())); + vec4.zeroVec(); + ensure("isExactlyZero:Fail " ,(true == vec4.isExactlyZero())); + } + + template<> template<> + void v4math_object::test<6>() + { + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + LLVector4 vec4(x,y,z,w),vec4a; + vec4a = vec4.scaleVec(vec4); + ensure("scaleVec:Fail " ,(is_approx_equal(x*x, vec4a.mV[VX]) && is_approx_equal(y*y, vec4a.mV[VY]) && is_approx_equal(z*z, vec4a.mV[VZ])&& is_approx_equal(w*w, vec4a.mV[VW]))); + } + + template<> template<> + void v4math_object::test<7>() + { + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + LLVector4 vec4(x,y,z,w); + ensure("1:operator [] failed " ,( x == vec4[0])); + ensure("2:operator [] failed " ,( y == vec4[1])); + ensure("3:operator [] failed " ,( z == vec4[2])); + ensure("4:operator [] failed " ,( w == vec4[3])); + x = 23.f, y = -.2361f, z = 3.25; + vec4.setVec(x,y,z); + F32 &ref1 = vec4[0]; + ensure("5:operator [] failed " ,( ref1 == vec4[0])); + F32 &ref2 = vec4[1]; + ensure("6:operator [] failed " ,( ref2 == vec4[1])); + F32 &ref3 = vec4[2]; + ensure("7:operator [] failed " ,( ref3 == vec4[2])); + F32 &ref4 = vec4[3]; + ensure("8:operator [] failed " ,( ref4 == vec4[3])); + } + + template<> template<> + void v4math_object::test<8>() + { + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + const F32 val[16] = { + 1.f, 2.f, 3.f, 0.f, + .34f, .1f, -.5f, 0.f, + 2.f, 1.23f, 1.234f, 0.f, + .89f, 0.f, 0.f, 0.f + }; + LLMatrix4 mat(val); + LLVector4 vec4(x,y,z,w),vec4a; + vec4.rotVec(mat); + vec4a.setVec(x,y,z,w); + vec4a.rotVec(mat); + ensure_equals("1:rotVec: Fail " ,vec4a, vec4); + F32 a = 2.32f, b = -23.2f, c = -34.1112f, d = 1.010112f; + LLQuaternion q(a,b,c,d); + LLVector4 vec4b(a,b,c,d),vec4c; + vec4b.rotVec(q); + vec4c.setVec(a, b, c, d); + vec4c.rotVec(q); + ensure_equals("2:rotVec: Fail " ,vec4b, vec4c); + } + + template<> template<> + void v4math_object::test<9>() + { + F32 x = 10.f, y = -2.3f, z = -.023f, w = -2.0f; + LLVector4 vec4(x,y,z,w),vec4a;; + std::ostringstream stream1, stream2; + stream1 << vec4; + vec4a.setVec(x,y,z,w); + stream2 << vec4a; + ensure("operator << failed",(stream1.str() == stream2.str())); + } + + template<> template<> + void v4math_object::test<10>() + { + F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f, w1 = .23f; + F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f, w2 = 1.3f; + LLVector4 vec4(x1,y1,z1,w1),vec4a(x2,y2,z2,w2),vec4b; + vec4b = vec4a + vec4; + ensure("1:operator+:Fail to initialize " ,(is_approx_equal(x1+x2,vec4b.mV[VX]) && is_approx_equal(y1+y2,vec4b.mV[VY]) && is_approx_equal(z1+z2,vec4b.mV[VZ]))); + x1 = -2.45f, y1 = 2.1f, z1 = 3.0f; + vec4.clearVec(); + vec4a.clearVec(); + vec4.setVec(x1,y1,z1); + vec4a +=vec4; + ensure_equals("2:operator+=: Fail to initialize", vec4a,vec4); + vec4a += vec4; + ensure("3:operator+=:Fail to initialize " ,(is_approx_equal(2*x1,vec4a.mV[VX]) && is_approx_equal(2*y1,vec4a.mV[VY]) && is_approx_equal(2*z1,vec4a.mV[VZ]))); + } + template<> template<> + void v4math_object::test<11>() + { + F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f, w1 = .23f; + F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f, w2 = 1.3f; + LLVector4 vec4(x1,y1,z1,w1),vec4a(x2,y2,z2,w2),vec4b; + vec4b = vec4a - vec4; + ensure("1:operator-:Fail to initialize " ,(is_approx_equal(x2-x1,vec4b.mV[VX]) && is_approx_equal(y2-y1,vec4b.mV[VY]) && is_approx_equal(z2-z1,vec4b.mV[VZ]))); + x1 = -2.45f, y1 = 2.1f, z1 = 3.0f; + vec4.clearVec(); + vec4a.clearVec(); + vec4.setVec(x1,y1,z1); + vec4a -=vec4; + ensure_equals("2:operator-=: Fail to initialize" , vec4a,-vec4); + vec4a -=vec4; + ensure("3:operator-=:Fail to initialize " ,(is_approx_equal(-2*x1,vec4a.mV[VX]) && is_approx_equal(-2*y1,vec4a.mV[VY]) && is_approx_equal(-2*z1,vec4a.mV[VZ]))); + } + + template<> template<> + void v4math_object::test<12>() + { + F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f; + F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f; + LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2); + F32 res = vec4 * vec4a; + ensure("1:operator* failed " ,is_approx_equal(res, x1*x2 + y1*y2 + z1*z2)); + vec4a.clearVec(); + F32 mulVal = 4.2f; + vec4a = vec4 * mulVal; + ensure("2:operator* failed " ,is_approx_equal(x1*mulVal,vec4a.mV[VX]) && is_approx_equal(y1*mulVal, vec4a.mV[VY])&& is_approx_equal(z1*mulVal, vec4a.mV[VZ])); + vec4a.clearVec(); + vec4a = mulVal * vec4 ; + ensure("3:operator* failed " ,is_approx_equal(x1*mulVal, vec4a.mV[VX]) && is_approx_equal(y1*mulVal, vec4a.mV[VY])&& is_approx_equal(z1*mulVal, vec4a.mV[VZ])); + vec4 *= mulVal; + ensure("4:operator*= failed " ,is_approx_equal(x1*mulVal, vec4.mV[VX]) && is_approx_equal(y1*mulVal, vec4.mV[VY])&& is_approx_equal(z1*mulVal, vec4.mV[VZ])); + } + + template<> template<> + void v4math_object::test<13>() + { + F32 x1 = 1.f, y1 = 2.f, z1 = -1.1f; + F32 x2 = 1.2f, y2 = 2.5f, z2 = 1.f; + LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2),vec4b; + vec4b = vec4 % vec4a; + ensure("1:operator% failed " ,is_approx_equal(y1*z2 - y2*z1, vec4b.mV[VX]) && is_approx_equal(z1*x2 -z2*x1, vec4b.mV[VY]) && is_approx_equal(x1*y2-x2*y1, vec4b.mV[VZ])); + vec4 %= vec4a; + ensure_equals("operator%= failed " ,vec4,vec4b); + } + + template<> template<> + void v4math_object::test<14>() + { + F32 x = 1.f, y = 2.f, z = -1.1f,div = 4.2f; + F32 t = 1.f / div; + LLVector4 vec4(x,y,z), vec4a; + vec4a = vec4/div; + ensure("1:operator/ failed " ,is_approx_equal(x*t, vec4a.mV[VX]) && is_approx_equal(y*t, vec4a.mV[VY])&& is_approx_equal(z*t, vec4a.mV[VZ])); + x = 1.23f, y = 4.f, z = -2.32f; + vec4.clearVec(); + vec4a.clearVec(); + vec4.setVec(x,y,z); + vec4a = vec4/div; + ensure("2:operator/ failed " ,is_approx_equal(x*t, vec4a.mV[VX]) && is_approx_equal(y*t, vec4a.mV[VY])&& is_approx_equal(z*t, vec4a.mV[VZ])); + vec4 /= div; + ensure("3:operator/ failed " ,is_approx_equal(x*t, vec4.mV[VX]) && is_approx_equal(y*t, vec4.mV[VY])&& is_approx_equal(z*t, vec4.mV[VZ])); + } + + template<> template<> + void v4math_object::test<15>() + { + F32 x = 1.f, y = 2.f, z = -1.1f; + LLVector4 vec4(x,y,z), vec4a; + ensure("operator!= failed " ,(vec4 != vec4a)); + vec4a = vec4; + ensure("operator== failed " ,(vec4 ==vec4a)); + } + + template<> template<> + void v4math_object::test<16>() + { + F32 x = 1.f, y = 2.f, z = -1.1f; + LLVector4 vec4(x,y,z), vec4a; + vec4a = - vec4; + ensure("operator- failed " , (vec4 == - vec4a)); + } + + template<> template<> + void v4math_object::test<17>() + { + F32 x = 1.f, y = 2.f, z = -1.1f,epsilon = .23425f; + LLVector4 vec4(x,y,z), vec4a(x,y,z); + ensure("1:are_parallel: Fail " ,(true == are_parallel(vec4a,vec4,epsilon))); + x = 21.f, y = 12.f, z = -123.1f; + vec4a.clearVec(); + vec4a.setVec(x,y,z); + ensure("2:are_parallel: Fail " ,(false == are_parallel(vec4a,vec4,epsilon))); + } + + template<> template<> + void v4math_object::test<18>() + { + F32 x = 1.f, y = 2.f, z = -1.1f; + F32 angle1, angle2; + LLVector4 vec4(x,y,z), vec4a(x,y,z); + angle1 = angle_between(vec4, vec4a); + vec4.normVec(); + vec4a.normVec(); + angle2 = acos(vec4 * vec4a); + ensure_approximately_equals("1:angle_between: Fail " ,angle1,angle2,8); + F32 x1 = 21.f, y1 = 2.23f, z1 = -1.1f; + LLVector4 vec4b(x,y,z), vec4c(x1,y1,z1); + angle1 = angle_between(vec4b, vec4c); + vec4b.normVec(); + vec4c.normVec(); + angle2 = acos(vec4b * vec4c); + ensure_approximately_equals("2:angle_between: Fail " ,angle1,angle2,8); + } + + template<> template<> + void v4math_object::test<19>() + { + F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, x2 = 1.3f, y2 = 1.f, z2 = 1.f; + F32 val1,val2; + LLVector4 vec4(x1,y1,z1),vec4a(x2,y2,z2); + val1 = dist_vec(vec4,vec4a); + val2 = (F32) sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); + ensure_equals("dist_vec: Fail ",val2, val1); + val1 = dist_vec_squared(vec4,vec4a); + val2 =((x1 - x2)*(x1 - x2) + (y1 - y2)* (y1 - y2) + (z1 - z2)* (z1 -z2)); + ensure_equals("dist_vec_squared: Fail ",val2, val1); + } + + template<> template<> + void v4math_object::test<20>() + { + F32 x1 =-2.3f, y1 = 2.f,z1 = 1.2f, w1 = -.23f, x2 = 1.3f, y2 = 1.f, z2 = 1.f,w2 = .12f; + F32 val = 2.3f,val1,val2,val3,val4; + LLVector4 vec4(x1,y1,z1,w1),vec4a(x2,y2,z2,w2); + val1 = x1 + (x2 - x1)* val; + val2 = y1 + (y2 - y1)* val; + val3 = z1 + (z2 - z1)* val; + val4 = w1 + (w2 - w1)* val; + LLVector4 vec4b = lerp(vec4,vec4a,val); + LLVector4 check(val1, val2, val3, val4); + ensure_equals("lerp failed", check, vec4b); + } + + template<> template<> + void v4math_object::test<21>() + { + F32 x = 1.f, y = 2.f, z = -1.1f; + LLVector4 vec4(x,y,z); + LLVector3 vec3 = vec4to3(vec4); + ensure("vec4to3 failed", ((x == vec3.mV[VX])&& (y == vec3.mV[VY]) && (z == vec3.mV[VZ]))); + LLVector4 vec4a = vec3to4(vec3); + ensure_equals("vec3to4 failed",vec4a,vec4); + } + + template<> template<> + void v4math_object::test<22>() + { + F32 x = 1.f, y = 2.f, z = -1.1f; + LLVector4 vec4(x,y,z); + LLSD llsd = vec4.getValue(); + LLVector3 vec3(llsd); + LLVector4 vec4a = vec3to4(vec3); + ensure_equals("getValue failed",vec4a,vec4); + } +} diff --git a/indra/llmath/tests/xform_test.cpp b/indra/llmath/tests/xform_test.cpp index 983ac37574..6d6a64ec4c 100644 --- a/indra/llmath/tests/xform_test.cpp +++ b/indra/llmath/tests/xform_test.cpp @@ -1,245 +1,245 @@ -/** - * @file xform_test.cpp - * @author Adroit - * @date March 2007 - * @brief Test cases for LLXform - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "../test/lltut.h" - -#include "../xform.h" - -namespace tut -{ - struct xform_test - { - }; - typedef test_group xform_test_t; - typedef xform_test_t::object xform_test_object_t; - tut::xform_test_t tut_xform_test("LLXForm"); - - //test case for init(), getParent(), getRotation(), getPositionW(), getWorldRotation() fns. - template<> template<> - void xform_test_object_t::test<1>() - { - LLXform xform_obj; - LLVector3 emptyVec(0.f,0.f,0.f); - LLVector3 initialScaleVec(1.f,1.f,1.f); - - ensure("LLXform empty constructor failed: ", !xform_obj.getParent() && !xform_obj.isChanged() && - xform_obj.getPosition() == emptyVec && - (xform_obj.getRotation()).isIdentity() && - xform_obj.getScale() == initialScaleVec && - xform_obj.getPositionW() == emptyVec && - (xform_obj.getWorldRotation()).isIdentity() && - !xform_obj.getScaleChildOffset()); - } - - // test cases for - // setScale(const LLVector3& scale) - // setScale(const F32 x, const F32 y, const F32 z) - // setRotation(const F32 x, const F32 y, const F32 z) - // setPosition(const F32 x, const F32 y, const F32 z) - // getLocalMat4(LLMatrix4 &mat) - template<> template<> - void xform_test_object_t::test<2>() - { - LLMatrix4 llmat4; - LLXform xform_obj; - - F32 x = 3.6f; - F32 y = 5.5f; - F32 z = 4.2f; - F32 w = 0.f; - F32 posz = z + 2.122f; - LLVector3 vec(x, y, z); - xform_obj.setScale(x, y, z); - xform_obj.setPosition(x, y, posz); - ensure("setScale failed: ", xform_obj.getScale() == vec); - - vec.setVec(x, y, posz); - ensure("getPosition failed: ", xform_obj.getPosition() == vec); - - x = x * 2.f; - y = y + 2.3f; - z = posz * 4.f; - vec.setVec(x, y, z); - xform_obj.setPositionX(x); - xform_obj.setPositionY(y); - xform_obj.setPositionZ(z); - ensure("setPositionX/Y/Z failed: ", xform_obj.getPosition() == vec); - - xform_obj.setScaleChildOffset(true); - ensure("setScaleChildOffset failed: ", xform_obj.getScaleChildOffset()); - - vec.setVec(x, y, z); - - xform_obj.addPosition(vec); - vec += vec; - ensure("addPosition failed: ", xform_obj.getPosition() == vec); - - xform_obj.setScale(vec); - ensure("setScale vector failed: ", xform_obj.getScale() == vec); - - LLQuaternion quat(x, y, z, w); - xform_obj.setRotation(quat); - ensure("setRotation quat failed: ", xform_obj.getRotation() == quat); - - xform_obj.setRotation(x, y, z, w); - ensure("getRotation 2 failed: ", xform_obj.getRotation() == quat); - - xform_obj.setRotation(x, y, z); - quat.setQuat(x,y,z); - ensure("setRotation xyz failed: ", xform_obj.getRotation() == quat); - - // LLXform::setRotation(const F32 x, const F32 y, const F32 z) - // Does normalization - // LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) - // Simply copies the individual values - does not do any normalization. - // Is that the expected behavior? - } - - // test cases for inline bool setParent(LLXform *parent) and getParent() fn. - template<> template<> - void xform_test_object_t::test<3>() - { - LLXform xform_obj; - LLXform par; - LLXform grandpar; - xform_obj.setParent(&par); - par.setParent(&grandpar); - ensure("setParent/getParent failed: ", &par == xform_obj.getParent()); - ensure("getRoot failed: ", &grandpar == xform_obj.getRoot()); - ensure("isRoot failed: ", grandpar.isRoot() && !par.isRoot() && !xform_obj.isRoot()); - ensure("isRootEdit failed: ", grandpar.isRootEdit() && !par.isRootEdit() && !xform_obj.isRootEdit()); - } - - template<> template<> - void xform_test_object_t::test<4>() - { - LLXform xform_obj; - xform_obj.setChanged(LLXform::TRANSLATED | LLXform::ROTATED | LLXform::SCALED); - ensure("setChanged/isChanged failed: ", xform_obj.isChanged()); - - xform_obj.clearChanged(LLXform::TRANSLATED | LLXform::ROTATED | LLXform::SCALED); - ensure("clearChanged failed: ", !xform_obj.isChanged()); - - LLVector3 llvect3(12.4f, -5.6f, 0.34f); - xform_obj.setScale(llvect3); - ensure("setScale did not set SCALED flag: ", xform_obj.isChanged(LLXform::SCALED)); - xform_obj.setPosition(1.2f, 2.3f, 3.4f); - ensure("setScale did not set TRANSLATED flag: ", xform_obj.isChanged(LLXform::TRANSLATED)); - ensure("TRANSLATED reset SCALED flag: ", xform_obj.isChanged(LLXform::TRANSLATED | LLXform::SCALED)); - xform_obj.clearChanged(LLXform::SCALED); - ensure("reset SCALED failed: ", !xform_obj.isChanged(LLXform::SCALED)); - xform_obj.setRotation(1, 2, 3, 4); - ensure("ROTATION flag not set ", xform_obj.isChanged(LLXform::TRANSLATED | LLXform::ROTATED)); - xform_obj.setScale(llvect3); - ensure("ROTATION flag not set ", xform_obj.isChanged(LLXform::MOVED)); - } - - //to test init() and getWorldMatrix() fns. - template<> template<> - void xform_test_object_t::test<5>() - { - LLXformMatrix formMatrix_obj; - formMatrix_obj.init(); - LLMatrix4 mat4_obj; - - ensure("1. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[0][0]); - ensure("2. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[0][1]); - ensure("3. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[0][2]); - ensure("4. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[0][3]); - ensure("5. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[1][0]); - ensure("6. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[1][1]); - ensure("7. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[1][2]); - ensure("8. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[1][3]); - ensure("9. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[2][0]); - ensure("10. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[2][1]); - ensure("11. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[2][2]); - ensure("12. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[2][3]); - ensure("13. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[3][0]); - ensure("14. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[3][1]); - ensure("15. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[3][2]); - ensure("16. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[3][3]); - } - - //to test mMin.clearVec() and mMax.clearVec() fns - template<> template<> - void xform_test_object_t::test<6>() - { - LLXformMatrix formMatrix_obj; - formMatrix_obj.init(); - LLVector3 llmin_vec3; - LLVector3 llmax_vec3; - formMatrix_obj.getMinMax(llmin_vec3, llmax_vec3); - ensure("1. The value is not NULL", 0.f == llmin_vec3.mV[0]); - ensure("2. The value is not NULL", 0.f == llmin_vec3.mV[1]); - ensure("3. The value is not NULL", 0.f == llmin_vec3.mV[2]); - ensure("4. The value is not NULL", 0.f == llmin_vec3.mV[0]); - ensure("5. The value is not NULL", 0.f == llmin_vec3.mV[1]); - ensure("6. The value is not NULL", 0.f == llmin_vec3.mV[2]); - } - - //test case of update() fn. - template<> template<> - void xform_test_object_t::test<7>() - { - LLXformMatrix formMatrix_obj; - - LLXformMatrix parent; - LLVector3 llvecpos(1.0, 2.0, 3.0); - LLVector3 llvecpospar(10.0, 20.0, 30.0); - formMatrix_obj.setPosition(llvecpos); - parent.setPosition(llvecpospar); - - LLVector3 llvecparentscale(1.0, 2.0, 0); - parent.setScaleChildOffset(true); - parent.setScale(llvecparentscale); - - LLQuaternion quat(1, 2, 3, 4); - LLQuaternion quatparent(5, 6, 7, 8); - formMatrix_obj.setRotation(quat); - parent.setRotation(quatparent); - formMatrix_obj.setParent(&parent); - - parent.update(); - formMatrix_obj.update(); - - LLVector3 worldPos = llvecpos; - worldPos.scaleVec(llvecparentscale); - worldPos *= quatparent; - worldPos += llvecpospar; - - LLQuaternion worldRot = quat * quatparent; - - ensure("getWorldPosition failed: ", formMatrix_obj.getWorldPosition() == worldPos); - ensure("getWorldRotation failed: ", formMatrix_obj.getWorldRotation() == worldRot); - - ensure("getWorldPosition for parent failed: ", parent.getWorldPosition() == llvecpospar); - ensure("getWorldRotation for parent failed: ", parent.getWorldRotation() == quatparent); - } -} - +/** + * @file xform_test.cpp + * @author Adroit + * @date March 2007 + * @brief Test cases for LLXform + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "../test/lltut.h" + +#include "../xform.h" + +namespace tut +{ + struct xform_test + { + }; + typedef test_group xform_test_t; + typedef xform_test_t::object xform_test_object_t; + tut::xform_test_t tut_xform_test("LLXForm"); + + //test case for init(), getParent(), getRotation(), getPositionW(), getWorldRotation() fns. + template<> template<> + void xform_test_object_t::test<1>() + { + LLXform xform_obj; + LLVector3 emptyVec(0.f,0.f,0.f); + LLVector3 initialScaleVec(1.f,1.f,1.f); + + ensure("LLXform empty constructor failed: ", !xform_obj.getParent() && !xform_obj.isChanged() && + xform_obj.getPosition() == emptyVec && + (xform_obj.getRotation()).isIdentity() && + xform_obj.getScale() == initialScaleVec && + xform_obj.getPositionW() == emptyVec && + (xform_obj.getWorldRotation()).isIdentity() && + !xform_obj.getScaleChildOffset()); + } + + // test cases for + // setScale(const LLVector3& scale) + // setScale(const F32 x, const F32 y, const F32 z) + // setRotation(const F32 x, const F32 y, const F32 z) + // setPosition(const F32 x, const F32 y, const F32 z) + // getLocalMat4(LLMatrix4 &mat) + template<> template<> + void xform_test_object_t::test<2>() + { + LLMatrix4 llmat4; + LLXform xform_obj; + + F32 x = 3.6f; + F32 y = 5.5f; + F32 z = 4.2f; + F32 w = 0.f; + F32 posz = z + 2.122f; + LLVector3 vec(x, y, z); + xform_obj.setScale(x, y, z); + xform_obj.setPosition(x, y, posz); + ensure("setScale failed: ", xform_obj.getScale() == vec); + + vec.setVec(x, y, posz); + ensure("getPosition failed: ", xform_obj.getPosition() == vec); + + x = x * 2.f; + y = y + 2.3f; + z = posz * 4.f; + vec.setVec(x, y, z); + xform_obj.setPositionX(x); + xform_obj.setPositionY(y); + xform_obj.setPositionZ(z); + ensure("setPositionX/Y/Z failed: ", xform_obj.getPosition() == vec); + + xform_obj.setScaleChildOffset(true); + ensure("setScaleChildOffset failed: ", xform_obj.getScaleChildOffset()); + + vec.setVec(x, y, z); + + xform_obj.addPosition(vec); + vec += vec; + ensure("addPosition failed: ", xform_obj.getPosition() == vec); + + xform_obj.setScale(vec); + ensure("setScale vector failed: ", xform_obj.getScale() == vec); + + LLQuaternion quat(x, y, z, w); + xform_obj.setRotation(quat); + ensure("setRotation quat failed: ", xform_obj.getRotation() == quat); + + xform_obj.setRotation(x, y, z, w); + ensure("getRotation 2 failed: ", xform_obj.getRotation() == quat); + + xform_obj.setRotation(x, y, z); + quat.setQuat(x,y,z); + ensure("setRotation xyz failed: ", xform_obj.getRotation() == quat); + + // LLXform::setRotation(const F32 x, const F32 y, const F32 z) + // Does normalization + // LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) + // Simply copies the individual values - does not do any normalization. + // Is that the expected behavior? + } + + // test cases for inline bool setParent(LLXform *parent) and getParent() fn. + template<> template<> + void xform_test_object_t::test<3>() + { + LLXform xform_obj; + LLXform par; + LLXform grandpar; + xform_obj.setParent(&par); + par.setParent(&grandpar); + ensure("setParent/getParent failed: ", &par == xform_obj.getParent()); + ensure("getRoot failed: ", &grandpar == xform_obj.getRoot()); + ensure("isRoot failed: ", grandpar.isRoot() && !par.isRoot() && !xform_obj.isRoot()); + ensure("isRootEdit failed: ", grandpar.isRootEdit() && !par.isRootEdit() && !xform_obj.isRootEdit()); + } + + template<> template<> + void xform_test_object_t::test<4>() + { + LLXform xform_obj; + xform_obj.setChanged(LLXform::TRANSLATED | LLXform::ROTATED | LLXform::SCALED); + ensure("setChanged/isChanged failed: ", xform_obj.isChanged()); + + xform_obj.clearChanged(LLXform::TRANSLATED | LLXform::ROTATED | LLXform::SCALED); + ensure("clearChanged failed: ", !xform_obj.isChanged()); + + LLVector3 llvect3(12.4f, -5.6f, 0.34f); + xform_obj.setScale(llvect3); + ensure("setScale did not set SCALED flag: ", xform_obj.isChanged(LLXform::SCALED)); + xform_obj.setPosition(1.2f, 2.3f, 3.4f); + ensure("setScale did not set TRANSLATED flag: ", xform_obj.isChanged(LLXform::TRANSLATED)); + ensure("TRANSLATED reset SCALED flag: ", xform_obj.isChanged(LLXform::TRANSLATED | LLXform::SCALED)); + xform_obj.clearChanged(LLXform::SCALED); + ensure("reset SCALED failed: ", !xform_obj.isChanged(LLXform::SCALED)); + xform_obj.setRotation(1, 2, 3, 4); + ensure("ROTATION flag not set ", xform_obj.isChanged(LLXform::TRANSLATED | LLXform::ROTATED)); + xform_obj.setScale(llvect3); + ensure("ROTATION flag not set ", xform_obj.isChanged(LLXform::MOVED)); + } + + //to test init() and getWorldMatrix() fns. + template<> template<> + void xform_test_object_t::test<5>() + { + LLXformMatrix formMatrix_obj; + formMatrix_obj.init(); + LLMatrix4 mat4_obj; + + ensure("1. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[0][0]); + ensure("2. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[0][1]); + ensure("3. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[0][2]); + ensure("4. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[0][3]); + ensure("5. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[1][0]); + ensure("6. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[1][1]); + ensure("7. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[1][2]); + ensure("8. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[1][3]); + ensure("9. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[2][0]); + ensure("10. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[2][1]); + ensure("11. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[2][2]); + ensure("12. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[2][3]); + ensure("13. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[3][0]); + ensure("14. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[3][1]); + ensure("15. The value is not NULL", 0.f == formMatrix_obj.getWorldMatrix().mMatrix[3][2]); + ensure("16. The value is not NULL", 1.f == formMatrix_obj.getWorldMatrix().mMatrix[3][3]); + } + + //to test mMin.clearVec() and mMax.clearVec() fns + template<> template<> + void xform_test_object_t::test<6>() + { + LLXformMatrix formMatrix_obj; + formMatrix_obj.init(); + LLVector3 llmin_vec3; + LLVector3 llmax_vec3; + formMatrix_obj.getMinMax(llmin_vec3, llmax_vec3); + ensure("1. The value is not NULL", 0.f == llmin_vec3.mV[0]); + ensure("2. The value is not NULL", 0.f == llmin_vec3.mV[1]); + ensure("3. The value is not NULL", 0.f == llmin_vec3.mV[2]); + ensure("4. The value is not NULL", 0.f == llmin_vec3.mV[0]); + ensure("5. The value is not NULL", 0.f == llmin_vec3.mV[1]); + ensure("6. The value is not NULL", 0.f == llmin_vec3.mV[2]); + } + + //test case of update() fn. + template<> template<> + void xform_test_object_t::test<7>() + { + LLXformMatrix formMatrix_obj; + + LLXformMatrix parent; + LLVector3 llvecpos(1.0, 2.0, 3.0); + LLVector3 llvecpospar(10.0, 20.0, 30.0); + formMatrix_obj.setPosition(llvecpos); + parent.setPosition(llvecpospar); + + LLVector3 llvecparentscale(1.0, 2.0, 0); + parent.setScaleChildOffset(true); + parent.setScale(llvecparentscale); + + LLQuaternion quat(1, 2, 3, 4); + LLQuaternion quatparent(5, 6, 7, 8); + formMatrix_obj.setRotation(quat); + parent.setRotation(quatparent); + formMatrix_obj.setParent(&parent); + + parent.update(); + formMatrix_obj.update(); + + LLVector3 worldPos = llvecpos; + worldPos.scaleVec(llvecparentscale); + worldPos *= quatparent; + worldPos += llvecpospar; + + LLQuaternion worldRot = quat * quatparent; + + ensure("getWorldPosition failed: ", formMatrix_obj.getWorldPosition() == worldPos); + ensure("getWorldRotation failed: ", formMatrix_obj.getWorldRotation() == worldRot); + + ensure("getWorldPosition for parent failed: ", parent.getWorldPosition() == llvecpospar); + ensure("getWorldRotation for parent failed: ", parent.getWorldRotation() == quatparent); + } +} + diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp index fd71c337fa..4649e13376 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -1,126 +1,126 @@ -/** - * @file v2math.cpp - * @brief LLVector2 class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -//#include "vmath.h" -#include "v2math.h" -#include "v3math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquaternion.h" - -// LLVector2 - -LLVector2 LLVector2::zero(0,0); - - -// Non-member functions - -// Sets all values to absolute value of their original values -// Returns true if data changed -bool LLVector2::abs() -{ - bool ret{ false }; - - if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } - if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } - - return ret; -} - - -F32 angle_between(const LLVector2& a, const LLVector2& b) -{ - LLVector2 an = a; - LLVector2 bn = b; - an.normVec(); - bn.normVec(); - F32 cosine = an * bn; - F32 angle = (cosine >= 1.0f) ? 0.0f : - (cosine <= -1.0f) ? F_PI : - acos(cosine); - return angle; -} - -bool are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon) -{ - LLVector2 an = a; - LLVector2 bn = b; - an.normVec(); - bn.normVec(); - F32 dot = an * bn; - if ( (1.0f - fabs(dot)) < epsilon) - { - return true; - } - return false; -} - - -F32 dist_vec(const LLVector2 &a, const LLVector2 &b) -{ - F32 x = a.mV[0] - b.mV[0]; - F32 y = a.mV[1] - b.mV[1]; - return (F32) sqrt( x*x + y*y ); -} - -F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b) -{ - F32 x = a.mV[0] - b.mV[0]; - F32 y = a.mV[1] - b.mV[1]; - return x*x + y*y; -} - -F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b) -{ - F32 x = a.mV[0] - b.mV[0]; - F32 y = a.mV[1] - b.mV[1]; - return x*x + y*y; -} - -LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u) -{ - return LLVector2( - 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(const LLSD& sd) -{ - mV[0] = (F32) sd[0].asReal(); - mV[1] = (F32) sd[1].asReal(); -} - +/** + * @file v2math.cpp + * @brief LLVector2 class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +//#include "vmath.h" +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquaternion.h" + +// LLVector2 + +LLVector2 LLVector2::zero(0,0); + + +// Non-member functions + +// Sets all values to absolute value of their original values +// Returns true if data changed +bool LLVector2::abs() +{ + bool ret{ false }; + + if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } + if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } + + return ret; +} + + +F32 angle_between(const LLVector2& a, const LLVector2& b) +{ + LLVector2 an = a; + LLVector2 bn = b; + an.normVec(); + bn.normVec(); + F32 cosine = an * bn; + F32 angle = (cosine >= 1.0f) ? 0.0f : + (cosine <= -1.0f) ? F_PI : + acos(cosine); + return angle; +} + +bool are_parallel(const LLVector2 &a, const LLVector2 &b, float epsilon) +{ + LLVector2 an = a; + LLVector2 bn = b; + an.normVec(); + bn.normVec(); + F32 dot = an * bn; + if ( (1.0f - fabs(dot)) < epsilon) + { + return true; + } + return false; +} + + +F32 dist_vec(const LLVector2 &a, const LLVector2 &b) +{ + F32 x = a.mV[0] - b.mV[0]; + F32 y = a.mV[1] - b.mV[1]; + return (F32) sqrt( x*x + y*y ); +} + +F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b) +{ + F32 x = a.mV[0] - b.mV[0]; + F32 y = a.mV[1] - b.mV[1]; + return x*x + y*y; +} + +F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b) +{ + F32 x = a.mV[0] - b.mV[0]; + F32 y = a.mV[1] - b.mV[1]; + return x*x + y*y; +} + +LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u) +{ + return LLVector2( + 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(const 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 327e937675..a61c946304 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -1,440 +1,440 @@ -/** - * @file v2math.h - * @brief LLVector2 class header file. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_V2MATH_H -#define LL_V2MATH_H - -#include "llmath.h" -#include "v3math.h" - -class LLVector4; -class LLMatrix3; -class LLQuaternion; - -// Llvector2 = |x y z w| - -static const U32 LENGTHOFVECTOR2 = 2; - -class LLVector2 -{ - public: - F32 mV[LENGTHOFVECTOR2]; - - static LLVector2 zero; - - LLVector2(); // Initializes LLVector2 to (0, 0) - LLVector2(F32 x, F32 y); // Initializes LLVector2 to (x. y) - LLVector2(const F32 *vec); // Initializes LLVector2 to (vec[0]. vec[1]) - explicit LLVector2(const LLVector3 &vec); // Initializes LLVector2 to (vec[0]. vec[1]) - explicit LLVector2(const LLSD &sd); - - // Clears LLVector2 to (0, 0). DEPRECATED - prefer zeroVec. - void clear(); - void setZero(); - void clearVec(); // deprecated - void zeroVec(); // deprecated - - void set(F32 x, F32 y); // Sets LLVector2 to (x, y) - void set(const LLVector2 &vec); // Sets LLVector2 to vec - void set(const F32 *vec); // Sets LLVector2 to vec - - LLSD getValue() const; - void setValue(const LLSD& sd); - - void setVec(F32 x, F32 y); // deprecated - void setVec(const LLVector2 &vec); // deprecated - void setVec(const F32 *vec); // deprecated - - inline bool isFinite() const; // checks to see if all values of LLVector2 are finite - - F32 length() const; // Returns magnitude of LLVector2 - F32 lengthSquared() const; // Returns magnitude squared of LLVector2 - F32 normalize(); // Normalizes and returns the magnitude of LLVector2 - - F32 magVec() const; // deprecated - F32 magVecSquared() const; // deprecated - F32 normVec(); // deprecated - - bool abs(); // sets all values to absolute value of original value (first octant), returns true if changed - - const LLVector2& scaleVec(const LLVector2& vec); // scales per component by vec - - bool isNull(); // Returns true if vector has a _very_small_ length - bool isExactlyZero() const { return !mV[VX] && !mV[VY]; } - - F32 operator[](int idx) const { return mV[idx]; } - F32 &operator[](int idx) { return mV[idx]; } - - friend bool operator<(const LLVector2 &a, const LLVector2 &b); // For sorting. x is "more significant" than y - friend LLVector2 operator+(const LLVector2 &a, const LLVector2 &b); // Return vector a + b - friend LLVector2 operator-(const LLVector2 &a, const LLVector2 &b); // Return vector a minus b - friend F32 operator*(const LLVector2 &a, const LLVector2 &b); // Return a dot b - friend LLVector2 operator%(const LLVector2 &a, const LLVector2 &b); // Return a cross b - friend LLVector2 operator/(const LLVector2 &a, F32 k); // Return a divided by scaler k - friend LLVector2 operator*(const LLVector2 &a, F32 k); // Return a times scaler k - friend LLVector2 operator*(F32 k, const LLVector2 &a); // Return a times scaler k - friend bool operator==(const LLVector2 &a, const LLVector2 &b); // Return a == b - friend bool operator!=(const LLVector2 &a, const LLVector2 &b); // Return a != b - - friend const LLVector2& operator+=(LLVector2 &a, const LLVector2 &b); // Return vector a + b - friend const LLVector2& operator-=(LLVector2 &a, const LLVector2 &b); // Return vector a minus b - friend const LLVector2& operator%=(LLVector2 &a, const LLVector2 &b); // Return a cross b - friend const LLVector2& operator*=(LLVector2 &a, F32 k); // Return a times scaler k - friend const LLVector2& operator/=(LLVector2 &a, F32 k); // Return a divided by scaler k - - friend LLVector2 operator-(const LLVector2 &a); // Return vector -a - - friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a -}; - - -// Non-member functions - -F32 angle_between(const LLVector2 &a, const LLVector2 &b); // Returns angle (radians) between a and b -bool are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel -F32 dist_vec(const LLVector2 &a, const LLVector2 &b); // Returns distance between a and b -F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b -F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b ignoring Z component -LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u); // Returns a vector that is a linear interpolation between a and b - -// Constructors - -inline LLVector2::LLVector2(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; -} - -inline LLVector2::LLVector2(F32 x, F32 y) -{ - mV[VX] = x; - mV[VY] = y; -} - -inline LLVector2::LLVector2(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; -} - -inline LLVector2::LLVector2(const LLVector3 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; -} - -inline LLVector2::LLVector2(const LLSD &sd) -{ - setValue(sd); -} - -// Clear and Assignment Functions - -inline void LLVector2::clear(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; -} - -inline void LLVector2::setZero(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; -} - -// deprecated -inline void LLVector2::clearVec(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; -} - -// deprecated -inline void LLVector2::zeroVec(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; -} - -inline void LLVector2::set(F32 x, F32 y) -{ - mV[VX] = x; - mV[VY] = y; -} - -inline void LLVector2::set(const LLVector2 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; -} - -inline void LLVector2::set(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; -} - - -// deprecated -inline void LLVector2::setVec(F32 x, F32 y) -{ - mV[VX] = x; - mV[VY] = y; -} - -// deprecated -inline void LLVector2::setVec(const LLVector2 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; -} - -// deprecated -inline void LLVector2::setVec(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; -} - - -// LLVector2 Magnitude and Normalization Functions - -inline F32 LLVector2::length(void) const -{ - return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); -} - -inline F32 LLVector2::lengthSquared(void) const -{ - return mV[0]*mV[0] + mV[1]*mV[1]; -} - -inline F32 LLVector2::normalize(void) -{ - F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); - F32 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mV[0] *= oomag; - mV[1] *= oomag; - } - else - { - mV[0] = 0.f; - mV[1] = 0.f; - mag = 0; - } - return (mag); -} - -// checker -inline bool LLVector2::isFinite() const -{ - return (llfinite(mV[VX]) && llfinite(mV[VY])); -} - -// deprecated -inline F32 LLVector2::magVec(void) const -{ - return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); -} - -// deprecated -inline F32 LLVector2::magVecSquared(void) const -{ - return mV[0]*mV[0] + mV[1]*mV[1]; -} - -// deprecated -inline F32 LLVector2::normVec(void) -{ - F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); - F32 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mV[0] *= oomag; - mV[1] *= oomag; - } - else - { - mV[0] = 0.f; - mV[1] = 0.f; - mag = 0; - } - return (mag); -} - -inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec) -{ - mV[VX] *= vec.mV[VX]; - mV[VY] *= vec.mV[VY]; - - return *this; -} - -inline bool LLVector2::isNull() -{ - if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] ) - { - return true; - } - return false; -} - - -// LLVector2 Operators - -// For sorting. By convention, x is "more significant" than y. -inline bool operator<(const LLVector2 &a, const LLVector2 &b) -{ - if( a.mV[VX] == b.mV[VX] ) - { - return a.mV[VY] < b.mV[VY]; - } - else - { - return a.mV[VX] < b.mV[VX]; - } -} - - -inline LLVector2 operator+(const LLVector2 &a, const LLVector2 &b) -{ - LLVector2 c(a); - return c += b; -} - -inline LLVector2 operator-(const LLVector2 &a, const LLVector2 &b) -{ - LLVector2 c(a); - return c -= b; -} - -inline F32 operator*(const LLVector2 &a, const LLVector2 &b) -{ - return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1]); -} - -inline LLVector2 operator%(const LLVector2 &a, const LLVector2 &b) -{ - return LLVector2(a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1], a.mV[1]*b.mV[0] - b.mV[1]*a.mV[0]); -} - -inline LLVector2 operator/(const LLVector2 &a, F32 k) -{ - F32 t = 1.f / k; - return LLVector2( a.mV[0] * t, a.mV[1] * t ); -} - -inline LLVector2 operator*(const LLVector2 &a, F32 k) -{ - return LLVector2( a.mV[0] * k, a.mV[1] * k ); -} - -inline LLVector2 operator*(F32 k, const LLVector2 &a) -{ - return LLVector2( a.mV[0] * k, a.mV[1] * k ); -} - -inline bool operator==(const LLVector2 &a, const LLVector2 &b) -{ - return ( (a.mV[0] == b.mV[0]) - &&(a.mV[1] == b.mV[1])); -} - -inline bool operator!=(const LLVector2 &a, const LLVector2 &b) -{ - return ( (a.mV[0] != b.mV[0]) - ||(a.mV[1] != b.mV[1])); -} - -inline const LLVector2& operator+=(LLVector2 &a, const LLVector2 &b) -{ - a.mV[0] += b.mV[0]; - a.mV[1] += b.mV[1]; - return a; -} - -inline const LLVector2& operator-=(LLVector2 &a, const LLVector2 &b) -{ - a.mV[0] -= b.mV[0]; - a.mV[1] -= b.mV[1]; - return a; -} - -inline const LLVector2& operator%=(LLVector2 &a, const LLVector2 &b) -{ - LLVector2 ret(a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1], a.mV[1]*b.mV[0] - b.mV[1]*a.mV[0]); - a = ret; - return a; -} - -inline const LLVector2& operator*=(LLVector2 &a, F32 k) -{ - a.mV[0] *= k; - a.mV[1] *= k; - return a; -} - -inline const LLVector2& operator/=(LLVector2 &a, F32 k) -{ - F32 t = 1.f / k; - a.mV[0] *= t; - a.mV[1] *= t; - return a; -} - -inline LLVector2 operator-(const LLVector2 &a) -{ - return LLVector2( -a.mV[0], -a.mV[1] ); -} - -inline void update_min_max(LLVector2& min, LLVector2& max, const LLVector2& pos) -{ - for (U32 i = 0; i < 2; i++) - { - if (min.mV[i] > pos.mV[i]) - { - min.mV[i] = pos.mV[i]; - } - if (max.mV[i] < pos.mV[i]) - { - max.mV[i] = pos.mV[i]; - } - } -} - -inline std::ostream& operator<<(std::ostream& s, const LLVector2 &a) -{ - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << " }"; - return s; -} - -#endif +/** + * @file v2math.h + * @brief LLVector2 class header file. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V2MATH_H +#define LL_V2MATH_H + +#include "llmath.h" +#include "v3math.h" + +class LLVector4; +class LLMatrix3; +class LLQuaternion; + +// Llvector2 = |x y z w| + +static const U32 LENGTHOFVECTOR2 = 2; + +class LLVector2 +{ + public: + F32 mV[LENGTHOFVECTOR2]; + + static LLVector2 zero; + + LLVector2(); // Initializes LLVector2 to (0, 0) + LLVector2(F32 x, F32 y); // Initializes LLVector2 to (x. y) + LLVector2(const F32 *vec); // Initializes LLVector2 to (vec[0]. vec[1]) + explicit LLVector2(const LLVector3 &vec); // Initializes LLVector2 to (vec[0]. vec[1]) + explicit LLVector2(const LLSD &sd); + + // Clears LLVector2 to (0, 0). DEPRECATED - prefer zeroVec. + void clear(); + void setZero(); + void clearVec(); // deprecated + void zeroVec(); // deprecated + + void set(F32 x, F32 y); // Sets LLVector2 to (x, y) + void set(const LLVector2 &vec); // Sets LLVector2 to vec + void set(const F32 *vec); // Sets LLVector2 to vec + + LLSD getValue() const; + void setValue(const LLSD& sd); + + void setVec(F32 x, F32 y); // deprecated + void setVec(const LLVector2 &vec); // deprecated + void setVec(const F32 *vec); // deprecated + + inline bool isFinite() const; // checks to see if all values of LLVector2 are finite + + F32 length() const; // Returns magnitude of LLVector2 + F32 lengthSquared() const; // Returns magnitude squared of LLVector2 + F32 normalize(); // Normalizes and returns the magnitude of LLVector2 + + F32 magVec() const; // deprecated + F32 magVecSquared() const; // deprecated + F32 normVec(); // deprecated + + bool abs(); // sets all values to absolute value of original value (first octant), returns true if changed + + const LLVector2& scaleVec(const LLVector2& vec); // scales per component by vec + + bool isNull(); // Returns true if vector has a _very_small_ length + bool isExactlyZero() const { return !mV[VX] && !mV[VY]; } + + F32 operator[](int idx) const { return mV[idx]; } + F32 &operator[](int idx) { return mV[idx]; } + + friend bool operator<(const LLVector2 &a, const LLVector2 &b); // For sorting. x is "more significant" than y + friend LLVector2 operator+(const LLVector2 &a, const LLVector2 &b); // Return vector a + b + friend LLVector2 operator-(const LLVector2 &a, const LLVector2 &b); // Return vector a minus b + friend F32 operator*(const LLVector2 &a, const LLVector2 &b); // Return a dot b + friend LLVector2 operator%(const LLVector2 &a, const LLVector2 &b); // Return a cross b + friend LLVector2 operator/(const LLVector2 &a, F32 k); // Return a divided by scaler k + friend LLVector2 operator*(const LLVector2 &a, F32 k); // Return a times scaler k + friend LLVector2 operator*(F32 k, const LLVector2 &a); // Return a times scaler k + friend bool operator==(const LLVector2 &a, const LLVector2 &b); // Return a == b + friend bool operator!=(const LLVector2 &a, const LLVector2 &b); // Return a != b + + friend const LLVector2& operator+=(LLVector2 &a, const LLVector2 &b); // Return vector a + b + friend const LLVector2& operator-=(LLVector2 &a, const LLVector2 &b); // Return vector a minus b + friend const LLVector2& operator%=(LLVector2 &a, const LLVector2 &b); // Return a cross b + friend const LLVector2& operator*=(LLVector2 &a, F32 k); // Return a times scaler k + friend const LLVector2& operator/=(LLVector2 &a, F32 k); // Return a divided by scaler k + + friend LLVector2 operator-(const LLVector2 &a); // Return vector -a + + friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a +}; + + +// Non-member functions + +F32 angle_between(const LLVector2 &a, const LLVector2 &b); // Returns angle (radians) between a and b +bool are_parallel(const LLVector2 &a, const LLVector2 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel +F32 dist_vec(const LLVector2 &a, const LLVector2 &b); // Returns distance between a and b +F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b +F32 dist_vec_squared2D(const LLVector2 &a, const LLVector2 &b);// Returns distance squared between a and b ignoring Z component +LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u); // Returns a vector that is a linear interpolation between a and b + +// Constructors + +inline LLVector2::LLVector2(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; +} + +inline LLVector2::LLVector2(F32 x, F32 y) +{ + mV[VX] = x; + mV[VY] = y; +} + +inline LLVector2::LLVector2(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; +} + +inline LLVector2::LLVector2(const LLVector3 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; +} + +inline LLVector2::LLVector2(const LLSD &sd) +{ + setValue(sd); +} + +// Clear and Assignment Functions + +inline void LLVector2::clear(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; +} + +inline void LLVector2::setZero(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; +} + +// deprecated +inline void LLVector2::clearVec(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; +} + +// deprecated +inline void LLVector2::zeroVec(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; +} + +inline void LLVector2::set(F32 x, F32 y) +{ + mV[VX] = x; + mV[VY] = y; +} + +inline void LLVector2::set(const LLVector2 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; +} + +inline void LLVector2::set(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; +} + + +// deprecated +inline void LLVector2::setVec(F32 x, F32 y) +{ + mV[VX] = x; + mV[VY] = y; +} + +// deprecated +inline void LLVector2::setVec(const LLVector2 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; +} + +// deprecated +inline void LLVector2::setVec(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; +} + + +// LLVector2 Magnitude and Normalization Functions + +inline F32 LLVector2::length(void) const +{ + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); +} + +inline F32 LLVector2::lengthSquared(void) const +{ + return mV[0]*mV[0] + mV[1]*mV[1]; +} + +inline F32 LLVector2::normalize(void) +{ + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); + F32 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mV[0] *= oomag; + mV[1] *= oomag; + } + else + { + mV[0] = 0.f; + mV[1] = 0.f; + mag = 0; + } + return (mag); +} + +// checker +inline bool LLVector2::isFinite() const +{ + return (llfinite(mV[VX]) && llfinite(mV[VY])); +} + +// deprecated +inline F32 LLVector2::magVec(void) const +{ + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); +} + +// deprecated +inline F32 LLVector2::magVecSquared(void) const +{ + return mV[0]*mV[0] + mV[1]*mV[1]; +} + +// deprecated +inline F32 LLVector2::normVec(void) +{ + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); + F32 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mV[0] *= oomag; + mV[1] *= oomag; + } + else + { + mV[0] = 0.f; + mV[1] = 0.f; + mag = 0; + } + return (mag); +} + +inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec) +{ + mV[VX] *= vec.mV[VX]; + mV[VY] *= vec.mV[VY]; + + return *this; +} + +inline bool LLVector2::isNull() +{ + if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] ) + { + return true; + } + return false; +} + + +// LLVector2 Operators + +// For sorting. By convention, x is "more significant" than y. +inline bool operator<(const LLVector2 &a, const LLVector2 &b) +{ + if( a.mV[VX] == b.mV[VX] ) + { + return a.mV[VY] < b.mV[VY]; + } + else + { + return a.mV[VX] < b.mV[VX]; + } +} + + +inline LLVector2 operator+(const LLVector2 &a, const LLVector2 &b) +{ + LLVector2 c(a); + return c += b; +} + +inline LLVector2 operator-(const LLVector2 &a, const LLVector2 &b) +{ + LLVector2 c(a); + return c -= b; +} + +inline F32 operator*(const LLVector2 &a, const LLVector2 &b) +{ + return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1]); +} + +inline LLVector2 operator%(const LLVector2 &a, const LLVector2 &b) +{ + return LLVector2(a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1], a.mV[1]*b.mV[0] - b.mV[1]*a.mV[0]); +} + +inline LLVector2 operator/(const LLVector2 &a, F32 k) +{ + F32 t = 1.f / k; + return LLVector2( a.mV[0] * t, a.mV[1] * t ); +} + +inline LLVector2 operator*(const LLVector2 &a, F32 k) +{ + return LLVector2( a.mV[0] * k, a.mV[1] * k ); +} + +inline LLVector2 operator*(F32 k, const LLVector2 &a) +{ + return LLVector2( a.mV[0] * k, a.mV[1] * k ); +} + +inline bool operator==(const LLVector2 &a, const LLVector2 &b) +{ + return ( (a.mV[0] == b.mV[0]) + &&(a.mV[1] == b.mV[1])); +} + +inline bool operator!=(const LLVector2 &a, const LLVector2 &b) +{ + return ( (a.mV[0] != b.mV[0]) + ||(a.mV[1] != b.mV[1])); +} + +inline const LLVector2& operator+=(LLVector2 &a, const LLVector2 &b) +{ + a.mV[0] += b.mV[0]; + a.mV[1] += b.mV[1]; + return a; +} + +inline const LLVector2& operator-=(LLVector2 &a, const LLVector2 &b) +{ + a.mV[0] -= b.mV[0]; + a.mV[1] -= b.mV[1]; + return a; +} + +inline const LLVector2& operator%=(LLVector2 &a, const LLVector2 &b) +{ + LLVector2 ret(a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1], a.mV[1]*b.mV[0] - b.mV[1]*a.mV[0]); + a = ret; + return a; +} + +inline const LLVector2& operator*=(LLVector2 &a, F32 k) +{ + a.mV[0] *= k; + a.mV[1] *= k; + return a; +} + +inline const LLVector2& operator/=(LLVector2 &a, F32 k) +{ + F32 t = 1.f / k; + a.mV[0] *= t; + a.mV[1] *= t; + return a; +} + +inline LLVector2 operator-(const LLVector2 &a) +{ + return LLVector2( -a.mV[0], -a.mV[1] ); +} + +inline void update_min_max(LLVector2& min, LLVector2& max, const LLVector2& pos) +{ + for (U32 i = 0; i < 2; i++) + { + if (min.mV[i] > pos.mV[i]) + { + min.mV[i] = pos.mV[i]; + } + if (max.mV[i] < pos.mV[i]) + { + max.mV[i] = pos.mV[i]; + } + } +} + +inline std::ostream& operator<<(std::ostream& s, const LLVector2 &a) +{ + s << "{ " << a.mV[VX] << ", " << a.mV[VY] << " }"; + return s; +} + +#endif diff --git a/indra/llmath/v3dmath.cpp b/indra/llmath/v3dmath.cpp index faa877a5cb..bb55c812b5 100644 --- a/indra/llmath/v3dmath.cpp +++ b/indra/llmath/v3dmath.cpp @@ -1,147 +1,147 @@ -/** - * @file v3dmath.cpp - * @brief LLVector3d class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -//#include // gcc 2.95.2 doesn't support sstream - -#include "v3dmath.h" - -//#include "vmath.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquaternion.h" -#include "llquantize.h" - -// LLVector3d -// WARNING: Don't use these for global const definitions! -// For example: -// const LLQuaternion(0.5f * F_PI, LLVector3d::zero); -// at the top of a *.cpp file might not give you what you think. -const LLVector3d LLVector3d::zero(0,0,0); -const LLVector3d LLVector3d::x_axis(1, 0, 0); -const LLVector3d LLVector3d::y_axis(0, 1, 0); -const LLVector3d LLVector3d::z_axis(0, 0, 1); -const LLVector3d LLVector3d::x_axis_neg(-1, 0, 0); -const LLVector3d LLVector3d::y_axis_neg(0, -1, 0); -const LLVector3d LLVector3d::z_axis_neg(0, 0, -1); - - -// Clamps each values to range (min,max). -// Returns true if data changed. -bool LLVector3d::clamp(F64 min, F64 max) -{ - bool ret{ false }; - - if (mdV[0] < min) { mdV[0] = min; ret = true; } - if (mdV[1] < min) { mdV[1] = min; ret = true; } - if (mdV[2] < min) { mdV[2] = min; ret = true; } - - if (mdV[0] > max) { mdV[0] = max; ret = true; } - if (mdV[1] > max) { mdV[1] = max; ret = true; } - if (mdV[2] > max) { mdV[2] = max; ret = true; } - - return ret; -} - -// Sets all values to absolute value of their original values -// Returns true if data changed -bool LLVector3d::abs() -{ - bool ret{ false }; - - if (mdV[0] < 0.0) { mdV[0] = -mdV[0]; ret = true; } - if (mdV[1] < 0.0) { mdV[1] = -mdV[1]; ret = true; } - if (mdV[2] < 0.0) { mdV[2] = -mdV[2]; ret = true; } - - return ret; -} - -std::ostream& operator<<(std::ostream& s, const LLVector3d &a) -{ - s << "{ " << a.mdV[VX] << ", " << a.mdV[VY] << ", " << a.mdV[VZ] << " }"; - return s; -} - -const LLVector3d& LLVector3d::operator=(const LLVector4 &a) -{ - mdV[0] = a.mV[0]; - mdV[1] = a.mV[1]; - mdV[2] = a.mV[2]; - return *this; -} - -const LLVector3d& LLVector3d::rotVec(const LLMatrix3 &mat) -{ - *this = *this * mat; - return *this; -} - -const LLVector3d& LLVector3d::rotVec(const LLQuaternion &q) -{ - *this = *this * q; - return *this; -} - -const LLVector3d& LLVector3d::rotVec(F64 angle, const LLVector3d &vec) -{ - if ( !vec.isExactlyZero() && angle ) - { - *this = *this * LLMatrix3((F32)angle, vec); - } - return *this; -} - -const LLVector3d& LLVector3d::rotVec(F64 angle, F64 x, F64 y, F64 z) -{ - LLVector3d vec(x, y, z); - if ( !vec.isExactlyZero() && angle ) - { - *this = *this * LLMatrix3((F32)angle, vec); - } - return *this; -} - - -bool LLVector3d::parseVector3d(const std::string& buf, LLVector3d* value) -{ - if( buf.empty() || value == nullptr) - { - return false; - } - - LLVector3d v; - S32 count = sscanf( buf.c_str(), "%lf %lf %lf", v.mdV + 0, v.mdV + 1, v.mdV + 2 ); - if( 3 == count ) - { - value->setVec( v ); - return true; - } - - return false; -} - +/** + * @file v3dmath.cpp + * @brief LLVector3d class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +//#include // gcc 2.95.2 doesn't support sstream + +#include "v3dmath.h" + +//#include "vmath.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquaternion.h" +#include "llquantize.h" + +// LLVector3d +// WARNING: Don't use these for global const definitions! +// For example: +// const LLQuaternion(0.5f * F_PI, LLVector3d::zero); +// at the top of a *.cpp file might not give you what you think. +const LLVector3d LLVector3d::zero(0,0,0); +const LLVector3d LLVector3d::x_axis(1, 0, 0); +const LLVector3d LLVector3d::y_axis(0, 1, 0); +const LLVector3d LLVector3d::z_axis(0, 0, 1); +const LLVector3d LLVector3d::x_axis_neg(-1, 0, 0); +const LLVector3d LLVector3d::y_axis_neg(0, -1, 0); +const LLVector3d LLVector3d::z_axis_neg(0, 0, -1); + + +// Clamps each values to range (min,max). +// Returns true if data changed. +bool LLVector3d::clamp(F64 min, F64 max) +{ + bool ret{ false }; + + if (mdV[0] < min) { mdV[0] = min; ret = true; } + if (mdV[1] < min) { mdV[1] = min; ret = true; } + if (mdV[2] < min) { mdV[2] = min; ret = true; } + + if (mdV[0] > max) { mdV[0] = max; ret = true; } + if (mdV[1] > max) { mdV[1] = max; ret = true; } + if (mdV[2] > max) { mdV[2] = max; ret = true; } + + return ret; +} + +// Sets all values to absolute value of their original values +// Returns true if data changed +bool LLVector3d::abs() +{ + bool ret{ false }; + + if (mdV[0] < 0.0) { mdV[0] = -mdV[0]; ret = true; } + if (mdV[1] < 0.0) { mdV[1] = -mdV[1]; ret = true; } + if (mdV[2] < 0.0) { mdV[2] = -mdV[2]; ret = true; } + + return ret; +} + +std::ostream& operator<<(std::ostream& s, const LLVector3d &a) +{ + s << "{ " << a.mdV[VX] << ", " << a.mdV[VY] << ", " << a.mdV[VZ] << " }"; + return s; +} + +const LLVector3d& LLVector3d::operator=(const LLVector4 &a) +{ + mdV[0] = a.mV[0]; + mdV[1] = a.mV[1]; + mdV[2] = a.mV[2]; + return *this; +} + +const LLVector3d& LLVector3d::rotVec(const LLMatrix3 &mat) +{ + *this = *this * mat; + return *this; +} + +const LLVector3d& LLVector3d::rotVec(const LLQuaternion &q) +{ + *this = *this * q; + return *this; +} + +const LLVector3d& LLVector3d::rotVec(F64 angle, const LLVector3d &vec) +{ + if ( !vec.isExactlyZero() && angle ) + { + *this = *this * LLMatrix3((F32)angle, vec); + } + return *this; +} + +const LLVector3d& LLVector3d::rotVec(F64 angle, F64 x, F64 y, F64 z) +{ + LLVector3d vec(x, y, z); + if ( !vec.isExactlyZero() && angle ) + { + *this = *this * LLMatrix3((F32)angle, vec); + } + return *this; +} + + +bool LLVector3d::parseVector3d(const std::string& buf, LLVector3d* value) +{ + if( buf.empty() || value == nullptr) + { + return false; + } + + LLVector3d v; + S32 count = sscanf( buf.c_str(), "%lf %lf %lf", v.mdV + 0, v.mdV + 1, v.mdV + 2 ); + if( 3 == count ) + { + value->setVec( v ); + return true; + } + + return false; +} + diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 2968bcd511..ece8c54ea4 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -1,530 +1,530 @@ -/** - * @file v3dmath.h - * @brief High precision 3 dimensional vector. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_V3DMATH_H -#define LL_V3DMATH_H - -#include "llerror.h" -#include "v3math.h" - -class LLVector3d -{ - public: - F64 mdV[3]; - - const static LLVector3d zero; - const static LLVector3d x_axis; - const static LLVector3d y_axis; - const static LLVector3d z_axis; - const static LLVector3d x_axis_neg; - const static LLVector3d y_axis_neg; - const static LLVector3d z_axis_neg; - - inline LLVector3d(); // Initializes LLVector3d to (0, 0, 0) - inline LLVector3d(const F64 x, const F64 y, const F64 z); // Initializes LLVector3d to (x. y, z) - inline explicit LLVector3d(const F64 *vec); // Initializes LLVector3d to (vec[0]. vec[1], vec[2]) - inline explicit LLVector3d(const LLVector3 &vec); - explicit LLVector3d(const LLSD& sd) - { - setValue(sd); - } - - void setValue(const LLSD& sd) - { - mdV[0] = sd[0].asReal(); - mdV[1] = sd[1].asReal(); - mdV[2] = sd[2].asReal(); - } - - LLSD getValue() const - { - LLSD ret; - ret[0] = mdV[0]; - ret[1] = mdV[1]; - ret[2] = mdV[2]; - return ret; - } - - inline bool isFinite() const; // checks to see if all values of LLVector3d are finite - bool clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns true if data changed - bool abs(); // sets all values to absolute value of original value (first octant), returns true if changed - - inline const LLVector3d& clear(); // Clears LLVector3d to (0, 0, 0, 1) - inline const LLVector3d& clearVec(); // deprecated - inline const LLVector3d& setZero(); // Zero LLVector3d to (0, 0, 0, 0) - inline const LLVector3d& zeroVec(); // deprecated - inline const LLVector3d& set(const F64 x, const F64 y, const F64 z); // Sets LLVector3d to (x, y, z, 1) - inline const LLVector3d& set(const LLVector3d &vec); // Sets LLVector3d to vec - inline const LLVector3d& set(const F64 *vec); // Sets LLVector3d to vec - inline const LLVector3d& set(const LLVector3 &vec); - inline const LLVector3d& setVec(const F64 x, const F64 y, const F64 z); // deprecated - inline const LLVector3d& setVec(const LLVector3d &vec); // deprecated - inline const LLVector3d& setVec(const F64 *vec); // deprecated - inline const LLVector3d& setVec(const LLVector3 &vec); // deprecated - - F64 magVec() const; // deprecated - F64 magVecSquared() const; // deprecated - inline F64 normVec(); // deprecated - - F64 length() const; // Returns magnitude of LLVector3d - F64 lengthSquared() const; // Returns magnitude squared of LLVector3d - inline F64 normalize(); // Normalizes and returns the magnitude of LLVector3d - - const LLVector3d& rotVec(const F64 angle, const LLVector3d &vec); // Rotates about vec by angle radians - const LLVector3d& rotVec(const F64 angle, const F64 x, const F64 y, const F64 z); // Rotates about x,y,z by angle radians - const LLVector3d& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat - const LLVector3d& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q - - bool isNull() const; // Returns true if vector has a _very_small_ length - bool isExactlyZero() const { return !mdV[VX] && !mdV[VY] && !mdV[VZ]; } - - const LLVector3d& operator=(const LLVector4 &a); - - F64 operator[](int idx) const { return mdV[idx]; } - F64 &operator[](int idx) { return mdV[idx]; } - - friend LLVector3d operator+(const LLVector3d& a, const LLVector3d& b); // Return vector a + b - friend LLVector3d operator-(const LLVector3d& a, const LLVector3d& b); // Return vector a minus b - friend F64 operator*(const LLVector3d& a, const LLVector3d& b); // Return a dot b - friend LLVector3d operator%(const LLVector3d& a, const LLVector3d& b); // Return a cross b - friend LLVector3d operator*(const LLVector3d& a, const F64 k); // Return a times scaler k - friend LLVector3d operator/(const LLVector3d& a, const F64 k); // Return a divided by scaler k - friend LLVector3d operator*(const F64 k, const LLVector3d& a); // Return a times scaler k - friend bool operator==(const LLVector3d& a, const LLVector3d& b); // Return a == b - friend bool operator!=(const LLVector3d& a, const LLVector3d& b); // Return a != b - - friend const LLVector3d& operator+=(LLVector3d& a, const LLVector3d& b); // Return vector a + b - friend const LLVector3d& operator-=(LLVector3d& a, const LLVector3d& b); // Return vector a minus b - friend const LLVector3d& operator%=(LLVector3d& a, const LLVector3d& b); // Return a cross b - friend const LLVector3d& operator*=(LLVector3d& a, const F64 k); // Return a times scaler k - friend const LLVector3d& operator/=(LLVector3d& a, const F64 k); // Return a divided by scaler k - - friend LLVector3d operator-(const LLVector3d& a); // Return vector -a - - friend std::ostream& operator<<(std::ostream& s, const LLVector3d& a); // Stream a - - static bool parseVector3d(const std::string& buf, LLVector3d* value); - -}; - -typedef LLVector3d LLGlobalVec; - -inline const LLVector3d &LLVector3d::set(const LLVector3 &vec) -{ - mdV[0] = vec.mV[0]; - mdV[1] = vec.mV[1]; - mdV[2] = vec.mV[2]; - return *this; -} - -inline const LLVector3d &LLVector3d::setVec(const LLVector3 &vec) -{ - mdV[0] = vec.mV[0]; - mdV[1] = vec.mV[1]; - mdV[2] = vec.mV[2]; - return *this; -} - - -inline LLVector3d::LLVector3d(void) -{ - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2] = 0.f; -} - -inline LLVector3d::LLVector3d(const F64 x, const F64 y, const F64 z) -{ - mdV[VX] = x; - mdV[VY] = y; - mdV[VZ] = z; -} - -inline LLVector3d::LLVector3d(const F64 *vec) -{ - mdV[VX] = vec[VX]; - mdV[VY] = vec[VY]; - mdV[VZ] = vec[VZ]; -} - -inline LLVector3d::LLVector3d(const LLVector3 &vec) -{ - mdV[VX] = vec.mV[VX]; - mdV[VY] = vec.mV[VY]; - mdV[VZ] = vec.mV[VZ]; -} - -/* -inline LLVector3d::LLVector3d(const LLVector3d ©) -{ - mdV[VX] = copy.mdV[VX]; - mdV[VY] = copy.mdV[VY]; - mdV[VZ] = copy.mdV[VZ]; -} -*/ - -// Destructors - -// checker -inline bool LLVector3d::isFinite() const -{ - return (llfinite(mdV[VX]) && llfinite(mdV[VY]) && llfinite(mdV[VZ])); -} - - -// Clear and Assignment Functions - -inline const LLVector3d& LLVector3d::clear(void) -{ - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2]= 0.f; - return (*this); -} - -inline const LLVector3d& LLVector3d::clearVec(void) -{ - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2]= 0.f; - return (*this); -} - -inline const LLVector3d& LLVector3d::setZero(void) -{ - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2] = 0.f; - return (*this); -} - -inline const LLVector3d& LLVector3d::zeroVec(void) -{ - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2] = 0.f; - return (*this); -} - -inline const LLVector3d& LLVector3d::set(const F64 x, const F64 y, const F64 z) -{ - mdV[VX] = x; - mdV[VY] = y; - mdV[VZ] = z; - return (*this); -} - -inline const LLVector3d& LLVector3d::set(const LLVector3d &vec) -{ - mdV[0] = vec.mdV[0]; - mdV[1] = vec.mdV[1]; - mdV[2] = vec.mdV[2]; - return (*this); -} - -inline const LLVector3d& LLVector3d::set(const F64 *vec) -{ - mdV[0] = vec[0]; - mdV[1] = vec[1]; - mdV[2] = vec[2]; - return (*this); -} - -inline const LLVector3d& LLVector3d::setVec(const F64 x, const F64 y, const F64 z) -{ - mdV[VX] = x; - mdV[VY] = y; - mdV[VZ] = z; - return (*this); -} - -inline const LLVector3d& LLVector3d::setVec(const LLVector3d &vec) -{ - mdV[0] = vec.mdV[0]; - mdV[1] = vec.mdV[1]; - mdV[2] = vec.mdV[2]; - return (*this); -} - -inline const LLVector3d& LLVector3d::setVec(const F64 *vec) -{ - mdV[0] = vec[0]; - mdV[1] = vec[1]; - mdV[2] = vec[2]; - return (*this); -} - -inline F64 LLVector3d::normVec(void) -{ - F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); - F64 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mdV[0] *= oomag; - mdV[1] *= oomag; - mdV[2] *= oomag; - } - else - { - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2] = 0.f; - mag = 0; - } - return (mag); -} - -inline F64 LLVector3d::normalize(void) -{ - F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); - F64 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mdV[0] *= oomag; - mdV[1] *= oomag; - mdV[2] *= oomag; - } - else - { - mdV[0] = 0.f; - mdV[1] = 0.f; - mdV[2] = 0.f; - mag = 0; - } - return (mag); -} - -// LLVector3d Magnitude and Normalization Functions - -inline F64 LLVector3d::magVec(void) const -{ - return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); -} - -inline F64 LLVector3d::magVecSquared(void) const -{ - return mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]; -} - -inline F64 LLVector3d::length(void) const -{ - return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); -} - -inline F64 LLVector3d::lengthSquared(void) const -{ - return mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]; -} - -inline LLVector3d operator+(const LLVector3d& a, const LLVector3d& b) -{ - LLVector3d c(a); - return c += b; -} - -inline LLVector3d operator-(const LLVector3d& a, const LLVector3d& b) -{ - LLVector3d c(a); - return c -= b; -} - -inline F64 operator*(const LLVector3d& a, const LLVector3d& b) -{ - return (a.mdV[0]*b.mdV[0] + a.mdV[1]*b.mdV[1] + a.mdV[2]*b.mdV[2]); -} - -inline LLVector3d operator%(const LLVector3d& a, const LLVector3d& b) -{ - return LLVector3d( a.mdV[1]*b.mdV[2] - b.mdV[1]*a.mdV[2], a.mdV[2]*b.mdV[0] - b.mdV[2]*a.mdV[0], a.mdV[0]*b.mdV[1] - b.mdV[0]*a.mdV[1] ); -} - -inline LLVector3d operator/(const LLVector3d& a, const F64 k) -{ - F64 t = 1.f / k; - return LLVector3d( a.mdV[0] * t, a.mdV[1] * t, a.mdV[2] * t ); -} - -inline LLVector3d operator*(const LLVector3d& a, const F64 k) -{ - return LLVector3d( a.mdV[0] * k, a.mdV[1] * k, a.mdV[2] * k ); -} - -inline LLVector3d operator*(F64 k, const LLVector3d& a) -{ - return LLVector3d( a.mdV[0] * k, a.mdV[1] * k, a.mdV[2] * k ); -} - -inline bool operator==(const LLVector3d& a, const LLVector3d& b) -{ - return ( (a.mdV[0] == b.mdV[0]) - &&(a.mdV[1] == b.mdV[1]) - &&(a.mdV[2] == b.mdV[2])); -} - -inline bool operator!=(const LLVector3d& a, const LLVector3d& b) -{ - return ( (a.mdV[0] != b.mdV[0]) - ||(a.mdV[1] != b.mdV[1]) - ||(a.mdV[2] != b.mdV[2])); -} - -inline const LLVector3d& operator+=(LLVector3d& a, const LLVector3d& b) -{ - a.mdV[0] += b.mdV[0]; - a.mdV[1] += b.mdV[1]; - a.mdV[2] += b.mdV[2]; - return a; -} - -inline const LLVector3d& operator-=(LLVector3d& a, const LLVector3d& b) -{ - a.mdV[0] -= b.mdV[0]; - a.mdV[1] -= b.mdV[1]; - a.mdV[2] -= b.mdV[2]; - return a; -} - -inline const LLVector3d& operator%=(LLVector3d& a, const LLVector3d& b) -{ - LLVector3d ret( a.mdV[1]*b.mdV[2] - b.mdV[1]*a.mdV[2], a.mdV[2]*b.mdV[0] - b.mdV[2]*a.mdV[0], a.mdV[0]*b.mdV[1] - b.mdV[0]*a.mdV[1]); - a = ret; - return a; -} - -inline const LLVector3d& operator*=(LLVector3d& a, const F64 k) -{ - a.mdV[0] *= k; - a.mdV[1] *= k; - a.mdV[2] *= k; - return a; -} - -inline const LLVector3d& operator/=(LLVector3d& a, const F64 k) -{ - F64 t = 1.f / k; - a.mdV[0] *= t; - a.mdV[1] *= t; - a.mdV[2] *= t; - return a; -} - -inline LLVector3d operator-(const LLVector3d& a) -{ - return LLVector3d( -a.mdV[0], -a.mdV[1], -a.mdV[2] ); -} - -inline F64 dist_vec(const LLVector3d& a, const LLVector3d& b) -{ - F64 x = a.mdV[0] - b.mdV[0]; - F64 y = a.mdV[1] - b.mdV[1]; - F64 z = a.mdV[2] - b.mdV[2]; - return (F32) sqrt( x*x + y*y + z*z ); -} - -inline F64 dist_vec_squared(const LLVector3d& a, const LLVector3d& b) -{ - F64 x = a.mdV[0] - b.mdV[0]; - F64 y = a.mdV[1] - b.mdV[1]; - F64 z = a.mdV[2] - b.mdV[2]; - return x*x + y*y + z*z; -} - -inline F64 dist_vec_squared2D(const LLVector3d& a, const LLVector3d& b) -{ - F64 x = a.mdV[0] - b.mdV[0]; - F64 y = a.mdV[1] - b.mdV[1]; - return x*x + y*y; -} - -inline LLVector3d lerp(const LLVector3d& a, const LLVector3d& b, const F64 u) -{ - return LLVector3d( - a.mdV[VX] + (b.mdV[VX] - a.mdV[VX]) * u, - a.mdV[VY] + (b.mdV[VY] - a.mdV[VY]) * u, - a.mdV[VZ] + (b.mdV[VZ] - a.mdV[VZ]) * u); -} - - -inline bool LLVector3d::isNull() const -{ - if ( F_APPROXIMATELY_ZERO > mdV[VX]*mdV[VX] + mdV[VY]*mdV[VY] + mdV[VZ]*mdV[VZ] ) - { - return true; - } - return false; -} - - -inline F64 angle_between(const LLVector3d& a, const LLVector3d& b) -{ - LLVector3d an = a; - LLVector3d bn = b; - an.normalize(); - bn.normalize(); - F64 cosine = an * bn; - F64 angle = (cosine >= 1.0f) ? 0.0f : - (cosine <= -1.0f) ? F_PI : - acos(cosine); - return angle; -} - -inline bool are_parallel(const LLVector3d& a, const LLVector3d& b, const F64 epsilon) -{ - LLVector3d an = a; - LLVector3d bn = b; - an.normalize(); - bn.normalize(); - F64 dot = an * bn; - if ( (1.0f - fabs(dot)) < epsilon) - { - return true; - } - return false; -} - -inline LLVector3d projected_vec(const LLVector3d& a, const LLVector3d& b) -{ - LLVector3d project_axis = b; - project_axis.normalize(); - return project_axis * (a * project_axis); -} - -inline LLVector3d inverse_projected_vec(const LLVector3d& a, const LLVector3d& b) -{ - LLVector3d normalized_a = a; - normalized_a.normalize(); - LLVector3d normalized_b = b; - F64 b_length = normalized_b.normalize(); - - F64 dot_product = normalized_a * normalized_b; - return normalized_a * (b_length / dot_product); -} - -#endif // LL_V3DMATH_H +/** + * @file v3dmath.h + * @brief High precision 3 dimensional vector. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V3DMATH_H +#define LL_V3DMATH_H + +#include "llerror.h" +#include "v3math.h" + +class LLVector3d +{ + public: + F64 mdV[3]; + + const static LLVector3d zero; + const static LLVector3d x_axis; + const static LLVector3d y_axis; + const static LLVector3d z_axis; + const static LLVector3d x_axis_neg; + const static LLVector3d y_axis_neg; + const static LLVector3d z_axis_neg; + + inline LLVector3d(); // Initializes LLVector3d to (0, 0, 0) + inline LLVector3d(const F64 x, const F64 y, const F64 z); // Initializes LLVector3d to (x. y, z) + inline explicit LLVector3d(const F64 *vec); // Initializes LLVector3d to (vec[0]. vec[1], vec[2]) + inline explicit LLVector3d(const LLVector3 &vec); + explicit LLVector3d(const LLSD& sd) + { + setValue(sd); + } + + void setValue(const LLSD& sd) + { + mdV[0] = sd[0].asReal(); + mdV[1] = sd[1].asReal(); + mdV[2] = sd[2].asReal(); + } + + LLSD getValue() const + { + LLSD ret; + ret[0] = mdV[0]; + ret[1] = mdV[1]; + ret[2] = mdV[2]; + return ret; + } + + inline bool isFinite() const; // checks to see if all values of LLVector3d are finite + bool clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns true if data changed + bool abs(); // sets all values to absolute value of original value (first octant), returns true if changed + + inline const LLVector3d& clear(); // Clears LLVector3d to (0, 0, 0, 1) + inline const LLVector3d& clearVec(); // deprecated + inline const LLVector3d& setZero(); // Zero LLVector3d to (0, 0, 0, 0) + inline const LLVector3d& zeroVec(); // deprecated + inline const LLVector3d& set(const F64 x, const F64 y, const F64 z); // Sets LLVector3d to (x, y, z, 1) + inline const LLVector3d& set(const LLVector3d &vec); // Sets LLVector3d to vec + inline const LLVector3d& set(const F64 *vec); // Sets LLVector3d to vec + inline const LLVector3d& set(const LLVector3 &vec); + inline const LLVector3d& setVec(const F64 x, const F64 y, const F64 z); // deprecated + inline const LLVector3d& setVec(const LLVector3d &vec); // deprecated + inline const LLVector3d& setVec(const F64 *vec); // deprecated + inline const LLVector3d& setVec(const LLVector3 &vec); // deprecated + + F64 magVec() const; // deprecated + F64 magVecSquared() const; // deprecated + inline F64 normVec(); // deprecated + + F64 length() const; // Returns magnitude of LLVector3d + F64 lengthSquared() const; // Returns magnitude squared of LLVector3d + inline F64 normalize(); // Normalizes and returns the magnitude of LLVector3d + + const LLVector3d& rotVec(const F64 angle, const LLVector3d &vec); // Rotates about vec by angle radians + const LLVector3d& rotVec(const F64 angle, const F64 x, const F64 y, const F64 z); // Rotates about x,y,z by angle radians + const LLVector3d& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat + const LLVector3d& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q + + bool isNull() const; // Returns true if vector has a _very_small_ length + bool isExactlyZero() const { return !mdV[VX] && !mdV[VY] && !mdV[VZ]; } + + const LLVector3d& operator=(const LLVector4 &a); + + F64 operator[](int idx) const { return mdV[idx]; } + F64 &operator[](int idx) { return mdV[idx]; } + + friend LLVector3d operator+(const LLVector3d& a, const LLVector3d& b); // Return vector a + b + friend LLVector3d operator-(const LLVector3d& a, const LLVector3d& b); // Return vector a minus b + friend F64 operator*(const LLVector3d& a, const LLVector3d& b); // Return a dot b + friend LLVector3d operator%(const LLVector3d& a, const LLVector3d& b); // Return a cross b + friend LLVector3d operator*(const LLVector3d& a, const F64 k); // Return a times scaler k + friend LLVector3d operator/(const LLVector3d& a, const F64 k); // Return a divided by scaler k + friend LLVector3d operator*(const F64 k, const LLVector3d& a); // Return a times scaler k + friend bool operator==(const LLVector3d& a, const LLVector3d& b); // Return a == b + friend bool operator!=(const LLVector3d& a, const LLVector3d& b); // Return a != b + + friend const LLVector3d& operator+=(LLVector3d& a, const LLVector3d& b); // Return vector a + b + friend const LLVector3d& operator-=(LLVector3d& a, const LLVector3d& b); // Return vector a minus b + friend const LLVector3d& operator%=(LLVector3d& a, const LLVector3d& b); // Return a cross b + friend const LLVector3d& operator*=(LLVector3d& a, const F64 k); // Return a times scaler k + friend const LLVector3d& operator/=(LLVector3d& a, const F64 k); // Return a divided by scaler k + + friend LLVector3d operator-(const LLVector3d& a); // Return vector -a + + friend std::ostream& operator<<(std::ostream& s, const LLVector3d& a); // Stream a + + static bool parseVector3d(const std::string& buf, LLVector3d* value); + +}; + +typedef LLVector3d LLGlobalVec; + +inline const LLVector3d &LLVector3d::set(const LLVector3 &vec) +{ + mdV[0] = vec.mV[0]; + mdV[1] = vec.mV[1]; + mdV[2] = vec.mV[2]; + return *this; +} + +inline const LLVector3d &LLVector3d::setVec(const LLVector3 &vec) +{ + mdV[0] = vec.mV[0]; + mdV[1] = vec.mV[1]; + mdV[2] = vec.mV[2]; + return *this; +} + + +inline LLVector3d::LLVector3d(void) +{ + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2] = 0.f; +} + +inline LLVector3d::LLVector3d(const F64 x, const F64 y, const F64 z) +{ + mdV[VX] = x; + mdV[VY] = y; + mdV[VZ] = z; +} + +inline LLVector3d::LLVector3d(const F64 *vec) +{ + mdV[VX] = vec[VX]; + mdV[VY] = vec[VY]; + mdV[VZ] = vec[VZ]; +} + +inline LLVector3d::LLVector3d(const LLVector3 &vec) +{ + mdV[VX] = vec.mV[VX]; + mdV[VY] = vec.mV[VY]; + mdV[VZ] = vec.mV[VZ]; +} + +/* +inline LLVector3d::LLVector3d(const LLVector3d ©) +{ + mdV[VX] = copy.mdV[VX]; + mdV[VY] = copy.mdV[VY]; + mdV[VZ] = copy.mdV[VZ]; +} +*/ + +// Destructors + +// checker +inline bool LLVector3d::isFinite() const +{ + return (llfinite(mdV[VX]) && llfinite(mdV[VY]) && llfinite(mdV[VZ])); +} + + +// Clear and Assignment Functions + +inline const LLVector3d& LLVector3d::clear(void) +{ + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2]= 0.f; + return (*this); +} + +inline const LLVector3d& LLVector3d::clearVec(void) +{ + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2]= 0.f; + return (*this); +} + +inline const LLVector3d& LLVector3d::setZero(void) +{ + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2] = 0.f; + return (*this); +} + +inline const LLVector3d& LLVector3d::zeroVec(void) +{ + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2] = 0.f; + return (*this); +} + +inline const LLVector3d& LLVector3d::set(const F64 x, const F64 y, const F64 z) +{ + mdV[VX] = x; + mdV[VY] = y; + mdV[VZ] = z; + return (*this); +} + +inline const LLVector3d& LLVector3d::set(const LLVector3d &vec) +{ + mdV[0] = vec.mdV[0]; + mdV[1] = vec.mdV[1]; + mdV[2] = vec.mdV[2]; + return (*this); +} + +inline const LLVector3d& LLVector3d::set(const F64 *vec) +{ + mdV[0] = vec[0]; + mdV[1] = vec[1]; + mdV[2] = vec[2]; + return (*this); +} + +inline const LLVector3d& LLVector3d::setVec(const F64 x, const F64 y, const F64 z) +{ + mdV[VX] = x; + mdV[VY] = y; + mdV[VZ] = z; + return (*this); +} + +inline const LLVector3d& LLVector3d::setVec(const LLVector3d &vec) +{ + mdV[0] = vec.mdV[0]; + mdV[1] = vec.mdV[1]; + mdV[2] = vec.mdV[2]; + return (*this); +} + +inline const LLVector3d& LLVector3d::setVec(const F64 *vec) +{ + mdV[0] = vec[0]; + mdV[1] = vec[1]; + mdV[2] = vec[2]; + return (*this); +} + +inline F64 LLVector3d::normVec(void) +{ + F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); + F64 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mdV[0] *= oomag; + mdV[1] *= oomag; + mdV[2] *= oomag; + } + else + { + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2] = 0.f; + mag = 0; + } + return (mag); +} + +inline F64 LLVector3d::normalize(void) +{ + F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); + F64 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mdV[0] *= oomag; + mdV[1] *= oomag; + mdV[2] *= oomag; + } + else + { + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2] = 0.f; + mag = 0; + } + return (mag); +} + +// LLVector3d Magnitude and Normalization Functions + +inline F64 LLVector3d::magVec(void) const +{ + return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); +} + +inline F64 LLVector3d::magVecSquared(void) const +{ + return mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]; +} + +inline F64 LLVector3d::length(void) const +{ + return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); +} + +inline F64 LLVector3d::lengthSquared(void) const +{ + return mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]; +} + +inline LLVector3d operator+(const LLVector3d& a, const LLVector3d& b) +{ + LLVector3d c(a); + return c += b; +} + +inline LLVector3d operator-(const LLVector3d& a, const LLVector3d& b) +{ + LLVector3d c(a); + return c -= b; +} + +inline F64 operator*(const LLVector3d& a, const LLVector3d& b) +{ + return (a.mdV[0]*b.mdV[0] + a.mdV[1]*b.mdV[1] + a.mdV[2]*b.mdV[2]); +} + +inline LLVector3d operator%(const LLVector3d& a, const LLVector3d& b) +{ + return LLVector3d( a.mdV[1]*b.mdV[2] - b.mdV[1]*a.mdV[2], a.mdV[2]*b.mdV[0] - b.mdV[2]*a.mdV[0], a.mdV[0]*b.mdV[1] - b.mdV[0]*a.mdV[1] ); +} + +inline LLVector3d operator/(const LLVector3d& a, const F64 k) +{ + F64 t = 1.f / k; + return LLVector3d( a.mdV[0] * t, a.mdV[1] * t, a.mdV[2] * t ); +} + +inline LLVector3d operator*(const LLVector3d& a, const F64 k) +{ + return LLVector3d( a.mdV[0] * k, a.mdV[1] * k, a.mdV[2] * k ); +} + +inline LLVector3d operator*(F64 k, const LLVector3d& a) +{ + return LLVector3d( a.mdV[0] * k, a.mdV[1] * k, a.mdV[2] * k ); +} + +inline bool operator==(const LLVector3d& a, const LLVector3d& b) +{ + return ( (a.mdV[0] == b.mdV[0]) + &&(a.mdV[1] == b.mdV[1]) + &&(a.mdV[2] == b.mdV[2])); +} + +inline bool operator!=(const LLVector3d& a, const LLVector3d& b) +{ + return ( (a.mdV[0] != b.mdV[0]) + ||(a.mdV[1] != b.mdV[1]) + ||(a.mdV[2] != b.mdV[2])); +} + +inline const LLVector3d& operator+=(LLVector3d& a, const LLVector3d& b) +{ + a.mdV[0] += b.mdV[0]; + a.mdV[1] += b.mdV[1]; + a.mdV[2] += b.mdV[2]; + return a; +} + +inline const LLVector3d& operator-=(LLVector3d& a, const LLVector3d& b) +{ + a.mdV[0] -= b.mdV[0]; + a.mdV[1] -= b.mdV[1]; + a.mdV[2] -= b.mdV[2]; + return a; +} + +inline const LLVector3d& operator%=(LLVector3d& a, const LLVector3d& b) +{ + LLVector3d ret( a.mdV[1]*b.mdV[2] - b.mdV[1]*a.mdV[2], a.mdV[2]*b.mdV[0] - b.mdV[2]*a.mdV[0], a.mdV[0]*b.mdV[1] - b.mdV[0]*a.mdV[1]); + a = ret; + return a; +} + +inline const LLVector3d& operator*=(LLVector3d& a, const F64 k) +{ + a.mdV[0] *= k; + a.mdV[1] *= k; + a.mdV[2] *= k; + return a; +} + +inline const LLVector3d& operator/=(LLVector3d& a, const F64 k) +{ + F64 t = 1.f / k; + a.mdV[0] *= t; + a.mdV[1] *= t; + a.mdV[2] *= t; + return a; +} + +inline LLVector3d operator-(const LLVector3d& a) +{ + return LLVector3d( -a.mdV[0], -a.mdV[1], -a.mdV[2] ); +} + +inline F64 dist_vec(const LLVector3d& a, const LLVector3d& b) +{ + F64 x = a.mdV[0] - b.mdV[0]; + F64 y = a.mdV[1] - b.mdV[1]; + F64 z = a.mdV[2] - b.mdV[2]; + return (F32) sqrt( x*x + y*y + z*z ); +} + +inline F64 dist_vec_squared(const LLVector3d& a, const LLVector3d& b) +{ + F64 x = a.mdV[0] - b.mdV[0]; + F64 y = a.mdV[1] - b.mdV[1]; + F64 z = a.mdV[2] - b.mdV[2]; + return x*x + y*y + z*z; +} + +inline F64 dist_vec_squared2D(const LLVector3d& a, const LLVector3d& b) +{ + F64 x = a.mdV[0] - b.mdV[0]; + F64 y = a.mdV[1] - b.mdV[1]; + return x*x + y*y; +} + +inline LLVector3d lerp(const LLVector3d& a, const LLVector3d& b, const F64 u) +{ + return LLVector3d( + a.mdV[VX] + (b.mdV[VX] - a.mdV[VX]) * u, + a.mdV[VY] + (b.mdV[VY] - a.mdV[VY]) * u, + a.mdV[VZ] + (b.mdV[VZ] - a.mdV[VZ]) * u); +} + + +inline bool LLVector3d::isNull() const +{ + if ( F_APPROXIMATELY_ZERO > mdV[VX]*mdV[VX] + mdV[VY]*mdV[VY] + mdV[VZ]*mdV[VZ] ) + { + return true; + } + return false; +} + + +inline F64 angle_between(const LLVector3d& a, const LLVector3d& b) +{ + LLVector3d an = a; + LLVector3d bn = b; + an.normalize(); + bn.normalize(); + F64 cosine = an * bn; + F64 angle = (cosine >= 1.0f) ? 0.0f : + (cosine <= -1.0f) ? F_PI : + acos(cosine); + return angle; +} + +inline bool are_parallel(const LLVector3d& a, const LLVector3d& b, const F64 epsilon) +{ + LLVector3d an = a; + LLVector3d bn = b; + an.normalize(); + bn.normalize(); + F64 dot = an * bn; + if ( (1.0f - fabs(dot)) < epsilon) + { + return true; + } + return false; +} + +inline LLVector3d projected_vec(const LLVector3d& a, const LLVector3d& b) +{ + LLVector3d project_axis = b; + project_axis.normalize(); + return project_axis * (a * project_axis); +} + +inline LLVector3d inverse_projected_vec(const LLVector3d& a, const LLVector3d& b) +{ + LLVector3d normalized_a = a; + normalized_a.normalize(); + LLVector3d normalized_b = b; + F64 b_length = normalized_b.normalize(); + + F64 dot_product = normalized_a * normalized_b; + return normalized_a * (b_length / dot_product); +} + +#endif // LL_V3DMATH_H diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 089d4ce6db..73ad2a4ed6 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -1,413 +1,413 @@ -/** - * @file v3math.cpp - * @brief LLVector3 class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "v3math.h" - -//#include "vmath.h" -#include "v2math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquaternion.h" -#include "llquantize.h" -#include "v3dmath.h" - -// LLVector3 -// WARNING: Don't use these for global const definitions! -// For example: -// const LLQuaternion(0.5f * F_PI, LLVector3::zero); -// at the top of a *.cpp file might not give you what you think. -const LLVector3 LLVector3::zero(0,0,0); -const LLVector3 LLVector3::x_axis(1.f, 0, 0); -const LLVector3 LLVector3::y_axis(0, 1.f, 0); -const LLVector3 LLVector3::z_axis(0, 0, 1.f); -const LLVector3 LLVector3::x_axis_neg(-1.f, 0, 0); -const LLVector3 LLVector3::y_axis_neg(0, -1.f, 0); -const LLVector3 LLVector3::z_axis_neg(0, 0, -1.f); -const LLVector3 LLVector3::all_one(1.f,1.f,1.f); - - -// Clamps each values to range (min,max). -// Returns true if data changed. -bool LLVector3::clamp(F32 min, F32 max) -{ - bool ret{ false }; - - if (mV[0] < min) { mV[0] = min; ret = true; } - if (mV[1] < min) { mV[1] = min; ret = true; } - if (mV[2] < min) { mV[2] = min; ret = true; } - - if (mV[0] > max) { mV[0] = max; ret = true; } - if (mV[1] > max) { mV[1] = max; ret = true; } - if (mV[2] > max) { mV[2] = max; ret = true; } - - return ret; -} - -// Clamps length to an upper limit. -// Returns true if the data changed -bool LLVector3::clampLength( F32 length_limit ) -{ - bool changed{ false }; - - F32 len = length(); - if (llfinite(len)) - { - if ( len > length_limit) - { - normalize(); - if (length_limit < 0.f) - { - length_limit = 0.f; - } - mV[0] *= length_limit; - mV[1] *= length_limit; - mV[2] *= length_limit; - changed = true; - } - } - else - { // this vector may still be salvagable - F32 max_abs_component = 0.f; - for (S32 i = 0; i < 3; ++i) - { - F32 abs_component = fabs(mV[i]); - if (llfinite(abs_component)) - { - if (abs_component > max_abs_component) - { - max_abs_component = abs_component; - } - } - else - { - // no it can't be salvaged --> clear it - clear(); - changed = true; - break; - } - } - if (!changed) - { - // yes it can be salvaged --> - // bring the components down before we normalize - mV[0] /= max_abs_component; - mV[1] /= max_abs_component; - mV[2] /= max_abs_component; - normalize(); - - if (length_limit < 0.f) - { - length_limit = 0.f; - } - mV[0] *= length_limit; - mV[1] *= length_limit; - mV[2] *= length_limit; - } - } - - return changed; -} - -bool LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec) -{ - bool ret{ false }; - - if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = true; } - if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = true; } - if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = true; } - - if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = true; } - if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = true; } - if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = true; } - - return ret; -} - - -// Sets all values to absolute value of their original values -// Returns true if data changed -bool LLVector3::abs() -{ - bool ret{ false }; - - if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } - if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } - if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = true; } - - return ret; -} - -// Quatizations -void LLVector3::quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz) -{ - F32 x = mV[VX]; - F32 y = mV[VY]; - F32 z = mV[VZ]; - - x = U16_to_F32(F32_to_U16(x, lowerxy, upperxy), lowerxy, upperxy); - y = U16_to_F32(F32_to_U16(y, lowerxy, upperxy), lowerxy, upperxy); - z = U16_to_F32(F32_to_U16(z, lowerz, upperz), lowerz, upperz); - - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; -} - -void LLVector3::quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz) -{ - mV[VX] = U8_to_F32(F32_to_U8(mV[VX], lowerxy, upperxy), lowerxy, upperxy);; - mV[VY] = U8_to_F32(F32_to_U8(mV[VY], lowerxy, upperxy), lowerxy, upperxy); - mV[VZ] = U8_to_F32(F32_to_U8(mV[VZ], lowerz, upperz), lowerz, upperz); -} - - -void LLVector3::snap(S32 sig_digits) -{ - mV[VX] = snap_to_sig_figs(mV[VX], sig_digits); - mV[VY] = snap_to_sig_figs(mV[VY], sig_digits); - mV[VZ] = snap_to_sig_figs(mV[VZ], sig_digits); -} - -const LLVector3& LLVector3::rotVec(const LLMatrix3 &mat) -{ - *this = *this * mat; - return *this; -} - -const LLVector3& LLVector3::rotVec(const LLQuaternion &q) -{ - *this = *this * 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 ) - { - *this = *this * LLQuaternion(angle, vec); - } - return *this; -} - -const LLVector3& LLVector3::rotVec(F32 angle, F32 x, F32 y, F32 z) -{ - LLVector3 vec(x, y, z); - if ( !vec.isExactlyZero() && angle ) - { - *this = *this * LLQuaternion(angle, vec); - } - return *this; -} - -const LLVector3& LLVector3::scaleVec(const LLVector3& vec) -{ - mV[VX] *= vec.mV[VX]; - mV[VY] *= vec.mV[VY]; - mV[VZ] *= vec.mV[VZ]; - - return *this; -} - -LLVector3 LLVector3::scaledVec(const LLVector3& vec) const -{ - LLVector3 ret = LLVector3(*this); - ret.scaleVec(vec); - return ret; -} - -const LLVector3& LLVector3::set(const LLVector3d &vec) -{ - mV[0] = (F32)vec.mdV[0]; - mV[1] = (F32)vec.mdV[1]; - mV[2] = (F32)vec.mdV[2]; - return (*this); -} - -const LLVector3& LLVector3::set(const LLVector4 &vec) -{ - mV[0] = vec.mV[0]; - mV[1] = vec.mV[1]; - mV[2] = vec.mV[2]; - return (*this); -} - -const LLVector3& LLVector3::setVec(const LLVector3d &vec) -{ - mV[0] = (F32)vec.mdV[0]; - mV[1] = (F32)vec.mdV[1]; - mV[2] = (F32)vec.mdV[2]; - return (*this); -} - -const LLVector3& LLVector3::setVec(const LLVector4 &vec) -{ - mV[0] = vec.mV[0]; - mV[1] = vec.mV[1]; - mV[2] = vec.mV[2]; - return (*this); -} - -LLVector3::LLVector3(const LLVector2 &vec) -{ - mV[VX] = (F32)vec.mV[VX]; - mV[VY] = (F32)vec.mV[VY]; - mV[VZ] = 0; -} - -LLVector3::LLVector3(const LLVector3d &vec) -{ - mV[VX] = (F32)vec.mdV[VX]; - mV[VY] = (F32)vec.mdV[VY]; - mV[VZ] = (F32)vec.mdV[VZ]; -} - -LLVector3::LLVector3(const LLVector4 &vec) -{ - mV[VX] = (F32)vec.mV[VX]; - mV[VY] = (F32)vec.mV[VY]; - mV[VZ] = (F32)vec.mV[VZ]; -} - -LLVector3::LLVector3(const LLVector4a& vec) - : LLVector3(vec.getF32ptr()) -{ - -} - -LLVector3::LLVector3(const LLSD& sd) -{ - setValue(sd); -} - -LLSD LLVector3::getValue() const -{ - LLSD ret; - ret[0] = mV[0]; - ret[1] = mV[1]; - ret[2] = mV[2]; - return ret; -} - -void LLVector3::setValue(const LLSD& sd) -{ - mV[0] = (F32) sd[0].asReal(); - mV[1] = (F32) sd[1].asReal(); - mV[2] = (F32) sd[2].asReal(); -} - -const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &rot) -{ - const F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; - const F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY]; - const F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ]; - const F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX]; - - a.mV[VX] = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; - a.mV[VY] = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; - a.mV[VZ] = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; - - return a; -} - -// static -bool LLVector3::parseVector3(const std::string& buf, LLVector3* value) -{ - if( buf.empty() || value == nullptr) - { - return false; - } - - LLVector3 v; - S32 count = sscanf( buf.c_str(), "%f %f %f", v.mV + 0, v.mV + 1, v.mV + 2 ); - if( 3 == count ) - { - value->setVec( v ); - return true; - } - - return false; -} - -// Displacement from query point to nearest neighbor point on bounding box. -// Returns zero vector for points within or on the box. -LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) -{ - LLVector3 offset; - for (S32 k=0; k<3; k++) - { - offset[k] = 0; - if (pos[k] < box[0][k]) - { - offset[k] = pos[k] - box[0][k]; - } - else if (pos[k] > box[1][k]) - { - offset[k] = pos[k] - box[1][k]; - } - } - return offset; -} - -bool box_valid_and_non_zero(const LLVector3* box) -{ - if (!box[0].isFinite() || !box[1].isFinite()) - { - return false; - } - LLVector3 zero_vec; - zero_vec.clear(); - if ((box[0] != zero_vec) || (box[1] != zero_vec)) - { - return true; - } - return false; -} - +/** + * @file v3math.cpp + * @brief LLVector3 class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "v3math.h" + +//#include "vmath.h" +#include "v2math.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquaternion.h" +#include "llquantize.h" +#include "v3dmath.h" + +// LLVector3 +// WARNING: Don't use these for global const definitions! +// For example: +// const LLQuaternion(0.5f * F_PI, LLVector3::zero); +// at the top of a *.cpp file might not give you what you think. +const LLVector3 LLVector3::zero(0,0,0); +const LLVector3 LLVector3::x_axis(1.f, 0, 0); +const LLVector3 LLVector3::y_axis(0, 1.f, 0); +const LLVector3 LLVector3::z_axis(0, 0, 1.f); +const LLVector3 LLVector3::x_axis_neg(-1.f, 0, 0); +const LLVector3 LLVector3::y_axis_neg(0, -1.f, 0); +const LLVector3 LLVector3::z_axis_neg(0, 0, -1.f); +const LLVector3 LLVector3::all_one(1.f,1.f,1.f); + + +// Clamps each values to range (min,max). +// Returns true if data changed. +bool LLVector3::clamp(F32 min, F32 max) +{ + bool ret{ false }; + + if (mV[0] < min) { mV[0] = min; ret = true; } + if (mV[1] < min) { mV[1] = min; ret = true; } + if (mV[2] < min) { mV[2] = min; ret = true; } + + if (mV[0] > max) { mV[0] = max; ret = true; } + if (mV[1] > max) { mV[1] = max; ret = true; } + if (mV[2] > max) { mV[2] = max; ret = true; } + + return ret; +} + +// Clamps length to an upper limit. +// Returns true if the data changed +bool LLVector3::clampLength( F32 length_limit ) +{ + bool changed{ false }; + + F32 len = length(); + if (llfinite(len)) + { + if ( len > length_limit) + { + normalize(); + if (length_limit < 0.f) + { + length_limit = 0.f; + } + mV[0] *= length_limit; + mV[1] *= length_limit; + mV[2] *= length_limit; + changed = true; + } + } + else + { // this vector may still be salvagable + F32 max_abs_component = 0.f; + for (S32 i = 0; i < 3; ++i) + { + F32 abs_component = fabs(mV[i]); + if (llfinite(abs_component)) + { + if (abs_component > max_abs_component) + { + max_abs_component = abs_component; + } + } + else + { + // no it can't be salvaged --> clear it + clear(); + changed = true; + break; + } + } + if (!changed) + { + // yes it can be salvaged --> + // bring the components down before we normalize + mV[0] /= max_abs_component; + mV[1] /= max_abs_component; + mV[2] /= max_abs_component; + normalize(); + + if (length_limit < 0.f) + { + length_limit = 0.f; + } + mV[0] *= length_limit; + mV[1] *= length_limit; + mV[2] *= length_limit; + } + } + + return changed; +} + +bool LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec) +{ + bool ret{ false }; + + if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = true; } + if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = true; } + if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = true; } + + if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = true; } + if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = true; } + if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = true; } + + return ret; +} + + +// Sets all values to absolute value of their original values +// Returns true if data changed +bool LLVector3::abs() +{ + bool ret{ false }; + + if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } + if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } + if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = true; } + + return ret; +} + +// Quatizations +void LLVector3::quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz) +{ + F32 x = mV[VX]; + F32 y = mV[VY]; + F32 z = mV[VZ]; + + x = U16_to_F32(F32_to_U16(x, lowerxy, upperxy), lowerxy, upperxy); + y = U16_to_F32(F32_to_U16(y, lowerxy, upperxy), lowerxy, upperxy); + z = U16_to_F32(F32_to_U16(z, lowerz, upperz), lowerz, upperz); + + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; +} + +void LLVector3::quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz) +{ + mV[VX] = U8_to_F32(F32_to_U8(mV[VX], lowerxy, upperxy), lowerxy, upperxy);; + mV[VY] = U8_to_F32(F32_to_U8(mV[VY], lowerxy, upperxy), lowerxy, upperxy); + mV[VZ] = U8_to_F32(F32_to_U8(mV[VZ], lowerz, upperz), lowerz, upperz); +} + + +void LLVector3::snap(S32 sig_digits) +{ + mV[VX] = snap_to_sig_figs(mV[VX], sig_digits); + mV[VY] = snap_to_sig_figs(mV[VY], sig_digits); + mV[VZ] = snap_to_sig_figs(mV[VZ], sig_digits); +} + +const LLVector3& LLVector3::rotVec(const LLMatrix3 &mat) +{ + *this = *this * mat; + return *this; +} + +const LLVector3& LLVector3::rotVec(const LLQuaternion &q) +{ + *this = *this * 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 ) + { + *this = *this * LLQuaternion(angle, vec); + } + return *this; +} + +const LLVector3& LLVector3::rotVec(F32 angle, F32 x, F32 y, F32 z) +{ + LLVector3 vec(x, y, z); + if ( !vec.isExactlyZero() && angle ) + { + *this = *this * LLQuaternion(angle, vec); + } + return *this; +} + +const LLVector3& LLVector3::scaleVec(const LLVector3& vec) +{ + mV[VX] *= vec.mV[VX]; + mV[VY] *= vec.mV[VY]; + mV[VZ] *= vec.mV[VZ]; + + return *this; +} + +LLVector3 LLVector3::scaledVec(const LLVector3& vec) const +{ + LLVector3 ret = LLVector3(*this); + ret.scaleVec(vec); + return ret; +} + +const LLVector3& LLVector3::set(const LLVector3d &vec) +{ + mV[0] = (F32)vec.mdV[0]; + mV[1] = (F32)vec.mdV[1]; + mV[2] = (F32)vec.mdV[2]; + return (*this); +} + +const LLVector3& LLVector3::set(const LLVector4 &vec) +{ + mV[0] = vec.mV[0]; + mV[1] = vec.mV[1]; + mV[2] = vec.mV[2]; + return (*this); +} + +const LLVector3& LLVector3::setVec(const LLVector3d &vec) +{ + mV[0] = (F32)vec.mdV[0]; + mV[1] = (F32)vec.mdV[1]; + mV[2] = (F32)vec.mdV[2]; + return (*this); +} + +const LLVector3& LLVector3::setVec(const LLVector4 &vec) +{ + mV[0] = vec.mV[0]; + mV[1] = vec.mV[1]; + mV[2] = vec.mV[2]; + return (*this); +} + +LLVector3::LLVector3(const LLVector2 &vec) +{ + mV[VX] = (F32)vec.mV[VX]; + mV[VY] = (F32)vec.mV[VY]; + mV[VZ] = 0; +} + +LLVector3::LLVector3(const LLVector3d &vec) +{ + mV[VX] = (F32)vec.mdV[VX]; + mV[VY] = (F32)vec.mdV[VY]; + mV[VZ] = (F32)vec.mdV[VZ]; +} + +LLVector3::LLVector3(const LLVector4 &vec) +{ + mV[VX] = (F32)vec.mV[VX]; + mV[VY] = (F32)vec.mV[VY]; + mV[VZ] = (F32)vec.mV[VZ]; +} + +LLVector3::LLVector3(const LLVector4a& vec) + : LLVector3(vec.getF32ptr()) +{ + +} + +LLVector3::LLVector3(const LLSD& sd) +{ + setValue(sd); +} + +LLSD LLVector3::getValue() const +{ + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + ret[2] = mV[2]; + return ret; +} + +void LLVector3::setValue(const LLSD& sd) +{ + mV[0] = (F32) sd[0].asReal(); + mV[1] = (F32) sd[1].asReal(); + mV[2] = (F32) sd[2].asReal(); +} + +const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &rot) +{ + const F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; + const F32 rx = rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY]; + const F32 ry = rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ]; + const F32 rz = rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX]; + + a.mV[VX] = - rw * rot.mQ[VX] + rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY]; + a.mV[VY] = - rw * rot.mQ[VY] + ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ]; + a.mV[VZ] = - rw * rot.mQ[VZ] + rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX]; + + return a; +} + +// static +bool LLVector3::parseVector3(const std::string& buf, LLVector3* value) +{ + if( buf.empty() || value == nullptr) + { + return false; + } + + LLVector3 v; + S32 count = sscanf( buf.c_str(), "%f %f %f", v.mV + 0, v.mV + 1, v.mV + 2 ); + if( 3 == count ) + { + value->setVec( v ); + return true; + } + + return false; +} + +// Displacement from query point to nearest neighbor point on bounding box. +// Returns zero vector for points within or on the box. +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) +{ + LLVector3 offset; + for (S32 k=0; k<3; k++) + { + offset[k] = 0; + if (pos[k] < box[0][k]) + { + offset[k] = pos[k] - box[0][k]; + } + else if (pos[k] > box[1][k]) + { + offset[k] = pos[k] - box[1][k]; + } + } + return offset; +} + +bool box_valid_and_non_zero(const LLVector3* box) +{ + if (!box[0].isFinite() || !box[1].isFinite()) + { + return false; + } + LLVector3 zero_vec; + zero_vec.clear(); + if ((box[0] != zero_vec) || (box[1] != zero_vec)) + { + return true; + } + return false; +} + diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index e43c756fe7..d063b15c74 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -1,612 +1,612 @@ -/** - * @file v3math.h - * @brief LLVector3 class header file. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_V3MATH_H -#define LL_V3MATH_H - -#include "llerror.h" -#include "llmath.h" - -#include "llsd.h" -class LLVector2; -class LLVector4; -class LLVector4a; -class LLMatrix3; -class LLMatrix4; -class LLVector3d; -class LLQuaternion; - -// LLvector3 = |x y z w| - -static const U32 LENGTHOFVECTOR3 = 3; - -class LLVector3 -{ - public: - F32 mV[LENGTHOFVECTOR3]; - - static const LLVector3 zero; - static const LLVector3 x_axis; - static const LLVector3 y_axis; - static const LLVector3 z_axis; - static const LLVector3 x_axis_neg; - static const LLVector3 y_axis_neg; - static const LLVector3 z_axis_neg; - static const LLVector3 all_one; - - inline LLVector3(); // Initializes LLVector3 to (0, 0, 0) - inline LLVector3(const F32 x, const F32 y, const F32 z); // Initializes LLVector3 to (x. y, z) - inline explicit LLVector3(const F32 *vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2]) - explicit LLVector3(const LLVector2 &vec); // Initializes LLVector3 to (vec[0]. vec[1], 0) - explicit LLVector3(const LLVector3d &vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2]) - explicit LLVector3(const LLVector4 &vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) - explicit LLVector3(const LLVector4a& vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) - explicit LLVector3(const LLSD& sd); - - - LLSD getValue() const; - - void setValue(const LLSD& sd); - - inline bool isFinite() const; // checks to see if all values of LLVector3 are finite - bool clamp(F32 min, F32 max); // Clamps all values to (min,max), returns true if data changed - bool clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector - bool clampLength( F32 length_limit ); // Scales vector to limit length to a value - - void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization - void quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization - void snap(S32 sig_digits); // snaps x,y,z to sig_digits decimal places - - bool abs(); // sets all values to absolute value of original value (first octant), returns true if changed - - inline void clear(); // Clears LLVector3 to (0, 0, 0) - inline void setZero(); // Clears LLVector3 to (0, 0, 0) - inline void clearVec(); // deprecated - inline void zeroVec(); // deprecated - - inline void set(F32 x, F32 y, F32 z); // Sets LLVector3 to (x, y, z, 1) - inline void set(const LLVector3 &vec); // Sets LLVector3 to vec - inline void set(const F32 *vec); // Sets LLVector3 to vec - const LLVector3& set(const LLVector4 &vec); - const LLVector3& set(const LLVector3d &vec);// Sets LLVector3 to vec - - inline void setVec(F32 x, F32 y, F32 z); // deprecated - inline void setVec(const LLVector3 &vec); // deprecated - inline void setVec(const F32 *vec); // deprecated - - const LLVector3& setVec(const LLVector4 &vec); // deprecated - const LLVector3& setVec(const LLVector3d &vec); // deprecated - - F32 length() const; // Returns magnitude of LLVector3 - F32 lengthSquared() const; // Returns magnitude squared of LLVector3 - F32 magVec() const; // deprecated - F32 magVecSquared() const; // deprecated - - inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3 - inline F32 normVec(); // deprecated - - inline bool inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max - - const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians - 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 - - bool isNull() const; // Returns true if vector has a _very_small_ length - bool isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; } - - F32 operator[](int idx) const { return mV[idx]; } - F32 &operator[](int idx) { return mV[idx]; } - - friend LLVector3 operator+(const LLVector3 &a, const LLVector3 &b); // Return vector a + b - friend LLVector3 operator-(const LLVector3 &a, const LLVector3 &b); // Return vector a minus b - friend F32 operator*(const LLVector3 &a, const LLVector3 &b); // Return a dot b - friend LLVector3 operator%(const LLVector3 &a, const LLVector3 &b); // Return a cross b - friend LLVector3 operator*(const LLVector3 &a, F32 k); // Return a times scaler k - friend LLVector3 operator/(const LLVector3 &a, F32 k); // Return a divided by scaler k - friend LLVector3 operator*(F32 k, const LLVector3 &a); // Return a times scaler k - friend bool operator==(const LLVector3 &a, const LLVector3 &b); // Return a == b - friend bool operator!=(const LLVector3 &a, const LLVector3 &b); // Return a != b - // less than operator useful for using vectors as std::map keys - friend bool operator<(const LLVector3 &a, const LLVector3 &b); // Return a < b - - friend const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b); // Return vector a + b - friend const LLVector3& operator-=(LLVector3 &a, const LLVector3 &b); // Return vector a minus b - friend const LLVector3& operator%=(LLVector3 &a, const LLVector3 &b); // Return a cross b - friend const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b); // Returns a * b; - friend const LLVector3& operator*=(LLVector3 &a, F32 k); // Return a times scaler k - friend const LLVector3& operator/=(LLVector3 &a, F32 k); // Return a divided by scaler k - friend const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &b); // Returns a * b; - - friend LLVector3 operator-(const LLVector3 &a); // Return vector -a - - friend std::ostream& operator<<(std::ostream& s, const LLVector3 &a); // Stream a - - static bool parseVector3(const std::string& buf, LLVector3* value); -}; - -typedef LLVector3 LLSimLocalVec; - -// Non-member functions - -F32 angle_between(const LLVector3 &a, const LLVector3 &b); // Returns angle (radians) between a and b -bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel -F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance between a and b -F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b -F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b ignoring Z component -LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b -LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a scaled such that projected_vec(inverse_projected_vec(a, b), b) == b; -LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec) -LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec) -LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b -LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. -bool box_valid_and_non_zero(const LLVector3* box); - -inline LLVector3::LLVector3(void) -{ - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; -} - -inline LLVector3::LLVector3(const F32 x, const F32 y, const F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; -} - -inline LLVector3::LLVector3(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; -} - -/* -inline LLVector3::LLVector3(const LLVector3 ©) -{ - mV[VX] = copy.mV[VX]; - mV[VY] = copy.mV[VY]; - mV[VZ] = copy.mV[VZ]; -} -*/ - -// Destructors - -// checker -inline bool LLVector3::isFinite() const -{ - return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ])); -} - - -// Clear and Assignment Functions - -inline void LLVector3::clear(void) -{ - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; -} - -inline void LLVector3::setZero(void) -{ - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; -} - -inline void LLVector3::clearVec(void) -{ - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; -} - -inline void LLVector3::zeroVec(void) -{ - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; -} - -inline void LLVector3::set(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; -} - -inline void LLVector3::set(const LLVector3 &vec) -{ - mV[0] = vec.mV[0]; - mV[1] = vec.mV[1]; - mV[2] = vec.mV[2]; -} - -inline void LLVector3::set(const F32 *vec) -{ - mV[0] = vec[0]; - mV[1] = vec[1]; - mV[2] = vec[2]; -} - -// deprecated -inline void LLVector3::setVec(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; -} - -// deprecated -inline void LLVector3::setVec(const LLVector3 &vec) -{ - mV[0] = vec.mV[0]; - mV[1] = vec.mV[1]; - mV[2] = vec.mV[2]; -} - -// deprecated -inline void LLVector3::setVec(const F32 *vec) -{ - mV[0] = vec[0]; - mV[1] = vec[1]; - mV[2] = vec[2]; -} - -inline F32 LLVector3::normalize(void) -{ - F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); - F32 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mV[0] *= oomag; - mV[1] *= oomag; - mV[2] *= oomag; - } - else - { - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; - mag = 0; - } - return (mag); -} - -// deprecated -inline F32 LLVector3::normVec(void) -{ - F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); - F32 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mV[0] *= oomag; - mV[1] *= oomag; - mV[2] *= oomag; - } - else - { - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; - mag = 0; - } - return (mag); -} - -// LLVector3 Magnitude and Normalization Functions - -inline F32 LLVector3::length(void) const -{ - return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); -} - -inline F32 LLVector3::lengthSquared(void) const -{ - return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; -} - -inline F32 LLVector3::magVec(void) const -{ - return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); -} - -inline F32 LLVector3::magVecSquared(void) const -{ - return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; -} - -inline bool LLVector3::inRange( F32 min, F32 max ) const -{ - return mV[0] >= min && mV[0] <= max && - mV[1] >= min && mV[1] <= max && - mV[2] >= min && mV[2] <= max; -} - -inline LLVector3 operator+(const LLVector3 &a, const LLVector3 &b) -{ - LLVector3 c(a); - return c += b; -} - -inline LLVector3 operator-(const LLVector3 &a, const LLVector3 &b) -{ - LLVector3 c(a); - return c -= b; -} - -inline F32 operator*(const LLVector3 &a, const LLVector3 &b) -{ - return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]); -} - -inline LLVector3 operator%(const LLVector3 &a, const LLVector3 &b) -{ - return LLVector3( a.mV[1]*b.mV[2] - b.mV[1]*a.mV[2], a.mV[2]*b.mV[0] - b.mV[2]*a.mV[0], a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1] ); -} - -inline LLVector3 operator/(const LLVector3 &a, F32 k) -{ - F32 t = 1.f / k; - return LLVector3( a.mV[0] * t, a.mV[1] * t, a.mV[2] * t ); -} - -inline LLVector3 operator*(const LLVector3 &a, F32 k) -{ - return LLVector3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k ); -} - -inline LLVector3 operator*(F32 k, const LLVector3 &a) -{ - return LLVector3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k ); -} - -inline bool operator==(const LLVector3 &a, const LLVector3 &b) -{ - return ( (a.mV[0] == b.mV[0]) - &&(a.mV[1] == b.mV[1]) - &&(a.mV[2] == b.mV[2])); -} - -inline bool operator!=(const LLVector3 &a, const LLVector3 &b) -{ - return ( (a.mV[0] != b.mV[0]) - ||(a.mV[1] != b.mV[1]) - ||(a.mV[2] != b.mV[2])); -} - -inline bool operator<(const LLVector3 &a, const LLVector3 &b) -{ - return (a.mV[0] < b.mV[0] - || (a.mV[0] == b.mV[0] - && (a.mV[1] < b.mV[1] - || ((a.mV[1] == b.mV[1]) - && a.mV[2] < b.mV[2])))); -} - -inline const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b) -{ - a.mV[0] += b.mV[0]; - a.mV[1] += b.mV[1]; - a.mV[2] += b.mV[2]; - return a; -} - -inline const LLVector3& operator-=(LLVector3 &a, const LLVector3 &b) -{ - a.mV[0] -= b.mV[0]; - a.mV[1] -= b.mV[1]; - a.mV[2] -= b.mV[2]; - return a; -} - -inline const LLVector3& operator%=(LLVector3 &a, const LLVector3 &b) -{ - LLVector3 ret( a.mV[1]*b.mV[2] - b.mV[1]*a.mV[2], a.mV[2]*b.mV[0] - b.mV[2]*a.mV[0], a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1]); - a = ret; - return a; -} - -inline const LLVector3& operator*=(LLVector3 &a, F32 k) -{ - a.mV[0] *= k; - a.mV[1] *= k; - a.mV[2] *= k; - return a; -} - -inline const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b) -{ - a.mV[0] *= b.mV[0]; - a.mV[1] *= b.mV[1]; - a.mV[2] *= b.mV[2]; - return a; -} - -inline const LLVector3& operator/=(LLVector3 &a, F32 k) -{ - F32 t = 1.f / k; - a.mV[0] *= t; - a.mV[1] *= t; - a.mV[2] *= t; - return a; -} - -inline LLVector3 operator-(const LLVector3 &a) -{ - return LLVector3( -a.mV[0], -a.mV[1], -a.mV[2] ); -} - -inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b) -{ - F32 x = a.mV[0] - b.mV[0]; - F32 y = a.mV[1] - b.mV[1]; - F32 z = a.mV[2] - b.mV[2]; - return (F32) sqrt( x*x + y*y + z*z ); -} - -inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b) -{ - F32 x = a.mV[0] - b.mV[0]; - F32 y = a.mV[1] - b.mV[1]; - F32 z = a.mV[2] - b.mV[2]; - return x*x + y*y + z*z; -} - -inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b) -{ - F32 x = a.mV[0] - b.mV[0]; - F32 y = a.mV[1] - b.mV[1]; - return x*x + y*y; -} - -inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b) -{ - F32 bb = b * b; - if (bb > FP_MAG_THRESHOLD * FP_MAG_THRESHOLD) - { - return ((a * b) / bb) * b; - } - else - { - return b.zero; - } -} - -inline LLVector3 inverse_projected_vec(const LLVector3& a, const LLVector3& b) -{ - LLVector3 normalized_a = a; - normalized_a.normalize(); - LLVector3 normalized_b = b; - F32 b_length = normalized_b.normalize(); - - F32 dot_product = normalized_a * normalized_b; - //NB: if a _|_ b, then returns an infinite vector - return normalized_a * (b_length / dot_product); -} - -inline LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b) -{ - return projected_vec(a, b); -} - -inline LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b) -{ - return a - projected_vec(a, b); -} - - -inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u) -{ - return LLVector3( - a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, - a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, - a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u); -} - - -inline bool LLVector3::isNull() const -{ - if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ] ) - { - return true; - } - return false; -} - -inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos) -{ - for (U32 i = 0; i < 3; i++) - { - if (min.mV[i] > pos.mV[i]) - { - min.mV[i] = pos.mV[i]; - } - if (max.mV[i] < pos.mV[i]) - { - max.mV[i] = pos.mV[i]; - } - } -} - -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) -{ - F32 ab = a * b; // dotproduct - if (ab == -0.0f) - { - ab = 0.0f; // get rid of negative zero - } - LLVector3 c = a % b; // crossproduct - return atan2f(sqrtf(c * c), ab); // return the angle -} - -inline bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) -{ - LLVector3 an = a; - LLVector3 bn = b; - an.normalize(); - bn.normalize(); - F32 dot = an * bn; - if ( (1.0f - fabs(dot)) < epsilon) - { - return true; - } - return false; -} - -inline std::ostream& operator<<(std::ostream& s, const LLVector3 &a) -{ - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }"; - return s; -} - -#endif +/** + * @file v3math.h + * @brief LLVector3 class header file. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V3MATH_H +#define LL_V3MATH_H + +#include "llerror.h" +#include "llmath.h" + +#include "llsd.h" +class LLVector2; +class LLVector4; +class LLVector4a; +class LLMatrix3; +class LLMatrix4; +class LLVector3d; +class LLQuaternion; + +// LLvector3 = |x y z w| + +static const U32 LENGTHOFVECTOR3 = 3; + +class LLVector3 +{ + public: + F32 mV[LENGTHOFVECTOR3]; + + static const LLVector3 zero; + static const LLVector3 x_axis; + static const LLVector3 y_axis; + static const LLVector3 z_axis; + static const LLVector3 x_axis_neg; + static const LLVector3 y_axis_neg; + static const LLVector3 z_axis_neg; + static const LLVector3 all_one; + + inline LLVector3(); // Initializes LLVector3 to (0, 0, 0) + inline LLVector3(const F32 x, const F32 y, const F32 z); // Initializes LLVector3 to (x. y, z) + inline explicit LLVector3(const F32 *vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2]) + explicit LLVector3(const LLVector2 &vec); // Initializes LLVector3 to (vec[0]. vec[1], 0) + explicit LLVector3(const LLVector3d &vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2]) + explicit LLVector3(const LLVector4 &vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) + explicit LLVector3(const LLVector4a& vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) + explicit LLVector3(const LLSD& sd); + + + LLSD getValue() const; + + void setValue(const LLSD& sd); + + inline bool isFinite() const; // checks to see if all values of LLVector3 are finite + bool clamp(F32 min, F32 max); // Clamps all values to (min,max), returns true if data changed + bool clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector + bool clampLength( F32 length_limit ); // Scales vector to limit length to a value + + void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization + void quantize8(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization + void snap(S32 sig_digits); // snaps x,y,z to sig_digits decimal places + + bool abs(); // sets all values to absolute value of original value (first octant), returns true if changed + + inline void clear(); // Clears LLVector3 to (0, 0, 0) + inline void setZero(); // Clears LLVector3 to (0, 0, 0) + inline void clearVec(); // deprecated + inline void zeroVec(); // deprecated + + inline void set(F32 x, F32 y, F32 z); // Sets LLVector3 to (x, y, z, 1) + inline void set(const LLVector3 &vec); // Sets LLVector3 to vec + inline void set(const F32 *vec); // Sets LLVector3 to vec + const LLVector3& set(const LLVector4 &vec); + const LLVector3& set(const LLVector3d &vec);// Sets LLVector3 to vec + + inline void setVec(F32 x, F32 y, F32 z); // deprecated + inline void setVec(const LLVector3 &vec); // deprecated + inline void setVec(const F32 *vec); // deprecated + + const LLVector3& setVec(const LLVector4 &vec); // deprecated + const LLVector3& setVec(const LLVector3d &vec); // deprecated + + F32 length() const; // Returns magnitude of LLVector3 + F32 lengthSquared() const; // Returns magnitude squared of LLVector3 + F32 magVec() const; // deprecated + F32 magVecSquared() const; // deprecated + + inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3 + inline F32 normVec(); // deprecated + + inline bool inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max + + const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians + 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 + + bool isNull() const; // Returns true if vector has a _very_small_ length + bool isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; } + + F32 operator[](int idx) const { return mV[idx]; } + F32 &operator[](int idx) { return mV[idx]; } + + friend LLVector3 operator+(const LLVector3 &a, const LLVector3 &b); // Return vector a + b + friend LLVector3 operator-(const LLVector3 &a, const LLVector3 &b); // Return vector a minus b + friend F32 operator*(const LLVector3 &a, const LLVector3 &b); // Return a dot b + friend LLVector3 operator%(const LLVector3 &a, const LLVector3 &b); // Return a cross b + friend LLVector3 operator*(const LLVector3 &a, F32 k); // Return a times scaler k + friend LLVector3 operator/(const LLVector3 &a, F32 k); // Return a divided by scaler k + friend LLVector3 operator*(F32 k, const LLVector3 &a); // Return a times scaler k + friend bool operator==(const LLVector3 &a, const LLVector3 &b); // Return a == b + friend bool operator!=(const LLVector3 &a, const LLVector3 &b); // Return a != b + // less than operator useful for using vectors as std::map keys + friend bool operator<(const LLVector3 &a, const LLVector3 &b); // Return a < b + + friend const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b); // Return vector a + b + friend const LLVector3& operator-=(LLVector3 &a, const LLVector3 &b); // Return vector a minus b + friend const LLVector3& operator%=(LLVector3 &a, const LLVector3 &b); // Return a cross b + friend const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b); // Returns a * b; + friend const LLVector3& operator*=(LLVector3 &a, F32 k); // Return a times scaler k + friend const LLVector3& operator/=(LLVector3 &a, F32 k); // Return a divided by scaler k + friend const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &b); // Returns a * b; + + friend LLVector3 operator-(const LLVector3 &a); // Return vector -a + + friend std::ostream& operator<<(std::ostream& s, const LLVector3 &a); // Stream a + + static bool parseVector3(const std::string& buf, LLVector3* value); +}; + +typedef LLVector3 LLSimLocalVec; + +// Non-member functions + +F32 angle_between(const LLVector3 &a, const LLVector3 &b); // Returns angle (radians) between a and b +bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel +F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance between a and b +F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b +F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b ignoring Z component +LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b +LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a scaled such that projected_vec(inverse_projected_vec(a, b), b) == b; +LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec) +LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec) +LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. +bool box_valid_and_non_zero(const LLVector3* box); + +inline LLVector3::LLVector3(void) +{ + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; +} + +inline LLVector3::LLVector3(const F32 x, const F32 y, const F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; +} + +inline LLVector3::LLVector3(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; +} + +/* +inline LLVector3::LLVector3(const LLVector3 ©) +{ + mV[VX] = copy.mV[VX]; + mV[VY] = copy.mV[VY]; + mV[VZ] = copy.mV[VZ]; +} +*/ + +// Destructors + +// checker +inline bool LLVector3::isFinite() const +{ + return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ])); +} + + +// Clear and Assignment Functions + +inline void LLVector3::clear(void) +{ + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; +} + +inline void LLVector3::setZero(void) +{ + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; +} + +inline void LLVector3::clearVec(void) +{ + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; +} + +inline void LLVector3::zeroVec(void) +{ + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; +} + +inline void LLVector3::set(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; +} + +inline void LLVector3::set(const LLVector3 &vec) +{ + mV[0] = vec.mV[0]; + mV[1] = vec.mV[1]; + mV[2] = vec.mV[2]; +} + +inline void LLVector3::set(const F32 *vec) +{ + mV[0] = vec[0]; + mV[1] = vec[1]; + mV[2] = vec[2]; +} + +// deprecated +inline void LLVector3::setVec(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; +} + +// deprecated +inline void LLVector3::setVec(const LLVector3 &vec) +{ + mV[0] = vec.mV[0]; + mV[1] = vec.mV[1]; + mV[2] = vec.mV[2]; +} + +// deprecated +inline void LLVector3::setVec(const F32 *vec) +{ + mV[0] = vec[0]; + mV[1] = vec[1]; + mV[2] = vec[2]; +} + +inline F32 LLVector3::normalize(void) +{ + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + F32 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mV[0] *= oomag; + mV[1] *= oomag; + mV[2] *= oomag; + } + else + { + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; + mag = 0; + } + return (mag); +} + +// deprecated +inline F32 LLVector3::normVec(void) +{ + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + F32 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mV[0] *= oomag; + mV[1] *= oomag; + mV[2] *= oomag; + } + else + { + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; + mag = 0; + } + return (mag); +} + +// LLVector3 Magnitude and Normalization Functions + +inline F32 LLVector3::length(void) const +{ + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); +} + +inline F32 LLVector3::lengthSquared(void) const +{ + return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; +} + +inline F32 LLVector3::magVec(void) const +{ + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); +} + +inline F32 LLVector3::magVecSquared(void) const +{ + return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; +} + +inline bool LLVector3::inRange( F32 min, F32 max ) const +{ + return mV[0] >= min && mV[0] <= max && + mV[1] >= min && mV[1] <= max && + mV[2] >= min && mV[2] <= max; +} + +inline LLVector3 operator+(const LLVector3 &a, const LLVector3 &b) +{ + LLVector3 c(a); + return c += b; +} + +inline LLVector3 operator-(const LLVector3 &a, const LLVector3 &b) +{ + LLVector3 c(a); + return c -= b; +} + +inline F32 operator*(const LLVector3 &a, const LLVector3 &b) +{ + return (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]); +} + +inline LLVector3 operator%(const LLVector3 &a, const LLVector3 &b) +{ + return LLVector3( a.mV[1]*b.mV[2] - b.mV[1]*a.mV[2], a.mV[2]*b.mV[0] - b.mV[2]*a.mV[0], a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1] ); +} + +inline LLVector3 operator/(const LLVector3 &a, F32 k) +{ + F32 t = 1.f / k; + return LLVector3( a.mV[0] * t, a.mV[1] * t, a.mV[2] * t ); +} + +inline LLVector3 operator*(const LLVector3 &a, F32 k) +{ + return LLVector3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k ); +} + +inline LLVector3 operator*(F32 k, const LLVector3 &a) +{ + return LLVector3( a.mV[0] * k, a.mV[1] * k, a.mV[2] * k ); +} + +inline bool operator==(const LLVector3 &a, const LLVector3 &b) +{ + return ( (a.mV[0] == b.mV[0]) + &&(a.mV[1] == b.mV[1]) + &&(a.mV[2] == b.mV[2])); +} + +inline bool operator!=(const LLVector3 &a, const LLVector3 &b) +{ + return ( (a.mV[0] != b.mV[0]) + ||(a.mV[1] != b.mV[1]) + ||(a.mV[2] != b.mV[2])); +} + +inline bool operator<(const LLVector3 &a, const LLVector3 &b) +{ + return (a.mV[0] < b.mV[0] + || (a.mV[0] == b.mV[0] + && (a.mV[1] < b.mV[1] + || ((a.mV[1] == b.mV[1]) + && a.mV[2] < b.mV[2])))); +} + +inline const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b) +{ + a.mV[0] += b.mV[0]; + a.mV[1] += b.mV[1]; + a.mV[2] += b.mV[2]; + return a; +} + +inline const LLVector3& operator-=(LLVector3 &a, const LLVector3 &b) +{ + a.mV[0] -= b.mV[0]; + a.mV[1] -= b.mV[1]; + a.mV[2] -= b.mV[2]; + return a; +} + +inline const LLVector3& operator%=(LLVector3 &a, const LLVector3 &b) +{ + LLVector3 ret( a.mV[1]*b.mV[2] - b.mV[1]*a.mV[2], a.mV[2]*b.mV[0] - b.mV[2]*a.mV[0], a.mV[0]*b.mV[1] - b.mV[0]*a.mV[1]); + a = ret; + return a; +} + +inline const LLVector3& operator*=(LLVector3 &a, F32 k) +{ + a.mV[0] *= k; + a.mV[1] *= k; + a.mV[2] *= k; + return a; +} + +inline const LLVector3& operator*=(LLVector3 &a, const LLVector3 &b) +{ + a.mV[0] *= b.mV[0]; + a.mV[1] *= b.mV[1]; + a.mV[2] *= b.mV[2]; + return a; +} + +inline const LLVector3& operator/=(LLVector3 &a, F32 k) +{ + F32 t = 1.f / k; + a.mV[0] *= t; + a.mV[1] *= t; + a.mV[2] *= t; + return a; +} + +inline LLVector3 operator-(const LLVector3 &a) +{ + return LLVector3( -a.mV[0], -a.mV[1], -a.mV[2] ); +} + +inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b) +{ + F32 x = a.mV[0] - b.mV[0]; + F32 y = a.mV[1] - b.mV[1]; + F32 z = a.mV[2] - b.mV[2]; + return (F32) sqrt( x*x + y*y + z*z ); +} + +inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b) +{ + F32 x = a.mV[0] - b.mV[0]; + F32 y = a.mV[1] - b.mV[1]; + F32 z = a.mV[2] - b.mV[2]; + return x*x + y*y + z*z; +} + +inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b) +{ + F32 x = a.mV[0] - b.mV[0]; + F32 y = a.mV[1] - b.mV[1]; + return x*x + y*y; +} + +inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b) +{ + F32 bb = b * b; + if (bb > FP_MAG_THRESHOLD * FP_MAG_THRESHOLD) + { + return ((a * b) / bb) * b; + } + else + { + return b.zero; + } +} + +inline LLVector3 inverse_projected_vec(const LLVector3& a, const LLVector3& b) +{ + LLVector3 normalized_a = a; + normalized_a.normalize(); + LLVector3 normalized_b = b; + F32 b_length = normalized_b.normalize(); + + F32 dot_product = normalized_a * normalized_b; + //NB: if a _|_ b, then returns an infinite vector + return normalized_a * (b_length / dot_product); +} + +inline LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b) +{ + return projected_vec(a, b); +} + +inline LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b) +{ + return a - projected_vec(a, b); +} + + +inline LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u) +{ + return LLVector3( + a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, + a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, + a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u); +} + + +inline bool LLVector3::isNull() const +{ + if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ] ) + { + return true; + } + return false; +} + +inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos) +{ + for (U32 i = 0; i < 3; i++) + { + if (min.mV[i] > pos.mV[i]) + { + min.mV[i] = pos.mV[i]; + } + if (max.mV[i] < pos.mV[i]) + { + max.mV[i] = pos.mV[i]; + } + } +} + +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) +{ + F32 ab = a * b; // dotproduct + if (ab == -0.0f) + { + ab = 0.0f; // get rid of negative zero + } + LLVector3 c = a % b; // crossproduct + return atan2f(sqrtf(c * c), ab); // return the angle +} + +inline bool are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) +{ + LLVector3 an = a; + LLVector3 bn = b; + an.normalize(); + bn.normalize(); + F32 dot = an * bn; + if ( (1.0f - fabs(dot)) < epsilon) + { + return true; + } + return false; +} + +inline std::ostream& operator<<(std::ostream& s, const LLVector3 &a) +{ + s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }"; + return s; +} + +#endif diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index 63ac1e9088..fd3548bc48 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -1,738 +1,738 @@ -/** - * @file v4color.cpp - * @brief LLColor4 class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llboost.h" - -#include "v4color.h" -#include "v4coloru.h" -#include "v3color.h" -#include "v4math.h" -#include "llmath.h" - -// LLColor4 - -////////////////////////////////////////////////////////////////////////////// - -LLColor4 LLColor4::red( 1.f, 0.f, 0.f, 1.f); -LLColor4 LLColor4::green( 0.f, 1.f, 0.f, 1.f); -LLColor4 LLColor4::blue( 0.f, 0.f, 1.f, 1.f); -LLColor4 LLColor4::black( 0.f, 0.f, 0.f, 1.f); -LLColor4 LLColor4::yellow( 1.f, 1.f, 0.f, 1.f); -LLColor4 LLColor4::magenta( 1.0f, 0.0f, 1.0f, 1.0f); -LLColor4 LLColor4::cyan( 0.0f, 1.0f, 1.0f, 1.0f); -LLColor4 LLColor4::white( 1.f, 1.f, 1.f, 1.f); -LLColor4 LLColor4::smoke( 0.5f, 0.5f, 0.5f, 0.5f); -LLColor4 LLColor4::grey( 0.5f, 0.5f, 0.5f, 1.0f); -LLColor4 LLColor4::orange( 1.f, 0.5, 0.f, 1.f ); -LLColor4 LLColor4::purple( 0.6f, 0.2f, 0.8f, 1.0f); -LLColor4 LLColor4::pink( 1.0f, 0.5f, 0.8f, 1.0f); -LLColor4 LLColor4::transparent( 0.f, 0.f, 0.f, 0.f ); - -////////////////////////////////////////////////////////////////////////////// - -LLColor4 LLColor4::grey1(0.8f, 0.8f, 0.8f, 1.0f); -LLColor4 LLColor4::grey2(0.6f, 0.6f, 0.6f, 1.0f); -LLColor4 LLColor4::grey3(0.4f, 0.4f, 0.4f, 1.0f); -LLColor4 LLColor4::grey4(0.3f, 0.3f, 0.3f, 1.0f); - -LLColor4 LLColor4::red1(1.0f, 0.0f, 0.0f, 1.0f); -LLColor4 LLColor4::red2(0.6f, 0.0f, 0.0f, 1.0f); -LLColor4 LLColor4::red3(1.0f, 0.2f, 0.2f, 1.0f); -LLColor4 LLColor4::red4(0.5f, 0.1f, 0.1f, 1.0f); -LLColor4 LLColor4::red5(0.8f, 0.1f, 0.0f, 1.0f); - -LLColor4 LLColor4::green1(0.0f, 1.0f, 0.0f, 1.0f); -LLColor4 LLColor4::green2(0.0f, 0.6f, 0.0f, 1.0f); -LLColor4 LLColor4::green3(0.0f, 0.4f, 0.0f, 1.0f); -LLColor4 LLColor4::green4(0.0f, 1.0f, 0.4f, 1.0f); -LLColor4 LLColor4::green5(0.2f, 0.6f, 0.4f, 1.0f); -LLColor4 LLColor4::green6(0.4f, 0.6f, 0.2f, 1.0f); - -LLColor4 LLColor4::blue1(0.0f, 0.0f, 1.0f, 1.0f); -LLColor4 LLColor4::blue2(0.0f, 0.4f, 1.0f, 1.0f); -LLColor4 LLColor4::blue3(0.2f, 0.2f, 0.8f, 1.0f); -LLColor4 LLColor4::blue4(0.0f, 0.0f, 0.6f, 1.0f); -LLColor4 LLColor4::blue5(0.4f, 0.2f, 1.0f, 1.0f); -LLColor4 LLColor4::blue6(0.4f, 0.5f, 1.0f, 1.0f); - -LLColor4 LLColor4::yellow1(1.0f, 1.0f, 0.0f, 1.0f); -LLColor4 LLColor4::yellow2(0.6f, 0.6f, 0.0f, 1.0f); -LLColor4 LLColor4::yellow3(0.8f, 1.0f, 0.2f, 1.0f); -LLColor4 LLColor4::yellow4(1.0f, 1.0f, 0.4f, 1.0f); -LLColor4 LLColor4::yellow5(0.6f, 0.4f, 0.2f, 1.0f); -LLColor4 LLColor4::yellow6(1.0f, 0.8f, 0.4f, 1.0f); -LLColor4 LLColor4::yellow7(0.8f, 0.8f, 0.0f, 1.0f); -LLColor4 LLColor4::yellow8(0.8f, 0.8f, 0.2f, 1.0f); -LLColor4 LLColor4::yellow9(0.8f, 0.8f, 0.4f, 1.0f); - -LLColor4 LLColor4::orange1(1.0f, 0.8f, 0.0f, 1.0f); -LLColor4 LLColor4::orange2(1.0f, 0.6f, 0.0f, 1.0f); -LLColor4 LLColor4::orange3(1.0f, 0.4f, 0.2f, 1.0f); -LLColor4 LLColor4::orange4(0.8f, 0.4f, 0.0f, 1.0f); -LLColor4 LLColor4::orange5(0.9f, 0.5f, 0.0f, 1.0f); -LLColor4 LLColor4::orange6(1.0f, 0.8f, 0.2f, 1.0f); - -LLColor4 LLColor4::magenta1(1.0f, 0.0f, 1.0f, 1.0f); -LLColor4 LLColor4::magenta2(0.6f, 0.2f, 0.4f, 1.0f); -LLColor4 LLColor4::magenta3(1.0f, 0.4f, 0.6f, 1.0f); -LLColor4 LLColor4::magenta4(1.0f, 0.2f, 0.8f, 1.0f); - -LLColor4 LLColor4::purple1(0.6f, 0.2f, 0.8f, 1.0f); -LLColor4 LLColor4::purple2(0.8f, 0.2f, 1.0f, 1.0f); -LLColor4 LLColor4::purple3(0.6f, 0.0f, 1.0f, 1.0f); -LLColor4 LLColor4::purple4(0.4f, 0.0f, 0.8f, 1.0f); -LLColor4 LLColor4::purple5(0.6f, 0.0f, 0.8f, 1.0f); -LLColor4 LLColor4::purple6(0.8f, 0.0f, 0.6f, 1.0f); - -LLColor4 LLColor4::pink1(1.0f, 0.5f, 0.8f, 1.0f); -LLColor4 LLColor4::pink2(1.0f, 0.8f, 0.9f, 1.0f); - -LLColor4 LLColor4::cyan1(0.0f, 1.0f, 1.0f, 1.0f); -LLColor4 LLColor4::cyan2(0.4f, 0.8f, 0.8f, 1.0f); -LLColor4 LLColor4::cyan3(0.0f, 1.0f, 0.6f, 1.0f); -LLColor4 LLColor4::cyan4(0.6f, 1.0f, 1.0f, 1.0f); -LLColor4 LLColor4::cyan5(0.2f, 0.6f, 1.0f, 1.0f); -LLColor4 LLColor4::cyan6(0.2f, 0.6f, 0.6f, 1.0f); - -////////////////////////////////////////////////////////////////////////////// - -// conversion -LLColor4::operator LLColor4U() const -{ - return LLColor4U( - (U8)llclampb(ll_round(mV[VRED]*255.f)), - (U8)llclampb(ll_round(mV[VGREEN]*255.f)), - (U8)llclampb(ll_round(mV[VBLUE]*255.f)), - (U8)llclampb(ll_round(mV[VALPHA]*255.f))); -} - -LLColor4::LLColor4(const LLColor3 &vec, F32 a) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = a; -} - -LLColor4::LLColor4(const LLColor4U& color4u) -{ - const F32 SCALE = 1.f/255.f; - mV[VX] = color4u.mV[VX] * SCALE; - mV[VY] = color4u.mV[VY] * SCALE; - mV[VZ] = color4u.mV[VZ] * SCALE; - mV[VW] = color4u.mV[VW] * SCALE; -} - -LLColor4::LLColor4(const LLVector4& vector4) -{ - mV[VX] = vector4.mV[VX]; - mV[VY] = vector4.mV[VY]; - mV[VZ] = vector4.mV[VZ]; - mV[VW] = vector4.mV[VW]; -} - -const LLColor4& LLColor4::set(const LLColor4U& color4u) -{ - const F32 SCALE = 1.f/255.f; - mV[VX] = color4u.mV[VX] * SCALE; - mV[VY] = color4u.mV[VY] * SCALE; - mV[VZ] = color4u.mV[VZ] * SCALE; - mV[VW] = color4u.mV[VW] * SCALE; - return (*this); -} - -const LLColor4& LLColor4::set(const LLColor3 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - -// no change to alpha! -// mV[VW] = 1.f; - - return (*this); -} - -const LLColor4& LLColor4::set(const LLColor3 &vec, F32 a) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = a; - return (*this); -} - -// deprecated -- use set() -const LLColor4& LLColor4::setVec(const LLColor4U& color4u) -{ - const F32 SCALE = 1.f/255.f; - mV[VX] = color4u.mV[VX] * SCALE; - mV[VY] = color4u.mV[VY] * SCALE; - mV[VZ] = color4u.mV[VZ] * SCALE; - mV[VW] = color4u.mV[VW] * SCALE; - return (*this); -} - -// deprecated -- use set() -const LLColor4& LLColor4::setVec(const LLColor3 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - -// no change to alpha! -// mV[VW] = 1.f; - - return (*this); -} - -// deprecated -- use set() -const LLColor4& LLColor4::setVec(const LLColor3 &vec, F32 a) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = a; - return (*this); -} - -void LLColor4::setValue(const LLSD& sd) -{ -#if 0 - // Clamping on setValue from LLSD is inconsistent with other set behavior - F32 val; - bool out_of_range = false; - val = sd[0].asReal(); - mV[0] = llclamp(val, 0.f, 1.f); - out_of_range = mV[0] != val; - - val = sd[1].asReal(); - mV[1] = llclamp(val, 0.f, 1.f); - out_of_range |= mV[1] != val; - - val = sd[2].asReal(); - mV[2] = llclamp(val, 0.f, 1.f); - out_of_range |= mV[2] != val; - - val = sd[3].asReal(); - mV[3] = llclamp(val, 0.f, 1.f); - out_of_range |= mV[3] != val; - - if (out_of_range) - { - LL_WARNS() << "LLSD color value out of range!" << LL_ENDL; - } -#else - mV[0] = (F32) sd[0].asReal(); - mV[1] = (F32) sd[1].asReal(); - mV[2] = (F32) sd[2].asReal(); - mV[3] = (F32) sd[3].asReal(); -#endif -} - -const LLColor4& LLColor4::operator=(const LLColor3 &a) -{ - mV[VX] = a.mV[VX]; - mV[VY] = a.mV[VY]; - mV[VZ] = a.mV[VZ]; - -// converting from an rgb sets a=1 (opaque) - mV[VW] = 1.f; - return (*this); -} - - -std::ostream& operator<<(std::ostream& s, const LLColor4 &a) -{ - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }"; - return s; -} - -bool operator==(const LLColor4 &a, const LLColor3 &b) -{ - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ])); -} - -bool operator!=(const LLColor4 &a, const LLColor3 &b) -{ - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ])); -} - -LLColor3 vec4to3(const LLColor4 &vec) -{ - LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); - return temp; -} - -LLColor4 vec3to4(const LLColor3 &vec) -{ - LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); - return temp; -} - -static F32 hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) -{ - if ( valHUeIn < 0.0f ) valHUeIn += 1.0f; - if ( valHUeIn > 1.0f ) valHUeIn -= 1.0f; - if ( ( 6.0f * valHUeIn ) < 1.0f ) return ( val1In + ( val2In - val1In ) * 6.0f * valHUeIn ); - if ( ( 2.0f * valHUeIn ) < 1.0f ) return ( val2In ); - if ( ( 3.0f * valHUeIn ) < 2.0f ) return ( val1In + ( val2In - val1In ) * ( ( 2.0f / 3.0f ) - valHUeIn ) * 6.0f ); - return ( val1In ); -} - -void LLColor4::setHSL ( F32 hValIn, F32 sValIn, F32 lValIn) -{ - if ( sValIn < 0.00001f ) - { - mV[VRED] = lValIn; - mV[VGREEN] = lValIn; - mV[VBLUE] = lValIn; - } - else - { - F32 interVal1; - F32 interVal2; - - if ( lValIn < 0.5f ) - interVal2 = lValIn * ( 1.0f + sValIn ); - else - interVal2 = ( lValIn + sValIn ) - ( sValIn * lValIn ); - - interVal1 = 2.0f * lValIn - interVal2; - - mV[VRED] = hueToRgb ( interVal1, interVal2, hValIn + ( 1.f / 3.f ) ); - mV[VGREEN] = hueToRgb ( interVal1, interVal2, hValIn ); - mV[VBLUE] = hueToRgb ( interVal1, interVal2, hValIn - ( 1.f / 3.f ) ); - } -} - -void LLColor4::calcHSL(F32* hue, F32* saturation, F32* luminance) const -{ - F32 var_R = mV[VRED]; - F32 var_G = mV[VGREEN]; - F32 var_B = mV[VBLUE]; - - F32 var_Min = ( var_R < ( var_G < var_B ? var_G : var_B ) ? var_R : ( var_G < var_B ? var_G : var_B ) ); - F32 var_Max = ( var_R > ( var_G > var_B ? var_G : var_B ) ? var_R : ( var_G > var_B ? var_G : var_B ) ); - - F32 del_Max = var_Max - var_Min; - - F32 L = ( var_Max + var_Min ) / 2.0f; - F32 H = 0.0f; - F32 S = 0.0f; - - if ( del_Max == 0.0f ) - { - H = 0.0f; - S = 0.0f; - } - else - { - if ( L < 0.5 ) - S = del_Max / ( var_Max + var_Min ); - else - S = del_Max / ( 2.0f - var_Max - var_Min ); - - F32 del_R = ( ( ( var_Max - var_R ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; - F32 del_G = ( ( ( var_Max - var_G ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; - F32 del_B = ( ( ( var_Max - var_B ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; - - if ( var_R >= var_Max ) - H = del_B - del_G; - else - if ( var_G >= var_Max ) - H = ( 1.0f / 3.0f ) + del_R - del_B; - else - if ( var_B >= var_Max ) - H = ( 2.0f / 3.0f ) + del_G - del_R; - - if ( H < 0.0f ) H += 1.0f; - if ( H > 1.0f ) H -= 1.0f; - } - - if (hue) *hue = H; - if (saturation) *saturation = S; - if (luminance) *luminance = L; -} - -// static -bool LLColor4::parseColor(const std::string& buf, LLColor4* color) -{ - if( buf.empty() || color == nullptr) - { - return false; - } - - boost_tokenizer tokens(buf, boost::char_separator(", ")); - boost_tokenizer::iterator token_iter = tokens.begin(); - if (token_iter == tokens.end()) - { - return false; - } - - // Grab the first token into a string, since we don't know - // if this is a float or a color name. - std::string color_name( (*token_iter) ); - ++token_iter; - - if (token_iter != tokens.end()) - { - // There are more tokens to read. This must be a vector. - LLColor4 v; - LLStringUtil::convertToF32( color_name, v.mV[VX] ); - LLStringUtil::convertToF32( *token_iter, v.mV[VY] ); - v.mV[VZ] = 0.0f; - v.mV[VW] = 1.0f; - - ++token_iter; - if (token_iter == tokens.end()) - { - // This is a malformed vector. - LL_WARNS() << "LLColor4::parseColor() malformed color " << buf << LL_ENDL; - } - else - { - // There is a z-component. - LLStringUtil::convertToF32( *token_iter, v.mV[VZ] ); - - ++token_iter; - if (token_iter != tokens.end()) - { - // There is an alpha component. - LLStringUtil::convertToF32( *token_iter, v.mV[VW] ); - } - } - - // Make sure all values are between 0 and 1. - if (v.mV[VX] > 1.f || v.mV[VY] > 1.f || v.mV[VZ] > 1.f || v.mV[VW] > 1.f) - { - v = v * (1.f / 255.f); - } - color->set( v ); - } - else // Single value. Read as a named color. - { - // We have a color name - if ( "red" == color_name ) - { - color->set(LLColor4::red); - } - else if ( "red1" == color_name ) - { - color->set(LLColor4::red1); - } - else if ( "red2" == color_name ) - { - color->set(LLColor4::red2); - } - else if ( "red3" == color_name ) - { - color->set(LLColor4::red3); - } - else if ( "red4" == color_name ) - { - color->set(LLColor4::red4); - } - else if ( "red5" == color_name ) - { - color->set(LLColor4::red5); - } - else if( "green" == color_name ) - { - color->set(LLColor4::green); - } - else if( "green1" == color_name ) - { - color->set(LLColor4::green1); - } - else if( "green2" == color_name ) - { - color->set(LLColor4::green2); - } - else if( "green3" == color_name ) - { - color->set(LLColor4::green3); - } - else if( "green4" == color_name ) - { - color->set(LLColor4::green4); - } - else if( "green5" == color_name ) - { - color->set(LLColor4::green5); - } - else if( "green6" == color_name ) - { - color->set(LLColor4::green6); - } - else if( "blue" == color_name ) - { - color->set(LLColor4::blue); - } - else if( "blue1" == color_name ) - { - color->set(LLColor4::blue1); - } - else if( "blue2" == color_name ) - { - color->set(LLColor4::blue2); - } - else if( "blue3" == color_name ) - { - color->set(LLColor4::blue3); - } - else if( "blue4" == color_name ) - { - color->set(LLColor4::blue4); - } - else if( "blue5" == color_name ) - { - color->set(LLColor4::blue5); - } - else if( "blue6" == color_name ) - { - color->set(LLColor4::blue6); - } - else if( "black" == color_name ) - { - color->set(LLColor4::black); - } - else if( "white" == color_name ) - { - color->set(LLColor4::white); - } - else if( "yellow" == color_name ) - { - color->set(LLColor4::yellow); - } - else if( "yellow1" == color_name ) - { - color->set(LLColor4::yellow1); - } - else if( "yellow2" == color_name ) - { - color->set(LLColor4::yellow2); - } - else if( "yellow3" == color_name ) - { - color->set(LLColor4::yellow3); - } - else if( "yellow4" == color_name ) - { - color->set(LLColor4::yellow4); - } - else if( "yellow5" == color_name ) - { - color->set(LLColor4::yellow5); - } - else if( "yellow6" == color_name ) - { - color->set(LLColor4::yellow6); - } - else if( "magenta" == color_name ) - { - color->set(LLColor4::magenta); - } - else if( "magenta1" == color_name ) - { - color->set(LLColor4::magenta1); - } - else if( "magenta2" == color_name ) - { - color->set(LLColor4::magenta2); - } - else if( "magenta3" == color_name ) - { - color->set(LLColor4::magenta3); - } - else if( "magenta4" == color_name ) - { - color->set(LLColor4::magenta4); - } - else if( "purple" == color_name ) - { - color->set(LLColor4::purple); - } - else if( "purple1" == color_name ) - { - color->set(LLColor4::purple1); - } - else if( "purple2" == color_name ) - { - color->set(LLColor4::purple2); - } - else if( "purple3" == color_name ) - { - color->set(LLColor4::purple3); - } - else if( "purple4" == color_name ) - { - color->set(LLColor4::purple4); - } - else if( "purple5" == color_name ) - { - color->set(LLColor4::purple5); - } - else if( "purple6" == color_name ) - { - color->set(LLColor4::purple6); - } - else if( "pink" == color_name ) - { - color->set(LLColor4::pink); - } - else if( "pink1" == color_name ) - { - color->set(LLColor4::pink1); - } - else if( "pink2" == color_name ) - { - color->set(LLColor4::pink2); - } - else if( "cyan" == color_name ) - { - color->set(LLColor4::cyan); - } - else if( "cyan1" == color_name ) - { - color->set(LLColor4::cyan1); - } - else if( "cyan2" == color_name ) - { - color->set(LLColor4::cyan2); - } - else if( "cyan3" == color_name ) - { - color->set(LLColor4::cyan3); - } - else if( "cyan4" == color_name ) - { - color->set(LLColor4::cyan4); - } - else if( "cyan5" == color_name ) - { - color->set(LLColor4::cyan5); - } - else if( "cyan6" == color_name ) - { - color->set(LLColor4::cyan6); - } - else if( "smoke" == color_name ) - { - color->set(LLColor4::smoke); - } - else if( "grey" == color_name ) - { - color->set(LLColor4::grey); - } - else if( "grey1" == color_name ) - { - color->set(LLColor4::grey1); - } - else if( "grey2" == color_name ) - { - color->set(LLColor4::grey2); - } - else if( "grey3" == color_name ) - { - color->set(LLColor4::grey3); - } - else if( "grey4" == color_name ) - { - color->set(LLColor4::grey4); - } - else if( "orange" == color_name ) - { - color->set(LLColor4::orange); - } - else if( "orange1" == color_name ) - { - color->set(LLColor4::orange1); - } - else if( "orange2" == color_name ) - { - color->set(LLColor4::orange2); - } - else if( "orange3" == color_name ) - { - color->set(LLColor4::orange3); - } - else if( "orange4" == color_name ) - { - color->set(LLColor4::orange4); - } - else if( "orange5" == color_name ) - { - color->set(LLColor4::orange5); - } - else if( "orange6" == color_name ) - { - color->set(LLColor4::orange6); - } - else if ( "clear" == color_name ) - { - color->set(0.f, 0.f, 0.f, 0.f); - } - else - { - LL_WARNS() << "invalid color " << color_name << LL_ENDL; - } - } - - return true; -} - -// static -bool LLColor4::parseColor4(const std::string& buf, LLColor4* value) -{ - if( buf.empty() || value == nullptr) - { - return false; - } - - LLColor4 v; - S32 count = sscanf( buf.c_str(), "%f, %f, %f, %f", v.mV + 0, v.mV + 1, v.mV + 2, v.mV + 3 ); - if (1 == count ) - { - // try this format - count = sscanf( buf.c_str(), "%f %f %f %f", v.mV + 0, v.mV + 1, v.mV + 2, v.mV + 3 ); - } - if( 4 == count ) - { - value->setVec( v ); - return true; - } - - return false; -} - -// EOF +/** + * @file v4color.cpp + * @brief LLColor4 class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llboost.h" + +#include "v4color.h" +#include "v4coloru.h" +#include "v3color.h" +#include "v4math.h" +#include "llmath.h" + +// LLColor4 + +////////////////////////////////////////////////////////////////////////////// + +LLColor4 LLColor4::red( 1.f, 0.f, 0.f, 1.f); +LLColor4 LLColor4::green( 0.f, 1.f, 0.f, 1.f); +LLColor4 LLColor4::blue( 0.f, 0.f, 1.f, 1.f); +LLColor4 LLColor4::black( 0.f, 0.f, 0.f, 1.f); +LLColor4 LLColor4::yellow( 1.f, 1.f, 0.f, 1.f); +LLColor4 LLColor4::magenta( 1.0f, 0.0f, 1.0f, 1.0f); +LLColor4 LLColor4::cyan( 0.0f, 1.0f, 1.0f, 1.0f); +LLColor4 LLColor4::white( 1.f, 1.f, 1.f, 1.f); +LLColor4 LLColor4::smoke( 0.5f, 0.5f, 0.5f, 0.5f); +LLColor4 LLColor4::grey( 0.5f, 0.5f, 0.5f, 1.0f); +LLColor4 LLColor4::orange( 1.f, 0.5, 0.f, 1.f ); +LLColor4 LLColor4::purple( 0.6f, 0.2f, 0.8f, 1.0f); +LLColor4 LLColor4::pink( 1.0f, 0.5f, 0.8f, 1.0f); +LLColor4 LLColor4::transparent( 0.f, 0.f, 0.f, 0.f ); + +////////////////////////////////////////////////////////////////////////////// + +LLColor4 LLColor4::grey1(0.8f, 0.8f, 0.8f, 1.0f); +LLColor4 LLColor4::grey2(0.6f, 0.6f, 0.6f, 1.0f); +LLColor4 LLColor4::grey3(0.4f, 0.4f, 0.4f, 1.0f); +LLColor4 LLColor4::grey4(0.3f, 0.3f, 0.3f, 1.0f); + +LLColor4 LLColor4::red1(1.0f, 0.0f, 0.0f, 1.0f); +LLColor4 LLColor4::red2(0.6f, 0.0f, 0.0f, 1.0f); +LLColor4 LLColor4::red3(1.0f, 0.2f, 0.2f, 1.0f); +LLColor4 LLColor4::red4(0.5f, 0.1f, 0.1f, 1.0f); +LLColor4 LLColor4::red5(0.8f, 0.1f, 0.0f, 1.0f); + +LLColor4 LLColor4::green1(0.0f, 1.0f, 0.0f, 1.0f); +LLColor4 LLColor4::green2(0.0f, 0.6f, 0.0f, 1.0f); +LLColor4 LLColor4::green3(0.0f, 0.4f, 0.0f, 1.0f); +LLColor4 LLColor4::green4(0.0f, 1.0f, 0.4f, 1.0f); +LLColor4 LLColor4::green5(0.2f, 0.6f, 0.4f, 1.0f); +LLColor4 LLColor4::green6(0.4f, 0.6f, 0.2f, 1.0f); + +LLColor4 LLColor4::blue1(0.0f, 0.0f, 1.0f, 1.0f); +LLColor4 LLColor4::blue2(0.0f, 0.4f, 1.0f, 1.0f); +LLColor4 LLColor4::blue3(0.2f, 0.2f, 0.8f, 1.0f); +LLColor4 LLColor4::blue4(0.0f, 0.0f, 0.6f, 1.0f); +LLColor4 LLColor4::blue5(0.4f, 0.2f, 1.0f, 1.0f); +LLColor4 LLColor4::blue6(0.4f, 0.5f, 1.0f, 1.0f); + +LLColor4 LLColor4::yellow1(1.0f, 1.0f, 0.0f, 1.0f); +LLColor4 LLColor4::yellow2(0.6f, 0.6f, 0.0f, 1.0f); +LLColor4 LLColor4::yellow3(0.8f, 1.0f, 0.2f, 1.0f); +LLColor4 LLColor4::yellow4(1.0f, 1.0f, 0.4f, 1.0f); +LLColor4 LLColor4::yellow5(0.6f, 0.4f, 0.2f, 1.0f); +LLColor4 LLColor4::yellow6(1.0f, 0.8f, 0.4f, 1.0f); +LLColor4 LLColor4::yellow7(0.8f, 0.8f, 0.0f, 1.0f); +LLColor4 LLColor4::yellow8(0.8f, 0.8f, 0.2f, 1.0f); +LLColor4 LLColor4::yellow9(0.8f, 0.8f, 0.4f, 1.0f); + +LLColor4 LLColor4::orange1(1.0f, 0.8f, 0.0f, 1.0f); +LLColor4 LLColor4::orange2(1.0f, 0.6f, 0.0f, 1.0f); +LLColor4 LLColor4::orange3(1.0f, 0.4f, 0.2f, 1.0f); +LLColor4 LLColor4::orange4(0.8f, 0.4f, 0.0f, 1.0f); +LLColor4 LLColor4::orange5(0.9f, 0.5f, 0.0f, 1.0f); +LLColor4 LLColor4::orange6(1.0f, 0.8f, 0.2f, 1.0f); + +LLColor4 LLColor4::magenta1(1.0f, 0.0f, 1.0f, 1.0f); +LLColor4 LLColor4::magenta2(0.6f, 0.2f, 0.4f, 1.0f); +LLColor4 LLColor4::magenta3(1.0f, 0.4f, 0.6f, 1.0f); +LLColor4 LLColor4::magenta4(1.0f, 0.2f, 0.8f, 1.0f); + +LLColor4 LLColor4::purple1(0.6f, 0.2f, 0.8f, 1.0f); +LLColor4 LLColor4::purple2(0.8f, 0.2f, 1.0f, 1.0f); +LLColor4 LLColor4::purple3(0.6f, 0.0f, 1.0f, 1.0f); +LLColor4 LLColor4::purple4(0.4f, 0.0f, 0.8f, 1.0f); +LLColor4 LLColor4::purple5(0.6f, 0.0f, 0.8f, 1.0f); +LLColor4 LLColor4::purple6(0.8f, 0.0f, 0.6f, 1.0f); + +LLColor4 LLColor4::pink1(1.0f, 0.5f, 0.8f, 1.0f); +LLColor4 LLColor4::pink2(1.0f, 0.8f, 0.9f, 1.0f); + +LLColor4 LLColor4::cyan1(0.0f, 1.0f, 1.0f, 1.0f); +LLColor4 LLColor4::cyan2(0.4f, 0.8f, 0.8f, 1.0f); +LLColor4 LLColor4::cyan3(0.0f, 1.0f, 0.6f, 1.0f); +LLColor4 LLColor4::cyan4(0.6f, 1.0f, 1.0f, 1.0f); +LLColor4 LLColor4::cyan5(0.2f, 0.6f, 1.0f, 1.0f); +LLColor4 LLColor4::cyan6(0.2f, 0.6f, 0.6f, 1.0f); + +////////////////////////////////////////////////////////////////////////////// + +// conversion +LLColor4::operator LLColor4U() const +{ + return LLColor4U( + (U8)llclampb(ll_round(mV[VRED]*255.f)), + (U8)llclampb(ll_round(mV[VGREEN]*255.f)), + (U8)llclampb(ll_round(mV[VBLUE]*255.f)), + (U8)llclampb(ll_round(mV[VALPHA]*255.f))); +} + +LLColor4::LLColor4(const LLColor3 &vec, F32 a) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = a; +} + +LLColor4::LLColor4(const LLColor4U& color4u) +{ + const F32 SCALE = 1.f/255.f; + mV[VX] = color4u.mV[VX] * SCALE; + mV[VY] = color4u.mV[VY] * SCALE; + mV[VZ] = color4u.mV[VZ] * SCALE; + mV[VW] = color4u.mV[VW] * SCALE; +} + +LLColor4::LLColor4(const LLVector4& vector4) +{ + mV[VX] = vector4.mV[VX]; + mV[VY] = vector4.mV[VY]; + mV[VZ] = vector4.mV[VZ]; + mV[VW] = vector4.mV[VW]; +} + +const LLColor4& LLColor4::set(const LLColor4U& color4u) +{ + const F32 SCALE = 1.f/255.f; + mV[VX] = color4u.mV[VX] * SCALE; + mV[VY] = color4u.mV[VY] * SCALE; + mV[VZ] = color4u.mV[VZ] * SCALE; + mV[VW] = color4u.mV[VW] * SCALE; + return (*this); +} + +const LLColor4& LLColor4::set(const LLColor3 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + +// no change to alpha! +// mV[VW] = 1.f; + + return (*this); +} + +const LLColor4& LLColor4::set(const LLColor3 &vec, F32 a) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = a; + return (*this); +} + +// deprecated -- use set() +const LLColor4& LLColor4::setVec(const LLColor4U& color4u) +{ + const F32 SCALE = 1.f/255.f; + mV[VX] = color4u.mV[VX] * SCALE; + mV[VY] = color4u.mV[VY] * SCALE; + mV[VZ] = color4u.mV[VZ] * SCALE; + mV[VW] = color4u.mV[VW] * SCALE; + return (*this); +} + +// deprecated -- use set() +const LLColor4& LLColor4::setVec(const LLColor3 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + +// no change to alpha! +// mV[VW] = 1.f; + + return (*this); +} + +// deprecated -- use set() +const LLColor4& LLColor4::setVec(const LLColor3 &vec, F32 a) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = a; + return (*this); +} + +void LLColor4::setValue(const LLSD& sd) +{ +#if 0 + // Clamping on setValue from LLSD is inconsistent with other set behavior + F32 val; + bool out_of_range = false; + val = sd[0].asReal(); + mV[0] = llclamp(val, 0.f, 1.f); + out_of_range = mV[0] != val; + + val = sd[1].asReal(); + mV[1] = llclamp(val, 0.f, 1.f); + out_of_range |= mV[1] != val; + + val = sd[2].asReal(); + mV[2] = llclamp(val, 0.f, 1.f); + out_of_range |= mV[2] != val; + + val = sd[3].asReal(); + mV[3] = llclamp(val, 0.f, 1.f); + out_of_range |= mV[3] != val; + + if (out_of_range) + { + LL_WARNS() << "LLSD color value out of range!" << LL_ENDL; + } +#else + mV[0] = (F32) sd[0].asReal(); + mV[1] = (F32) sd[1].asReal(); + mV[2] = (F32) sd[2].asReal(); + mV[3] = (F32) sd[3].asReal(); +#endif +} + +const LLColor4& LLColor4::operator=(const LLColor3 &a) +{ + mV[VX] = a.mV[VX]; + mV[VY] = a.mV[VY]; + mV[VZ] = a.mV[VZ]; + +// converting from an rgb sets a=1 (opaque) + mV[VW] = 1.f; + return (*this); +} + + +std::ostream& operator<<(std::ostream& s, const LLColor4 &a) +{ + s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }"; + return s; +} + +bool operator==(const LLColor4 &a, const LLColor3 &b) +{ + return ( (a.mV[VX] == b.mV[VX]) + &&(a.mV[VY] == b.mV[VY]) + &&(a.mV[VZ] == b.mV[VZ])); +} + +bool operator!=(const LLColor4 &a, const LLColor3 &b) +{ + return ( (a.mV[VX] != b.mV[VX]) + ||(a.mV[VY] != b.mV[VY]) + ||(a.mV[VZ] != b.mV[VZ])); +} + +LLColor3 vec4to3(const LLColor4 &vec) +{ + LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); + return temp; +} + +LLColor4 vec3to4(const LLColor3 &vec) +{ + LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); + return temp; +} + +static F32 hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) +{ + if ( valHUeIn < 0.0f ) valHUeIn += 1.0f; + if ( valHUeIn > 1.0f ) valHUeIn -= 1.0f; + if ( ( 6.0f * valHUeIn ) < 1.0f ) return ( val1In + ( val2In - val1In ) * 6.0f * valHUeIn ); + if ( ( 2.0f * valHUeIn ) < 1.0f ) return ( val2In ); + if ( ( 3.0f * valHUeIn ) < 2.0f ) return ( val1In + ( val2In - val1In ) * ( ( 2.0f / 3.0f ) - valHUeIn ) * 6.0f ); + return ( val1In ); +} + +void LLColor4::setHSL ( F32 hValIn, F32 sValIn, F32 lValIn) +{ + if ( sValIn < 0.00001f ) + { + mV[VRED] = lValIn; + mV[VGREEN] = lValIn; + mV[VBLUE] = lValIn; + } + else + { + F32 interVal1; + F32 interVal2; + + if ( lValIn < 0.5f ) + interVal2 = lValIn * ( 1.0f + sValIn ); + else + interVal2 = ( lValIn + sValIn ) - ( sValIn * lValIn ); + + interVal1 = 2.0f * lValIn - interVal2; + + mV[VRED] = hueToRgb ( interVal1, interVal2, hValIn + ( 1.f / 3.f ) ); + mV[VGREEN] = hueToRgb ( interVal1, interVal2, hValIn ); + mV[VBLUE] = hueToRgb ( interVal1, interVal2, hValIn - ( 1.f / 3.f ) ); + } +} + +void LLColor4::calcHSL(F32* hue, F32* saturation, F32* luminance) const +{ + F32 var_R = mV[VRED]; + F32 var_G = mV[VGREEN]; + F32 var_B = mV[VBLUE]; + + F32 var_Min = ( var_R < ( var_G < var_B ? var_G : var_B ) ? var_R : ( var_G < var_B ? var_G : var_B ) ); + F32 var_Max = ( var_R > ( var_G > var_B ? var_G : var_B ) ? var_R : ( var_G > var_B ? var_G : var_B ) ); + + F32 del_Max = var_Max - var_Min; + + F32 L = ( var_Max + var_Min ) / 2.0f; + F32 H = 0.0f; + F32 S = 0.0f; + + if ( del_Max == 0.0f ) + { + H = 0.0f; + S = 0.0f; + } + else + { + if ( L < 0.5 ) + S = del_Max / ( var_Max + var_Min ); + else + S = del_Max / ( 2.0f - var_Max - var_Min ); + + F32 del_R = ( ( ( var_Max - var_R ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; + F32 del_G = ( ( ( var_Max - var_G ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; + F32 del_B = ( ( ( var_Max - var_B ) / 6.0f ) + ( del_Max / 2.0f ) ) / del_Max; + + if ( var_R >= var_Max ) + H = del_B - del_G; + else + if ( var_G >= var_Max ) + H = ( 1.0f / 3.0f ) + del_R - del_B; + else + if ( var_B >= var_Max ) + H = ( 2.0f / 3.0f ) + del_G - del_R; + + if ( H < 0.0f ) H += 1.0f; + if ( H > 1.0f ) H -= 1.0f; + } + + if (hue) *hue = H; + if (saturation) *saturation = S; + if (luminance) *luminance = L; +} + +// static +bool LLColor4::parseColor(const std::string& buf, LLColor4* color) +{ + if( buf.empty() || color == nullptr) + { + return false; + } + + boost_tokenizer tokens(buf, boost::char_separator(", ")); + boost_tokenizer::iterator token_iter = tokens.begin(); + if (token_iter == tokens.end()) + { + return false; + } + + // Grab the first token into a string, since we don't know + // if this is a float or a color name. + std::string color_name( (*token_iter) ); + ++token_iter; + + if (token_iter != tokens.end()) + { + // There are more tokens to read. This must be a vector. + LLColor4 v; + LLStringUtil::convertToF32( color_name, v.mV[VX] ); + LLStringUtil::convertToF32( *token_iter, v.mV[VY] ); + v.mV[VZ] = 0.0f; + v.mV[VW] = 1.0f; + + ++token_iter; + if (token_iter == tokens.end()) + { + // This is a malformed vector. + LL_WARNS() << "LLColor4::parseColor() malformed color " << buf << LL_ENDL; + } + else + { + // There is a z-component. + LLStringUtil::convertToF32( *token_iter, v.mV[VZ] ); + + ++token_iter; + if (token_iter != tokens.end()) + { + // There is an alpha component. + LLStringUtil::convertToF32( *token_iter, v.mV[VW] ); + } + } + + // Make sure all values are between 0 and 1. + if (v.mV[VX] > 1.f || v.mV[VY] > 1.f || v.mV[VZ] > 1.f || v.mV[VW] > 1.f) + { + v = v * (1.f / 255.f); + } + color->set( v ); + } + else // Single value. Read as a named color. + { + // We have a color name + if ( "red" == color_name ) + { + color->set(LLColor4::red); + } + else if ( "red1" == color_name ) + { + color->set(LLColor4::red1); + } + else if ( "red2" == color_name ) + { + color->set(LLColor4::red2); + } + else if ( "red3" == color_name ) + { + color->set(LLColor4::red3); + } + else if ( "red4" == color_name ) + { + color->set(LLColor4::red4); + } + else if ( "red5" == color_name ) + { + color->set(LLColor4::red5); + } + else if( "green" == color_name ) + { + color->set(LLColor4::green); + } + else if( "green1" == color_name ) + { + color->set(LLColor4::green1); + } + else if( "green2" == color_name ) + { + color->set(LLColor4::green2); + } + else if( "green3" == color_name ) + { + color->set(LLColor4::green3); + } + else if( "green4" == color_name ) + { + color->set(LLColor4::green4); + } + else if( "green5" == color_name ) + { + color->set(LLColor4::green5); + } + else if( "green6" == color_name ) + { + color->set(LLColor4::green6); + } + else if( "blue" == color_name ) + { + color->set(LLColor4::blue); + } + else if( "blue1" == color_name ) + { + color->set(LLColor4::blue1); + } + else if( "blue2" == color_name ) + { + color->set(LLColor4::blue2); + } + else if( "blue3" == color_name ) + { + color->set(LLColor4::blue3); + } + else if( "blue4" == color_name ) + { + color->set(LLColor4::blue4); + } + else if( "blue5" == color_name ) + { + color->set(LLColor4::blue5); + } + else if( "blue6" == color_name ) + { + color->set(LLColor4::blue6); + } + else if( "black" == color_name ) + { + color->set(LLColor4::black); + } + else if( "white" == color_name ) + { + color->set(LLColor4::white); + } + else if( "yellow" == color_name ) + { + color->set(LLColor4::yellow); + } + else if( "yellow1" == color_name ) + { + color->set(LLColor4::yellow1); + } + else if( "yellow2" == color_name ) + { + color->set(LLColor4::yellow2); + } + else if( "yellow3" == color_name ) + { + color->set(LLColor4::yellow3); + } + else if( "yellow4" == color_name ) + { + color->set(LLColor4::yellow4); + } + else if( "yellow5" == color_name ) + { + color->set(LLColor4::yellow5); + } + else if( "yellow6" == color_name ) + { + color->set(LLColor4::yellow6); + } + else if( "magenta" == color_name ) + { + color->set(LLColor4::magenta); + } + else if( "magenta1" == color_name ) + { + color->set(LLColor4::magenta1); + } + else if( "magenta2" == color_name ) + { + color->set(LLColor4::magenta2); + } + else if( "magenta3" == color_name ) + { + color->set(LLColor4::magenta3); + } + else if( "magenta4" == color_name ) + { + color->set(LLColor4::magenta4); + } + else if( "purple" == color_name ) + { + color->set(LLColor4::purple); + } + else if( "purple1" == color_name ) + { + color->set(LLColor4::purple1); + } + else if( "purple2" == color_name ) + { + color->set(LLColor4::purple2); + } + else if( "purple3" == color_name ) + { + color->set(LLColor4::purple3); + } + else if( "purple4" == color_name ) + { + color->set(LLColor4::purple4); + } + else if( "purple5" == color_name ) + { + color->set(LLColor4::purple5); + } + else if( "purple6" == color_name ) + { + color->set(LLColor4::purple6); + } + else if( "pink" == color_name ) + { + color->set(LLColor4::pink); + } + else if( "pink1" == color_name ) + { + color->set(LLColor4::pink1); + } + else if( "pink2" == color_name ) + { + color->set(LLColor4::pink2); + } + else if( "cyan" == color_name ) + { + color->set(LLColor4::cyan); + } + else if( "cyan1" == color_name ) + { + color->set(LLColor4::cyan1); + } + else if( "cyan2" == color_name ) + { + color->set(LLColor4::cyan2); + } + else if( "cyan3" == color_name ) + { + color->set(LLColor4::cyan3); + } + else if( "cyan4" == color_name ) + { + color->set(LLColor4::cyan4); + } + else if( "cyan5" == color_name ) + { + color->set(LLColor4::cyan5); + } + else if( "cyan6" == color_name ) + { + color->set(LLColor4::cyan6); + } + else if( "smoke" == color_name ) + { + color->set(LLColor4::smoke); + } + else if( "grey" == color_name ) + { + color->set(LLColor4::grey); + } + else if( "grey1" == color_name ) + { + color->set(LLColor4::grey1); + } + else if( "grey2" == color_name ) + { + color->set(LLColor4::grey2); + } + else if( "grey3" == color_name ) + { + color->set(LLColor4::grey3); + } + else if( "grey4" == color_name ) + { + color->set(LLColor4::grey4); + } + else if( "orange" == color_name ) + { + color->set(LLColor4::orange); + } + else if( "orange1" == color_name ) + { + color->set(LLColor4::orange1); + } + else if( "orange2" == color_name ) + { + color->set(LLColor4::orange2); + } + else if( "orange3" == color_name ) + { + color->set(LLColor4::orange3); + } + else if( "orange4" == color_name ) + { + color->set(LLColor4::orange4); + } + else if( "orange5" == color_name ) + { + color->set(LLColor4::orange5); + } + else if( "orange6" == color_name ) + { + color->set(LLColor4::orange6); + } + else if ( "clear" == color_name ) + { + color->set(0.f, 0.f, 0.f, 0.f); + } + else + { + LL_WARNS() << "invalid color " << color_name << LL_ENDL; + } + } + + return true; +} + +// static +bool LLColor4::parseColor4(const std::string& buf, LLColor4* value) +{ + if( buf.empty() || value == nullptr) + { + return false; + } + + LLColor4 v; + S32 count = sscanf( buf.c_str(), "%f, %f, %f, %f", v.mV + 0, v.mV + 1, v.mV + 2, v.mV + 3 ); + if (1 == count ) + { + // try this format + count = sscanf( buf.c_str(), "%f %f %f %f", v.mV + 0, v.mV + 1, v.mV + 2, v.mV + 3 ); + } + if( 4 == count ) + { + value->setVec( v ); + return true; + } + + return false; +} + +// EOF diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index b92522a5db..1e20ab977a 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -1,723 +1,723 @@ -/** - * @file v4color.h - * @brief LLColor4 class header file. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_V4COLOR_H -#define LL_V4COLOR_H - -#include "llerror.h" -//#include "vmath.h" -#include "llmath.h" -#include "llsd.h" - -class LLColor3; -class LLColor4U; -class LLVector4; - -// LLColor4 = |x y z w| - -static const U32 LENGTHOFCOLOR4 = 4; - -static const U32 MAX_LENGTH_OF_COLOR_NAME = 15; //Give plenty of room for additional colors... - -class LLColor4 -{ - public: - F32 mV[LENGTHOFCOLOR4]; - LLColor4(); // Initializes LLColor4 to (0, 0, 0, 1) - LLColor4(F32 r, F32 g, F32 b); // Initializes LLColor4 to (r, g, b, 1) - LLColor4(F32 r, F32 g, F32 b, F32 a); // Initializes LLColor4 to (r. g, b, a) - LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a) - explicit LLColor4(const LLSD& sd); - explicit LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1) - explicit LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc)) - explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion - explicit LLColor4(const LLVector4& vector4); // "explicit" to avoid automatic conversion - - LLSD getValue() const - { - LLSD ret; - ret[0] = mV[0]; - ret[1] = mV[1]; - ret[2] = mV[2]; - ret[3] = mV[3]; - return ret; - } - - void setValue(const LLSD& sd); - - void setHSL(F32 hue, F32 saturation, F32 luminance); - void calcHSL(F32* hue, F32* saturation, F32* luminance) const; - - const LLColor4& setToBlack(); // zero LLColor4 to (0, 0, 0, 1) - const LLColor4& setToWhite(); // zero LLColor4 to (0, 0, 0, 1) - - const LLColor4& setVec(F32 r, F32 g, F32 b, F32 a); // deprecated -- use set() - const LLColor4& setVec(F32 r, F32 g, F32 b); // deprecated -- use set() - const LLColor4& setVec(const LLColor4 &vec); // deprecated -- use set() - const LLColor4& setVec(const LLColor3 &vec); // deprecated -- use set() - const LLColor4& setVec(const LLColor3 &vec, F32 a); // deprecated -- use set() - const LLColor4& setVec(const F32 *vec); // deprecated -- use set() - const LLColor4& setVec(const LLColor4U& color4u); // deprecated -- use set() - - const LLColor4& set(F32 r, F32 g, F32 b, F32 a); // Sets LLColor4 to (r, g, b, a) - const LLColor4& set(F32 r, F32 g, F32 b); // Sets LLColor4 to (r, g, b) (no change in a) - const LLColor4& set(const LLColor4 &vec); // Sets LLColor4 to vec - const LLColor4& set(const LLColor3 &vec); // Sets LLColor4 to LLColor3 vec (no change in alpha) - const LLColor4& set(const LLColor3 &vec, F32 a); // Sets LLColor4 to LLColor3 vec, with alpha specified - const LLColor4& set(const F32 *vec); // Sets LLColor4 to vec - const LLColor4& set(const F64 *vec); // Sets LLColor4 to (double)vec - const LLColor4& set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled. - - // set from a vector of unknown type and size - // may leave some data unmodified - template - const LLColor4& set(const std::vector& v); - - // write to a vector of unknown type and size - // maye leave some data unmodified - template - void write(std::vector& v) const; - - const LLColor4& setAlpha(F32 a); - - F32 magVec() const; // deprecated -- use length() - F32 magVecSquared() const; // deprecated -- use lengthSquared() - F32 normVec(); // deprecated -- use normalize() - - F32 length() const; // Returns magnitude of LLColor4 - F32 lengthSquared() const; // Returns magnitude squared of LLColor4 - F32 normalize(); // deprecated -- use normalize() - - bool isOpaque() { return mV[VALPHA] == 1.f; } - - F32 operator[](int idx) const { return mV[idx]; } - F32 &operator[](int idx) { return mV[idx]; } - - 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 - friend LLColor4 operator*(const LLColor4 &a, const LLColor4 &b); // Return component wise a * b - friend LLColor4 operator*(const LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change) - friend LLColor4 operator/(const LLColor4 &a, F32 k); // Return rgb divided by scalar k (no alpha change) - friend LLColor4 operator*(F32 k, const LLColor4 &a); // Return rgb times scaler k (no alpha change) - friend LLColor4 operator%(const LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change) - friend LLColor4 operator%(F32 k, const LLColor4 &a); // Return alpha times scaler k (no rgb change) - - friend bool operator==(const LLColor4 &a, const LLColor4 &b); // Return a == b - friend bool operator!=(const LLColor4 &a, const LLColor4 &b); // Return a != b - - friend bool operator==(const LLColor4 &a, const LLColor3 &b); // Return a == b - friend bool operator!=(const LLColor4 &a, const LLColor3 &b); // Return a != b - - friend const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b); // Return vector a + b - friend const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b); // Return vector a minus b - friend const LLColor4& operator*=(LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change) - friend const LLColor4& operator%=(LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change) - - friend const LLColor4& operator*=(LLColor4 &a, const LLColor4 &b); // Doesn't multiply alpha! (for lighting) - - // conversion - operator LLColor4U() const; - - // Basic color values. - static LLColor4 red; - static LLColor4 green; - static LLColor4 blue; - static LLColor4 black; - static LLColor4 white; - static LLColor4 yellow; - static LLColor4 magenta; - static LLColor4 cyan; - static LLColor4 smoke; - static LLColor4 grey; - static LLColor4 orange; - static LLColor4 purple; - static LLColor4 pink; - static LLColor4 transparent; - - // Extra color values. - static LLColor4 grey1; - static LLColor4 grey2; - static LLColor4 grey3; - static LLColor4 grey4; - - static LLColor4 red1; - static LLColor4 red2; - static LLColor4 red3; - static LLColor4 red4; - static LLColor4 red5; - - static LLColor4 green1; - static LLColor4 green2; - static LLColor4 green3; - static LLColor4 green4; - static LLColor4 green5; - static LLColor4 green6; - - static LLColor4 blue1; - static LLColor4 blue2; - static LLColor4 blue3; - static LLColor4 blue4; - static LLColor4 blue5; - static LLColor4 blue6; - - static LLColor4 yellow1; - static LLColor4 yellow2; - static LLColor4 yellow3; - static LLColor4 yellow4; - static LLColor4 yellow5; - static LLColor4 yellow6; - static LLColor4 yellow7; - static LLColor4 yellow8; - static LLColor4 yellow9; - - static LLColor4 orange1; - static LLColor4 orange2; - static LLColor4 orange3; - static LLColor4 orange4; - static LLColor4 orange5; - static LLColor4 orange6; - - static LLColor4 magenta1; - static LLColor4 magenta2; - static LLColor4 magenta3; - static LLColor4 magenta4; - - static LLColor4 purple1; - static LLColor4 purple2; - static LLColor4 purple3; - static LLColor4 purple4; - static LLColor4 purple5; - static LLColor4 purple6; - - static LLColor4 pink1; - static LLColor4 pink2; - - static LLColor4 cyan1; - static LLColor4 cyan2; - static LLColor4 cyan3; - static LLColor4 cyan4; - static LLColor4 cyan5; - static LLColor4 cyan6; - - static bool parseColor(const std::string& buf, LLColor4* color); - static bool parseColor4(const std::string& buf, LLColor4* color); - - inline void clamp(); -}; - - -// Non-member functions -F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b -F32 distVec_squared(const LLColor4 &a, const LLColor4 &b); // Returns distance squared between a and b -LLColor3 vec4to3(const LLColor4 &vec); -LLColor4 vec3to4(const LLColor3 &vec); -LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u); - -inline LLColor4::LLColor4(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; -} - -inline LLColor4::LLColor4(const LLSD& sd) -{ - this->setValue(sd); -} - -inline LLColor4::LLColor4(F32 r, F32 g, F32 b) -{ - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = 1.f; -} - -inline LLColor4::LLColor4(F32 r, F32 g, F32 b, F32 a) -{ - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = a; -} - -inline LLColor4::LLColor4(U32 clr) -{ - mV[VX] = (clr&0xff) * (1.0f/255.0f); - mV[VY] = ((clr>>8)&0xff) * (1.0f/255.0f); - mV[VZ] = ((clr>>16)&0xff) * (1.0f/255.0f); - mV[VW] = (clr>>24) * (1.0f/255.0f); -} - - -inline LLColor4::LLColor4(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; -} - -inline const LLColor4& LLColor4::setToBlack(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; - return (*this); -} - -inline const LLColor4& LLColor4::setToWhite(void) -{ - mV[VX] = 1.f; - mV[VY] = 1.f; - mV[VZ] = 1.f; - mV[VW] = 1.f; - return (*this); -} - -inline const LLColor4& LLColor4::set(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - -// no change to alpha! -// mV[VW] = 1.f; - - return (*this); -} - -inline const LLColor4& LLColor4::set(F32 x, F32 y, F32 z, F32 a) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = a; - return (*this); -} - -inline const LLColor4& LLColor4::set(const LLColor4 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; - return (*this); -} - - -inline const LLColor4& LLColor4::set(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; - return (*this); -} - -inline const LLColor4& LLColor4::set(const F64 *vec) -{ - mV[VX] = static_cast(vec[VX]); - mV[VY] = static_cast(vec[VY]); - mV[VZ] = static_cast(vec[VZ]); - mV[VW] = static_cast(vec[VW]); - return (*this); -} - -// deprecated -inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - -// no change to alpha! -// mV[VW] = 1.f; - - return (*this); -} - -// deprecated -inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z, F32 a) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = a; - return (*this); -} - -// deprecated -inline const LLColor4& LLColor4::setVec(const LLColor4 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; - return (*this); -} - - -// deprecated -inline const LLColor4& LLColor4::setVec(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; - return (*this); -} - -inline const LLColor4& LLColor4::setAlpha(F32 a) -{ - mV[VW] = a; - return (*this); -} - -// LLColor4 Magnitude and Normalization Functions - -inline F32 LLColor4::length(void) const -{ - return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); -} - -inline F32 LLColor4::lengthSquared(void) const -{ - return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; -} - -inline F32 LLColor4::normalize(void) -{ - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); - F32 oomag; - - if (mag) - { - oomag = 1.f/mag; - mV[VX] *= oomag; - mV[VY] *= oomag; - mV[VZ] *= oomag; - } - return (mag); -} - -// deprecated -inline F32 LLColor4::magVec(void) const -{ - return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); -} - -// deprecated -inline F32 LLColor4::magVecSquared(void) const -{ - return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; -} - -// deprecated -inline F32 LLColor4::normVec(void) -{ - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); - F32 oomag; - - if (mag) - { - oomag = 1.f/mag; - mV[VX] *= oomag; - mV[VY] *= oomag; - mV[VZ] *= oomag; - } - return (mag); -} - -// LLColor4 Operators - - -inline LLColor4 operator+(const LLColor4 &a, const LLColor4 &b) -{ - return LLColor4( - a.mV[VX] + b.mV[VX], - a.mV[VY] + b.mV[VY], - a.mV[VZ] + b.mV[VZ], - a.mV[VW] + b.mV[VW]); -} - -inline LLColor4 operator-(const LLColor4 &a, const LLColor4 &b) -{ - return LLColor4( - a.mV[VX] - b.mV[VX], - a.mV[VY] - b.mV[VY], - a.mV[VZ] - b.mV[VZ], - a.mV[VW] - b.mV[VW]); -} - -inline LLColor4 operator*(const LLColor4 &a, const LLColor4 &b) -{ - return LLColor4( - a.mV[VX] * b.mV[VX], - a.mV[VY] * b.mV[VY], - a.mV[VZ] * b.mV[VZ], - a.mV[VW] * b.mV[VW]); -} - -inline LLColor4 operator*(const LLColor4 &a, F32 k) -{ - // only affects rgb (not a!) - return LLColor4( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); -} - -inline LLColor4 operator/(const LLColor4 &a, F32 k) -{ - return LLColor4( - a.mV[VX] / k, - a.mV[VY] / k, - a.mV[VZ] / k, - a.mV[VW]); -} - -inline LLColor4 operator*(F32 k, const LLColor4 &a) -{ - // only affects rgb (not a!) - return LLColor4( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); -} - -inline LLColor4 operator%(F32 k, const LLColor4 &a) -{ - // only affects alpha (not rgb!) - return LLColor4( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k); -} - -inline LLColor4 operator%(const LLColor4 &a, F32 k) -{ - // only affects alpha (not rgb!) - return LLColor4( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k); -} - -inline bool operator==(const LLColor4 &a, const LLColor4 &b) -{ - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ]) - &&(a.mV[VW] == b.mV[VW])); -} - -inline bool operator!=(const LLColor4 &a, const LLColor4 &b) -{ - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ]) - ||(a.mV[VW] != b.mV[VW])); -} - -inline const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b) -{ - a.mV[VX] += b.mV[VX]; - a.mV[VY] += b.mV[VY]; - a.mV[VZ] += b.mV[VZ]; - a.mV[VW] += b.mV[VW]; - return a; -} - -inline const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b) -{ - a.mV[VX] -= b.mV[VX]; - a.mV[VY] -= b.mV[VY]; - a.mV[VZ] -= b.mV[VZ]; - a.mV[VW] -= b.mV[VW]; - return a; -} - -inline const LLColor4& operator*=(LLColor4 &a, F32 k) -{ - // only affects rgb (not a!) - a.mV[VX] *= k; - a.mV[VY] *= k; - a.mV[VZ] *= k; - return a; -} - -inline const LLColor4& operator *=(LLColor4 &a, const LLColor4 &b) -{ - a.mV[VX] *= b.mV[VX]; - a.mV[VY] *= b.mV[VY]; - a.mV[VZ] *= b.mV[VZ]; -// a.mV[VW] *= b.mV[VW]; - return a; -} - -inline const LLColor4& operator%=(LLColor4 &a, F32 k) -{ - // only affects alpha (not rgb!) - a.mV[VW] *= k; - return a; -} - - -// Non-member functions - -inline F32 distVec(const LLColor4 &a, const LLColor4 &b) -{ - LLColor4 vec = a - b; - return (vec.length()); -} - -inline F32 distVec_squared(const LLColor4 &a, const LLColor4 &b) -{ - LLColor4 vec = a - b; - return (vec.lengthSquared()); -} - -inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u) -{ - return LLColor4( - a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, - a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, - a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * 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() -{ - // Clamp the color... - if (mV[0] < 0.f) - { - mV[0] = 0.f; - } - else if (mV[0] > 1.f) - { - mV[0] = 1.f; - } - if (mV[1] < 0.f) - { - mV[1] = 0.f; - } - else if (mV[1] > 1.f) - { - mV[1] = 1.f; - } - if (mV[2] < 0.f) - { - mV[2] = 0.f; - } - else if (mV[2] > 1.f) - { - mV[2] = 1.f; - } - if (mV[3] < 0.f) - { - mV[3] = 0.f; - } - else if (mV[3] > 1.f) - { - mV[3] = 1.f; - } -} - -// Return the given linear space color value in gamma corrected (sRGB) space -inline const LLColor4 srgbColor4(const LLColor4 &a) { - LLColor4 srgbColor; - - srgbColor.mV[0] = linearTosRGB(a.mV[0]); - srgbColor.mV[1] = linearTosRGB(a.mV[1]); - srgbColor.mV[2] = linearTosRGB(a.mV[2]); - srgbColor.mV[3] = a.mV[3]; - - return srgbColor; -} - -// Return the given gamma corrected (sRGB) color in linear space -inline const LLColor4 linearColor4(const LLColor4 &a) -{ - LLColor4 linearColor; - linearColor.mV[0] = sRGBtoLinear(a.mV[0]); - linearColor.mV[1] = sRGBtoLinear(a.mV[1]); - linearColor.mV[2] = sRGBtoLinear(a.mV[2]); - linearColor.mV[3] = a.mV[3]; - - return linearColor; -} - -template -const LLColor4& LLColor4::set(const std::vector& v) -{ - for (S32 i = 0; i < llmin((S32)v.size(), 4); ++i) - { - mV[i] = v[i]; - } - - return *this; -} - -template -void LLColor4::write(std::vector& v) const -{ - for (int i = 0; i < llmin((S32)v.size(), 4); ++i) - { - v[i] = mV[i]; - } -} - -#endif - +/** + * @file v4color.h + * @brief LLColor4 class header file. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V4COLOR_H +#define LL_V4COLOR_H + +#include "llerror.h" +//#include "vmath.h" +#include "llmath.h" +#include "llsd.h" + +class LLColor3; +class LLColor4U; +class LLVector4; + +// LLColor4 = |x y z w| + +static const U32 LENGTHOFCOLOR4 = 4; + +static const U32 MAX_LENGTH_OF_COLOR_NAME = 15; //Give plenty of room for additional colors... + +class LLColor4 +{ + public: + F32 mV[LENGTHOFCOLOR4]; + LLColor4(); // Initializes LLColor4 to (0, 0, 0, 1) + LLColor4(F32 r, F32 g, F32 b); // Initializes LLColor4 to (r, g, b, 1) + LLColor4(F32 r, F32 g, F32 b, F32 a); // Initializes LLColor4 to (r. g, b, a) + LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a) + explicit LLColor4(const LLSD& sd); + explicit LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1) + explicit LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc)) + explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion + explicit LLColor4(const LLVector4& vector4); // "explicit" to avoid automatic conversion + + LLSD getValue() const + { + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + ret[2] = mV[2]; + ret[3] = mV[3]; + return ret; + } + + void setValue(const LLSD& sd); + + void setHSL(F32 hue, F32 saturation, F32 luminance); + void calcHSL(F32* hue, F32* saturation, F32* luminance) const; + + const LLColor4& setToBlack(); // zero LLColor4 to (0, 0, 0, 1) + const LLColor4& setToWhite(); // zero LLColor4 to (0, 0, 0, 1) + + const LLColor4& setVec(F32 r, F32 g, F32 b, F32 a); // deprecated -- use set() + const LLColor4& setVec(F32 r, F32 g, F32 b); // deprecated -- use set() + const LLColor4& setVec(const LLColor4 &vec); // deprecated -- use set() + const LLColor4& setVec(const LLColor3 &vec); // deprecated -- use set() + const LLColor4& setVec(const LLColor3 &vec, F32 a); // deprecated -- use set() + const LLColor4& setVec(const F32 *vec); // deprecated -- use set() + const LLColor4& setVec(const LLColor4U& color4u); // deprecated -- use set() + + const LLColor4& set(F32 r, F32 g, F32 b, F32 a); // Sets LLColor4 to (r, g, b, a) + const LLColor4& set(F32 r, F32 g, F32 b); // Sets LLColor4 to (r, g, b) (no change in a) + const LLColor4& set(const LLColor4 &vec); // Sets LLColor4 to vec + const LLColor4& set(const LLColor3 &vec); // Sets LLColor4 to LLColor3 vec (no change in alpha) + const LLColor4& set(const LLColor3 &vec, F32 a); // Sets LLColor4 to LLColor3 vec, with alpha specified + const LLColor4& set(const F32 *vec); // Sets LLColor4 to vec + const LLColor4& set(const F64 *vec); // Sets LLColor4 to (double)vec + const LLColor4& set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled. + + // set from a vector of unknown type and size + // may leave some data unmodified + template + const LLColor4& set(const std::vector& v); + + // write to a vector of unknown type and size + // maye leave some data unmodified + template + void write(std::vector& v) const; + + const LLColor4& setAlpha(F32 a); + + F32 magVec() const; // deprecated -- use length() + F32 magVecSquared() const; // deprecated -- use lengthSquared() + F32 normVec(); // deprecated -- use normalize() + + F32 length() const; // Returns magnitude of LLColor4 + F32 lengthSquared() const; // Returns magnitude squared of LLColor4 + F32 normalize(); // deprecated -- use normalize() + + bool isOpaque() { return mV[VALPHA] == 1.f; } + + F32 operator[](int idx) const { return mV[idx]; } + F32 &operator[](int idx) { return mV[idx]; } + + 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 + friend LLColor4 operator*(const LLColor4 &a, const LLColor4 &b); // Return component wise a * b + friend LLColor4 operator*(const LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change) + friend LLColor4 operator/(const LLColor4 &a, F32 k); // Return rgb divided by scalar k (no alpha change) + friend LLColor4 operator*(F32 k, const LLColor4 &a); // Return rgb times scaler k (no alpha change) + friend LLColor4 operator%(const LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change) + friend LLColor4 operator%(F32 k, const LLColor4 &a); // Return alpha times scaler k (no rgb change) + + friend bool operator==(const LLColor4 &a, const LLColor4 &b); // Return a == b + friend bool operator!=(const LLColor4 &a, const LLColor4 &b); // Return a != b + + friend bool operator==(const LLColor4 &a, const LLColor3 &b); // Return a == b + friend bool operator!=(const LLColor4 &a, const LLColor3 &b); // Return a != b + + friend const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b); // Return vector a + b + friend const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b); // Return vector a minus b + friend const LLColor4& operator*=(LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change) + friend const LLColor4& operator%=(LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change) + + friend const LLColor4& operator*=(LLColor4 &a, const LLColor4 &b); // Doesn't multiply alpha! (for lighting) + + // conversion + operator LLColor4U() const; + + // Basic color values. + static LLColor4 red; + static LLColor4 green; + static LLColor4 blue; + static LLColor4 black; + static LLColor4 white; + static LLColor4 yellow; + static LLColor4 magenta; + static LLColor4 cyan; + static LLColor4 smoke; + static LLColor4 grey; + static LLColor4 orange; + static LLColor4 purple; + static LLColor4 pink; + static LLColor4 transparent; + + // Extra color values. + static LLColor4 grey1; + static LLColor4 grey2; + static LLColor4 grey3; + static LLColor4 grey4; + + static LLColor4 red1; + static LLColor4 red2; + static LLColor4 red3; + static LLColor4 red4; + static LLColor4 red5; + + static LLColor4 green1; + static LLColor4 green2; + static LLColor4 green3; + static LLColor4 green4; + static LLColor4 green5; + static LLColor4 green6; + + static LLColor4 blue1; + static LLColor4 blue2; + static LLColor4 blue3; + static LLColor4 blue4; + static LLColor4 blue5; + static LLColor4 blue6; + + static LLColor4 yellow1; + static LLColor4 yellow2; + static LLColor4 yellow3; + static LLColor4 yellow4; + static LLColor4 yellow5; + static LLColor4 yellow6; + static LLColor4 yellow7; + static LLColor4 yellow8; + static LLColor4 yellow9; + + static LLColor4 orange1; + static LLColor4 orange2; + static LLColor4 orange3; + static LLColor4 orange4; + static LLColor4 orange5; + static LLColor4 orange6; + + static LLColor4 magenta1; + static LLColor4 magenta2; + static LLColor4 magenta3; + static LLColor4 magenta4; + + static LLColor4 purple1; + static LLColor4 purple2; + static LLColor4 purple3; + static LLColor4 purple4; + static LLColor4 purple5; + static LLColor4 purple6; + + static LLColor4 pink1; + static LLColor4 pink2; + + static LLColor4 cyan1; + static LLColor4 cyan2; + static LLColor4 cyan3; + static LLColor4 cyan4; + static LLColor4 cyan5; + static LLColor4 cyan6; + + static bool parseColor(const std::string& buf, LLColor4* color); + static bool parseColor4(const std::string& buf, LLColor4* color); + + inline void clamp(); +}; + + +// Non-member functions +F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b +F32 distVec_squared(const LLColor4 &a, const LLColor4 &b); // Returns distance squared between a and b +LLColor3 vec4to3(const LLColor4 &vec); +LLColor4 vec3to4(const LLColor3 &vec); +LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u); + +inline LLColor4::LLColor4(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; + mV[VZ] = 0.f; + mV[VW] = 1.f; +} + +inline LLColor4::LLColor4(const LLSD& sd) +{ + this->setValue(sd); +} + +inline LLColor4::LLColor4(F32 r, F32 g, F32 b) +{ + mV[VX] = r; + mV[VY] = g; + mV[VZ] = b; + mV[VW] = 1.f; +} + +inline LLColor4::LLColor4(F32 r, F32 g, F32 b, F32 a) +{ + mV[VX] = r; + mV[VY] = g; + mV[VZ] = b; + mV[VW] = a; +} + +inline LLColor4::LLColor4(U32 clr) +{ + mV[VX] = (clr&0xff) * (1.0f/255.0f); + mV[VY] = ((clr>>8)&0xff) * (1.0f/255.0f); + mV[VZ] = ((clr>>16)&0xff) * (1.0f/255.0f); + mV[VW] = (clr>>24) * (1.0f/255.0f); +} + + +inline LLColor4::LLColor4(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; +} + +inline const LLColor4& LLColor4::setToBlack(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; + mV[VZ] = 0.f; + mV[VW] = 1.f; + return (*this); +} + +inline const LLColor4& LLColor4::setToWhite(void) +{ + mV[VX] = 1.f; + mV[VY] = 1.f; + mV[VZ] = 1.f; + mV[VW] = 1.f; + return (*this); +} + +inline const LLColor4& LLColor4::set(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + +// no change to alpha! +// mV[VW] = 1.f; + + return (*this); +} + +inline const LLColor4& LLColor4::set(F32 x, F32 y, F32 z, F32 a) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = a; + return (*this); +} + +inline const LLColor4& LLColor4::set(const LLColor4 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = vec.mV[VW]; + return (*this); +} + + +inline const LLColor4& LLColor4::set(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; + return (*this); +} + +inline const LLColor4& LLColor4::set(const F64 *vec) +{ + mV[VX] = static_cast(vec[VX]); + mV[VY] = static_cast(vec[VY]); + mV[VZ] = static_cast(vec[VZ]); + mV[VW] = static_cast(vec[VW]); + return (*this); +} + +// deprecated +inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + +// no change to alpha! +// mV[VW] = 1.f; + + return (*this); +} + +// deprecated +inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z, F32 a) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = a; + return (*this); +} + +// deprecated +inline const LLColor4& LLColor4::setVec(const LLColor4 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = vec.mV[VW]; + return (*this); +} + + +// deprecated +inline const LLColor4& LLColor4::setVec(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; + return (*this); +} + +inline const LLColor4& LLColor4::setAlpha(F32 a) +{ + mV[VW] = a; + return (*this); +} + +// LLColor4 Magnitude and Normalization Functions + +inline F32 LLColor4::length(void) const +{ + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); +} + +inline F32 LLColor4::lengthSquared(void) const +{ + return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; +} + +inline F32 LLColor4::normalize(void) +{ + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 oomag; + + if (mag) + { + oomag = 1.f/mag; + mV[VX] *= oomag; + mV[VY] *= oomag; + mV[VZ] *= oomag; + } + return (mag); +} + +// deprecated +inline F32 LLColor4::magVec(void) const +{ + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); +} + +// deprecated +inline F32 LLColor4::magVecSquared(void) const +{ + return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; +} + +// deprecated +inline F32 LLColor4::normVec(void) +{ + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 oomag; + + if (mag) + { + oomag = 1.f/mag; + mV[VX] *= oomag; + mV[VY] *= oomag; + mV[VZ] *= oomag; + } + return (mag); +} + +// LLColor4 Operators + + +inline LLColor4 operator+(const LLColor4 &a, const LLColor4 &b) +{ + return LLColor4( + a.mV[VX] + b.mV[VX], + a.mV[VY] + b.mV[VY], + a.mV[VZ] + b.mV[VZ], + a.mV[VW] + b.mV[VW]); +} + +inline LLColor4 operator-(const LLColor4 &a, const LLColor4 &b) +{ + return LLColor4( + a.mV[VX] - b.mV[VX], + a.mV[VY] - b.mV[VY], + a.mV[VZ] - b.mV[VZ], + a.mV[VW] - b.mV[VW]); +} + +inline LLColor4 operator*(const LLColor4 &a, const LLColor4 &b) +{ + return LLColor4( + a.mV[VX] * b.mV[VX], + a.mV[VY] * b.mV[VY], + a.mV[VZ] * b.mV[VZ], + a.mV[VW] * b.mV[VW]); +} + +inline LLColor4 operator*(const LLColor4 &a, F32 k) +{ + // only affects rgb (not a!) + return LLColor4( + a.mV[VX] * k, + a.mV[VY] * k, + a.mV[VZ] * k, + a.mV[VW]); +} + +inline LLColor4 operator/(const LLColor4 &a, F32 k) +{ + return LLColor4( + a.mV[VX] / k, + a.mV[VY] / k, + a.mV[VZ] / k, + a.mV[VW]); +} + +inline LLColor4 operator*(F32 k, const LLColor4 &a) +{ + // only affects rgb (not a!) + return LLColor4( + a.mV[VX] * k, + a.mV[VY] * k, + a.mV[VZ] * k, + a.mV[VW]); +} + +inline LLColor4 operator%(F32 k, const LLColor4 &a) +{ + // only affects alpha (not rgb!) + return LLColor4( + a.mV[VX], + a.mV[VY], + a.mV[VZ], + a.mV[VW] * k); +} + +inline LLColor4 operator%(const LLColor4 &a, F32 k) +{ + // only affects alpha (not rgb!) + return LLColor4( + a.mV[VX], + a.mV[VY], + a.mV[VZ], + a.mV[VW] * k); +} + +inline bool operator==(const LLColor4 &a, const LLColor4 &b) +{ + return ( (a.mV[VX] == b.mV[VX]) + &&(a.mV[VY] == b.mV[VY]) + &&(a.mV[VZ] == b.mV[VZ]) + &&(a.mV[VW] == b.mV[VW])); +} + +inline bool operator!=(const LLColor4 &a, const LLColor4 &b) +{ + return ( (a.mV[VX] != b.mV[VX]) + ||(a.mV[VY] != b.mV[VY]) + ||(a.mV[VZ] != b.mV[VZ]) + ||(a.mV[VW] != b.mV[VW])); +} + +inline const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b) +{ + a.mV[VX] += b.mV[VX]; + a.mV[VY] += b.mV[VY]; + a.mV[VZ] += b.mV[VZ]; + a.mV[VW] += b.mV[VW]; + return a; +} + +inline const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b) +{ + a.mV[VX] -= b.mV[VX]; + a.mV[VY] -= b.mV[VY]; + a.mV[VZ] -= b.mV[VZ]; + a.mV[VW] -= b.mV[VW]; + return a; +} + +inline const LLColor4& operator*=(LLColor4 &a, F32 k) +{ + // only affects rgb (not a!) + a.mV[VX] *= k; + a.mV[VY] *= k; + a.mV[VZ] *= k; + return a; +} + +inline const LLColor4& operator *=(LLColor4 &a, const LLColor4 &b) +{ + a.mV[VX] *= b.mV[VX]; + a.mV[VY] *= b.mV[VY]; + a.mV[VZ] *= b.mV[VZ]; +// a.mV[VW] *= b.mV[VW]; + return a; +} + +inline const LLColor4& operator%=(LLColor4 &a, F32 k) +{ + // only affects alpha (not rgb!) + a.mV[VW] *= k; + return a; +} + + +// Non-member functions + +inline F32 distVec(const LLColor4 &a, const LLColor4 &b) +{ + LLColor4 vec = a - b; + return (vec.length()); +} + +inline F32 distVec_squared(const LLColor4 &a, const LLColor4 &b) +{ + LLColor4 vec = a - b; + return (vec.lengthSquared()); +} + +inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u) +{ + return LLColor4( + a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, + a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, + a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * 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() +{ + // Clamp the color... + if (mV[0] < 0.f) + { + mV[0] = 0.f; + } + else if (mV[0] > 1.f) + { + mV[0] = 1.f; + } + if (mV[1] < 0.f) + { + mV[1] = 0.f; + } + else if (mV[1] > 1.f) + { + mV[1] = 1.f; + } + if (mV[2] < 0.f) + { + mV[2] = 0.f; + } + else if (mV[2] > 1.f) + { + mV[2] = 1.f; + } + if (mV[3] < 0.f) + { + mV[3] = 0.f; + } + else if (mV[3] > 1.f) + { + mV[3] = 1.f; + } +} + +// Return the given linear space color value in gamma corrected (sRGB) space +inline const LLColor4 srgbColor4(const LLColor4 &a) { + LLColor4 srgbColor; + + srgbColor.mV[0] = linearTosRGB(a.mV[0]); + srgbColor.mV[1] = linearTosRGB(a.mV[1]); + srgbColor.mV[2] = linearTosRGB(a.mV[2]); + srgbColor.mV[3] = a.mV[3]; + + return srgbColor; +} + +// Return the given gamma corrected (sRGB) color in linear space +inline const LLColor4 linearColor4(const LLColor4 &a) +{ + LLColor4 linearColor; + linearColor.mV[0] = sRGBtoLinear(a.mV[0]); + linearColor.mV[1] = sRGBtoLinear(a.mV[1]); + linearColor.mV[2] = sRGBtoLinear(a.mV[2]); + linearColor.mV[3] = a.mV[3]; + + return linearColor; +} + +template +const LLColor4& LLColor4::set(const std::vector& v) +{ + for (S32 i = 0; i < llmin((S32)v.size(), 4); ++i) + { + mV[i] = v[i]; + } + + return *this; +} + +template +void LLColor4::write(std::vector& v) const +{ + for (int i = 0; i < llmin((S32)v.size(), 4); ++i) + { + v[i] = mV[i]; + } +} + +#endif + diff --git a/indra/llmath/v4coloru.cpp b/indra/llmath/v4coloru.cpp index 500d8ed8ab..45d310856a 100644 --- a/indra/llmath/v4coloru.cpp +++ b/indra/llmath/v4coloru.cpp @@ -1,120 +1,120 @@ -/** - * @file v4coloru.cpp - * @brief LLColor4U class implementation. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -//#include "v3coloru.h" -#include "v4coloru.h" -#include "v4color.h" -//#include "vmath.h" -#include "llmath.h" - -// LLColor4U -LLColor4U LLColor4U::white(255, 255, 255, 255); -LLColor4U LLColor4U::black( 0, 0, 0, 255); -LLColor4U LLColor4U::red (255, 0, 0, 255); -LLColor4U LLColor4U::green( 0, 255, 0, 255); -LLColor4U LLColor4U::blue ( 0, 0, 255, 255); - -// conversion -/* inlined to fix gcc compile link error -LLColor4U::operator LLColor4() -{ - return(LLColor4((F32)mV[VRED]/255.f,(F32)mV[VGREEN]/255.f,(F32)mV[VBLUE]/255.f,(F32)mV[VALPHA]/255.f)); -} -*/ - -// Constructors - - -/* -LLColor4U::LLColor4U(const LLColor3 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = 255; -} -*/ - - -// Clear and Assignment Functions - - - -// LLColor4U Operators - -/* -LLColor4U LLColor4U::operator=(const LLColor3 &a) -{ - mV[VX] = a.mV[VX]; - mV[VY] = a.mV[VY]; - mV[VZ] = a.mV[VZ]; - -// converting from an rgb sets a=1 (opaque) - mV[VW] = 255; - return (*this); -} -*/ - - -std::ostream& operator<<(std::ostream& s, const LLColor4U &a) -{ - s << "{ " << (S32)a.mV[VX] << ", " << (S32)a.mV[VY] << ", " << (S32)a.mV[VZ] << ", " << (S32)a.mV[VW] << " }"; - return s; -} - -// static -bool LLColor4U::parseColor4U(const std::string& buf, LLColor4U* value) -{ - if( buf.empty() || value == nullptr) - { - return false; - } - - U32 v[4]; - S32 count = sscanf( buf.c_str(), "%u, %u, %u, %u", v + 0, v + 1, v + 2, v + 3 ); - if (1 == count ) - { - // try this format - count = sscanf( buf.c_str(), "%u %u %u %u", v + 0, v + 1, v + 2, v + 3 ); - } - if( 4 != count ) - { - return false; - } - - for( S32 i = 0; i < 4; i++ ) - { - if( v[i] > U8_MAX ) - { - return false; - } - } - - value->set( U8(v[0]), U8(v[1]), U8(v[2]), U8(v[3]) ); - return true; -} +/** + * @file v4coloru.cpp + * @brief LLColor4U class implementation. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +//#include "v3coloru.h" +#include "v4coloru.h" +#include "v4color.h" +//#include "vmath.h" +#include "llmath.h" + +// LLColor4U +LLColor4U LLColor4U::white(255, 255, 255, 255); +LLColor4U LLColor4U::black( 0, 0, 0, 255); +LLColor4U LLColor4U::red (255, 0, 0, 255); +LLColor4U LLColor4U::green( 0, 255, 0, 255); +LLColor4U LLColor4U::blue ( 0, 0, 255, 255); + +// conversion +/* inlined to fix gcc compile link error +LLColor4U::operator LLColor4() +{ + return(LLColor4((F32)mV[VRED]/255.f,(F32)mV[VGREEN]/255.f,(F32)mV[VBLUE]/255.f,(F32)mV[VALPHA]/255.f)); +} +*/ + +// Constructors + + +/* +LLColor4U::LLColor4U(const LLColor3 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = 255; +} +*/ + + +// Clear and Assignment Functions + + + +// LLColor4U Operators + +/* +LLColor4U LLColor4U::operator=(const LLColor3 &a) +{ + mV[VX] = a.mV[VX]; + mV[VY] = a.mV[VY]; + mV[VZ] = a.mV[VZ]; + +// converting from an rgb sets a=1 (opaque) + mV[VW] = 255; + return (*this); +} +*/ + + +std::ostream& operator<<(std::ostream& s, const LLColor4U &a) +{ + s << "{ " << (S32)a.mV[VX] << ", " << (S32)a.mV[VY] << ", " << (S32)a.mV[VZ] << ", " << (S32)a.mV[VW] << " }"; + return s; +} + +// static +bool LLColor4U::parseColor4U(const std::string& buf, LLColor4U* value) +{ + if( buf.empty() || value == nullptr) + { + return false; + } + + U32 v[4]; + S32 count = sscanf( buf.c_str(), "%u, %u, %u, %u", v + 0, v + 1, v + 2, v + 3 ); + if (1 == count ) + { + // try this format + count = sscanf( buf.c_str(), "%u %u %u %u", v + 0, v + 1, v + 2, v + 3 ); + } + if( 4 != count ) + { + return false; + } + + for( S32 i = 0; i < 4; i++ ) + { + if( v[i] > U8_MAX ) + { + return false; + } + } + + value->set( U8(v[0]), U8(v[1]), U8(v[2]), U8(v[3]) ); + return true; +} diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index ce15540866..6d921d12fa 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -1,585 +1,585 @@ -/** - * @file v4coloru.h - * @brief The LLColor4U class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_V4COLORU_H -#define LL_V4COLORU_H - -#include "llerror.h" -//#include "vmath.h" -#include "llmath.h" -//#include "v4color.h" - -#include "v3color.h" -#include "v4color.h" - -//class LLColor3U; -class LLColor4; - -// LLColor4U = | red green blue alpha | - -static const U32 LENGTHOFCOLOR4U = 4; - - -class LLColor4U -{ -public: - - U8 mV[LENGTHOFCOLOR4U]; - - LLColor4U(); // Initializes LLColor4U to (0, 0, 0, 1) - LLColor4U(U8 r, U8 g, U8 b); // Initializes LLColor4U to (r, g, b, 1) - LLColor4U(U8 r, U8 g, U8 b, U8 a); // Initializes LLColor4U to (r. g, b, a) - LLColor4U(const U8 *vec); // Initializes LLColor4U to (vec[0]. vec[1], vec[2], 1) - explicit LLColor4U(const LLSD& sd) - { - setValue(sd); - } - - void setValue(const LLSD& sd) - { - mV[0] = sd[0].asInteger(); - mV[1] = sd[1].asInteger(); - mV[2] = sd[2].asInteger(); - mV[3] = sd[3].asInteger(); - } - - LLSD getValue() const - { - LLSD ret; - ret[0] = mV[0]; - ret[1] = mV[1]; - ret[2] = mV[2]; - ret[3] = mV[3]; - return ret; - } - - const LLColor4U& setToBlack(); // zero LLColor4U to (0, 0, 0, 1) - const LLColor4U& setToWhite(); // zero LLColor4U to (0, 0, 0, 1) - - const LLColor4U& set(U8 r, U8 g, U8 b, U8 a);// Sets LLColor4U to (r, g, b, a) - const LLColor4U& set(U8 r, U8 g, U8 b); // Sets LLColor4U to (r, g, b) (no change in a) - const LLColor4U& set(const LLColor4U &vec); // Sets LLColor4U to vec - const LLColor4U& set(const U8 *vec); // Sets LLColor4U to vec - - const LLColor4U& setVec(U8 r, U8 g, U8 b, U8 a); // deprecated -- use set() - const LLColor4U& setVec(U8 r, U8 g, U8 b); // deprecated -- use set() - const LLColor4U& setVec(const LLColor4U &vec); // deprecated -- use set() - const LLColor4U& setVec(const U8 *vec); // deprecated -- use set() - - const LLColor4U& setAlpha(U8 a); - - F32 magVec() const; // deprecated -- use length() - F32 magVecSquared() const; // deprecated -- use lengthSquared() - - F32 length() const; // Returns magnitude squared of LLColor4U - F32 lengthSquared() const; // Returns magnitude squared of LLColor4U - - friend std::ostream& operator<<(std::ostream& s, const LLColor4U &a); // Print a - friend LLColor4U operator+(const LLColor4U &a, const LLColor4U &b); // Return vector a + b - friend LLColor4U operator-(const LLColor4U &a, const LLColor4U &b); // Return vector a minus b - friend LLColor4U operator*(const LLColor4U &a, const LLColor4U &b); // Return a * b - friend bool operator==(const LLColor4U &a, const LLColor4U &b); // Return a == b - friend bool operator!=(const LLColor4U &a, const LLColor4U &b); // Return a != b - - friend const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b); // Return vector a + b - friend const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b); // Return vector a minus b - friend const LLColor4U& operator*=(LLColor4U &a, U8 k); // Return rgb times scaler k (no alpha change) - friend const LLColor4U& operator%=(LLColor4U &a, U8 k); // Return alpha times scaler k (no rgb change) - - LLColor4U addClampMax(const LLColor4U &color); // Add and clamp the max - - LLColor4U multAll(const F32 k); // Multiply ALL channels by scalar k - - inline void setVecScaleClamp(const LLColor3 &color); - inline void setVecScaleClamp(const LLColor4 &color); - - static bool parseColor4U(const std::string& buf, LLColor4U* value); - - // conversion - operator LLColor4() const - { - return LLColor4(*this); - } - - U32 asRGBA() const; - void fromRGBA( U32 aVal ); - - static LLColor4U white; - static LLColor4U black; - static LLColor4U red; - static LLColor4U green; - static LLColor4U blue; -}; - - -// Non-member functions -F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b -F32 distVec_squared(const LLColor4U &a, const LLColor4U &b); // Returns distance squared between a and b - - -inline LLColor4U::LLColor4U() -{ - mV[VX] = 0; - mV[VY] = 0; - mV[VZ] = 0; - mV[VW] = 255; -} - -inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b) -{ - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = 255; -} - -inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b, U8 a) -{ - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = a; -} - -inline LLColor4U::LLColor4U(const U8 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; -} - -/* -inline LLColor4U::operator LLColor4() -{ - return(LLColor4((F32)mV[VRED]/255.f,(F32)mV[VGREEN]/255.f,(F32)mV[VBLUE]/255.f,(F32)mV[VALPHA]/255.f)); -} -*/ - -inline const LLColor4U& LLColor4U::setToBlack(void) -{ - mV[VX] = 0; - mV[VY] = 0; - mV[VZ] = 0; - mV[VW] = 255; - return (*this); -} - -inline const LLColor4U& LLColor4U::setToWhite(void) -{ - mV[VX] = 255; - mV[VY] = 255; - mV[VZ] = 255; - mV[VW] = 255; - return (*this); -} - -inline const LLColor4U& LLColor4U::set(const U8 x, const U8 y, const U8 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - -// no change to alpha! -// mV[VW] = 255; - - return (*this); -} - -inline const LLColor4U& LLColor4U::set(const U8 r, const U8 g, const U8 b, U8 a) -{ - mV[0] = r; - mV[1] = g; - mV[2] = b; - mV[3] = a; - return (*this); -} - -inline const LLColor4U& LLColor4U::set(const LLColor4U &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; - return (*this); -} - -inline const LLColor4U& LLColor4U::set(const U8 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; - return (*this); -} - -// deprecated -inline const LLColor4U& LLColor4U::setVec(const U8 x, const U8 y, const U8 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - -// no change to alpha! -// mV[VW] = 255; - - return (*this); -} - -// deprecated -inline const LLColor4U& LLColor4U::setVec(const U8 r, const U8 g, const U8 b, U8 a) -{ - mV[0] = r; - mV[1] = g; - mV[2] = b; - mV[3] = a; - return (*this); -} - -// deprecated -inline const LLColor4U& LLColor4U::setVec(const LLColor4U &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; - return (*this); -} - -// deprecated -inline const LLColor4U& LLColor4U::setVec(const U8 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; - return (*this); -} - -inline const LLColor4U& LLColor4U::setAlpha(U8 a) -{ - mV[VW] = a; - return (*this); -} - -// LLColor4U Magnitude and Normalization Functions - -inline F32 LLColor4U::length(void) const -{ - return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); -} - -inline F32 LLColor4U::lengthSquared(void) const -{ - return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ]; -} - -// deprecated -inline F32 LLColor4U::magVec(void) const -{ - return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); -} - -// deprecated -inline F32 LLColor4U::magVecSquared(void) const -{ - return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ]; -} - -inline LLColor4U operator+(const LLColor4U &a, const LLColor4U &b) -{ - return LLColor4U( - a.mV[VX] + b.mV[VX], - a.mV[VY] + b.mV[VY], - a.mV[VZ] + b.mV[VZ], - a.mV[VW] + b.mV[VW]); -} - -inline LLColor4U operator-(const LLColor4U &a, const LLColor4U &b) -{ - return LLColor4U( - a.mV[VX] - b.mV[VX], - a.mV[VY] - b.mV[VY], - a.mV[VZ] - b.mV[VZ], - a.mV[VW] - b.mV[VW]); -} - -inline LLColor4U operator*(const LLColor4U &a, const LLColor4U &b) -{ - return LLColor4U( - a.mV[VX] * b.mV[VX], - a.mV[VY] * b.mV[VY], - a.mV[VZ] * b.mV[VZ], - a.mV[VW] * b.mV[VW]); -} - -inline LLColor4U LLColor4U::addClampMax(const LLColor4U &color) -{ - return LLColor4U(llmin((S32)mV[VX] + color.mV[VX], 255), - llmin((S32)mV[VY] + color.mV[VY], 255), - llmin((S32)mV[VZ] + color.mV[VZ], 255), - llmin((S32)mV[VW] + color.mV[VW], 255)); -} - -inline LLColor4U LLColor4U::multAll(const F32 k) -{ - // Round to nearest - return LLColor4U( - (U8)ll_round(mV[VX] * k), - (U8)ll_round(mV[VY] * k), - (U8)ll_round(mV[VZ] * k), - (U8)ll_round(mV[VW] * k)); -} -/* -inline LLColor4U operator*(const LLColor4U &a, U8 k) -{ - // only affects rgb (not a!) - return LLColor4U( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); -} - -inline LLColor4U operator*(U8 k, const LLColor4U &a) -{ - // only affects rgb (not a!) - return LLColor4U( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); -} - -inline LLColor4U operator%(U8 k, const LLColor4U &a) -{ - // only affects alpha (not rgb!) - return LLColor4U( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k ); -} - -inline LLColor4U operator%(const LLColor4U &a, U8 k) -{ - // only affects alpha (not rgb!) - return LLColor4U( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k ); -} -*/ - -inline bool operator==(const LLColor4U &a, const LLColor4U &b) -{ - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ]) - &&(a.mV[VW] == b.mV[VW])); -} - -inline bool operator!=(const LLColor4U &a, const LLColor4U &b) -{ - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ]) - ||(a.mV[VW] != b.mV[VW])); -} - -inline const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b) -{ - a.mV[VX] += b.mV[VX]; - a.mV[VY] += b.mV[VY]; - a.mV[VZ] += b.mV[VZ]; - a.mV[VW] += b.mV[VW]; - return a; -} - -inline const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b) -{ - a.mV[VX] -= b.mV[VX]; - a.mV[VY] -= b.mV[VY]; - a.mV[VZ] -= b.mV[VZ]; - a.mV[VW] -= b.mV[VW]; - return a; -} - -inline const LLColor4U& operator*=(LLColor4U &a, U8 k) -{ - // only affects rgb (not a!) - a.mV[VX] *= k; - a.mV[VY] *= k; - a.mV[VZ] *= k; - return a; -} - -inline const LLColor4U& operator%=(LLColor4U &a, U8 k) -{ - // only affects alpha (not rgb!) - a.mV[VW] *= k; - return a; -} - -inline F32 distVec(const LLColor4U &a, const LLColor4U &b) -{ - LLColor4U vec = a - b; - return (vec.length()); -} - -inline F32 distVec_squared(const LLColor4U &a, const LLColor4U &b) -{ - LLColor4U vec = a - b; - return (vec.lengthSquared()); -} - -void LLColor4U::setVecScaleClamp(const LLColor4& color) -{ - F32 color_scale_factor = 255.f; - F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); - if (max_color > 1.f) - { - color_scale_factor /= max_color; - } - const S32 MAX_COLOR = 255; - S32 r = ll_round(color.mV[0] * color_scale_factor); - if (r > MAX_COLOR) - { - r = MAX_COLOR; - } - else if (r < 0) - { - r = 0; - } - mV[0] = r; - - S32 g = ll_round(color.mV[1] * color_scale_factor); - if (g > MAX_COLOR) - { - g = MAX_COLOR; - } - else if (g < 0) - { - g = 0; - } - mV[1] = g; - - S32 b = ll_round(color.mV[2] * color_scale_factor); - if (b > MAX_COLOR) - { - b = MAX_COLOR; - } - else if (b < 0) - { - b = 0; - } - mV[2] = b; - - // Alpha shouldn't be scaled, just clamped... - S32 a = ll_round(color.mV[3] * MAX_COLOR); - if (a > MAX_COLOR) - { - a = MAX_COLOR; - } - else if (a < 0) - { - a = 0; - } - mV[3] = a; -} - -void LLColor4U::setVecScaleClamp(const LLColor3& color) -{ - F32 color_scale_factor = 255.f; - F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); - if (max_color > 1.f) - { - color_scale_factor /= max_color; - } - - const S32 MAX_COLOR = 255; - S32 r = ll_round(color.mV[0] * color_scale_factor); - if (r > MAX_COLOR) - { - r = MAX_COLOR; - } - else - if (r < 0) - { - r = 0; - } - mV[0] = r; - - S32 g = ll_round(color.mV[1] * color_scale_factor); - if (g > MAX_COLOR) - { - g = MAX_COLOR; - } - else - if (g < 0) - { - g = 0; - } - mV[1] = g; - - S32 b = ll_round(color.mV[2] * color_scale_factor); - if (b > MAX_COLOR) - { - b = MAX_COLOR; - } - if (b < 0) - { - b = 0; - } - mV[2] = b; - - mV[3] = 255; -} - -inline U32 LLColor4U::asRGBA() const -{ - // Little endian: values are swapped in memory. The original code access the array like a U32, so we need to swap here - - return (mV[3] << 24) | (mV[2] << 16) | (mV[1] << 8) | mV[0]; -} - -inline void LLColor4U::fromRGBA( U32 aVal ) -{ - // Little endian: values are swapped in memory. The original code access the array like a U32, so we need to swap here - - mV[ 0 ] = aVal & 0xFF; - aVal >>= 8; - mV[ 1 ] = aVal & 0xFF; - aVal >>= 8; - mV[ 2 ] = aVal & 0xFF; - aVal >>= 8; - mV[ 3 ] = aVal & 0xFF; -} - - -#endif - +/** + * @file v4coloru.h + * @brief The LLColor4U class. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V4COLORU_H +#define LL_V4COLORU_H + +#include "llerror.h" +//#include "vmath.h" +#include "llmath.h" +//#include "v4color.h" + +#include "v3color.h" +#include "v4color.h" + +//class LLColor3U; +class LLColor4; + +// LLColor4U = | red green blue alpha | + +static const U32 LENGTHOFCOLOR4U = 4; + + +class LLColor4U +{ +public: + + U8 mV[LENGTHOFCOLOR4U]; + + LLColor4U(); // Initializes LLColor4U to (0, 0, 0, 1) + LLColor4U(U8 r, U8 g, U8 b); // Initializes LLColor4U to (r, g, b, 1) + LLColor4U(U8 r, U8 g, U8 b, U8 a); // Initializes LLColor4U to (r. g, b, a) + LLColor4U(const U8 *vec); // Initializes LLColor4U to (vec[0]. vec[1], vec[2], 1) + explicit LLColor4U(const LLSD& sd) + { + setValue(sd); + } + + void setValue(const LLSD& sd) + { + mV[0] = sd[0].asInteger(); + mV[1] = sd[1].asInteger(); + mV[2] = sd[2].asInteger(); + mV[3] = sd[3].asInteger(); + } + + LLSD getValue() const + { + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + ret[2] = mV[2]; + ret[3] = mV[3]; + return ret; + } + + const LLColor4U& setToBlack(); // zero LLColor4U to (0, 0, 0, 1) + const LLColor4U& setToWhite(); // zero LLColor4U to (0, 0, 0, 1) + + const LLColor4U& set(U8 r, U8 g, U8 b, U8 a);// Sets LLColor4U to (r, g, b, a) + const LLColor4U& set(U8 r, U8 g, U8 b); // Sets LLColor4U to (r, g, b) (no change in a) + const LLColor4U& set(const LLColor4U &vec); // Sets LLColor4U to vec + const LLColor4U& set(const U8 *vec); // Sets LLColor4U to vec + + const LLColor4U& setVec(U8 r, U8 g, U8 b, U8 a); // deprecated -- use set() + const LLColor4U& setVec(U8 r, U8 g, U8 b); // deprecated -- use set() + const LLColor4U& setVec(const LLColor4U &vec); // deprecated -- use set() + const LLColor4U& setVec(const U8 *vec); // deprecated -- use set() + + const LLColor4U& setAlpha(U8 a); + + F32 magVec() const; // deprecated -- use length() + F32 magVecSquared() const; // deprecated -- use lengthSquared() + + F32 length() const; // Returns magnitude squared of LLColor4U + F32 lengthSquared() const; // Returns magnitude squared of LLColor4U + + friend std::ostream& operator<<(std::ostream& s, const LLColor4U &a); // Print a + friend LLColor4U operator+(const LLColor4U &a, const LLColor4U &b); // Return vector a + b + friend LLColor4U operator-(const LLColor4U &a, const LLColor4U &b); // Return vector a minus b + friend LLColor4U operator*(const LLColor4U &a, const LLColor4U &b); // Return a * b + friend bool operator==(const LLColor4U &a, const LLColor4U &b); // Return a == b + friend bool operator!=(const LLColor4U &a, const LLColor4U &b); // Return a != b + + friend const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b); // Return vector a + b + friend const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b); // Return vector a minus b + friend const LLColor4U& operator*=(LLColor4U &a, U8 k); // Return rgb times scaler k (no alpha change) + friend const LLColor4U& operator%=(LLColor4U &a, U8 k); // Return alpha times scaler k (no rgb change) + + LLColor4U addClampMax(const LLColor4U &color); // Add and clamp the max + + LLColor4U multAll(const F32 k); // Multiply ALL channels by scalar k + + inline void setVecScaleClamp(const LLColor3 &color); + inline void setVecScaleClamp(const LLColor4 &color); + + static bool parseColor4U(const std::string& buf, LLColor4U* value); + + // conversion + operator LLColor4() const + { + return LLColor4(*this); + } + + U32 asRGBA() const; + void fromRGBA( U32 aVal ); + + static LLColor4U white; + static LLColor4U black; + static LLColor4U red; + static LLColor4U green; + static LLColor4U blue; +}; + + +// Non-member functions +F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b +F32 distVec_squared(const LLColor4U &a, const LLColor4U &b); // Returns distance squared between a and b + + +inline LLColor4U::LLColor4U() +{ + mV[VX] = 0; + mV[VY] = 0; + mV[VZ] = 0; + mV[VW] = 255; +} + +inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b) +{ + mV[VX] = r; + mV[VY] = g; + mV[VZ] = b; + mV[VW] = 255; +} + +inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b, U8 a) +{ + mV[VX] = r; + mV[VY] = g; + mV[VZ] = b; + mV[VW] = a; +} + +inline LLColor4U::LLColor4U(const U8 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; +} + +/* +inline LLColor4U::operator LLColor4() +{ + return(LLColor4((F32)mV[VRED]/255.f,(F32)mV[VGREEN]/255.f,(F32)mV[VBLUE]/255.f,(F32)mV[VALPHA]/255.f)); +} +*/ + +inline const LLColor4U& LLColor4U::setToBlack(void) +{ + mV[VX] = 0; + mV[VY] = 0; + mV[VZ] = 0; + mV[VW] = 255; + return (*this); +} + +inline const LLColor4U& LLColor4U::setToWhite(void) +{ + mV[VX] = 255; + mV[VY] = 255; + mV[VZ] = 255; + mV[VW] = 255; + return (*this); +} + +inline const LLColor4U& LLColor4U::set(const U8 x, const U8 y, const U8 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + +// no change to alpha! +// mV[VW] = 255; + + return (*this); +} + +inline const LLColor4U& LLColor4U::set(const U8 r, const U8 g, const U8 b, U8 a) +{ + mV[0] = r; + mV[1] = g; + mV[2] = b; + mV[3] = a; + return (*this); +} + +inline const LLColor4U& LLColor4U::set(const LLColor4U &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = vec.mV[VW]; + return (*this); +} + +inline const LLColor4U& LLColor4U::set(const U8 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; + return (*this); +} + +// deprecated +inline const LLColor4U& LLColor4U::setVec(const U8 x, const U8 y, const U8 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + +// no change to alpha! +// mV[VW] = 255; + + return (*this); +} + +// deprecated +inline const LLColor4U& LLColor4U::setVec(const U8 r, const U8 g, const U8 b, U8 a) +{ + mV[0] = r; + mV[1] = g; + mV[2] = b; + mV[3] = a; + return (*this); +} + +// deprecated +inline const LLColor4U& LLColor4U::setVec(const LLColor4U &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = vec.mV[VW]; + return (*this); +} + +// deprecated +inline const LLColor4U& LLColor4U::setVec(const U8 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; + return (*this); +} + +inline const LLColor4U& LLColor4U::setAlpha(U8 a) +{ + mV[VW] = a; + return (*this); +} + +// LLColor4U Magnitude and Normalization Functions + +inline F32 LLColor4U::length(void) const +{ + return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); +} + +inline F32 LLColor4U::lengthSquared(void) const +{ + return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ]; +} + +// deprecated +inline F32 LLColor4U::magVec(void) const +{ + return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); +} + +// deprecated +inline F32 LLColor4U::magVecSquared(void) const +{ + return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ]; +} + +inline LLColor4U operator+(const LLColor4U &a, const LLColor4U &b) +{ + return LLColor4U( + a.mV[VX] + b.mV[VX], + a.mV[VY] + b.mV[VY], + a.mV[VZ] + b.mV[VZ], + a.mV[VW] + b.mV[VW]); +} + +inline LLColor4U operator-(const LLColor4U &a, const LLColor4U &b) +{ + return LLColor4U( + a.mV[VX] - b.mV[VX], + a.mV[VY] - b.mV[VY], + a.mV[VZ] - b.mV[VZ], + a.mV[VW] - b.mV[VW]); +} + +inline LLColor4U operator*(const LLColor4U &a, const LLColor4U &b) +{ + return LLColor4U( + a.mV[VX] * b.mV[VX], + a.mV[VY] * b.mV[VY], + a.mV[VZ] * b.mV[VZ], + a.mV[VW] * b.mV[VW]); +} + +inline LLColor4U LLColor4U::addClampMax(const LLColor4U &color) +{ + return LLColor4U(llmin((S32)mV[VX] + color.mV[VX], 255), + llmin((S32)mV[VY] + color.mV[VY], 255), + llmin((S32)mV[VZ] + color.mV[VZ], 255), + llmin((S32)mV[VW] + color.mV[VW], 255)); +} + +inline LLColor4U LLColor4U::multAll(const F32 k) +{ + // Round to nearest + return LLColor4U( + (U8)ll_round(mV[VX] * k), + (U8)ll_round(mV[VY] * k), + (U8)ll_round(mV[VZ] * k), + (U8)ll_round(mV[VW] * k)); +} +/* +inline LLColor4U operator*(const LLColor4U &a, U8 k) +{ + // only affects rgb (not a!) + return LLColor4U( + a.mV[VX] * k, + a.mV[VY] * k, + a.mV[VZ] * k, + a.mV[VW]); +} + +inline LLColor4U operator*(U8 k, const LLColor4U &a) +{ + // only affects rgb (not a!) + return LLColor4U( + a.mV[VX] * k, + a.mV[VY] * k, + a.mV[VZ] * k, + a.mV[VW]); +} + +inline LLColor4U operator%(U8 k, const LLColor4U &a) +{ + // only affects alpha (not rgb!) + return LLColor4U( + a.mV[VX], + a.mV[VY], + a.mV[VZ], + a.mV[VW] * k ); +} + +inline LLColor4U operator%(const LLColor4U &a, U8 k) +{ + // only affects alpha (not rgb!) + return LLColor4U( + a.mV[VX], + a.mV[VY], + a.mV[VZ], + a.mV[VW] * k ); +} +*/ + +inline bool operator==(const LLColor4U &a, const LLColor4U &b) +{ + return ( (a.mV[VX] == b.mV[VX]) + &&(a.mV[VY] == b.mV[VY]) + &&(a.mV[VZ] == b.mV[VZ]) + &&(a.mV[VW] == b.mV[VW])); +} + +inline bool operator!=(const LLColor4U &a, const LLColor4U &b) +{ + return ( (a.mV[VX] != b.mV[VX]) + ||(a.mV[VY] != b.mV[VY]) + ||(a.mV[VZ] != b.mV[VZ]) + ||(a.mV[VW] != b.mV[VW])); +} + +inline const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b) +{ + a.mV[VX] += b.mV[VX]; + a.mV[VY] += b.mV[VY]; + a.mV[VZ] += b.mV[VZ]; + a.mV[VW] += b.mV[VW]; + return a; +} + +inline const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b) +{ + a.mV[VX] -= b.mV[VX]; + a.mV[VY] -= b.mV[VY]; + a.mV[VZ] -= b.mV[VZ]; + a.mV[VW] -= b.mV[VW]; + return a; +} + +inline const LLColor4U& operator*=(LLColor4U &a, U8 k) +{ + // only affects rgb (not a!) + a.mV[VX] *= k; + a.mV[VY] *= k; + a.mV[VZ] *= k; + return a; +} + +inline const LLColor4U& operator%=(LLColor4U &a, U8 k) +{ + // only affects alpha (not rgb!) + a.mV[VW] *= k; + return a; +} + +inline F32 distVec(const LLColor4U &a, const LLColor4U &b) +{ + LLColor4U vec = a - b; + return (vec.length()); +} + +inline F32 distVec_squared(const LLColor4U &a, const LLColor4U &b) +{ + LLColor4U vec = a - b; + return (vec.lengthSquared()); +} + +void LLColor4U::setVecScaleClamp(const LLColor4& color) +{ + F32 color_scale_factor = 255.f; + F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); + if (max_color > 1.f) + { + color_scale_factor /= max_color; + } + const S32 MAX_COLOR = 255; + S32 r = ll_round(color.mV[0] * color_scale_factor); + if (r > MAX_COLOR) + { + r = MAX_COLOR; + } + else if (r < 0) + { + r = 0; + } + mV[0] = r; + + S32 g = ll_round(color.mV[1] * color_scale_factor); + if (g > MAX_COLOR) + { + g = MAX_COLOR; + } + else if (g < 0) + { + g = 0; + } + mV[1] = g; + + S32 b = ll_round(color.mV[2] * color_scale_factor); + if (b > MAX_COLOR) + { + b = MAX_COLOR; + } + else if (b < 0) + { + b = 0; + } + mV[2] = b; + + // Alpha shouldn't be scaled, just clamped... + S32 a = ll_round(color.mV[3] * MAX_COLOR); + if (a > MAX_COLOR) + { + a = MAX_COLOR; + } + else if (a < 0) + { + a = 0; + } + mV[3] = a; +} + +void LLColor4U::setVecScaleClamp(const LLColor3& color) +{ + F32 color_scale_factor = 255.f; + F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); + if (max_color > 1.f) + { + color_scale_factor /= max_color; + } + + const S32 MAX_COLOR = 255; + S32 r = ll_round(color.mV[0] * color_scale_factor); + if (r > MAX_COLOR) + { + r = MAX_COLOR; + } + else + if (r < 0) + { + r = 0; + } + mV[0] = r; + + S32 g = ll_round(color.mV[1] * color_scale_factor); + if (g > MAX_COLOR) + { + g = MAX_COLOR; + } + else + if (g < 0) + { + g = 0; + } + mV[1] = g; + + S32 b = ll_round(color.mV[2] * color_scale_factor); + if (b > MAX_COLOR) + { + b = MAX_COLOR; + } + if (b < 0) + { + b = 0; + } + mV[2] = b; + + mV[3] = 255; +} + +inline U32 LLColor4U::asRGBA() const +{ + // Little endian: values are swapped in memory. The original code access the array like a U32, so we need to swap here + + return (mV[3] << 24) | (mV[2] << 16) | (mV[1] << 8) | mV[0]; +} + +inline void LLColor4U::fromRGBA( U32 aVal ) +{ + // Little endian: values are swapped in memory. The original code access the array like a U32, so we need to swap here + + mV[ 0 ] = aVal & 0xFF; + aVal >>= 8; + mV[ 1 ] = aVal & 0xFF; + aVal >>= 8; + mV[ 2 ] = aVal & 0xFF; + aVal >>= 8; + mV[ 3 ] = aVal & 0xFF; +} + + +#endif + diff --git a/indra/llmath/v4math.cpp b/indra/llmath/v4math.cpp index bee6fc3ee8..0aa6eb09c3 100644 --- a/indra/llmath/v4math.cpp +++ b/indra/llmath/v4math.cpp @@ -1,120 +1,120 @@ -/** - * @file v4math.cpp - * @brief LLVector4 class implementation. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -//#include "vmath.h" -#include "v3math.h" -#include "v4math.h" -#include "m4math.h" -#include "m3math.h" -#include "llquaternion.h" - -// LLVector4 - -// Axis-Angle rotations -const LLVector4& LLVector4::rotVec(const LLMatrix4 &mat) -{ - *this = *this * mat; - return *this; -} - -const LLVector4& LLVector4::rotVec(const LLQuaternion &q) -{ - *this = *this * q; - return *this; -} - -const LLVector4& LLVector4::scaleVec(const LLVector4& vec) -{ - mV[VX] *= vec.mV[VX]; - mV[VY] *= vec.mV[VY]; - mV[VZ] *= vec.mV[VZ]; - mV[VW] *= vec.mV[VW]; - - return *this; -} - -// Sets all values to absolute value of their original values -// Returns true if data changed -bool LLVector4::abs() -{ - bool ret{ false }; - - if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } - if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } - if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = true; } - if (mV[3] < 0.f) { mV[3] = -mV[3]; ret = true; } - - return ret; -} - - -std::ostream& operator<<(std::ostream& s, const LLVector4 &a) -{ - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }"; - return s; -} - - -// Non-member functions - -F32 angle_between( const LLVector4& a, const LLVector4& b ) -{ - LLVector4 an = a; - LLVector4 bn = b; - an.normalize(); - bn.normalize(); - F32 cosine = an * bn; - F32 angle = (cosine >= 1.0f) ? 0.0f : - (cosine <= -1.0f) ? F_PI : - acos(cosine); - return angle; -} - -bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon) -{ - LLVector4 an = a; - LLVector4 bn = b; - an.normalize(); - bn.normalize(); - F32 dot = an * bn; - if ( (1.0f - fabs(dot)) < epsilon) - return true; - return false; -} - - -LLVector3 vec4to3(const LLVector4 &vec) -{ - return LLVector3( vec.mV[VX], vec.mV[VY], vec.mV[VZ] ); -} - -LLVector4 vec3to4(const LLVector3 &vec) -{ - return LLVector4(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); -} - +/** + * @file v4math.cpp + * @brief LLVector4 class implementation. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +//#include "vmath.h" +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "m3math.h" +#include "llquaternion.h" + +// LLVector4 + +// Axis-Angle rotations +const LLVector4& LLVector4::rotVec(const LLMatrix4 &mat) +{ + *this = *this * mat; + return *this; +} + +const LLVector4& LLVector4::rotVec(const LLQuaternion &q) +{ + *this = *this * q; + return *this; +} + +const LLVector4& LLVector4::scaleVec(const LLVector4& vec) +{ + mV[VX] *= vec.mV[VX]; + mV[VY] *= vec.mV[VY]; + mV[VZ] *= vec.mV[VZ]; + mV[VW] *= vec.mV[VW]; + + return *this; +} + +// Sets all values to absolute value of their original values +// Returns true if data changed +bool LLVector4::abs() +{ + bool ret{ false }; + + if (mV[0] < 0.f) { mV[0] = -mV[0]; ret = true; } + if (mV[1] < 0.f) { mV[1] = -mV[1]; ret = true; } + if (mV[2] < 0.f) { mV[2] = -mV[2]; ret = true; } + if (mV[3] < 0.f) { mV[3] = -mV[3]; ret = true; } + + return ret; +} + + +std::ostream& operator<<(std::ostream& s, const LLVector4 &a) +{ + s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }"; + return s; +} + + +// Non-member functions + +F32 angle_between( const LLVector4& a, const LLVector4& b ) +{ + LLVector4 an = a; + LLVector4 bn = b; + an.normalize(); + bn.normalize(); + F32 cosine = an * bn; + F32 angle = (cosine >= 1.0f) ? 0.0f : + (cosine <= -1.0f) ? F_PI : + acos(cosine); + return angle; +} + +bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon) +{ + LLVector4 an = a; + LLVector4 bn = b; + an.normalize(); + bn.normalize(); + F32 dot = an * bn; + if ( (1.0f - fabs(dot)) < epsilon) + return true; + return false; +} + + +LLVector3 vec4to3(const LLVector4 &vec) +{ + return LLVector3( vec.mV[VX], vec.mV[VY], vec.mV[VZ] ); +} + +LLVector4 vec3to4(const LLVector3 &vec) +{ + return LLVector4(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); +} + diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 2a21edf198..7ed22212d3 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -1,549 +1,549 @@ -/** - * @file v4math.h - * @brief LLVector4 class header file. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_V4MATH_H -#define LL_V4MATH_H - -#include "llerror.h" -#include "llmath.h" -#include "v3math.h" -#include "v2math.h" - -class LLMatrix3; -class LLMatrix4; -class LLQuaternion; - -// LLVector4 = |x y z w| - -static const U32 LENGTHOFVECTOR4 = 4; - -class LLVector4 -{ - public: - F32 mV[LENGTHOFVECTOR4]; - LLVector4(); // Initializes LLVector4 to (0, 0, 0, 1) - explicit LLVector4(const F32 *vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2], vec[3]) - explicit LLVector4(const F64 *vec); // Initialized LLVector4 to ((F32) vec[0], (F32) vec[1], (F32) vec[3], (F32) vec[4]); - explicit LLVector4(const LLVector2 &vec); - explicit LLVector4(const LLVector2 &vec, F32 z, F32 w); - explicit LLVector4(const LLVector3 &vec); // Initializes LLVector4 to (vec, 1) - explicit LLVector4(const LLVector3 &vec, F32 w); // Initializes LLVector4 to (vec, w) - explicit LLVector4(const LLSD &sd); - LLVector4(F32 x, F32 y, F32 z); // Initializes LLVector4 to (x. y, z, 1) - LLVector4(F32 x, F32 y, F32 z, F32 w); - - LLSD getValue() const - { - LLSD ret; - ret[0] = mV[0]; - ret[1] = mV[1]; - ret[2] = mV[2]; - ret[3] = mV[3]; - return ret; - } - - void setValue(const LLSD& sd) - { - mV[0] = sd[0].asReal(); - mV[1] = sd[1].asReal(); - mV[2] = sd[2].asReal(); - mV[3] = sd[3].asReal(); - } - - - inline bool isFinite() const; // checks to see if all values of LLVector3 are finite - - inline void clear(); // Clears LLVector4 to (0, 0, 0, 1) - inline void clearVec(); // deprecated - inline void zeroVec(); // deprecated - - inline void set(F32 x, F32 y, F32 z); // Sets LLVector4 to (x, y, z, 1) - inline void set(F32 x, F32 y, F32 z, F32 w); // Sets LLVector4 to (x, y, z, w) - inline void set(const LLVector4 &vec); // Sets LLVector4 to vec - inline void set(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec - inline void set(const F32 *vec); // Sets LLVector4 to vec - - inline void setVec(F32 x, F32 y, F32 z); // deprecated - inline void setVec(F32 x, F32 y, F32 z, F32 w); // deprecated - inline void setVec(const LLVector4 &vec); // deprecated - inline void setVec(const LLVector3 &vec, F32 w = 1.f); // deprecated - inline void setVec(const F32 *vec); // deprecated - - F32 length() const; // Returns magnitude of LLVector4 - F32 lengthSquared() const; // Returns magnitude squared of LLVector4 - F32 normalize(); // Normalizes and returns the magnitude of LLVector4 - - F32 magVec() const; // deprecated - F32 magVecSquared() const; // deprecated - F32 normVec(); // deprecated - - // Sets all values to absolute value of their original values - // Returns true if data changed - bool abs(); - - bool isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; } - bool isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; } - - const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat - const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q - - const LLVector4& scaleVec(const LLVector4& vec); // Scales component-wise by vec - - F32 operator[](int idx) const { return mV[idx]; } - F32 &operator[](int idx) { return mV[idx]; } - - friend std::ostream& operator<<(std::ostream& s, const LLVector4 &a); // Print a - friend LLVector4 operator+(const LLVector4 &a, const LLVector4 &b); // Return vector a + b - friend LLVector4 operator-(const LLVector4 &a, const LLVector4 &b); // Return vector a minus b - friend F32 operator*(const LLVector4 &a, const LLVector4 &b); // Return a dot b - friend LLVector4 operator%(const LLVector4 &a, const LLVector4 &b); // Return a cross b - friend LLVector4 operator/(const LLVector4 &a, F32 k); // Return a divided by scaler k - friend LLVector4 operator*(const LLVector4 &a, F32 k); // Return a times scaler k - friend LLVector4 operator*(F32 k, const LLVector4 &a); // Return a times scaler k - friend bool operator==(const LLVector4 &a, const LLVector4 &b); // Return a == b - friend bool operator!=(const LLVector4 &a, const LLVector4 &b); // Return a != b - - friend const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b); // Return vector a + b - friend const LLVector4& operator-=(LLVector4 &a, const LLVector4 &b); // Return vector a minus b - friend const LLVector4& operator%=(LLVector4 &a, const LLVector4 &b); // Return a cross b - friend const LLVector4& operator*=(LLVector4 &a, F32 k); // Return a times scaler k - friend const LLVector4& operator/=(LLVector4 &a, F32 k); // Return a divided by scaler k - - friend LLVector4 operator-(const LLVector4 &a); // Return vector -a -}; - -// Non-member functions -F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b -bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon = F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel -F32 dist_vec(const LLVector4 &a, const LLVector4 &b); // Returns distance between a and b -F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b); // Returns distance squared between a and b -LLVector3 vec4to3(const LLVector4 &vec); -LLVector4 vec3to4(const LLVector3 &vec); -LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u); // Returns a vector that is a linear interpolation between a and b - -// Constructors - -inline LLVector4::LLVector4(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; -} - -inline LLVector4::LLVector4(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = 1.f; -} - -inline LLVector4::LLVector4(F32 x, F32 y, F32 z, F32 w) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = w; -} - -inline LLVector4::LLVector4(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; -} - -inline LLVector4::LLVector4(const F64 *vec) -{ - mV[VX] = (F32) vec[VX]; - mV[VY] = (F32) vec[VY]; - mV[VZ] = (F32) vec[VZ]; - mV[VW] = (F32) vec[VW]; -} - -inline LLVector4::LLVector4(const LLVector2 &vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = 0.f; - mV[VW] = 0.f; -} - -inline LLVector4::LLVector4(const LLVector2 &vec, F32 z, F32 w) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = z; - mV[VW] = w; -} - -inline LLVector4::LLVector4(const LLVector3 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = 1.f; -} - -inline LLVector4::LLVector4(const LLVector3 &vec, F32 w) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = w; -} - -inline LLVector4::LLVector4(const LLSD &sd) -{ - setValue(sd); -} - - -inline bool LLVector4::isFinite() const -{ - return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW])); -} - -// Clear and Assignment Functions - -inline void LLVector4::clear(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; -} - -// deprecated -inline void LLVector4::clearVec(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; -} - -// deprecated -inline void LLVector4::zeroVec(void) -{ - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 0.f; -} - -inline void LLVector4::set(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = 1.f; -} - -inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = w; -} - -inline void LLVector4::set(const LLVector4 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; -} - -inline void LLVector4::set(const LLVector3 &vec, F32 w) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = w; -} - -inline void LLVector4::set(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; -} - - -// deprecated -inline void LLVector4::setVec(F32 x, F32 y, F32 z) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = 1.f; -} - -// deprecated -inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w) -{ - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = w; -} - -// deprecated -inline void LLVector4::setVec(const LLVector4 &vec) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; -} - -// deprecated -inline void LLVector4::setVec(const LLVector3 &vec, F32 w) -{ - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = w; -} - -// deprecated -inline void LLVector4::setVec(const F32 *vec) -{ - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; -} - -// LLVector4 Magnitude and Normalization Functions - -inline F32 LLVector4::length(void) const -{ - return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); -} - -inline F32 LLVector4::lengthSquared(void) const -{ - return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; -} - -inline F32 LLVector4::magVec(void) const -{ - return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); -} - -inline F32 LLVector4::magVecSquared(void) const -{ - return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; -} - -// LLVector4 Operators - -inline LLVector4 operator+(const LLVector4 &a, const LLVector4 &b) -{ - LLVector4 c(a); - return c += b; -} - -inline LLVector4 operator-(const LLVector4 &a, const LLVector4 &b) -{ - LLVector4 c(a); - return c -= b; -} - -inline F32 operator*(const LLVector4 &a, const LLVector4 &b) -{ - return (a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ]); -} - -inline LLVector4 operator%(const LLVector4 &a, const LLVector4 &b) -{ - return LLVector4(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]); -} - -inline LLVector4 operator/(const LLVector4 &a, F32 k) -{ - F32 t = 1.f / k; - return LLVector4( a.mV[VX] * t, a.mV[VY] * t, a.mV[VZ] * t ); -} - - -inline LLVector4 operator*(const LLVector4 &a, F32 k) -{ - return LLVector4( a.mV[VX] * k, a.mV[VY] * k, a.mV[VZ] * k ); -} - -inline LLVector4 operator*(F32 k, const LLVector4 &a) -{ - return LLVector4( a.mV[VX] * k, a.mV[VY] * k, a.mV[VZ] * k ); -} - -inline bool operator==(const LLVector4 &a, const LLVector4 &b) -{ - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ])); -} - -inline bool operator!=(const LLVector4 &a, const LLVector4 &b) -{ - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ]) - ||(a.mV[VW] != b.mV[VW]) ); -} - -inline const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b) -{ - a.mV[VX] += b.mV[VX]; - a.mV[VY] += b.mV[VY]; - a.mV[VZ] += b.mV[VZ]; - return a; -} - -inline const LLVector4& operator-=(LLVector4 &a, const LLVector4 &b) -{ - a.mV[VX] -= b.mV[VX]; - a.mV[VY] -= b.mV[VY]; - a.mV[VZ] -= b.mV[VZ]; - return a; -} - -inline const LLVector4& operator%=(LLVector4 &a, const LLVector4 &b) -{ - LLVector4 ret(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]); - a = ret; - return a; -} - -inline const LLVector4& operator*=(LLVector4 &a, F32 k) -{ - a.mV[VX] *= k; - a.mV[VY] *= k; - a.mV[VZ] *= k; - return a; -} - -inline const LLVector4& operator/=(LLVector4 &a, F32 k) -{ - F32 t = 1.f / k; - a.mV[VX] *= t; - a.mV[VY] *= t; - a.mV[VZ] *= t; - return a; -} - -inline LLVector4 operator-(const LLVector4 &a) -{ - return LLVector4( -a.mV[VX], -a.mV[VY], -a.mV[VZ] ); -} - -inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b) -{ - LLVector4 vec = a - b; - return (vec.length()); -} - -inline F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b) -{ - LLVector4 vec = a - b; - return (vec.lengthSquared()); -} - -inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u) -{ - return LLVector4( - a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, - a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, - a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u, - a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u); -} - -inline F32 LLVector4::normalize(void) -{ - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); - F32 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mV[VX] *= oomag; - mV[VY] *= oomag; - mV[VZ] *= oomag; - } - else - { - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; - mag = 0; - } - return (mag); -} - -// deprecated -inline F32 LLVector4::normVec(void) -{ - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); - F32 oomag; - - if (mag > FP_MAG_THRESHOLD) - { - oomag = 1.f/mag; - mV[VX] *= oomag; - mV[VY] *= oomag; - mV[VZ] *= oomag; - } - else - { - mV[0] = 0.f; - mV[1] = 0.f; - mV[2] = 0.f; - mag = 0; - } - return (mag); -} - -// Because apparently some parts of the viewer use this for color info. -inline const LLVector4 srgbVector4(const LLVector4 &a) { - LLVector4 srgbColor; - - srgbColor.mV[0] = linearTosRGB(a.mV[0]); - srgbColor.mV[1] = linearTosRGB(a.mV[1]); - srgbColor.mV[2] = linearTosRGB(a.mV[2]); - srgbColor.mV[3] = a.mV[3]; - - return srgbColor; -} - - -#endif - +/** + * @file v4math.h + * @brief LLVector4 class header file. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V4MATH_H +#define LL_V4MATH_H + +#include "llerror.h" +#include "llmath.h" +#include "v3math.h" +#include "v2math.h" + +class LLMatrix3; +class LLMatrix4; +class LLQuaternion; + +// LLVector4 = |x y z w| + +static const U32 LENGTHOFVECTOR4 = 4; + +class LLVector4 +{ + public: + F32 mV[LENGTHOFVECTOR4]; + LLVector4(); // Initializes LLVector4 to (0, 0, 0, 1) + explicit LLVector4(const F32 *vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2], vec[3]) + explicit LLVector4(const F64 *vec); // Initialized LLVector4 to ((F32) vec[0], (F32) vec[1], (F32) vec[3], (F32) vec[4]); + explicit LLVector4(const LLVector2 &vec); + explicit LLVector4(const LLVector2 &vec, F32 z, F32 w); + explicit LLVector4(const LLVector3 &vec); // Initializes LLVector4 to (vec, 1) + explicit LLVector4(const LLVector3 &vec, F32 w); // Initializes LLVector4 to (vec, w) + explicit LLVector4(const LLSD &sd); + LLVector4(F32 x, F32 y, F32 z); // Initializes LLVector4 to (x. y, z, 1) + LLVector4(F32 x, F32 y, F32 z, F32 w); + + LLSD getValue() const + { + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + ret[2] = mV[2]; + ret[3] = mV[3]; + return ret; + } + + void setValue(const LLSD& sd) + { + mV[0] = sd[0].asReal(); + mV[1] = sd[1].asReal(); + mV[2] = sd[2].asReal(); + mV[3] = sd[3].asReal(); + } + + + inline bool isFinite() const; // checks to see if all values of LLVector3 are finite + + inline void clear(); // Clears LLVector4 to (0, 0, 0, 1) + inline void clearVec(); // deprecated + inline void zeroVec(); // deprecated + + inline void set(F32 x, F32 y, F32 z); // Sets LLVector4 to (x, y, z, 1) + inline void set(F32 x, F32 y, F32 z, F32 w); // Sets LLVector4 to (x, y, z, w) + inline void set(const LLVector4 &vec); // Sets LLVector4 to vec + inline void set(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec + inline void set(const F32 *vec); // Sets LLVector4 to vec + + inline void setVec(F32 x, F32 y, F32 z); // deprecated + inline void setVec(F32 x, F32 y, F32 z, F32 w); // deprecated + inline void setVec(const LLVector4 &vec); // deprecated + inline void setVec(const LLVector3 &vec, F32 w = 1.f); // deprecated + inline void setVec(const F32 *vec); // deprecated + + F32 length() const; // Returns magnitude of LLVector4 + F32 lengthSquared() const; // Returns magnitude squared of LLVector4 + F32 normalize(); // Normalizes and returns the magnitude of LLVector4 + + F32 magVec() const; // deprecated + F32 magVecSquared() const; // deprecated + F32 normVec(); // deprecated + + // Sets all values to absolute value of their original values + // Returns true if data changed + bool abs(); + + bool isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; } + bool isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; } + + const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat + const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q + + const LLVector4& scaleVec(const LLVector4& vec); // Scales component-wise by vec + + F32 operator[](int idx) const { return mV[idx]; } + F32 &operator[](int idx) { return mV[idx]; } + + friend std::ostream& operator<<(std::ostream& s, const LLVector4 &a); // Print a + friend LLVector4 operator+(const LLVector4 &a, const LLVector4 &b); // Return vector a + b + friend LLVector4 operator-(const LLVector4 &a, const LLVector4 &b); // Return vector a minus b + friend F32 operator*(const LLVector4 &a, const LLVector4 &b); // Return a dot b + friend LLVector4 operator%(const LLVector4 &a, const LLVector4 &b); // Return a cross b + friend LLVector4 operator/(const LLVector4 &a, F32 k); // Return a divided by scaler k + friend LLVector4 operator*(const LLVector4 &a, F32 k); // Return a times scaler k + friend LLVector4 operator*(F32 k, const LLVector4 &a); // Return a times scaler k + friend bool operator==(const LLVector4 &a, const LLVector4 &b); // Return a == b + friend bool operator!=(const LLVector4 &a, const LLVector4 &b); // Return a != b + + friend const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b); // Return vector a + b + friend const LLVector4& operator-=(LLVector4 &a, const LLVector4 &b); // Return vector a minus b + friend const LLVector4& operator%=(LLVector4 &a, const LLVector4 &b); // Return a cross b + friend const LLVector4& operator*=(LLVector4 &a, F32 k); // Return a times scaler k + friend const LLVector4& operator/=(LLVector4 &a, F32 k); // Return a divided by scaler k + + friend LLVector4 operator-(const LLVector4 &a); // Return vector -a +}; + +// Non-member functions +F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b +bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon = F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel +F32 dist_vec(const LLVector4 &a, const LLVector4 &b); // Returns distance between a and b +F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b); // Returns distance squared between a and b +LLVector3 vec4to3(const LLVector4 &vec); +LLVector4 vec3to4(const LLVector3 &vec); +LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u); // Returns a vector that is a linear interpolation between a and b + +// Constructors + +inline LLVector4::LLVector4(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; + mV[VZ] = 0.f; + mV[VW] = 1.f; +} + +inline LLVector4::LLVector4(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = 1.f; +} + +inline LLVector4::LLVector4(F32 x, F32 y, F32 z, F32 w) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = w; +} + +inline LLVector4::LLVector4(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; +} + +inline LLVector4::LLVector4(const F64 *vec) +{ + mV[VX] = (F32) vec[VX]; + mV[VY] = (F32) vec[VY]; + mV[VZ] = (F32) vec[VZ]; + mV[VW] = (F32) vec[VW]; +} + +inline LLVector4::LLVector4(const LLVector2 &vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = 0.f; + mV[VW] = 0.f; +} + +inline LLVector4::LLVector4(const LLVector2 &vec, F32 z, F32 w) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = z; + mV[VW] = w; +} + +inline LLVector4::LLVector4(const LLVector3 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = 1.f; +} + +inline LLVector4::LLVector4(const LLVector3 &vec, F32 w) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = w; +} + +inline LLVector4::LLVector4(const LLSD &sd) +{ + setValue(sd); +} + + +inline bool LLVector4::isFinite() const +{ + return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW])); +} + +// Clear and Assignment Functions + +inline void LLVector4::clear(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; + mV[VZ] = 0.f; + mV[VW] = 1.f; +} + +// deprecated +inline void LLVector4::clearVec(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; + mV[VZ] = 0.f; + mV[VW] = 1.f; +} + +// deprecated +inline void LLVector4::zeroVec(void) +{ + mV[VX] = 0.f; + mV[VY] = 0.f; + mV[VZ] = 0.f; + mV[VW] = 0.f; +} + +inline void LLVector4::set(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = 1.f; +} + +inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = w; +} + +inline void LLVector4::set(const LLVector4 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = vec.mV[VW]; +} + +inline void LLVector4::set(const LLVector3 &vec, F32 w) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = w; +} + +inline void LLVector4::set(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; +} + + +// deprecated +inline void LLVector4::setVec(F32 x, F32 y, F32 z) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = 1.f; +} + +// deprecated +inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w) +{ + mV[VX] = x; + mV[VY] = y; + mV[VZ] = z; + mV[VW] = w; +} + +// deprecated +inline void LLVector4::setVec(const LLVector4 &vec) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = vec.mV[VW]; +} + +// deprecated +inline void LLVector4::setVec(const LLVector3 &vec, F32 w) +{ + mV[VX] = vec.mV[VX]; + mV[VY] = vec.mV[VY]; + mV[VZ] = vec.mV[VZ]; + mV[VW] = w; +} + +// deprecated +inline void LLVector4::setVec(const F32 *vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = vec[VZ]; + mV[VW] = vec[VW]; +} + +// LLVector4 Magnitude and Normalization Functions + +inline F32 LLVector4::length(void) const +{ + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); +} + +inline F32 LLVector4::lengthSquared(void) const +{ + return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; +} + +inline F32 LLVector4::magVec(void) const +{ + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); +} + +inline F32 LLVector4::magVecSquared(void) const +{ + return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; +} + +// LLVector4 Operators + +inline LLVector4 operator+(const LLVector4 &a, const LLVector4 &b) +{ + LLVector4 c(a); + return c += b; +} + +inline LLVector4 operator-(const LLVector4 &a, const LLVector4 &b) +{ + LLVector4 c(a); + return c -= b; +} + +inline F32 operator*(const LLVector4 &a, const LLVector4 &b) +{ + return (a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ]); +} + +inline LLVector4 operator%(const LLVector4 &a, const LLVector4 &b) +{ + return LLVector4(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]); +} + +inline LLVector4 operator/(const LLVector4 &a, F32 k) +{ + F32 t = 1.f / k; + return LLVector4( a.mV[VX] * t, a.mV[VY] * t, a.mV[VZ] * t ); +} + + +inline LLVector4 operator*(const LLVector4 &a, F32 k) +{ + return LLVector4( a.mV[VX] * k, a.mV[VY] * k, a.mV[VZ] * k ); +} + +inline LLVector4 operator*(F32 k, const LLVector4 &a) +{ + return LLVector4( a.mV[VX] * k, a.mV[VY] * k, a.mV[VZ] * k ); +} + +inline bool operator==(const LLVector4 &a, const LLVector4 &b) +{ + return ( (a.mV[VX] == b.mV[VX]) + &&(a.mV[VY] == b.mV[VY]) + &&(a.mV[VZ] == b.mV[VZ])); +} + +inline bool operator!=(const LLVector4 &a, const LLVector4 &b) +{ + return ( (a.mV[VX] != b.mV[VX]) + ||(a.mV[VY] != b.mV[VY]) + ||(a.mV[VZ] != b.mV[VZ]) + ||(a.mV[VW] != b.mV[VW]) ); +} + +inline const LLVector4& operator+=(LLVector4 &a, const LLVector4 &b) +{ + a.mV[VX] += b.mV[VX]; + a.mV[VY] += b.mV[VY]; + a.mV[VZ] += b.mV[VZ]; + return a; +} + +inline const LLVector4& operator-=(LLVector4 &a, const LLVector4 &b) +{ + a.mV[VX] -= b.mV[VX]; + a.mV[VY] -= b.mV[VY]; + a.mV[VZ] -= b.mV[VZ]; + return a; +} + +inline const LLVector4& operator%=(LLVector4 &a, const LLVector4 &b) +{ + LLVector4 ret(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]); + a = ret; + return a; +} + +inline const LLVector4& operator*=(LLVector4 &a, F32 k) +{ + a.mV[VX] *= k; + a.mV[VY] *= k; + a.mV[VZ] *= k; + return a; +} + +inline const LLVector4& operator/=(LLVector4 &a, F32 k) +{ + F32 t = 1.f / k; + a.mV[VX] *= t; + a.mV[VY] *= t; + a.mV[VZ] *= t; + return a; +} + +inline LLVector4 operator-(const LLVector4 &a) +{ + return LLVector4( -a.mV[VX], -a.mV[VY], -a.mV[VZ] ); +} + +inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b) +{ + LLVector4 vec = a - b; + return (vec.length()); +} + +inline F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b) +{ + LLVector4 vec = a - b; + return (vec.lengthSquared()); +} + +inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u) +{ + return LLVector4( + a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, + a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, + a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u, + a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u); +} + +inline F32 LLVector4::normalize(void) +{ + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mV[VX] *= oomag; + mV[VY] *= oomag; + mV[VZ] *= oomag; + } + else + { + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; + mag = 0; + } + return (mag); +} + +// deprecated +inline F32 LLVector4::normVec(void) +{ + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 oomag; + + if (mag > FP_MAG_THRESHOLD) + { + oomag = 1.f/mag; + mV[VX] *= oomag; + mV[VY] *= oomag; + mV[VZ] *= oomag; + } + else + { + mV[0] = 0.f; + mV[1] = 0.f; + mV[2] = 0.f; + mag = 0; + } + return (mag); +} + +// Because apparently some parts of the viewer use this for color info. +inline const LLVector4 srgbVector4(const LLVector4 &a) { + LLVector4 srgbColor; + + srgbColor.mV[0] = linearTosRGB(a.mV[0]); + srgbColor.mV[1] = linearTosRGB(a.mV[1]); + srgbColor.mV[2] = linearTosRGB(a.mV[2]); + srgbColor.mV[3] = a.mV[3]; + + return srgbColor; +} + + +#endif + diff --git a/indra/llmath/xform.cpp b/indra/llmath/xform.cpp index 239c1ca195..39bbb94c9f 100644 --- a/indra/llmath/xform.cpp +++ b/indra/llmath/xform.cpp @@ -1,119 +1,119 @@ -/** - * @file xform.cpp - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "xform.h" - -LLXform::LLXform() -{ - init(); -} - -LLXform::~LLXform() -{ -} - -// Link optimization - don't inline these LL_WARNS() -void LLXform::warn(const char* const msg) -{ - LL_WARNS() << msg << LL_ENDL; -} - -LLXform* LLXform::getRoot() const -{ - const LLXform* root = this; - while(root->mParent) - { - root = root->mParent; - } - return (LLXform*)root; -} - -bool LLXform::isRoot() const -{ - return (!mParent); -} - -bool LLXform::isRootEdit() const -{ - return (!mParent); -} - -LLXformMatrix::~LLXformMatrix() -{ -} - -void LLXformMatrix::update() -{ - if (mParent) - { - mWorldPosition = mPosition; - if (mParent->getScaleChildOffset()) - { - mWorldPosition.scaleVec(mParent->getScale()); - } - mWorldPosition *= mParent->getWorldRotation(); - mWorldPosition += mParent->getWorldPosition(); - mWorldRotation = mRotation * mParent->getWorldRotation(); - } - else - { - mWorldPosition = mPosition; - mWorldRotation = mRotation; - } -} - -void LLXformMatrix::updateMatrix(bool update_bounds) -{ - update(); - - mWorldMatrix.initAll(mScale, mWorldRotation, mWorldPosition); - - if (update_bounds && (mChanged & MOVED)) - { - mMin.mV[0] = mMax.mV[0] = mWorldMatrix.mMatrix[3][0]; - mMin.mV[1] = mMax.mV[1] = mWorldMatrix.mMatrix[3][1]; - mMin.mV[2] = mMax.mV[2] = mWorldMatrix.mMatrix[3][2]; - - F32 f0 = (fabs(mWorldMatrix.mMatrix[0][0])+fabs(mWorldMatrix.mMatrix[1][0])+fabs(mWorldMatrix.mMatrix[2][0])) * 0.5f; - F32 f1 = (fabs(mWorldMatrix.mMatrix[0][1])+fabs(mWorldMatrix.mMatrix[1][1])+fabs(mWorldMatrix.mMatrix[2][1])) * 0.5f; - F32 f2 = (fabs(mWorldMatrix.mMatrix[0][2])+fabs(mWorldMatrix.mMatrix[1][2])+fabs(mWorldMatrix.mMatrix[2][2])) * 0.5f; - - mMin.mV[0] -= f0; - mMin.mV[1] -= f1; - mMin.mV[2] -= f2; - - mMax.mV[0] += f0; - mMax.mV[1] += f1; - mMax.mV[2] += f2; - } -} - -void LLXformMatrix::getMinMax(LLVector3& min, LLVector3& max) const -{ - min = mMin; - max = mMax; -} +/** + * @file xform.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "xform.h" + +LLXform::LLXform() +{ + init(); +} + +LLXform::~LLXform() +{ +} + +// Link optimization - don't inline these LL_WARNS() +void LLXform::warn(const char* const msg) +{ + LL_WARNS() << msg << LL_ENDL; +} + +LLXform* LLXform::getRoot() const +{ + const LLXform* root = this; + while(root->mParent) + { + root = root->mParent; + } + return (LLXform*)root; +} + +bool LLXform::isRoot() const +{ + return (!mParent); +} + +bool LLXform::isRootEdit() const +{ + return (!mParent); +} + +LLXformMatrix::~LLXformMatrix() +{ +} + +void LLXformMatrix::update() +{ + if (mParent) + { + mWorldPosition = mPosition; + if (mParent->getScaleChildOffset()) + { + mWorldPosition.scaleVec(mParent->getScale()); + } + mWorldPosition *= mParent->getWorldRotation(); + mWorldPosition += mParent->getWorldPosition(); + mWorldRotation = mRotation * mParent->getWorldRotation(); + } + else + { + mWorldPosition = mPosition; + mWorldRotation = mRotation; + } +} + +void LLXformMatrix::updateMatrix(bool update_bounds) +{ + update(); + + mWorldMatrix.initAll(mScale, mWorldRotation, mWorldPosition); + + if (update_bounds && (mChanged & MOVED)) + { + mMin.mV[0] = mMax.mV[0] = mWorldMatrix.mMatrix[3][0]; + mMin.mV[1] = mMax.mV[1] = mWorldMatrix.mMatrix[3][1]; + mMin.mV[2] = mMax.mV[2] = mWorldMatrix.mMatrix[3][2]; + + F32 f0 = (fabs(mWorldMatrix.mMatrix[0][0])+fabs(mWorldMatrix.mMatrix[1][0])+fabs(mWorldMatrix.mMatrix[2][0])) * 0.5f; + F32 f1 = (fabs(mWorldMatrix.mMatrix[0][1])+fabs(mWorldMatrix.mMatrix[1][1])+fabs(mWorldMatrix.mMatrix[2][1])) * 0.5f; + F32 f2 = (fabs(mWorldMatrix.mMatrix[0][2])+fabs(mWorldMatrix.mMatrix[1][2])+fabs(mWorldMatrix.mMatrix[2][2])) * 0.5f; + + mMin.mV[0] -= f0; + mMin.mV[1] -= f1; + mMin.mV[2] -= f2; + + mMax.mV[0] += f0; + mMax.mV[1] += f1; + mMax.mV[2] += f2; + } +} + +void LLXformMatrix::getMinMax(LLVector3& min, LLVector3& max) const +{ + min = mMin; + max = mMax; +} diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 0b583ce189..7434301670 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -1,315 +1,315 @@ -/** - * @file xform.h - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_XFORM_H -#define LL_XFORM_H - -#include "v3math.h" -#include "m4math.h" -#include "llquaternion.h" - -constexpr F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f -constexpr F32 MIN_OBJECT_Z = -256.f; -constexpr F32 DEFAULT_MAX_PRIM_SCALE = 64.f; -constexpr F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f; -constexpr F32 MIN_PRIM_SCALE = 0.01f; -constexpr F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX - -class LLXform -{ -protected: - LLVector3 mPosition; - LLQuaternion mRotation; - LLVector3 mScale; - - //RN: TODO: move these world transform members to LLXformMatrix - // as they are *never* updated or accessed in the base class - LLVector3 mWorldPosition; - LLQuaternion mWorldRotation; - - LLXform* mParent; - U32 mChanged; - - bool mScaleChildOffset; - -public: - typedef enum e_changed_flags - { - UNCHANGED = 0x00, - TRANSLATED = 0x01, - ROTATED = 0x02, - SCALED = 0x04, - SHIFTED = 0x08, - GEOMETRY = 0x10, - TEXTURE = 0x20, - MOVED = TRANSLATED|ROTATED|SCALED, - SILHOUETTE = 0x40, - ALL_CHANGED = 0x7f - }EChangedFlags; - - void init() - { - mParent = NULL; - mChanged = UNCHANGED; - mPosition.setVec(0,0,0); - mRotation.loadIdentity(); - mScale. setVec(1,1,1); - mWorldPosition.clearVec(); - mWorldRotation.loadIdentity(); - mScaleChildOffset = false; - } - - LLXform(); - virtual ~LLXform(); - - void getLocalMat4(LLMatrix4 &mat) const { mat.initAll(mScale, mRotation, mPosition); } - - inline bool setParent(LLXform *parent); - - inline void setPosition(const LLVector3& pos); - inline void setPosition(const F32 x, const F32 y, const F32 z); - inline void setPositionX(const F32 x); - inline void setPositionY(const F32 y); - inline void setPositionZ(const F32 z); - inline void addPosition(const LLVector3& pos); - - - inline void setScale(const LLVector3& scale); - inline void setScale(const F32 x, const F32 y, const F32 z); - inline void setRotation(const LLQuaternion& rot); - inline void setRotation(const F32 x, const F32 y, const F32 z); - inline void setRotation(const F32 x, const F32 y, const F32 z, const F32 s); - - // Above functions must be inline for speed, but also - // need to emit warnings. LL_WARNS() causes inline LLError::CallSite - // static objects that make more work for the linker. - // Avoid inline LL_WARNS() by calling this function. - void warn(const char* const msg); - - void setChanged(const U32 bits) { mChanged |= bits; } - bool isChanged() const { return mChanged; } - bool isChanged(const U32 bits) const { return mChanged & bits; } - void clearChanged() { mChanged = 0; } - void clearChanged(U32 bits) { mChanged &= ~bits; } - - void setScaleChildOffset(bool scale) { mScaleChildOffset = scale; } - bool getScaleChildOffset() { return mScaleChildOffset; } - - LLXform* getParent() const { return mParent; } - LLXform* getRoot() const; - virtual bool isRoot() const; - virtual bool isRootEdit() const; - - const LLVector3& getPosition() const { return mPosition; } - const LLVector3& getScale() const { return mScale; } - const LLQuaternion& getRotation() const { return mRotation; } - const LLVector3& getPositionW() const { return mWorldPosition; } - const LLQuaternion& getWorldRotation() const { return mWorldRotation; } - const LLVector3& getWorldPosition() const { return mWorldPosition; } -}; - -class LLXformMatrix : public LLXform -{ -public: - LLXformMatrix() : LLXform() {}; - virtual ~LLXformMatrix(); - - const LLMatrix4& getWorldMatrix() const { return mWorldMatrix; } - void setWorldMatrix (const LLMatrix4& mat) { mWorldMatrix = mat; } - - void init() - { - mWorldMatrix.setIdentity(); - mMin.clearVec(); - mMax.clearVec(); - - LLXform::init(); - } - - void update(); - void updateMatrix(bool update_bounds = true); - void getMinMax(LLVector3& min,LLVector3& max) const; - -protected: - LLMatrix4 mWorldMatrix; - LLVector3 mMin; - LLVector3 mMax; - -}; - -bool LLXform::setParent(LLXform* parent) -{ - // Validate and make sure we're not creating a loop - if (parent == mParent) - { - return true; - } - if (parent) - { - LLXform *cur_par = parent->mParent; - while (cur_par) - { - if (cur_par == this) - { - //warn("LLXform::setParent Creating loop when setting parent!"); - return false; - } - cur_par = cur_par->mParent; - } - } - mParent = parent; - return true; -} - -void LLXform::setPosition(const LLVector3& pos) -{ - setChanged(TRANSLATED); - if (pos.isFinite()) - mPosition = pos; - else - { - mPosition.clearVec(); - warn("Non Finite in LLXform::setPosition(LLVector3)"); - } -} - -void LLXform::setPosition(const F32 x, const F32 y, const F32 z) -{ - setChanged(TRANSLATED); - if (llfinite(x) && llfinite(y) && llfinite(z)) - mPosition.setVec(x,y,z); - else - { - mPosition.clearVec(); - warn("Non Finite in LLXform::setPosition(F32,F32,F32)"); - } -} - -void LLXform::setPositionX(const F32 x) -{ - setChanged(TRANSLATED); - if (llfinite(x)) - mPosition.mV[VX] = x; - else - { - mPosition.mV[VX] = 0.f; - warn("Non Finite in LLXform::setPositionX"); - } -} - -void LLXform::setPositionY(const F32 y) -{ - setChanged(TRANSLATED); - if (llfinite(y)) - mPosition.mV[VY] = y; - else - { - mPosition.mV[VY] = 0.f; - warn("Non Finite in LLXform::setPositionY"); - } -} - -void LLXform::setPositionZ(const F32 z) -{ - setChanged(TRANSLATED); - if (llfinite(z)) - mPosition.mV[VZ] = z; - else - { - mPosition.mV[VZ] = 0.f; - warn("Non Finite in LLXform::setPositionZ"); - } -} - -void LLXform::addPosition(const LLVector3& pos) -{ - setChanged(TRANSLATED); - if (pos.isFinite()) - mPosition += pos; - else - warn("Non Finite in LLXform::addPosition"); -} - -void LLXform::setScale(const LLVector3& scale) -{ - setChanged(SCALED); - if (scale.isFinite()) - mScale = scale; - else - { - mScale.setVec(1.f, 1.f, 1.f); - warn("Non Finite in LLXform::setScale"); - } -} -void LLXform::setScale(const F32 x, const F32 y, const F32 z) -{ - setChanged(SCALED); - if (llfinite(x) && llfinite(y) && llfinite(z)) - mScale.setVec(x,y,z); - else - { - mScale.setVec(1.f, 1.f, 1.f); - warn("Non Finite in LLXform::setScale"); - } -} -void LLXform::setRotation(const LLQuaternion& rot) -{ - setChanged(ROTATED); - if (rot.isFinite()) - mRotation = rot; - else - { - mRotation.loadIdentity(); - warn("Non Finite in LLXform::setRotation"); - } -} -void LLXform::setRotation(const F32 x, const F32 y, const F32 z) -{ - setChanged(ROTATED); - if (llfinite(x) && llfinite(y) && llfinite(z)) - { - mRotation.setQuat(x,y,z); - } - else - { - mRotation.loadIdentity(); - warn("Non Finite in LLXform::setRotation"); - } -} -void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) -{ - setChanged(ROTATED); - if (llfinite(x) && llfinite(y) && llfinite(z) && llfinite(s)) - { - mRotation.mQ[VX] = x; mRotation.mQ[VY] = y; mRotation.mQ[VZ] = z; mRotation.mQ[VS] = s; - } - else - { - mRotation.loadIdentity(); - warn("Non Finite in LLXform::setRotation"); - } -} - -#endif +/** + * @file xform.h + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_XFORM_H +#define LL_XFORM_H + +#include "v3math.h" +#include "m4math.h" +#include "llquaternion.h" + +constexpr F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f +constexpr F32 MIN_OBJECT_Z = -256.f; +constexpr F32 DEFAULT_MAX_PRIM_SCALE = 64.f; +constexpr F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = 10.f; +constexpr F32 MIN_PRIM_SCALE = 0.01f; +constexpr F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX + +class LLXform +{ +protected: + LLVector3 mPosition; + LLQuaternion mRotation; + LLVector3 mScale; + + //RN: TODO: move these world transform members to LLXformMatrix + // as they are *never* updated or accessed in the base class + LLVector3 mWorldPosition; + LLQuaternion mWorldRotation; + + LLXform* mParent; + U32 mChanged; + + bool mScaleChildOffset; + +public: + typedef enum e_changed_flags + { + UNCHANGED = 0x00, + TRANSLATED = 0x01, + ROTATED = 0x02, + SCALED = 0x04, + SHIFTED = 0x08, + GEOMETRY = 0x10, + TEXTURE = 0x20, + MOVED = TRANSLATED|ROTATED|SCALED, + SILHOUETTE = 0x40, + ALL_CHANGED = 0x7f + }EChangedFlags; + + void init() + { + mParent = NULL; + mChanged = UNCHANGED; + mPosition.setVec(0,0,0); + mRotation.loadIdentity(); + mScale. setVec(1,1,1); + mWorldPosition.clearVec(); + mWorldRotation.loadIdentity(); + mScaleChildOffset = false; + } + + LLXform(); + virtual ~LLXform(); + + void getLocalMat4(LLMatrix4 &mat) const { mat.initAll(mScale, mRotation, mPosition); } + + inline bool setParent(LLXform *parent); + + inline void setPosition(const LLVector3& pos); + inline void setPosition(const F32 x, const F32 y, const F32 z); + inline void setPositionX(const F32 x); + inline void setPositionY(const F32 y); + inline void setPositionZ(const F32 z); + inline void addPosition(const LLVector3& pos); + + + inline void setScale(const LLVector3& scale); + inline void setScale(const F32 x, const F32 y, const F32 z); + inline void setRotation(const LLQuaternion& rot); + inline void setRotation(const F32 x, const F32 y, const F32 z); + inline void setRotation(const F32 x, const F32 y, const F32 z, const F32 s); + + // Above functions must be inline for speed, but also + // need to emit warnings. LL_WARNS() causes inline LLError::CallSite + // static objects that make more work for the linker. + // Avoid inline LL_WARNS() by calling this function. + void warn(const char* const msg); + + void setChanged(const U32 bits) { mChanged |= bits; } + bool isChanged() const { return mChanged; } + bool isChanged(const U32 bits) const { return mChanged & bits; } + void clearChanged() { mChanged = 0; } + void clearChanged(U32 bits) { mChanged &= ~bits; } + + void setScaleChildOffset(bool scale) { mScaleChildOffset = scale; } + bool getScaleChildOffset() { return mScaleChildOffset; } + + LLXform* getParent() const { return mParent; } + LLXform* getRoot() const; + virtual bool isRoot() const; + virtual bool isRootEdit() const; + + const LLVector3& getPosition() const { return mPosition; } + const LLVector3& getScale() const { return mScale; } + const LLQuaternion& getRotation() const { return mRotation; } + const LLVector3& getPositionW() const { return mWorldPosition; } + const LLQuaternion& getWorldRotation() const { return mWorldRotation; } + const LLVector3& getWorldPosition() const { return mWorldPosition; } +}; + +class LLXformMatrix : public LLXform +{ +public: + LLXformMatrix() : LLXform() {}; + virtual ~LLXformMatrix(); + + const LLMatrix4& getWorldMatrix() const { return mWorldMatrix; } + void setWorldMatrix (const LLMatrix4& mat) { mWorldMatrix = mat; } + + void init() + { + mWorldMatrix.setIdentity(); + mMin.clearVec(); + mMax.clearVec(); + + LLXform::init(); + } + + void update(); + void updateMatrix(bool update_bounds = true); + void getMinMax(LLVector3& min,LLVector3& max) const; + +protected: + LLMatrix4 mWorldMatrix; + LLVector3 mMin; + LLVector3 mMax; + +}; + +bool LLXform::setParent(LLXform* parent) +{ + // Validate and make sure we're not creating a loop + if (parent == mParent) + { + return true; + } + if (parent) + { + LLXform *cur_par = parent->mParent; + while (cur_par) + { + if (cur_par == this) + { + //warn("LLXform::setParent Creating loop when setting parent!"); + return false; + } + cur_par = cur_par->mParent; + } + } + mParent = parent; + return true; +} + +void LLXform::setPosition(const LLVector3& pos) +{ + setChanged(TRANSLATED); + if (pos.isFinite()) + mPosition = pos; + else + { + mPosition.clearVec(); + warn("Non Finite in LLXform::setPosition(LLVector3)"); + } +} + +void LLXform::setPosition(const F32 x, const F32 y, const F32 z) +{ + setChanged(TRANSLATED); + if (llfinite(x) && llfinite(y) && llfinite(z)) + mPosition.setVec(x,y,z); + else + { + mPosition.clearVec(); + warn("Non Finite in LLXform::setPosition(F32,F32,F32)"); + } +} + +void LLXform::setPositionX(const F32 x) +{ + setChanged(TRANSLATED); + if (llfinite(x)) + mPosition.mV[VX] = x; + else + { + mPosition.mV[VX] = 0.f; + warn("Non Finite in LLXform::setPositionX"); + } +} + +void LLXform::setPositionY(const F32 y) +{ + setChanged(TRANSLATED); + if (llfinite(y)) + mPosition.mV[VY] = y; + else + { + mPosition.mV[VY] = 0.f; + warn("Non Finite in LLXform::setPositionY"); + } +} + +void LLXform::setPositionZ(const F32 z) +{ + setChanged(TRANSLATED); + if (llfinite(z)) + mPosition.mV[VZ] = z; + else + { + mPosition.mV[VZ] = 0.f; + warn("Non Finite in LLXform::setPositionZ"); + } +} + +void LLXform::addPosition(const LLVector3& pos) +{ + setChanged(TRANSLATED); + if (pos.isFinite()) + mPosition += pos; + else + warn("Non Finite in LLXform::addPosition"); +} + +void LLXform::setScale(const LLVector3& scale) +{ + setChanged(SCALED); + if (scale.isFinite()) + mScale = scale; + else + { + mScale.setVec(1.f, 1.f, 1.f); + warn("Non Finite in LLXform::setScale"); + } +} +void LLXform::setScale(const F32 x, const F32 y, const F32 z) +{ + setChanged(SCALED); + if (llfinite(x) && llfinite(y) && llfinite(z)) + mScale.setVec(x,y,z); + else + { + mScale.setVec(1.f, 1.f, 1.f); + warn("Non Finite in LLXform::setScale"); + } +} +void LLXform::setRotation(const LLQuaternion& rot) +{ + setChanged(ROTATED); + if (rot.isFinite()) + mRotation = rot; + else + { + mRotation.loadIdentity(); + warn("Non Finite in LLXform::setRotation"); + } +} +void LLXform::setRotation(const F32 x, const F32 y, const F32 z) +{ + setChanged(ROTATED); + if (llfinite(x) && llfinite(y) && llfinite(z)) + { + mRotation.setQuat(x,y,z); + } + else + { + mRotation.loadIdentity(); + warn("Non Finite in LLXform::setRotation"); + } +} +void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) +{ + setChanged(ROTATED); + if (llfinite(x) && llfinite(y) && llfinite(z) && llfinite(s)) + { + mRotation.mQ[VX] = x; mRotation.mQ[VY] = y; mRotation.mQ[VZ] = z; mRotation.mQ[VS] = s; + } + else + { + mRotation.loadIdentity(); + warn("Non Finite in LLXform::setRotation"); + } +} + +#endif -- cgit v1.2.3 From cb3bd8865aa0f9fb8a247ea595cf1973057ba91f Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 30 May 2024 15:41:36 +0200 Subject: Fix a bunch of uninitialized variable warnings that showed up in Visual Studio --- indra/llmath/llsimdtypes.h | 4 ++-- indra/llmath/llvector4a.h | 2 +- indra/llmath/llvector4logical.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llsimdtypes.h b/indra/llmath/llsimdtypes.h index 9db152adf8..11462170fb 100644 --- a/indra/llmath/llsimdtypes.h +++ b/indra/llmath/llsimdtypes.h @@ -60,7 +60,7 @@ public: inline operator bool() const { return static_cast(m_bool); } private: - int m_bool; + int m_bool{ 0 }; }; #if LL_WINDOWS @@ -118,7 +118,7 @@ public: } private: - LLQuad mQ; + LLQuad mQ{}; }; #endif //LL_SIMD_TYPES_H diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 8f0ee4b739..ea80b33e2d 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -322,7 +322,7 @@ public: inline operator LLQuad() const; private: - LLQuad mQ; + LLQuad mQ{}; }; inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p) diff --git a/indra/llmath/llvector4logical.h b/indra/llmath/llvector4logical.h index d08b5513d9..70759eef5c 100644 --- a/indra/llmath/llvector4logical.h +++ b/indra/llmath/llvector4logical.h @@ -120,7 +120,7 @@ public: private: - LLQuad mQ; + LLQuad mQ{}; }; #endif //LL_VECTOR4ALOGICAL_H -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/llmath/llsphere.cpp | 2 +- indra/llmath/lltreenode.h | 2 +- indra/llmath/llvolume.cpp | 18 +++++++++--------- indra/llmath/llvolume.h | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index 89349af6c8..5f48764455 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -185,7 +185,7 @@ LLSphere LLSphere::getBoundingSphere(const std::vector& sphere_list) // TODO -- improve the accuracy for small collections of spheres LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f ); - S32 sphere_count = sphere_list.size(); + auto sphere_count = sphere_list.size(); if (1 == sphere_count) { // trivial case -- single sphere diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index f648a114ca..e3d30206b7 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -57,7 +57,7 @@ public: virtual bool remove(T* data); virtual void notifyRemoval(T* data); virtual U32 hasListeners() const { return !mListeners.empty(); } - virtual U32 getListenerCount() const { return mListeners.size(); } + virtual U32 getListenerCount() const { return static_cast(mListeners.size()); } virtual LLTreeListener* getListener(U32 index) const { if (index < mListeners.size()) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e6001626f3..b6f710f979 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2392,7 +2392,7 @@ bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size) bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) { { - U32 face_count = mdl.size(); + auto face_count = mdl.size(); if (face_count == 0) { //no faces unpacked, treat as failed decode @@ -2424,7 +2424,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) LLSD::Binary idx = mdl[i]["TriangleList"]; //copy out indices - S32 num_indices = idx.size() / 2; + auto num_indices = idx.size() / 2; const S32 indices_to_discard = num_indices % 3; if (indices_to_discard > 0) { @@ -2432,7 +2432,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) LL_WARNS() << "Incomplete triangle discarded from face! Indices count " << num_indices << " was not divisible by 3. face index: " << i << " Total: " << face_count << LL_ENDL; num_indices -= indices_to_discard; } - face.resizeIndices(num_indices); + face.resizeIndices(static_cast(num_indices)); if (num_indices > 2 && !face.mIndices) { @@ -2453,7 +2453,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) } //copy out vertices - U32 num_verts = pos.size()/(3*2); + U32 num_verts = static_cast(pos.size())/(3*2); face.resizeVertices(num_verts); if (num_verts > 0 && !face.mPositions) @@ -5015,13 +5015,13 @@ void LLVolumeFace::remap() { // Generate a remap buffer std::vector remap(mNumVertices); - S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0], + S32 remap_vertices_count = static_cast(LLMeshOptimizer::generateRemapMultiU16(&remap[0], mIndices, mNumIndices, mPositions, mNormals, mTexCoords, - mNumVertices); + mNumVertices)); // Allocate new buffers S32 size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF; @@ -5565,7 +5565,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) U32 stream_count = data.w.empty() ? 4 : 5; - size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); + S32 vert_count = static_cast(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count)); if (vert_count < 65535 && vert_count != 0) { @@ -6648,8 +6648,8 @@ void LLVolumeFace::pushIndex(const U16& idx) void LLVolumeFace::fillFromLegacyData(std::vector& v, std::vector& idx) { - resizeVertices(v.size()); - resizeIndices(idx.size()); + resizeVertices(static_cast(v.size())); + resizeIndices(static_cast(idx.size())); for (U32 i = 0; i < v.size(); ++i) { diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 44a24f8496..e812e5f0cc 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1019,7 +1019,7 @@ public: U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } U8 getPathType() const { return mParams.getPathParams().getCurveType(); } S32 getNumFaces() const; - S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } + S32 getNumVolumeFaces() const { return static_cast(mVolumeFaces.size()); } F32 getDetail() const { return mDetail; } F32 getSurfaceArea() const { return mSurfaceArea; } const LLVolumeParams& getParams() const { return mParams; } -- cgit v1.2.3 From c0fad3028fd55c2067ce6a0ae4382cffe1014284 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 16:42:43 +0200 Subject: Re-enable compiler warnings C4018, C4100, C4231 and C4506 --- indra/llmath/lloctree.h | 2 +- indra/llmath/llvolume.cpp | 28 ++++++++++++++-------------- indra/llmath/llvolumeoctree.cpp | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 475ce20ae6..eaa2763d2d 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -453,7 +453,7 @@ public: S32 i = data->getBinIndex(); - if (i >= 0 && i < getElementCount()) + if (i >= 0 && i < (S32)getElementCount()) { if (mData[i] == data) { //found it diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index b6f710f979..bbe08f3c9c 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -410,7 +410,7 @@ public: llassert(!branch->isLeaf()); // Empty leaf } - for (S32 i = 0; i < branch->getChildCount(); ++i) + for (U32 i = 0; i < branch->getChildCount(); ++i) { //stretch by child extents LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); min.setMin(min, child->mExtents[0]); @@ -2717,7 +2717,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) if (do_reverse_triangles) { - for (U32 j = 0; j < face.mNumIndices; j += 3) + for (S32 j = 0; j < face.mNumIndices; j += 3) { // swap the 2nd and 3rd index S32 swap = face.mIndices[j+1]; @@ -2754,7 +2754,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) min_tc = face.mTexCoords[0]; max_tc = face.mTexCoords[0]; - for (U32 j = 1; j < face.mNumVertices; ++j) + for (S32 j = 1; j < face.mNumVertices; ++j) { update_min_max(min_tc, max_tc, face.mTexCoords[j]); } @@ -3850,7 +3850,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, LLVector4a* v = (LLVector4a*)face.mPositions; LLVector4a* n = (LLVector4a*)face.mNormals; - for (U32 j = 0; j < face.mNumIndices / 3; j++) + for (S32 j = 0; j < face.mNumIndices / 3; j++) { for (S32 k = 0; k < 3; k++) { @@ -3976,7 +3976,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, LLVector4a* v = (LLVector4a*) face.mPositions; LLVector4a* n = (LLVector4a*) face.mNormals; - for (U32 j = 0; j < face.mNumIndices/3; j++) + for (S32 j = 0; j < face.mNumIndices/3; j++) { //approximate normal S32 v1 = face.mIndices[j*3+0]; @@ -4013,7 +4013,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, } //for each triangle - for (U32 j = 0; j < face.mNumIndices/3; j++) + for (S32 j = 0; j < face.mNumIndices/3; j++) { if (fFacing[j] == (AWAY | TOWARDS)) { //this is a degenerate triangle @@ -5066,7 +5066,7 @@ void LLVolumeFace::optimize(F32 angle_cutoff) range.setSub(mExtents[1],mExtents[0]); //remove redundant vertices - for (U32 i = 0; i < mNumIndices; ++i) + for (S32 i = 0; i < mNumIndices; ++i) { U16 index = mIndices[i]; @@ -5452,7 +5452,7 @@ struct MikktData LLVector3 inv_scale(1.f / face->mNormalizedScale.mV[0], 1.f / face->mNormalizedScale.mV[1], 1.f / face->mNormalizedScale.mV[2]); - for (int i = 0; i < face->mNumIndices; ++i) + for (S32 i = 0; i < face->mNumIndices; ++i) { U32 idx = face->mIndices[i]; @@ -5463,7 +5463,7 @@ struct MikktData n[i].normalize(); tc[i].set(face->mTexCoords[idx]); - if (idx >= face->mNumVertices) + if (idx >= (U32)face->mNumVertices) { // invalid index // replace with a valid index to avoid crashes @@ -5582,11 +5582,11 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) allocateTangents(mNumVertices); - for (int i = 0; i < mNumIndices; ++i) + for (S32 i = 0; i < mNumIndices; ++i) { U32 src_idx = i; U32 dst_idx = remap[i]; - if (dst_idx >= mNumVertices) + if (dst_idx >= (U32)mNumVertices) { dst_idx = mNumVertices - 1; // Shouldn't happen, figure out what gets returned in remap and why. @@ -5613,7 +5613,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) scale.load3(mNormalizedScale.mV); scale.getF32ptr()[3] = 1.f; - for (int i = 0; i < mNumVertices; ++i) + for (S32 i = 0; i < mNumVertices; ++i) { mPositions[i].mul(inv_scale); mNormals[i].mul(scale); @@ -6472,7 +6472,7 @@ void LLVolumeFace::createTangents() CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents); //normalize normals - for (U32 i = 0; i < mNumVertices; i++) + for (S32 i = 0; i < mNumVertices; i++) { //bump map/planar projection code requires normals to be normalized mNormals[i].normalize3fast(); @@ -6744,7 +6744,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) { // Get s value for tex-coord. S32 index = mBeginS + s; - if (index >= profile.size()) + if (index >= (S32)profile.size()) { // edge? ss = flat ? 1.f - begin_stex : 1.f; diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index 74d496fa02..abcd47ea23 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -113,7 +113,7 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNodemBounds[0], vl->mBounds[1])) { node->accept(this); - for (S32 i = 0; i < node->getChildCount(); ++i) + for (U32 i = 0; i < node->getChildCount(); ++i) { traverse(node->getChild(i)); } -- cgit v1.2.3 From 4b52dd754b41948efca0087ccac6d813f1fcce3f Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 18:16:13 +0200 Subject: Fix incorrect use of VX/VY/VZ/VW indices when color components are accessed --- indra/llmath/tests/v4color_test.cpp | 60 ++++---- indra/llmath/tests/v4coloru_test.cpp | 70 ++++----- indra/llmath/v3color.cpp | 2 +- indra/llmath/v3color.h | 18 +-- indra/llmath/v4color.cpp | 112 +++++++------- indra/llmath/v4color.h | 274 +++++++++++++++++------------------ indra/llmath/v4coloru.cpp | 18 +-- indra/llmath/v4coloru.h | 218 ++++++++++++++-------------- 8 files changed, 386 insertions(+), 386 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/tests/v4color_test.cpp b/indra/llmath/tests/v4color_test.cpp index 3b3adbda0d..e5d914a065 100644 --- a/indra/llmath/tests/v4color_test.cpp +++ b/indra/llmath/tests/v4color_test.cpp @@ -49,23 +49,23 @@ namespace tut void v4color_object::test<1>() { LLColor4 llcolor4; - ensure("1:LLColor4:Fail to initialize ", ((0 == llcolor4.mV[VX]) && (0 == llcolor4.mV[VY]) && (0 == llcolor4.mV[VZ])&& (1.0f == llcolor4.mV[VW]))); + ensure("1:LLColor4:Fail to initialize ", ((0 == llcolor4.mV[VRED]) && (0 == llcolor4.mV[VGREEN]) && (0 == llcolor4.mV[VBLUE])&& (1.0f == llcolor4.mV[VALPHA]))); F32 r = 0x20, g = 0xFFFF, b = 0xFF, a = 0xAF; LLColor4 llcolor4a(r,g,b); - ensure("2:LLColor4:Fail to initialize ", ((r == llcolor4a.mV[VX]) && (g == llcolor4a.mV[VY]) && (b == llcolor4a.mV[VZ])&& (1.0f == llcolor4a.mV[VW]))); + ensure("2:LLColor4:Fail to initialize ", ((r == llcolor4a.mV[VRED]) && (g == llcolor4a.mV[VGREEN]) && (b == llcolor4a.mV[VBLUE])&& (1.0f == llcolor4a.mV[VALPHA]))); LLColor4 llcolor4b(r,g,b,a); - ensure("3:LLColor4:Fail to initialize ", ((r == llcolor4b.mV[VX]) && (g == llcolor4b.mV[VY]) && (b == llcolor4b.mV[VZ])&& (a == llcolor4b.mV[VW]))); + ensure("3:LLColor4:Fail to initialize ", ((r == llcolor4b.mV[VRED]) && (g == llcolor4b.mV[VGREEN]) && (b == llcolor4b.mV[VBLUE])&& (a == llcolor4b.mV[VALPHA]))); const F32 vec[4] = {.112f ,23.2f, -4.2f, -.0001f}; LLColor4 llcolor4c(vec); - ensure("4:LLColor4:Fail to initialize ", ((vec[0] == llcolor4c.mV[VX]) && (vec[1] == llcolor4c.mV[VY]) && (vec[2] == llcolor4c.mV[VZ])&& (vec[3] == llcolor4c.mV[VW]))); + ensure("4:LLColor4:Fail to initialize ", ((vec[0] == llcolor4c.mV[VRED]) && (vec[1] == llcolor4c.mV[VGREEN]) && (vec[2] == llcolor4c.mV[VBLUE])&& (vec[3] == llcolor4c.mV[VALPHA]))); LLColor3 llcolor3(-2.23f,1.01f,42.3f); F32 val = -.1f; LLColor4 llcolor4d(llcolor3,val); - ensure("5:LLColor4:Fail to initialize ", ((llcolor3.mV[VX] == llcolor4d.mV[VX]) && (llcolor3.mV[VY] == llcolor4d.mV[VY]) && (llcolor3.mV[VZ] == llcolor4d.mV[VZ])&& (val == llcolor4d.mV[VW]))); + ensure("5:LLColor4:Fail to initialize ", ((llcolor3.mV[VRED] == llcolor4d.mV[VRED]) && (llcolor3.mV[VGREEN] == llcolor4d.mV[VGREEN]) && (llcolor3.mV[VBLUE] == llcolor4d.mV[VBLUE])&& (val == llcolor4d.mV[VALPHA]))); LLSD sd = llcolor4d.getValue(); LLColor4 llcolor4e(sd); @@ -76,7 +76,7 @@ namespace tut LLColor4 llcolor4g(color4u); const F32 SCALE = 1.f/255.f; F32 r2 = r1*SCALE, g2 = g1* SCALE, b2 = b1* SCALE; - ensure("7:LLColor4:Fail to initialize ", ((r2 == llcolor4g.mV[VX]) && (g2 == llcolor4g.mV[VY]) && (b2 == llcolor4g.mV[VZ]))); + ensure("7:LLColor4:Fail to initialize ", ((r2 == llcolor4g.mV[VRED]) && (g2 == llcolor4g.mV[VGREEN]) && (b2 == llcolor4g.mV[VBLUE]))); } template<> template<> @@ -98,10 +98,10 @@ namespace tut F32 r = 0x20, g = 0xFFFF, b = 0xFF,a = 0xAF; LLColor4 llcolor4(r,g,b,a); llcolor4.setToBlack(); - ensure("setToBlack:Fail to set the black ", ((0 == llcolor4.mV[VX]) && (0 == llcolor4.mV[VY]) && (0 == llcolor4.mV[VZ])&& (1.0f == llcolor4.mV[VW]))); + ensure("setToBlack:Fail to set the black ", ((0 == llcolor4.mV[VRED]) && (0 == llcolor4.mV[VGREEN]) && (0 == llcolor4.mV[VBLUE])&& (1.0f == llcolor4.mV[VALPHA]))); llcolor4.setToWhite(); - ensure("setToWhite:Fail to set the white ", ((1.f == llcolor4.mV[VX]) && (1.f == llcolor4.mV[VY]) && (1.f == llcolor4.mV[VZ])&& (1.0f == llcolor4.mV[VW]))); + ensure("setToWhite:Fail to set the white ", ((1.f == llcolor4.mV[VRED]) && (1.f == llcolor4.mV[VGREEN]) && (1.f == llcolor4.mV[VBLUE])&& (1.0f == llcolor4.mV[VALPHA]))); } template<> template<> @@ -110,10 +110,10 @@ namespace tut F32 r = 0x20, g = 0xFFFF, b = 0xFF, a = 0xAF; LLColor4 llcolor4; llcolor4.setVec(r,g,b); - ensure("1:setVec:Fail to set the values ", ((r == llcolor4.mV[VX]) && (g == llcolor4.mV[VY]) && (b == llcolor4.mV[VZ])&& (1.f == llcolor4.mV[VW]))); + ensure("1:setVec:Fail to set the values ", ((r == llcolor4.mV[VRED]) && (g == llcolor4.mV[VGREEN]) && (b == llcolor4.mV[VBLUE])&& (1.f == llcolor4.mV[VALPHA]))); llcolor4.setVec(r,g,b,a); - ensure("2:setVec:Fail to set the values ", ((r == llcolor4.mV[VX]) && (g == llcolor4.mV[VY]) && (b == llcolor4.mV[VZ])&& (a == llcolor4.mV[VW]))); + ensure("2:setVec:Fail to set the values ", ((r == llcolor4.mV[VRED]) && (g == llcolor4.mV[VGREEN]) && (b == llcolor4.mV[VBLUE])&& (a == llcolor4.mV[VALPHA]))); LLColor4 llcolor4a; llcolor4a.setVec(llcolor4); @@ -121,23 +121,23 @@ namespace tut LLColor3 llcolor3(-2.23f,1.01f,42.3f); llcolor4a.setVec(llcolor3); - ensure("4:setVec:Fail to set the values ", ((llcolor3.mV[VX] == llcolor4a.mV[VX]) && (llcolor3.mV[VY] == llcolor4a.mV[VY]) && (llcolor3.mV[VZ] == llcolor4a.mV[VZ]))); + ensure("4:setVec:Fail to set the values ", ((llcolor3.mV[VRED] == llcolor4a.mV[VRED]) && (llcolor3.mV[VGREEN] == llcolor4a.mV[VGREEN]) && (llcolor3.mV[VBLUE] == llcolor4a.mV[VBLUE]))); F32 val = -.33f; llcolor4a.setVec(llcolor3,val); - ensure("4:setVec:Fail to set the values ", ((llcolor3.mV[VX] == llcolor4a.mV[VX]) && (llcolor3.mV[VY] == llcolor4a.mV[VY]) && (llcolor3.mV[VZ] == llcolor4a.mV[VZ]) && (val == llcolor4a.mV[VW]))); + ensure("4:setVec:Fail to set the values ", ((llcolor3.mV[VRED] == llcolor4a.mV[VRED]) && (llcolor3.mV[VGREEN] == llcolor4a.mV[VGREEN]) && (llcolor3.mV[VBLUE] == llcolor4a.mV[VBLUE]) && (val == llcolor4a.mV[VALPHA]))); const F32 vec[4] = {.112f ,23.2f, -4.2f, -.0001f}; LLColor4 llcolor4c; llcolor4c.setVec(vec); - ensure("5:setVec:Fail to initialize ", ((vec[0] == llcolor4c.mV[VX]) && (vec[1] == llcolor4c.mV[VY]) && (vec[2] == llcolor4c.mV[VZ])&& (vec[3] == llcolor4c.mV[VW]))); + ensure("5:setVec:Fail to initialize ", ((vec[0] == llcolor4c.mV[VRED]) && (vec[1] == llcolor4c.mV[VGREEN]) && (vec[2] == llcolor4c.mV[VBLUE])&& (vec[3] == llcolor4c.mV[VALPHA]))); U8 r1 = 0xF2, g1 = 0xFA, b1= 0xBF; LLColor4U color4u(r1,g1,b1); llcolor4.setVec(color4u); const F32 SCALE = 1.f/255.f; F32 r2 = r1*SCALE, g2 = g1* SCALE, b2 = b1* SCALE; - ensure("6:setVec:Fail to initialize ", ((r2 == llcolor4.mV[VX]) && (g2 == llcolor4.mV[VY]) && (b2 == llcolor4.mV[VZ]))); + ensure("6:setVec:Fail to initialize ", ((r2 == llcolor4.mV[VRED]) && (g2 == llcolor4.mV[VGREEN]) && (b2 == llcolor4.mV[VBLUE]))); } template<> template<> @@ -146,7 +146,7 @@ namespace tut F32 alpha = 0xAF; LLColor4 llcolor4; llcolor4.setAlpha(alpha); - ensure("setAlpha:Fail to initialize ", (alpha == llcolor4.mV[VW])); + ensure("setAlpha:Fail to initialize ", (alpha == llcolor4.mV[VALPHA])); } template<> template<> @@ -209,7 +209,7 @@ namespace tut LLColor3 llcolor3(r,g,b); LLColor4 llcolor4a,llcolor4b; llcolor4a = llcolor3; - ensure("Operator=:Fail to initialize ", ((llcolor3.mV[0] == llcolor4a.mV[VX]) && (llcolor3.mV[1] == llcolor4a.mV[VY]) && (llcolor3.mV[2] == llcolor4a.mV[VZ]))); + ensure("Operator=:Fail to initialize ", ((llcolor3.mV[0] == llcolor4a.mV[VRED]) && (llcolor3.mV[1] == llcolor4a.mV[VGREEN]) && (llcolor3.mV[2] == llcolor4a.mV[VBLUE]))); LLSD sd = llcolor4a.getValue(); llcolor4b = LLColor4(sd); ensure_equals("Operator= LLSD:Fail ", llcolor4a, llcolor4b); @@ -234,10 +234,10 @@ namespace tut F32 r2 = 0xABF, g2 = 0xFB, b2 = 0xFFF; LLColor4 llcolor4a(r1,g1,b1),llcolor4b(r2,g2,b2),llcolor4c; llcolor4c = llcolor4b + llcolor4a; - ensure("operator+:Fail to Add the values ", (is_approx_equal(r1+r2,llcolor4c.mV[VX]) && is_approx_equal(g1+g2,llcolor4c.mV[VY]) && is_approx_equal(b1+b2,llcolor4c.mV[VZ]))); + ensure("operator+:Fail to Add the values ", (is_approx_equal(r1+r2,llcolor4c.mV[VRED]) && is_approx_equal(g1+g2,llcolor4c.mV[VGREEN]) && is_approx_equal(b1+b2,llcolor4c.mV[VBLUE]))); llcolor4b += llcolor4a; - ensure("operator+=:Fail to Add the values ", (is_approx_equal(r1+r2,llcolor4b.mV[VX]) && is_approx_equal(g1+g2,llcolor4b.mV[VY]) && is_approx_equal(b1+b2,llcolor4b.mV[VZ]))); + ensure("operator+=:Fail to Add the values ", (is_approx_equal(r1+r2,llcolor4b.mV[VRED]) && is_approx_equal(g1+g2,llcolor4b.mV[VGREEN]) && is_approx_equal(b1+b2,llcolor4b.mV[VBLUE]))); } template<> template<> @@ -247,10 +247,10 @@ namespace tut F32 r2 = 0xABF, g2 = 0xFB, b2 = 0xFFF; LLColor4 llcolor4a(r1,g1,b1),llcolor4b(r2,g2,b2),llcolor4c; llcolor4c = llcolor4a - llcolor4b; - ensure("operator-:Fail to subtract the values ", (is_approx_equal(r1-r2,llcolor4c.mV[VX]) && is_approx_equal(g1-g2,llcolor4c.mV[VY]) && is_approx_equal(b1-b2,llcolor4c.mV[VZ]))); + ensure("operator-:Fail to subtract the values ", (is_approx_equal(r1-r2,llcolor4c.mV[VRED]) && is_approx_equal(g1-g2,llcolor4c.mV[VGREEN]) && is_approx_equal(b1-b2,llcolor4c.mV[VBLUE]))); llcolor4a -= llcolor4b; - ensure("operator-=:Fail to subtract the values ", (is_approx_equal(r1-r2,llcolor4a.mV[VX]) && is_approx_equal(g1-g2,llcolor4a.mV[VY]) && is_approx_equal(b1-b2,llcolor4a.mV[VZ]))); + ensure("operator-=:Fail to subtract the values ", (is_approx_equal(r1-r2,llcolor4a.mV[VRED]) && is_approx_equal(g1-g2,llcolor4a.mV[VGREEN]) && is_approx_equal(b1-b2,llcolor4a.mV[VBLUE]))); } template<> template<> @@ -260,20 +260,20 @@ namespace tut F32 r2 = 0xABF, g2 = 0xFB, b2 = 0xFFF; LLColor4 llcolor4a(r1,g1,b1),llcolor4b(r2,g2,b2),llcolor4c; llcolor4c = llcolor4a * llcolor4b; - ensure("1:operator*:Fail to multiply the values", (is_approx_equal(r1*r2,llcolor4c.mV[VX]) && is_approx_equal(g1*g2,llcolor4c.mV[VY]) && is_approx_equal(b1*b2,llcolor4c.mV[VZ]))); + ensure("1:operator*:Fail to multiply the values", (is_approx_equal(r1*r2,llcolor4c.mV[VRED]) && is_approx_equal(g1*g2,llcolor4c.mV[VGREEN]) && is_approx_equal(b1*b2,llcolor4c.mV[VBLUE]))); F32 mulVal = 3.33f; llcolor4c = llcolor4a * mulVal; - ensure("2:operator*:Fail ", (is_approx_equal(r1*mulVal,llcolor4c.mV[VX]) && is_approx_equal(g1*mulVal,llcolor4c.mV[VY]) && is_approx_equal(b1*mulVal,llcolor4c.mV[VZ]))); + ensure("2:operator*:Fail ", (is_approx_equal(r1*mulVal,llcolor4c.mV[VRED]) && is_approx_equal(g1*mulVal,llcolor4c.mV[VGREEN]) && is_approx_equal(b1*mulVal,llcolor4c.mV[VBLUE]))); llcolor4c = mulVal * llcolor4a; - ensure("3:operator*:Fail to multiply the values", (is_approx_equal(r1*mulVal,llcolor4c.mV[VX]) && is_approx_equal(g1*mulVal,llcolor4c.mV[VY]) && is_approx_equal(b1*mulVal,llcolor4c.mV[VZ]))); + ensure("3:operator*:Fail to multiply the values", (is_approx_equal(r1*mulVal,llcolor4c.mV[VRED]) && is_approx_equal(g1*mulVal,llcolor4c.mV[VGREEN]) && is_approx_equal(b1*mulVal,llcolor4c.mV[VBLUE]))); llcolor4a *= mulVal; - ensure("4:operator*=:Fail to multiply the values ", (is_approx_equal(r1*mulVal,llcolor4a.mV[VX]) && is_approx_equal(g1*mulVal,llcolor4a.mV[VY]) && is_approx_equal(b1*mulVal,llcolor4a.mV[VZ]))); + ensure("4:operator*=:Fail to multiply the values ", (is_approx_equal(r1*mulVal,llcolor4a.mV[VRED]) && is_approx_equal(g1*mulVal,llcolor4a.mV[VGREEN]) && is_approx_equal(b1*mulVal,llcolor4a.mV[VBLUE]))); LLColor4 llcolor4d(r1,g1,b1),llcolor4e(r2,g2,b2); llcolor4e *= llcolor4d; - ensure("5:operator*=:Fail to multiply the values ", (is_approx_equal(r1*r2,llcolor4e.mV[VX]) && is_approx_equal(g1*g2,llcolor4e.mV[VY]) && is_approx_equal(b1*b2,llcolor4e.mV[VZ]))); + ensure("5:operator*=:Fail to multiply the values ", (is_approx_equal(r1*r2,llcolor4e.mV[VRED]) && is_approx_equal(g1*g2,llcolor4e.mV[VGREEN]) && is_approx_equal(b1*b2,llcolor4e.mV[VBLUE]))); } template<> template<> @@ -283,13 +283,13 @@ namespace tut F32 div = 12.345f; LLColor4 llcolor4a(r,g,b,a),llcolor4b; llcolor4b = llcolor4a % div;//chnage only alpha value nor r,g,b; - ensure("1operator%:Fail ", (is_approx_equal(r,llcolor4b.mV[VX]) && is_approx_equal(g,llcolor4b.mV[VY]) && is_approx_equal(b,llcolor4b.mV[VZ])&& is_approx_equal(div*a,llcolor4b.mV[VW]))); + ensure("1operator%:Fail ", (is_approx_equal(r,llcolor4b.mV[VRED]) && is_approx_equal(g,llcolor4b.mV[VGREEN]) && is_approx_equal(b,llcolor4b.mV[VBLUE])&& is_approx_equal(div*a,llcolor4b.mV[VALPHA]))); llcolor4b = div % llcolor4a; - ensure("2operator%:Fail ", (is_approx_equal(r,llcolor4b.mV[VX]) && is_approx_equal(g,llcolor4b.mV[VY]) && is_approx_equal(b,llcolor4b.mV[VZ])&& is_approx_equal(div*a,llcolor4b.mV[VW]))); + ensure("2operator%:Fail ", (is_approx_equal(r,llcolor4b.mV[VRED]) && is_approx_equal(g,llcolor4b.mV[VGREEN]) && is_approx_equal(b,llcolor4b.mV[VBLUE])&& is_approx_equal(div*a,llcolor4b.mV[VALPHA]))); llcolor4a %= div; - ensure("operator%=:Fail ", (is_approx_equal(a*div,llcolor4a.mV[VW]))); + ensure("operator%=:Fail ", (is_approx_equal(a*div,llcolor4a.mV[VALPHA]))); } template<> template<> @@ -312,7 +312,7 @@ namespace tut F32 r = 0x20, g = 0xFFFF, b = 0xFF; LLColor4 llcolor4a(r,g,b),llcolor4b; LLColor3 llcolor3 = vec4to3(llcolor4a); - ensure("vec4to3:Fail to convert vec4 to vec3 ", (is_approx_equal(llcolor3.mV[VX],llcolor4a.mV[VX]) && is_approx_equal(llcolor3.mV[VY],llcolor4a.mV[VY]) && is_approx_equal(llcolor3.mV[VZ],llcolor4a.mV[VZ]))); + ensure("vec4to3:Fail to convert vec4 to vec3 ", (is_approx_equal(llcolor3.mV[VRED],llcolor4a.mV[VRED]) && is_approx_equal(llcolor3.mV[VGREEN],llcolor4a.mV[VGREEN]) && is_approx_equal(llcolor3.mV[VBLUE],llcolor4a.mV[VBLUE]))); llcolor4b = vec3to4(llcolor3); ensure_equals("vec3to4:Fail to convert vec3 to vec4 ", llcolor4b, llcolor4a); } @@ -324,7 +324,7 @@ namespace tut F32 r2 = 0xABF, g2 = 0xFB, b2 = 0xFFF; LLColor4 llcolor4a(r1,g1,b1),llcolor4b(r2,g2,b2),llcolor4c; llcolor4c = lerp(llcolor4a,llcolor4b,val); - ensure("lerp:Fail ", (is_approx_equal(r1 + (r2 - r1)* val,llcolor4c.mV[VX]) && is_approx_equal(g1 + (g2 - g1)* val,llcolor4c.mV[VY]) && is_approx_equal(b1 + (b2 - b1)* val,llcolor4c.mV[VZ]))); + ensure("lerp:Fail ", (is_approx_equal(r1 + (r2 - r1)* val,llcolor4c.mV[VRED]) && is_approx_equal(g1 + (g2 - g1)* val,llcolor4c.mV[VGREEN]) && is_approx_equal(b1 + (b2 - b1)* val,llcolor4c.mV[VBLUE]))); } template<> template<> diff --git a/indra/llmath/tests/v4coloru_test.cpp b/indra/llmath/tests/v4coloru_test.cpp index 55cef0fea1..9d707d18c5 100644 --- a/indra/llmath/tests/v4coloru_test.cpp +++ b/indra/llmath/tests/v4coloru_test.cpp @@ -48,18 +48,18 @@ namespace tut void v4coloru_object::test<1>() { LLColor4U llcolor4u; - ensure("1:LLColor4u:Fail to initialize ", ((0 == llcolor4u.mV[VX]) && (0 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + ensure("1:LLColor4u:Fail to initialize ", ((0 == llcolor4u.mV[VRED]) && (0 == llcolor4u.mV[VGREEN]) && (0 == llcolor4u.mV[VBLUE])&& (255 == llcolor4u.mV[VALPHA]))); U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; LLColor4U llcolor4u1(r,g,b); - ensure("2:LLColor4u:Fail to initialize ", ((r == llcolor4u1.mV[VX]) && (g == llcolor4u1.mV[VY]) && (b == llcolor4u1.mV[VZ])&& (255 == llcolor4u1.mV[VW]))); + ensure("2:LLColor4u:Fail to initialize ", ((r == llcolor4u1.mV[VRED]) && (g == llcolor4u1.mV[VGREEN]) && (b == llcolor4u1.mV[VBLUE])&& (255 == llcolor4u1.mV[VALPHA]))); LLColor4U llcolor4u2(r,g,b,a); - ensure("3:LLColor4u:Fail to initialize ", ((r == llcolor4u2.mV[VX]) && (g == llcolor4u2.mV[VY]) && (b == llcolor4u2.mV[VZ])&& (a == llcolor4u2.mV[VW]))); + ensure("3:LLColor4u:Fail to initialize ", ((r == llcolor4u2.mV[VRED]) && (g == llcolor4u2.mV[VGREEN]) && (b == llcolor4u2.mV[VBLUE])&& (a == llcolor4u2.mV[VALPHA]))); const U8 vec[4] = {0x12,0xFF,0xAF,0x23}; LLColor4U llcolor4u3(vec); - ensure("4:LLColor4u:Fail to initialize ", ((vec[0] == llcolor4u3.mV[VX]) && (vec[1] == llcolor4u3.mV[VY]) && (vec[2] == llcolor4u3.mV[VZ])&& (vec[3] == llcolor4u3.mV[VW]))); + ensure("4:LLColor4u:Fail to initialize ", ((vec[0] == llcolor4u3.mV[VRED]) && (vec[1] == llcolor4u3.mV[VGREEN]) && (vec[2] == llcolor4u3.mV[VBLUE])&& (vec[3] == llcolor4u3.mV[VALPHA]))); LLSD sd = llcolor4u3.getValue(); LLColor4U llcolor4u4(sd); @@ -82,10 +82,10 @@ namespace tut U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; LLColor4U llcolor4u(r,g,b,a); llcolor4u.setToBlack(); - ensure("setToBlack:Fail to set black ", ((0 == llcolor4u.mV[VX]) && (0 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + ensure("setToBlack:Fail to set black ", ((0 == llcolor4u.mV[VRED]) && (0 == llcolor4u.mV[VGREEN]) && (0 == llcolor4u.mV[VBLUE])&& (255 == llcolor4u.mV[VALPHA]))); llcolor4u.setToWhite(); - ensure("setToWhite:Fail to white ", ((255 == llcolor4u.mV[VX]) && (255 == llcolor4u.mV[VY]) && (255 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + ensure("setToWhite:Fail to white ", ((255 == llcolor4u.mV[VRED]) && (255 == llcolor4u.mV[VGREEN]) && (255 == llcolor4u.mV[VBLUE])&& (255 == llcolor4u.mV[VALPHA]))); } template<> template<> @@ -104,11 +104,11 @@ namespace tut U8 r = 0x12, g = 0xFF, b = 0xAF, a = 0x23; LLColor4U llcolor4u; llcolor4u.setVec(r,g,b,a); - ensure("1:setVec:Fail to set the values ", ((r == llcolor4u.mV[VX]) && (g == llcolor4u.mV[VY]) && (b == llcolor4u.mV[VZ])&& (a == llcolor4u.mV[VW]))); + ensure("1:setVec:Fail to set the values ", ((r == llcolor4u.mV[VRED]) && (g == llcolor4u.mV[VGREEN]) && (b == llcolor4u.mV[VBLUE])&& (a == llcolor4u.mV[VALPHA]))); llcolor4u.setToBlack(); llcolor4u.setVec(r,g,b); - ensure("2:setVec:Fail to set the values ", ((r == llcolor4u.mV[VX]) && (g == llcolor4u.mV[VY]) && (b == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + ensure("2:setVec:Fail to set the values ", ((r == llcolor4u.mV[VRED]) && (g == llcolor4u.mV[VGREEN]) && (b == llcolor4u.mV[VBLUE])&& (255 == llcolor4u.mV[VALPHA]))); LLColor4U llcolor4u1; llcolor4u1.setVec(llcolor4u); @@ -117,7 +117,7 @@ namespace tut const U8 vec[4] = {0x12,0xFF,0xAF,0x23}; LLColor4U llcolor4u2; llcolor4u2.setVec(vec); - ensure("4:setVec:Fail to set the values ", ((vec[0] == llcolor4u2.mV[VX]) && (vec[1] == llcolor4u2.mV[VY]) && (vec[2] == llcolor4u2.mV[VZ])&& (vec[3] == llcolor4u2.mV[VW]))); + ensure("4:setVec:Fail to set the values ", ((vec[0] == llcolor4u2.mV[VRED]) && (vec[1] == llcolor4u2.mV[VGREEN]) && (vec[2] == llcolor4u2.mV[VBLUE])&& (vec[3] == llcolor4u2.mV[VALPHA]))); } template<> template<> @@ -126,7 +126,7 @@ namespace tut U8 alpha = 0x12; LLColor4U llcolor4u; llcolor4u.setAlpha(alpha); - ensure("setAlpha:Fail to set alpha value ", (alpha == llcolor4u.mV[VW])); + ensure("setAlpha:Fail to set alpha value ", (alpha == llcolor4u.mV[VALPHA])); } template<> template<> @@ -159,29 +159,29 @@ namespace tut llcolor4u3 = llcolor4u1 + llcolor4u2; ensure_equals( "1a.operator+:Fail to Add the values ", - llcolor4u3.mV[VX], + llcolor4u3.mV[VRED], (U8)(r1+r2)); ensure_equals( "1b.operator+:Fail to Add the values ", - llcolor4u3.mV[VY], + llcolor4u3.mV[VGREEN], (U8)(g1+g2)); ensure_equals( "1c.operator+:Fail to Add the values ", - llcolor4u3.mV[VZ], + llcolor4u3.mV[VBLUE], (U8)(b1+b2)); llcolor4u2 += llcolor4u1; ensure_equals( "2a.operator+=:Fail to Add the values ", - llcolor4u2.mV[VX], + llcolor4u2.mV[VRED], (U8)(r1+r2)); ensure_equals( "2b.operator+=:Fail to Add the values ", - llcolor4u2.mV[VY], + llcolor4u2.mV[VGREEN], (U8)(g1+g2)); ensure_equals( "2c.operator+=:Fail to Add the values ", - llcolor4u2.mV[VZ], + llcolor4u2.mV[VBLUE], (U8)(b1+b2)); } @@ -194,29 +194,29 @@ namespace tut llcolor4u3 = llcolor4u1 - llcolor4u2; ensure_equals( "1a. operator-:Fail to Add the values ", - llcolor4u3.mV[VX], + llcolor4u3.mV[VRED], (U8)(r1-r2)); ensure_equals( "1b. operator-:Fail to Add the values ", - llcolor4u3.mV[VY], + llcolor4u3.mV[VGREEN], (U8)(g1-g2)); ensure_equals( "1c. operator-:Fail to Add the values ", - llcolor4u3.mV[VZ], + llcolor4u3.mV[VBLUE], (U8)(b1-b2)); llcolor4u1 -= llcolor4u2; ensure_equals( "2a. operator-=:Fail to Add the values ", - llcolor4u1.mV[VX], + llcolor4u1.mV[VRED], (U8)(r1-r2)); ensure_equals( "2b. operator-=:Fail to Add the values ", - llcolor4u1.mV[VY], + llcolor4u1.mV[VGREEN], (U8)(g1-g2)); ensure_equals( "2c. operator-=:Fail to Add the values ", - llcolor4u1.mV[VZ], + llcolor4u1.mV[VBLUE], (U8)(b1-b2)); } @@ -229,30 +229,30 @@ namespace tut llcolor4u3 = llcolor4u1 * llcolor4u2; ensure_equals( "1a. operator*:Fail to multiply the values", - llcolor4u3.mV[VX], + llcolor4u3.mV[VRED], (U8)(r1*r2)); ensure_equals( "1b. operator*:Fail to multiply the values", - llcolor4u3.mV[VY], + llcolor4u3.mV[VGREEN], (U8)(g1*g2)); ensure_equals( "1c. operator*:Fail to multiply the values", - llcolor4u3.mV[VZ], + llcolor4u3.mV[VBLUE], (U8)(b1*b2)); U8 mulVal = 123; llcolor4u1 *= mulVal; ensure_equals( "2a. operator*=:Fail to multiply the values", - llcolor4u1.mV[VX], + llcolor4u1.mV[VRED], (U8)(r1*mulVal)); ensure_equals( "2b. operator*=:Fail to multiply the values", - llcolor4u1.mV[VY], + llcolor4u1.mV[VGREEN], (U8)(g1*mulVal)); ensure_equals( "2c. operator*=:Fail to multiply the values", - llcolor4u1.mV[VZ], + llcolor4u1.mV[VBLUE], (U8)(b1*mulVal)); } @@ -274,7 +274,7 @@ namespace tut LLColor4U llcolor4u(r,g,b,a); U8 modVal = 45; llcolor4u %= modVal; - ensure_equals("operator%=:Fail ", llcolor4u.mV[VW], (U8)(a * modVal)); + ensure_equals("operator%=:Fail ", llcolor4u.mV[VALPHA], (U8)(a * modVal)); } template<> template<> @@ -284,7 +284,7 @@ namespace tut LLColor4U llcolor4u1(r,g,b,a); std::string color("12, 23, 132, 50"); LLColor4U::parseColor4U(color, &llcolor4u1); - ensure("parseColor4U() failed to parse the color value ", ((12 == llcolor4u1.mV[VX]) && (23 == llcolor4u1.mV[VY]) && (132 == llcolor4u1.mV[VZ])&& (50 == llcolor4u1.mV[VW]))); + ensure("parseColor4U() failed to parse the color value ", ((12 == llcolor4u1.mV[VRED]) && (23 == llcolor4u1.mV[VGREEN]) && (132 == llcolor4u1.mV[VBLUE])&& (50 == llcolor4u1.mV[VALPHA]))); color = "12, 23, 132"; ensure("2:parseColor4U() failed to parse the color value ", (false == LLColor4U::parseColor4U(color, &llcolor4u1))); @@ -300,8 +300,8 @@ namespace tut LLColor4U llcolor4u(r,g,b,a),llcolor4u1; const F32 fVal = 3.f; llcolor4u1 = llcolor4u.multAll(fVal); - ensure("multAll:Fail to multiply ", (((U8)ll_round(r * fVal) == llcolor4u1.mV[VX]) && (U8)ll_round(g * fVal) == llcolor4u1.mV[VY] - && ((U8)ll_round(b * fVal) == llcolor4u1.mV[VZ])&& ((U8)ll_round(a * fVal) == llcolor4u1.mV[VW]))); + ensure("multAll:Fail to multiply ", (((U8)ll_round(r * fVal) == llcolor4u1.mV[VRED]) && (U8)ll_round(g * fVal) == llcolor4u1.mV[VGREEN] + && ((U8)ll_round(b * fVal) == llcolor4u1.mV[VBLUE])&& ((U8)ll_round(a * fVal) == llcolor4u1.mV[VALPHA]))); } template<> template<> @@ -311,13 +311,13 @@ namespace tut U8 r2 = 23, g2 = 230, b2 = 124, a2 = 255; LLColor4U llcolor4u(r1,g1,b1,a1),llcolor4u1(r2,g2,b2,a2); llcolor4u1 = llcolor4u1.addClampMax(llcolor4u); - ensure("1:addClampMax():Fail to add the value ", ((r1+r2 == llcolor4u1.mV[VX]) && (255 == llcolor4u1.mV[VY]) && (b1+b2 == llcolor4u1.mV[VZ])&& (255 == llcolor4u1.mV[VW]))); + ensure("1:addClampMax():Fail to add the value ", ((r1+r2 == llcolor4u1.mV[VRED]) && (255 == llcolor4u1.mV[VGREEN]) && (b1+b2 == llcolor4u1.mV[VBLUE])&& (255 == llcolor4u1.mV[VALPHA]))); r1 = 132, g1 = 3, b1 = 3, a1 = 2; r2 = 123, g2 = 230, b2 = 154, a2 = 25; LLColor4U llcolor4u2(r1,g1,b1,a1),llcolor4u3(r2,g2,b2,a2); llcolor4u3 = llcolor4u3.addClampMax(llcolor4u2); - ensure("2:addClampMax():Fail to add the value ", ((255 == llcolor4u3.mV[VX]) && (g1+g2 == llcolor4u3.mV[VY]) && (b1+b2 == llcolor4u3.mV[VZ])&& (a1+a2 == llcolor4u3.mV[VW]))); + ensure("2:addClampMax():Fail to add the value ", ((255 == llcolor4u3.mV[VRED]) && (g1+g2 == llcolor4u3.mV[VGREEN]) && (b1+b2 == llcolor4u3.mV[VBLUE])&& (a1+a2 == llcolor4u3.mV[VALPHA]))); } template<> template<> @@ -331,6 +331,6 @@ namespace tut F32 color_scale_factor = MAX_COLOR/r; S32 r2 = ll_round(r * color_scale_factor); S32 g2 = ll_round(g * color_scale_factor); - ensure("setVecScaleClamp():Fail to add the value ", ((r2 == llcolor4u.mV[VX]) && (g2 == llcolor4u.mV[VY]) && (0 == llcolor4u.mV[VZ])&& (255 == llcolor4u.mV[VW]))); + ensure("setVecScaleClamp():Fail to add the value ", ((r2 == llcolor4u.mV[VRED]) && (g2 == llcolor4u.mV[VGREEN]) && (0 == llcolor4u.mV[VBLUE])&& (255 == llcolor4u.mV[VALPHA]))); } } diff --git a/indra/llmath/v3color.cpp b/indra/llmath/v3color.cpp index 9fe9c8d5e5..4367b993f8 100644 --- a/indra/llmath/v3color.cpp +++ b/indra/llmath/v3color.cpp @@ -63,7 +63,7 @@ const LLColor3& LLColor3::operator=(const LLColor4 &a) std::ostream& operator<<(std::ostream& s, const LLColor3 &a) { - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }"; + s << "{ " << a.mV[VRED] << ", " << a.mV[VGREEN] << ", " << a.mV[VBLUE] << " }"; return s; } diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index ea26e9eb76..7b92f85a0c 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -196,17 +196,17 @@ inline LLColor3::LLColor3(void) inline LLColor3::LLColor3(F32 r, F32 g, F32 b) { - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; + mV[VRED] = r; + mV[VGREEN] = g; + mV[VBLUE] = b; } inline LLColor3::LLColor3(const F32 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; } #if LL_WINDOWS @@ -226,11 +226,11 @@ inline LLColor3::LLColor3(const char* color_string) // takes a string of format char tempstr[7]; strncpy(tempstr,color_string,6); /* Flawfinder: ignore */ tempstr[6] = '\0'; - mV[VZ] = (F32)strtol(&tempstr[4],NULL,16)/255.f; + mV[VBLUE] = (F32)strtol(&tempstr[4],NULL,16)/255.f; tempstr[4] = '\0'; - mV[VY] = (F32)strtol(&tempstr[2],NULL,16)/255.f; + mV[VGREEN] = (F32)strtol(&tempstr[2],NULL,16)/255.f; tempstr[2] = '\0'; - mV[VX] = (F32)strtol(&tempstr[0],NULL,16)/255.f; + mV[VRED] = (F32)strtol(&tempstr[0],NULL,16)/255.f; } inline const LLColor3& LLColor3::setToBlack(void) diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index fd3548bc48..ad13656bbd 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -133,57 +133,57 @@ LLColor4::operator LLColor4U() const LLColor4::LLColor4(const LLColor3 &vec, F32 a) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = a; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = a; } LLColor4::LLColor4(const LLColor4U& color4u) { const F32 SCALE = 1.f/255.f; - mV[VX] = color4u.mV[VX] * SCALE; - mV[VY] = color4u.mV[VY] * SCALE; - mV[VZ] = color4u.mV[VZ] * SCALE; - mV[VW] = color4u.mV[VW] * SCALE; + mV[VRED] = color4u.mV[VRED] * SCALE; + mV[VGREEN] = color4u.mV[VGREEN] * SCALE; + mV[VBLUE] = color4u.mV[VBLUE] * SCALE; + mV[VALPHA] = color4u.mV[VALPHA] * SCALE; } LLColor4::LLColor4(const LLVector4& vector4) { - mV[VX] = vector4.mV[VX]; - mV[VY] = vector4.mV[VY]; - mV[VZ] = vector4.mV[VZ]; - mV[VW] = vector4.mV[VW]; + mV[VRED] = vector4.mV[VRED]; + mV[VGREEN] = vector4.mV[VGREEN]; + mV[VBLUE] = vector4.mV[VBLUE]; + mV[VALPHA] = vector4.mV[VALPHA]; } const LLColor4& LLColor4::set(const LLColor4U& color4u) { const F32 SCALE = 1.f/255.f; - mV[VX] = color4u.mV[VX] * SCALE; - mV[VY] = color4u.mV[VY] * SCALE; - mV[VZ] = color4u.mV[VZ] * SCALE; - mV[VW] = color4u.mV[VW] * SCALE; + mV[VRED] = color4u.mV[VRED] * SCALE; + mV[VGREEN] = color4u.mV[VGREEN] * SCALE; + mV[VBLUE] = color4u.mV[VBLUE] * SCALE; + mV[VALPHA] = color4u.mV[VALPHA] * SCALE; return (*this); } const LLColor4& LLColor4::set(const LLColor3 &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; // no change to alpha! -// mV[VW] = 1.f; +// mV[VALPHA] = 1.f; return (*this); } const LLColor4& LLColor4::set(const LLColor3 &vec, F32 a) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = a; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = a; return (*this); } @@ -191,22 +191,22 @@ const LLColor4& LLColor4::set(const LLColor3 &vec, F32 a) const LLColor4& LLColor4::setVec(const LLColor4U& color4u) { const F32 SCALE = 1.f/255.f; - mV[VX] = color4u.mV[VX] * SCALE; - mV[VY] = color4u.mV[VY] * SCALE; - mV[VZ] = color4u.mV[VZ] * SCALE; - mV[VW] = color4u.mV[VW] * SCALE; + mV[VRED] = color4u.mV[VRED] * SCALE; + mV[VGREEN] = color4u.mV[VGREEN] * SCALE; + mV[VBLUE] = color4u.mV[VBLUE] * SCALE; + mV[VALPHA] = color4u.mV[VALPHA] * SCALE; return (*this); } // deprecated -- use set() const LLColor4& LLColor4::setVec(const LLColor3 &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; // no change to alpha! -// mV[VW] = 1.f; +// mV[VALPHA] = 1.f; return (*this); } @@ -214,10 +214,10 @@ const LLColor4& LLColor4::setVec(const LLColor3 &vec) // deprecated -- use set() const LLColor4& LLColor4::setVec(const LLColor3 &vec, F32 a) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = a; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = a; return (*this); } @@ -257,45 +257,45 @@ void LLColor4::setValue(const LLSD& sd) const LLColor4& LLColor4::operator=(const LLColor3 &a) { - mV[VX] = a.mV[VX]; - mV[VY] = a.mV[VY]; - mV[VZ] = a.mV[VZ]; + mV[VRED] = a.mV[VRED]; + mV[VGREEN] = a.mV[VGREEN]; + mV[VBLUE] = a.mV[VBLUE]; // converting from an rgb sets a=1 (opaque) - mV[VW] = 1.f; + mV[VALPHA] = 1.f; return (*this); } std::ostream& operator<<(std::ostream& s, const LLColor4 &a) { - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << ", " << a.mV[VW] << " }"; + s << "{ " << a.mV[VRED] << ", " << a.mV[VGREEN] << ", " << a.mV[VBLUE] << ", " << a.mV[VALPHA] << " }"; return s; } bool operator==(const LLColor4 &a, const LLColor3 &b) { - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ])); + return ( (a.mV[VRED] == b.mV[VRED]) + &&(a.mV[VGREEN] == b.mV[VGREEN]) + &&(a.mV[VBLUE] == b.mV[VBLUE])); } bool operator!=(const LLColor4 &a, const LLColor3 &b) { - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ])); + return ( (a.mV[VRED] != b.mV[VRED]) + ||(a.mV[VGREEN] != b.mV[VGREEN]) + ||(a.mV[VBLUE] != b.mV[VBLUE])); } LLColor3 vec4to3(const LLColor4 &vec) { - LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); + LLColor3 temp(vec.mV[VRED], vec.mV[VGREEN], vec.mV[VBLUE]); return temp; } LLColor4 vec3to4(const LLColor3 &vec) { - LLColor3 temp(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); + LLColor3 temp(vec.mV[VRED], vec.mV[VGREEN], vec.mV[VBLUE]); return temp; } @@ -408,10 +408,10 @@ bool LLColor4::parseColor(const std::string& buf, LLColor4* color) { // There are more tokens to read. This must be a vector. LLColor4 v; - LLStringUtil::convertToF32( color_name, v.mV[VX] ); - LLStringUtil::convertToF32( *token_iter, v.mV[VY] ); - v.mV[VZ] = 0.0f; - v.mV[VW] = 1.0f; + LLStringUtil::convertToF32( color_name, v.mV[VRED] ); + LLStringUtil::convertToF32( *token_iter, v.mV[VGREEN] ); + v.mV[VBLUE] = 0.0f; + v.mV[VALPHA] = 1.0f; ++token_iter; if (token_iter == tokens.end()) @@ -422,18 +422,18 @@ bool LLColor4::parseColor(const std::string& buf, LLColor4* color) else { // There is a z-component. - LLStringUtil::convertToF32( *token_iter, v.mV[VZ] ); + LLStringUtil::convertToF32( *token_iter, v.mV[VBLUE] ); ++token_iter; if (token_iter != tokens.end()) { // There is an alpha component. - LLStringUtil::convertToF32( *token_iter, v.mV[VW] ); + LLStringUtil::convertToF32( *token_iter, v.mV[VALPHA] ); } } // Make sure all values are between 0 and 1. - if (v.mV[VX] > 1.f || v.mV[VY] > 1.f || v.mV[VZ] > 1.f || v.mV[VW] > 1.f) + if (v.mV[VRED] > 1.f || v.mV[VGREEN] > 1.f || v.mV[VBLUE] > 1.f || v.mV[VALPHA] > 1.f) { v = v * (1.f / 255.f); } diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 1e20ab977a..e9bb6a07ba 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -242,10 +242,10 @@ LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u); inline LLColor4::LLColor4(void) { - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; + mV[VRED] = 0.f; + mV[VGREEN] = 0.f; + mV[VBLUE] = 0.f; + mV[VALPHA] = 1.f; } inline LLColor4::LLColor4(const LLSD& sd) @@ -255,113 +255,113 @@ inline LLColor4::LLColor4(const LLSD& sd) inline LLColor4::LLColor4(F32 r, F32 g, F32 b) { - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = 1.f; + mV[VRED] = r; + mV[VGREEN] = g; + mV[VBLUE] = b; + mV[VALPHA] = 1.f; } inline LLColor4::LLColor4(F32 r, F32 g, F32 b, F32 a) { - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = a; + mV[VRED] = r; + mV[VGREEN] = g; + mV[VBLUE] = b; + mV[VALPHA] = a; } inline LLColor4::LLColor4(U32 clr) { - mV[VX] = (clr&0xff) * (1.0f/255.0f); - mV[VY] = ((clr>>8)&0xff) * (1.0f/255.0f); - mV[VZ] = ((clr>>16)&0xff) * (1.0f/255.0f); - mV[VW] = (clr>>24) * (1.0f/255.0f); + mV[VRED] = (clr&0xff) * (1.0f/255.0f); + mV[VGREEN] = ((clr>>8)&0xff) * (1.0f/255.0f); + mV[VBLUE] = ((clr>>16)&0xff) * (1.0f/255.0f); + mV[VALPHA] = (clr>>24) * (1.0f/255.0f); } inline LLColor4::LLColor4(const F32 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; + mV[VALPHA] = vec[VALPHA]; } inline const LLColor4& LLColor4::setToBlack(void) { - mV[VX] = 0.f; - mV[VY] = 0.f; - mV[VZ] = 0.f; - mV[VW] = 1.f; + mV[VRED] = 0.f; + mV[VGREEN] = 0.f; + mV[VBLUE] = 0.f; + mV[VALPHA] = 1.f; return (*this); } inline const LLColor4& LLColor4::setToWhite(void) { - mV[VX] = 1.f; - mV[VY] = 1.f; - mV[VZ] = 1.f; - mV[VW] = 1.f; + mV[VRED] = 1.f; + mV[VGREEN] = 1.f; + mV[VBLUE] = 1.f; + mV[VALPHA] = 1.f; return (*this); } inline const LLColor4& LLColor4::set(F32 x, F32 y, F32 z) { - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; + mV[VRED] = x; + mV[VGREEN] = y; + mV[VBLUE] = z; // no change to alpha! -// mV[VW] = 1.f; +// mV[VALPHA] = 1.f; return (*this); } inline const LLColor4& LLColor4::set(F32 x, F32 y, F32 z, F32 a) { - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = a; + mV[VRED] = x; + mV[VGREEN] = y; + mV[VBLUE] = z; + mV[VALPHA] = a; return (*this); } inline const LLColor4& LLColor4::set(const LLColor4 &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = vec.mV[VALPHA]; return (*this); } inline const LLColor4& LLColor4::set(const F32 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; + mV[VALPHA] = vec[VALPHA]; return (*this); } inline const LLColor4& LLColor4::set(const F64 *vec) { - mV[VX] = static_cast(vec[VX]); - mV[VY] = static_cast(vec[VY]); - mV[VZ] = static_cast(vec[VZ]); - mV[VW] = static_cast(vec[VW]); + mV[VRED] = static_cast(vec[VRED]); + mV[VGREEN] = static_cast(vec[VGREEN]); + mV[VBLUE] = static_cast(vec[VBLUE]); + mV[VALPHA] = static_cast(vec[VALPHA]); return (*this); } // deprecated inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z) { - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; + mV[VRED] = x; + mV[VGREEN] = y; + mV[VBLUE] = z; // no change to alpha! -// mV[VW] = 1.f; +// mV[VALPHA] = 1.f; return (*this); } @@ -369,20 +369,20 @@ inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z) // deprecated inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z, F32 a) { - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; - mV[VW] = a; + mV[VRED] = x; + mV[VGREEN] = y; + mV[VBLUE] = z; + mV[VALPHA] = a; return (*this); } // deprecated inline const LLColor4& LLColor4::setVec(const LLColor4 &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = vec.mV[VALPHA]; return (*this); } @@ -390,16 +390,16 @@ inline const LLColor4& LLColor4::setVec(const LLColor4 &vec) // deprecated inline const LLColor4& LLColor4::setVec(const F32 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; + mV[VALPHA] = vec[VALPHA]; return (*this); } inline const LLColor4& LLColor4::setAlpha(F32 a) { - mV[VW] = a; + mV[VALPHA] = a; return (*this); } @@ -407,25 +407,25 @@ inline const LLColor4& LLColor4::setAlpha(F32 a) inline F32 LLColor4::length(void) const { - return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + return (F32) sqrt(mV[VRED]*mV[VRED] + mV[VGREEN]*mV[VGREEN] + mV[VBLUE]*mV[VBLUE]); } inline F32 LLColor4::lengthSquared(void) const { - return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; + return mV[VRED]*mV[VRED] + mV[VGREEN]*mV[VGREEN] + mV[VBLUE]*mV[VBLUE]; } inline F32 LLColor4::normalize(void) { - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = (F32) sqrt(mV[VRED]*mV[VRED] + mV[VGREEN]*mV[VGREEN] + mV[VBLUE]*mV[VBLUE]); F32 oomag; if (mag) { oomag = 1.f/mag; - mV[VX] *= oomag; - mV[VY] *= oomag; - mV[VZ] *= oomag; + mV[VRED] *= oomag; + mV[VGREEN] *= oomag; + mV[VBLUE] *= oomag; } return (mag); } @@ -433,27 +433,27 @@ inline F32 LLColor4::normalize(void) // deprecated inline F32 LLColor4::magVec(void) const { - return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + return (F32) sqrt(mV[VRED]*mV[VRED] + mV[VGREEN]*mV[VGREEN] + mV[VBLUE]*mV[VBLUE]); } // deprecated inline F32 LLColor4::magVecSquared(void) const { - return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; + return mV[VRED]*mV[VRED] + mV[VGREEN]*mV[VGREEN] + mV[VBLUE]*mV[VBLUE]; } // deprecated inline F32 LLColor4::normVec(void) { - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = (F32) sqrt(mV[VRED]*mV[VRED] + mV[VGREEN]*mV[VGREEN] + mV[VBLUE]*mV[VBLUE]); F32 oomag; if (mag) { oomag = 1.f/mag; - mV[VX] *= oomag; - mV[VY] *= oomag; - mV[VZ] *= oomag; + mV[VRED] *= oomag; + mV[VGREEN] *= oomag; + mV[VBLUE] *= oomag; } return (mag); } @@ -464,135 +464,135 @@ inline F32 LLColor4::normVec(void) inline LLColor4 operator+(const LLColor4 &a, const LLColor4 &b) { return LLColor4( - a.mV[VX] + b.mV[VX], - a.mV[VY] + b.mV[VY], - a.mV[VZ] + b.mV[VZ], - a.mV[VW] + b.mV[VW]); + a.mV[VRED] + b.mV[VRED], + a.mV[VGREEN] + b.mV[VGREEN], + a.mV[VBLUE] + b.mV[VBLUE], + a.mV[VALPHA] + b.mV[VALPHA]); } inline LLColor4 operator-(const LLColor4 &a, const LLColor4 &b) { return LLColor4( - a.mV[VX] - b.mV[VX], - a.mV[VY] - b.mV[VY], - a.mV[VZ] - b.mV[VZ], - a.mV[VW] - b.mV[VW]); + a.mV[VRED] - b.mV[VRED], + a.mV[VGREEN] - b.mV[VGREEN], + a.mV[VBLUE] - b.mV[VBLUE], + a.mV[VALPHA] - b.mV[VALPHA]); } inline LLColor4 operator*(const LLColor4 &a, const LLColor4 &b) { return LLColor4( - a.mV[VX] * b.mV[VX], - a.mV[VY] * b.mV[VY], - a.mV[VZ] * b.mV[VZ], - a.mV[VW] * b.mV[VW]); + a.mV[VRED] * b.mV[VRED], + a.mV[VGREEN] * b.mV[VGREEN], + a.mV[VBLUE] * b.mV[VBLUE], + a.mV[VALPHA] * b.mV[VALPHA]); } inline LLColor4 operator*(const LLColor4 &a, F32 k) { // only affects rgb (not a!) return LLColor4( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); + a.mV[VRED] * k, + a.mV[VGREEN] * k, + a.mV[VBLUE] * k, + a.mV[VALPHA]); } inline LLColor4 operator/(const LLColor4 &a, F32 k) { return LLColor4( - a.mV[VX] / k, - a.mV[VY] / k, - a.mV[VZ] / k, - a.mV[VW]); + a.mV[VRED] / k, + a.mV[VGREEN] / k, + a.mV[VBLUE] / k, + a.mV[VALPHA]); } inline LLColor4 operator*(F32 k, const LLColor4 &a) { // only affects rgb (not a!) return LLColor4( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); + a.mV[VRED] * k, + a.mV[VGREEN] * k, + a.mV[VBLUE] * k, + a.mV[VALPHA]); } inline LLColor4 operator%(F32 k, const LLColor4 &a) { // only affects alpha (not rgb!) return LLColor4( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k); + a.mV[VRED], + a.mV[VGREEN], + a.mV[VBLUE], + a.mV[VALPHA] * k); } inline LLColor4 operator%(const LLColor4 &a, F32 k) { // only affects alpha (not rgb!) return LLColor4( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k); + a.mV[VRED], + a.mV[VGREEN], + a.mV[VBLUE], + a.mV[VALPHA] * k); } inline bool operator==(const LLColor4 &a, const LLColor4 &b) { - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ]) - &&(a.mV[VW] == b.mV[VW])); + return ( (a.mV[VRED] == b.mV[VRED]) + &&(a.mV[VGREEN] == b.mV[VGREEN]) + &&(a.mV[VBLUE] == b.mV[VBLUE]) + &&(a.mV[VALPHA] == b.mV[VALPHA])); } inline bool operator!=(const LLColor4 &a, const LLColor4 &b) { - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ]) - ||(a.mV[VW] != b.mV[VW])); + return ( (a.mV[VRED] != b.mV[VRED]) + ||(a.mV[VGREEN] != b.mV[VGREEN]) + ||(a.mV[VBLUE] != b.mV[VBLUE]) + ||(a.mV[VALPHA] != b.mV[VALPHA])); } inline const LLColor4& operator+=(LLColor4 &a, const LLColor4 &b) { - a.mV[VX] += b.mV[VX]; - a.mV[VY] += b.mV[VY]; - a.mV[VZ] += b.mV[VZ]; - a.mV[VW] += b.mV[VW]; + a.mV[VRED] += b.mV[VRED]; + a.mV[VGREEN] += b.mV[VGREEN]; + a.mV[VBLUE] += b.mV[VBLUE]; + a.mV[VALPHA] += b.mV[VALPHA]; return a; } inline const LLColor4& operator-=(LLColor4 &a, const LLColor4 &b) { - a.mV[VX] -= b.mV[VX]; - a.mV[VY] -= b.mV[VY]; - a.mV[VZ] -= b.mV[VZ]; - a.mV[VW] -= b.mV[VW]; + a.mV[VRED] -= b.mV[VRED]; + a.mV[VGREEN] -= b.mV[VGREEN]; + a.mV[VBLUE] -= b.mV[VBLUE]; + a.mV[VALPHA] -= b.mV[VALPHA]; return a; } inline const LLColor4& operator*=(LLColor4 &a, F32 k) { // only affects rgb (not a!) - a.mV[VX] *= k; - a.mV[VY] *= k; - a.mV[VZ] *= k; + a.mV[VRED] *= k; + a.mV[VGREEN] *= k; + a.mV[VBLUE] *= k; return a; } inline const LLColor4& operator *=(LLColor4 &a, const LLColor4 &b) { - a.mV[VX] *= b.mV[VX]; - a.mV[VY] *= b.mV[VY]; - a.mV[VZ] *= b.mV[VZ]; -// a.mV[VW] *= b.mV[VW]; + a.mV[VRED] *= b.mV[VRED]; + a.mV[VGREEN] *= b.mV[VGREEN]; + a.mV[VBLUE] *= b.mV[VBLUE]; +// a.mV[VALPHA] *= b.mV[VALPHA]; return a; } inline const LLColor4& operator%=(LLColor4 &a, F32 k) { // only affects alpha (not rgb!) - a.mV[VW] *= k; + a.mV[VALPHA] *= k; return a; } @@ -614,10 +614,10 @@ inline F32 distVec_squared(const LLColor4 &a, const LLColor4 &b) inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u) { return LLColor4( - a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, - a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u, - a.mV[VZ] + (b.mV[VZ] - a.mV[VZ]) * u, - a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u); + a.mV[VRED] + (b.mV[VRED] - a.mV[VRED]) * u, + a.mV[VGREEN] + (b.mV[VGREEN] - a.mV[VGREEN]) * u, + a.mV[VBLUE] + (b.mV[VBLUE] - a.mV[VBLUE]) * u, + a.mV[VALPHA] + (b.mV[VALPHA] - a.mV[VALPHA]) * u); } inline bool LLColor4::operator<(const LLColor4& rhs) const diff --git a/indra/llmath/v4coloru.cpp b/indra/llmath/v4coloru.cpp index 45d310856a..acf349245a 100644 --- a/indra/llmath/v4coloru.cpp +++ b/indra/llmath/v4coloru.cpp @@ -53,10 +53,10 @@ LLColor4U::operator LLColor4() /* LLColor4U::LLColor4U(const LLColor3 &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = 255; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = 255; } */ @@ -70,12 +70,12 @@ LLColor4U::LLColor4U(const LLColor3 &vec) /* LLColor4U LLColor4U::operator=(const LLColor3 &a) { - mV[VX] = a.mV[VX]; - mV[VY] = a.mV[VY]; - mV[VZ] = a.mV[VZ]; + mV[VRED] = a.mV[VRED]; + mV[VGREEN] = a.mV[VGREEN]; + mV[VBLUE] = a.mV[VBLUE]; // converting from an rgb sets a=1 (opaque) - mV[VW] = 255; + mV[VALPHA] = 255; return (*this); } */ @@ -83,7 +83,7 @@ LLColor4U LLColor4U::operator=(const LLColor3 &a) std::ostream& operator<<(std::ostream& s, const LLColor4U &a) { - s << "{ " << (S32)a.mV[VX] << ", " << (S32)a.mV[VY] << ", " << (S32)a.mV[VZ] << ", " << (S32)a.mV[VW] << " }"; + s << "{ " << (S32)a.mV[VRED] << ", " << (S32)a.mV[VGREEN] << ", " << (S32)a.mV[VBLUE] << ", " << (S32)a.mV[VALPHA] << " }"; return s; } diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index 6d921d12fa..29128a08a7 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -142,34 +142,34 @@ F32 distVec_squared(const LLColor4U &a, const LLColor4U &b); // Returns d inline LLColor4U::LLColor4U() { - mV[VX] = 0; - mV[VY] = 0; - mV[VZ] = 0; - mV[VW] = 255; + mV[VRED] = 0; + mV[VGREEN] = 0; + mV[VBLUE] = 0; + mV[VALPHA] = 255; } inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b) { - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = 255; + mV[VRED] = r; + mV[VGREEN] = g; + mV[VBLUE] = b; + mV[VALPHA] = 255; } inline LLColor4U::LLColor4U(U8 r, U8 g, U8 b, U8 a) { - mV[VX] = r; - mV[VY] = g; - mV[VZ] = b; - mV[VW] = a; + mV[VRED] = r; + mV[VGREEN] = g; + mV[VBLUE] = b; + mV[VALPHA] = a; } inline LLColor4U::LLColor4U(const U8 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; + mV[VALPHA] = vec[VALPHA]; } /* @@ -181,30 +181,30 @@ inline LLColor4U::operator LLColor4() inline const LLColor4U& LLColor4U::setToBlack(void) { - mV[VX] = 0; - mV[VY] = 0; - mV[VZ] = 0; - mV[VW] = 255; + mV[VRED] = 0; + mV[VGREEN] = 0; + mV[VBLUE] = 0; + mV[VALPHA] = 255; return (*this); } inline const LLColor4U& LLColor4U::setToWhite(void) { - mV[VX] = 255; - mV[VY] = 255; - mV[VZ] = 255; - mV[VW] = 255; + mV[VRED] = 255; + mV[VGREEN] = 255; + mV[VBLUE] = 255; + mV[VALPHA] = 255; return (*this); } inline const LLColor4U& LLColor4U::set(const U8 x, const U8 y, const U8 z) { - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; + mV[VRED] = x; + mV[VGREEN] = y; + mV[VBLUE] = z; // no change to alpha! -// mV[VW] = 255; +// mV[VALPHA] = 255; return (*this); } @@ -220,31 +220,31 @@ inline const LLColor4U& LLColor4U::set(const U8 r, const U8 g, const U8 b, U8 a) inline const LLColor4U& LLColor4U::set(const LLColor4U &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = vec.mV[VALPHA]; return (*this); } inline const LLColor4U& LLColor4U::set(const U8 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; + mV[VALPHA] = vec[VALPHA]; return (*this); } // deprecated inline const LLColor4U& LLColor4U::setVec(const U8 x, const U8 y, const U8 z) { - mV[VX] = x; - mV[VY] = y; - mV[VZ] = z; + mV[VRED] = x; + mV[VGREEN] = y; + mV[VBLUE] = z; // no change to alpha! -// mV[VW] = 255; +// mV[VALPHA] = 255; return (*this); } @@ -262,26 +262,26 @@ inline const LLColor4U& LLColor4U::setVec(const U8 r, const U8 g, const U8 b, U8 // deprecated inline const LLColor4U& LLColor4U::setVec(const LLColor4U &vec) { - mV[VX] = vec.mV[VX]; - mV[VY] = vec.mV[VY]; - mV[VZ] = vec.mV[VZ]; - mV[VW] = vec.mV[VW]; + mV[VRED] = vec.mV[VRED]; + mV[VGREEN] = vec.mV[VGREEN]; + mV[VBLUE] = vec.mV[VBLUE]; + mV[VALPHA] = vec.mV[VALPHA]; return (*this); } // deprecated inline const LLColor4U& LLColor4U::setVec(const U8 *vec) { - mV[VX] = vec[VX]; - mV[VY] = vec[VY]; - mV[VZ] = vec[VZ]; - mV[VW] = vec[VW]; + mV[VRED] = vec[VRED]; + mV[VGREEN] = vec[VGREEN]; + mV[VBLUE] = vec[VBLUE]; + mV[VALPHA] = vec[VALPHA]; return (*this); } inline const LLColor4U& LLColor4U::setAlpha(U8 a) { - mV[VW] = a; + mV[VALPHA] = a; return (*this); } @@ -289,159 +289,159 @@ inline const LLColor4U& LLColor4U::setAlpha(U8 a) inline F32 LLColor4U::length(void) const { - return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); + return (F32) sqrt( ((F32)mV[VRED]) * mV[VRED] + ((F32)mV[VGREEN]) * mV[VGREEN] + ((F32)mV[VBLUE]) * mV[VBLUE] ); } inline F32 LLColor4U::lengthSquared(void) const { - return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ]; + return ((F32)mV[VRED]) * mV[VRED] + ((F32)mV[VGREEN]) * mV[VGREEN] + ((F32)mV[VBLUE]) * mV[VBLUE]; } // deprecated inline F32 LLColor4U::magVec(void) const { - return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); + return (F32) sqrt( ((F32)mV[VRED]) * mV[VRED] + ((F32)mV[VGREEN]) * mV[VGREEN] + ((F32)mV[VBLUE]) * mV[VBLUE] ); } // deprecated inline F32 LLColor4U::magVecSquared(void) const { - return ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ]; + return ((F32)mV[VRED]) * mV[VRED] + ((F32)mV[VGREEN]) * mV[VGREEN] + ((F32)mV[VBLUE]) * mV[VBLUE]; } inline LLColor4U operator+(const LLColor4U &a, const LLColor4U &b) { return LLColor4U( - a.mV[VX] + b.mV[VX], - a.mV[VY] + b.mV[VY], - a.mV[VZ] + b.mV[VZ], - a.mV[VW] + b.mV[VW]); + a.mV[VRED] + b.mV[VRED], + a.mV[VGREEN] + b.mV[VGREEN], + a.mV[VBLUE] + b.mV[VBLUE], + a.mV[VALPHA] + b.mV[VALPHA]); } inline LLColor4U operator-(const LLColor4U &a, const LLColor4U &b) { return LLColor4U( - a.mV[VX] - b.mV[VX], - a.mV[VY] - b.mV[VY], - a.mV[VZ] - b.mV[VZ], - a.mV[VW] - b.mV[VW]); + a.mV[VRED] - b.mV[VRED], + a.mV[VGREEN] - b.mV[VGREEN], + a.mV[VBLUE] - b.mV[VBLUE], + a.mV[VALPHA] - b.mV[VALPHA]); } inline LLColor4U operator*(const LLColor4U &a, const LLColor4U &b) { return LLColor4U( - a.mV[VX] * b.mV[VX], - a.mV[VY] * b.mV[VY], - a.mV[VZ] * b.mV[VZ], - a.mV[VW] * b.mV[VW]); + a.mV[VRED] * b.mV[VRED], + a.mV[VGREEN] * b.mV[VGREEN], + a.mV[VBLUE] * b.mV[VBLUE], + a.mV[VALPHA] * b.mV[VALPHA]); } inline LLColor4U LLColor4U::addClampMax(const LLColor4U &color) { - return LLColor4U(llmin((S32)mV[VX] + color.mV[VX], 255), - llmin((S32)mV[VY] + color.mV[VY], 255), - llmin((S32)mV[VZ] + color.mV[VZ], 255), - llmin((S32)mV[VW] + color.mV[VW], 255)); + return LLColor4U(llmin((S32)mV[VRED] + color.mV[VRED], 255), + llmin((S32)mV[VGREEN] + color.mV[VGREEN], 255), + llmin((S32)mV[VBLUE] + color.mV[VBLUE], 255), + llmin((S32)mV[VALPHA] + color.mV[VALPHA], 255)); } inline LLColor4U LLColor4U::multAll(const F32 k) { // Round to nearest return LLColor4U( - (U8)ll_round(mV[VX] * k), - (U8)ll_round(mV[VY] * k), - (U8)ll_round(mV[VZ] * k), - (U8)ll_round(mV[VW] * k)); + (U8)ll_round(mV[VRED] * k), + (U8)ll_round(mV[VGREEN] * k), + (U8)ll_round(mV[VBLUE] * k), + (U8)ll_round(mV[VALPHA] * k)); } /* inline LLColor4U operator*(const LLColor4U &a, U8 k) { // only affects rgb (not a!) return LLColor4U( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); + a.mV[VRED] * k, + a.mV[VGREEN] * k, + a.mV[VBLUE] * k, + a.mV[VALPHA]); } inline LLColor4U operator*(U8 k, const LLColor4U &a) { // only affects rgb (not a!) return LLColor4U( - a.mV[VX] * k, - a.mV[VY] * k, - a.mV[VZ] * k, - a.mV[VW]); + a.mV[VRED] * k, + a.mV[VGREEN] * k, + a.mV[VBLUE] * k, + a.mV[VALPHA]); } inline LLColor4U operator%(U8 k, const LLColor4U &a) { // only affects alpha (not rgb!) return LLColor4U( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k ); + a.mV[VRED], + a.mV[VGREEN], + a.mV[VBLUE], + a.mV[VALPHA] * k ); } inline LLColor4U operator%(const LLColor4U &a, U8 k) { // only affects alpha (not rgb!) return LLColor4U( - a.mV[VX], - a.mV[VY], - a.mV[VZ], - a.mV[VW] * k ); + a.mV[VRED], + a.mV[VGREEN], + a.mV[VBLUE], + a.mV[VALPHA] * k ); } */ inline bool operator==(const LLColor4U &a, const LLColor4U &b) { - return ( (a.mV[VX] == b.mV[VX]) - &&(a.mV[VY] == b.mV[VY]) - &&(a.mV[VZ] == b.mV[VZ]) - &&(a.mV[VW] == b.mV[VW])); + return ( (a.mV[VRED] == b.mV[VRED]) + &&(a.mV[VGREEN] == b.mV[VGREEN]) + &&(a.mV[VBLUE] == b.mV[VBLUE]) + &&(a.mV[VALPHA] == b.mV[VALPHA])); } inline bool operator!=(const LLColor4U &a, const LLColor4U &b) { - return ( (a.mV[VX] != b.mV[VX]) - ||(a.mV[VY] != b.mV[VY]) - ||(a.mV[VZ] != b.mV[VZ]) - ||(a.mV[VW] != b.mV[VW])); + return ( (a.mV[VRED] != b.mV[VRED]) + ||(a.mV[VGREEN] != b.mV[VGREEN]) + ||(a.mV[VBLUE] != b.mV[VBLUE]) + ||(a.mV[VALPHA] != b.mV[VALPHA])); } inline const LLColor4U& operator+=(LLColor4U &a, const LLColor4U &b) { - a.mV[VX] += b.mV[VX]; - a.mV[VY] += b.mV[VY]; - a.mV[VZ] += b.mV[VZ]; - a.mV[VW] += b.mV[VW]; + a.mV[VRED] += b.mV[VRED]; + a.mV[VGREEN] += b.mV[VGREEN]; + a.mV[VBLUE] += b.mV[VBLUE]; + a.mV[VALPHA] += b.mV[VALPHA]; return a; } inline const LLColor4U& operator-=(LLColor4U &a, const LLColor4U &b) { - a.mV[VX] -= b.mV[VX]; - a.mV[VY] -= b.mV[VY]; - a.mV[VZ] -= b.mV[VZ]; - a.mV[VW] -= b.mV[VW]; + a.mV[VRED] -= b.mV[VRED]; + a.mV[VGREEN] -= b.mV[VGREEN]; + a.mV[VBLUE] -= b.mV[VBLUE]; + a.mV[VALPHA] -= b.mV[VALPHA]; return a; } inline const LLColor4U& operator*=(LLColor4U &a, U8 k) { // only affects rgb (not a!) - a.mV[VX] *= k; - a.mV[VY] *= k; - a.mV[VZ] *= k; + a.mV[VRED] *= k; + a.mV[VGREEN] *= k; + a.mV[VBLUE] *= k; return a; } inline const LLColor4U& operator%=(LLColor4U &a, U8 k) { // only affects alpha (not rgb!) - a.mV[VW] *= k; + a.mV[VALPHA] *= k; return a; } -- cgit v1.2.3