diff options
Diffstat (limited to 'indra/llmath')
92 files changed, 13580 insertions, 2254 deletions
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index d287a5063a..9dadad7dd3 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -15,12 +15,16 @@ set(llmath_SOURCE_FILES llcamera.cpp llcoordframe.cpp llline.cpp + llmatrix3a.cpp + llmodularmath.cpp llperlin.cpp llquaternion.cpp llrect.cpp llsphere.cpp + llvector4a.cpp llvolume.cpp llvolumemgr.cpp + llvolumeoctree.cpp llsdutil_math.cpp m3math.cpp m4math.cpp @@ -48,20 +52,33 @@ set(llmath_HEADER_FILES llinterp.h llline.h llmath.h + llmatrix3a.h + llmatrix3a.inl + llmodularmath.h lloctree.h llperlin.h llplane.h llquantize.h llquaternion.h + llquaternion2.h + llquaternion2.inl llrect.h + llsimdmath.h + llsimdtypes.h + llsimdtypes.inl llsphere.h lltreenode.h + llvector4a.h + llvector4a.inl + llvector4logical.h llv4math.h llv4matrix3.h llv4matrix4.h llv4vector3.h llvolume.h llvolumemgr.h + llvolumeoctree.h + llsdutil_math.h m3math.h m4math.h raytrace.h @@ -82,11 +99,30 @@ list(APPEND llmath_SOURCE_FILES ${llmath_HEADER_FILES}) add_library (llmath ${llmath_SOURCE_FILES}) +# Add tests +if (LL_TESTS) + include(LLAddBuildTest) + # UNIT TESTS + SET(llmath_TEST_SOURCE_FILES + llbboxlocal.cpp + llmodularmath.cpp + llrect.cpp + v2math.cpp + v3color.cpp + v4color.cpp + v4coloru.cpp + ) + LL_ADD_PROJECT_UNIT_TESTS(llmath "${llmath_TEST_SOURCE_FILES}") -include(LLAddBuildTest) -SET(llmath_TEST_SOURCE_FILES - # WARNING: Please don't write tests against LLCommon or LLMath until this issue is resolved: https://jira.lindenlab.com/jira/browse/DEV-29456 - # llvolume.cpp - ) -LL_ADD_PROJECT_UNIT_TESTS(llmath "${llmath_TEST_SOURCE_FILES}") - + # INTEGRATION TESTS + set(test_libs llmath llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) + # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests. + LL_ADD_INTEGRATION_TEST(llbbox llbbox.cpp "${test_libs}") + LL_ADD_INTEGRATION_TEST(llquaternion llquaternion.cpp "${test_libs}") + LL_ADD_INTEGRATION_TEST(mathmisc "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(m3math "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(v3dmath v3dmath.cpp "${test_libs}") + LL_ADD_INTEGRATION_TEST(v3math v3math.cpp "${test_libs}") + LL_ADD_INTEGRATION_TEST(v4math v4math.cpp "${test_libs}") + LL_ADD_INTEGRATION_TEST(xform xform.cpp "${test_libs}") +endif (LL_TESTS) diff --git a/indra/llmath/camera.h b/indra/llmath/camera.h index ce41f8781d..26f3c3d19f 100644 --- a/indra/llmath/camera.h +++ b/indra/llmath/camera.h @@ -2,31 +2,25 @@ * @file camera.h * @brief Legacy wrapper header. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/coordframe.h b/indra/llmath/coordframe.h index b8a1c14abf..271bcb433c 100644 --- a/indra/llmath/coordframe.h +++ b/indra/llmath/coordframe.h @@ -2,31 +2,25 @@ * @file coordframe.h * @brief Legacy wrapper header. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index acf93a2a38..3e2c05a6e6 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -2,34 +2,30 @@ * @file llbbox.cpp * @brief General purpose bounding box class (Not axis aligned) * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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" @@ -93,6 +89,19 @@ void LLBBox::addBBoxAgent(const LLBBox& b) } } +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 ) { @@ -151,6 +160,15 @@ BOOL LLBBox::containsPointAgent(const LLVector3& p) const 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) diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index cd29551b01..28e69b75e1 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -2,31 +2,25 @@ * @file llbbox.h * @brief General purpose bounding box class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,9 +51,11 @@ public: 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; } @@ -86,6 +82,8 @@ public: 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); diff --git a/indra/llmath/llbboxlocal.cpp b/indra/llmath/llbboxlocal.cpp index 3d0dbb0762..bf0c1a7b93 100644 --- a/indra/llmath/llbboxlocal.cpp +++ b/indra/llmath/llbboxlocal.cpp @@ -2,31 +2,25 @@ * @file llbboxlocal.cpp * @brief General purpose bounding box class (Not axis aligned). * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llbboxlocal.h b/indra/llmath/llbboxlocal.h index 0d1e5a3ae5..defb899248 100644 --- a/indra/llmath/llbboxlocal.h +++ b/indra/llmath/llbboxlocal.h @@ -2,31 +2,25 @@ * @file llbboxlocal.h * @brief General purpose bounding box class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index 0f343bcefe..22ba26f99b 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -2,31 +2,25 @@ * @file llcamera.cpp * @brief Implementation of the LLCamera class. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -45,17 +39,18 @@ LLCamera::LLCamera() : mNearPlane(DEFAULT_NEAR_PLANE), mFarPlane(DEFAULT_FAR_PLANE), mFixedDistance(-1.f), - mPlaneCount(6) + mPlaneCount(6), + mFrustumCornerDist(0.f) { calculateFrustumPlanes(); } - LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) : LLCoordFrame(), mViewHeightInPixels(view_height_in_pixels), mFixedDistance(-1.f), - mPlaneCount(6) + mPlaneCount(6), + mFrustumCornerDist(0.f) { mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); @@ -65,6 +60,10 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p setView(vertical_fov_rads); } +LLCamera::~LLCamera() +{ + +} // ---------------- LLCamera::getFoo() member functions ---------------- @@ -86,11 +85,11 @@ F32 LLCamera::getMaxView() const // ---------------- LLCamera::setFoo() member functions ---------------- -void LLCamera::setUserClipPlane(LLPlane plane) +void LLCamera::setUserClipPlane(LLPlane& plane) { mPlaneCount = 7; - mAgentPlanes[6].p = plane; - mAgentPlanes[6].mask = calcPlaneMask(plane); + mAgentPlanes[6] = plane; + mPlaneMask[6] = plane.calcPlaneMask(); } void LLCamera::disableUserClipPlane() @@ -162,158 +161,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer) // ---------------- test methods ---------------- -S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius) +S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius) { - static const LLVector3 scaler[] = { - LLVector3(-1,-1,-1), - LLVector3( 1,-1,-1), - LLVector3(-1, 1,-1), - LLVector3( 1, 1,-1), - LLVector3(-1,-1, 1), - LLVector3( 1,-1, 1), - LLVector3(-1, 1, 1), - LLVector3( 1, 1, 1) + static const LLVector4a scaler[] = { + LLVector4a(-1,-1,-1), + LLVector4a( 1,-1,-1), + LLVector4a(-1, 1,-1), + LLVector4a( 1, 1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1,-1, 1), + LLVector4a(-1, 1, 1), + LLVector4a( 1, 1, 1) }; U8 mask = 0; - S32 result = 2; - - if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist) - { //box is larger than frustum, check frustum quads against box planes - - static const LLVector3 dir[] = - { - LLVector3(1, 0, 0), - LLVector3(-1, 0, 0), - LLVector3(0, 1, 0), - LLVector3(0, -1, 0), - LLVector3(0, 0, 1), - LLVector3(0, 0, -1) - }; - - U32 quads[] = - { - 0, 1, 2, 3, - 0, 1, 5, 4, - 2, 3, 7, 6, - 3, 0, 7, 4, - 1, 2, 6, 4, - 4, 5, 6, 7 - }; - - result = 0; - - BOOL total_inside = TRUE; - for (U32 i = 0; i < 6; i++) - { - LLVector3 p = center + radius.scaledVec(dir[i]); - F32 d = -p*dir[i]; - - for (U32 j = 0; j < 6; j++) - { //for each quad - F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d; - if (dist > 0) - { //at least one frustum point is outside the AABB - total_inside = FALSE; - for (U32 k = 1; k < 4; k++) - { //for each other point on quad - if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f) - { //quad is straddling some plane of AABB - return 1; - } - } - } - else - { - for (U32 k = 1; k < 4; k++) - { - if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f) - { - return 1; - } - } - } - } - } - - if (total_inside) - { - result = 1; - } - } - else + bool result = false; + LLVector4a rscale, maxp, minp; + LLSimdScalar d; + for (U32 i = 0; i < mPlaneCount; i++) { - for (U32 i = 0; i < mPlaneCount; i++) + mask = mPlaneMask[i]; + if (mask != 0xff) { - mask = mAgentPlanes[i].mask; - LLPlane p = mAgentPlanes[i].p; - LLVector3 n = LLVector3(p); - float d = p.mV[3]; - LLVector3 rscale = radius.scaledVec(scaler[mask]); - - LLVector3 minp = center - rscale; - LLVector3 maxp = center + rscale; - - if (n * minp > -d) + const LLPlane& p(mAgentPlanes[i]); + p.getAt<3>(d); + rscale.setMul(radius, scaler[mask]); + minp.setSub(center, rscale); + d = -d; + if (p.dot3(minp).getF32() > d) { return 0; } - - if (n * maxp > -d) + + if(!result) { - result = 1; + maxp.setAdd(center, rscale); + result = (p.dot3(maxp).getF32() > d); } } } - - return result; + return result?1:2; } -S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius) + +S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) { - static const LLVector3 scaler[] = { - LLVector3(-1,-1,-1), - LLVector3( 1,-1,-1), - LLVector3(-1, 1,-1), - LLVector3( 1, 1,-1), - LLVector3(-1,-1, 1), - LLVector3( 1,-1, 1), - LLVector3(-1, 1, 1), - LLVector3( 1, 1, 1) + static const LLVector4a scaler[] = { + LLVector4a(-1,-1,-1), + LLVector4a( 1,-1,-1), + LLVector4a(-1, 1,-1), + LLVector4a( 1, 1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1,-1, 1), + LLVector4a(-1, 1, 1), + LLVector4a( 1, 1, 1) }; U8 mask = 0; - S32 result = 2; - + bool result = false; + LLVector4a rscale, maxp, minp; + LLSimdScalar d; for (U32 i = 0; i < mPlaneCount; i++) { - if (i == 5) - { - continue; - } - - mask = mAgentPlanes[i].mask; - LLPlane p = mAgentPlanes[i].p; - LLVector3 n = LLVector3(p); - float d = p.mV[3]; - LLVector3 rscale = radius.scaledVec(scaler[mask]); - - LLVector3 minp = center - rscale; - LLVector3 maxp = center + rscale; - - if (n * minp > -d) + mask = mPlaneMask[i]; + if ((i != 5) && (mask != 0xff)) { - return 0; - } - - if (n * maxp > -d) - { - result = 1; + const LLPlane& p(mAgentPlanes[i]); + p.getAt<3>(d); + rscale.setMul(radius, scaler[mask]); + minp.setSub(center, rscale); + d = -d; + if (p.dot3(minp).getF32() > d) + { + return 0; + } + + if(!result) + { + maxp.setAdd(center, rscale); + result = (p.dot3(maxp).getF32() > d); + } } } - return result; + return result?1:2; } int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius) @@ -434,23 +366,22 @@ int LLCamera::sphereInFrustumOld(const LLVector3 &sphere_center, const F32 radiu int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) const { // Returns 1 if sphere is in frustum, 0 if not. - int res = 2; + bool res = false; for (int i = 0; i < 6; i++) { - float d = mAgentPlanes[i].p.dist(sphere_center); - - if (d > radius) + if (mPlaneMask[i] != 0xff) { - return 0; - } + float d = mAgentPlanes[i].dist(sphere_center); - if (d > -radius) - { - res = 1; + if (d > radius) + { + return 0; + } + res = res || (d > -radius); } } - return res; + return res?1:2; } @@ -602,29 +533,21 @@ LLPlane planeFromPoints(LLVector3 p1, LLVector3 p2, LLVector3 p3) return LLPlane(p1, n); } -U8 LLCamera::calcPlaneMask(const LLPlane& plane) + +void LLCamera::ignoreAgentFrustumPlane(S32 idx) { - U8 mask = 0; - - if (plane.mV[0] >= 0) + if (idx < 0 || idx > (S32) mPlaneCount) { - mask |= 1; - } - if (plane.mV[1] >= 0) - { - mask |= 2; - } - if (plane.mV[2] >= 0) - { - mask |= 4; + return; } - return mask; + mPlaneMask[idx] = 0xff; + mAgentPlanes[idx].clear(); } void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) { - + for (int i = 0; i < 8; i++) { mAgentFrustum[i] = frust[i]; @@ -637,27 +560,27 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) //order of planes is important, keep most likely to fail in the front of the list //near - frust[0], frust[1], frust[2] - mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]); + mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]); //far - mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]); + mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]); //left - mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]); + mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]); //right - mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]); + mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]); //top - mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]); + mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]); //bottom - mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]); + mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]); //cache plane octant facing mask for use in AABBInFrustum for (U32 i = 0; i < mPlaneCount; i++) { - mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p); + mPlaneMask[i] = mAgentPlanes[i].calcPlaneMask(); } } @@ -684,6 +607,7 @@ void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom) mLocalPlanes[PLANE_BOTTOM].setVec( a, c, b); //calculate center and radius squared of frustum in world absolute coordinates + static LLVector3 const X_AXIS(1.f, 0.f, 0.f); mFrustCenter = X_AXIS*mFarPlane*0.5f; mFrustCenter = transformToAbsolute(mFrustCenter); mFrustRadiusSquared = mFarPlane*0.5f; @@ -710,9 +634,10 @@ void LLCamera::calculateWorldFrustumPlanes() F32 d; LLVector3 center = mOrigin - mXAxis*mNearPlane; mWorldPlanePos = center; + LLVector3 pnorm; for (int p=0; p<4; p++) { - LLVector3 pnorm = LLVector3(mLocalPlanes[p]); + mLocalPlanes[p].getVector3(pnorm); LLVector3 norm = rotateToAbsolute(pnorm); norm.normVec(); d = -(center * norm); @@ -722,13 +647,15 @@ void LLCamera::calculateWorldFrustumPlanes() LLVector3 zaxis(0, 0, 1.0f); F32 yaw = getYaw(); { - LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]); + LLVector3 tnorm; + mLocalPlanes[PLANE_LEFT].getVector3(tnorm); tnorm.rotVec(yaw, zaxis); d = -(mOrigin * tnorm); mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d); } { - LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]); + LLVector3 tnorm; + mLocalPlanes[PLANE_RIGHT].getVector3(tnorm); tnorm.rotVec(yaw, zaxis); d = -(mOrigin * tnorm); mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d); diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index 23ee1157f9..ec67b91d05 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -2,31 +2,25 @@ * @file llcamera.h * @brief Header file for the LLCamera class. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,6 +31,7 @@ #include "llmath.h" #include "llcoordframe.h" #include "llplane.h" +#include "llvector4a.h" const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD; const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f; @@ -56,15 +51,6 @@ const F32 MIN_FAR_PLANE = 0.2f; static const F32 MIN_FIELD_OF_VIEW = 5.0f * DEG_TO_RAD; static const F32 MAX_FIELD_OF_VIEW = 175.f * DEG_TO_RAD; -static const LLVector3 X_AXIS(1.f,0.f,0.f); -static const LLVector3 Y_AXIS(0.f,1.f,0.f); -static const LLVector3 Z_AXIS(0.f,0.f,1.f); - -static const LLVector3 NEG_X_AXIS(-1.f,0.f,0.f); -static const LLVector3 NEG_Y_AXIS(0.f,-1.f,0.f); -static const LLVector3 NEG_Z_AXIS(0.f,0.f,-1.f); - - // An LLCamera is an LLCoorFrame with a view frustum. // This means that it has several methods for moving it around // that are inherited from the LLCoordFrame() class : @@ -79,6 +65,12 @@ class LLCamera : public LLCoordFrame { public: + + LLCamera(const LLCamera& rhs) + { + *this = rhs; + } + enum { PLANE_LEFT = 0, PLANE_RIGHT = 1, @@ -93,6 +85,17 @@ public: PLANE_TOP_MASK = (1<<PLANE_TOP), PLANE_ALL_MASK = 0xf }; + + enum + { + AGENT_PLANE_LEFT = 0, + AGENT_PLANE_RIGHT, + AGENT_PLANE_NEAR, + AGENT_PLANE_BOTTOM, + AGENT_PLANE_TOP, + AGENT_PLANE_FAR, + }; + enum { HORIZ_PLANE_LEFT = 0, HORIZ_PLANE_RIGHT = 1, @@ -105,6 +108,9 @@ public: }; private: + LLPlane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP + U8 mPlaneMask[8]; // 8 for alignment + F32 mView; // angle between top and bottom frustum planes in radians. F32 mAspect; // width/height S32 mViewHeightInPixels; // for ViewHeightInPixels() only @@ -118,29 +124,22 @@ private: LLPlane mWorldPlanes[PLANE_NUM]; LLPlane mHorizPlanes[HORIZ_PLANE_NUM]; - struct frustum_plane - { - frustum_plane() : mask(0) {} - LLPlane p; - U8 mask; - }; - frustum_plane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP - U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in LLVector3 mWorldPlanePos; // Position of World Planes (may be offset from camera) public: LLVector3 mAgentFrustum[8]; //8 corners of 6-plane frustum F32 mFrustumCornerDist; //distance to corner of frustum against far clip plane - + LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; } + public: LLCamera(); LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane); - virtual ~LLCamera(){} // no-op virtual destructor + virtual ~LLCamera(); + - void setUserClipPlane(LLPlane plane); + void setUserClipPlane(LLPlane& plane); void disableUserClipPlane(); - U8 calcPlaneMask(const LLPlane& plane); virtual void setView(F32 vertical_fov_rads); void setViewHeightInPixels(S32 height); void setAspect(F32 new_aspect); @@ -179,14 +178,16 @@ public: // Return number of bytes copied. size_t readFrustumFromBuffer(const char *buffer); void calcAgentFrustumPlanes(LLVector3* frust); + void ignoreAgentFrustumPlane(S32 idx); + // Returns 1 if partly in, 2 if fully in. // NOTE: 'center' is in absolute frame. S32 sphereInFrustumOld(const LLVector3 ¢er, const F32 radius) const; S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const; S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); } S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); } - S32 AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius); - S32 AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius); + S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius); + S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius); //does a quick 'n dirty sphere-sphere check S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius); diff --git a/indra/llmath/llcoord.h b/indra/llmath/llcoord.h index 9d46a8b454..706ad92787 100644 --- a/indra/llmath/llcoord.h +++ b/indra/llmath/llcoord.h @@ -1,31 +1,25 @@ /** * @file llcoord.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,8 +53,11 @@ public: {} LLCoordGL(S32 x, S32 y) : LLCoord(x, y) {} + bool operator==(const LLCoordGL& other) const { return mX == other.mX && mY == other.mY; } + bool operator!=(const LLCoordGL& other) const { return !(*this == other); } }; +//bool operator ==(const LLCoordGL& a, const LLCoordGL& b); // Window coords include things like window borders, // menu regions, etc. @@ -71,6 +68,8 @@ public: {} LLCoordWindow(S32 x, S32 y) : LLCoord(x, y) {} + bool operator==(const LLCoordWindow& other) const { return mX == other.mX && mY == other.mY; } + bool operator!=(const LLCoordWindow& other) const { return !(*this == other); } }; @@ -82,6 +81,8 @@ public: {} LLCoordScreen(S32 x, S32 y) : LLCoord(x, y) {} + bool operator==(const LLCoordScreen& other) const { return mX == other.mX && mY == other.mY; } + bool operator!=(const LLCoordScreen& other) const { return !(*this == other); } }; class LLCoordFont : public LLCoord @@ -96,6 +97,8 @@ public: void set(S32 x, S32 y) { LLCoord::set(x,y); mZ = 0.f; } void set(S32 x, S32 y, F32 z) { mX = x; mY = y; mZ = z; } + bool operator==(const LLCoordFont& other) const { return mX == other.mX && mY == other.mY; } + bool operator!=(const LLCoordFont& other) const { return !(*this == other); } }; diff --git a/indra/llmath/llcoordframe.cpp b/indra/llmath/llcoordframe.cpp index 673a8f2b04..7dd8e43185 100644 --- a/indra/llmath/llcoordframe.cpp +++ b/indra/llmath/llcoordframe.cpp @@ -2,31 +2,25 @@ * @file llcoordframe.cpp * @brief LLCoordFrame class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llcoordframe.h b/indra/llmath/llcoordframe.h index 89b5d8beff..909adf260c 100644 --- a/indra/llmath/llcoordframe.h +++ b/indra/llmath/llcoordframe.h @@ -2,31 +2,25 @@ * @file llcoordframe.h * @brief LLCoordFrame class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llinterp.h b/indra/llmath/llinterp.h index 8beeef480b..5187646179 100644 --- a/indra/llmath/llinterp.h +++ b/indra/llmath/llinterp.h @@ -1,37 +1,38 @@ /** * @file llinterp.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 @@ -47,7 +48,7 @@ template <typename Type> class LLInterp { public: - LLInterp(); + LLInterp(); virtual ~LLInterp() {} virtual void start(); @@ -144,6 +145,7 @@ protected: template <typename Type> LLInterp<Type>::LLInterp() +: mStartVal(Type()), mEndVal(Type()), mCurVal(Type()) { mStartTime = 0.f; mEndTime = 1.f; diff --git a/indra/llmath/llline.cpp b/indra/llmath/llline.cpp index b198573206..ef10d1e7fa 100644 --- a/indra/llmath/llline.cpp +++ b/indra/llmath/llline.cpp @@ -3,31 +3,25 @@ * @author Andrew Meadows * @brief Simple line class that can compute nearest approach between two lines * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llline.h b/indra/llmath/llline.h index 9ab41b162b..e1cbc1323e 100644 --- a/indra/llmath/llline.h +++ b/indra/llmath/llline.h @@ -4,31 +4,25 @@ * @author Andrew Meadows * @brief Simple line for computing nearest approach between two infinite lines * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index f85c4f39f4..eea7c977fb 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -2,31 +2,25 @@ * @file llmath.h * @brief Useful math constants and macros. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -35,6 +29,7 @@ #include <cmath> #include <cstdlib> +#include <vector> #include "lldefs.h" //#include "llstl.h" // *TODO: Remove when LLString is gone //#include "llstring.h" // *TODO: Remove when LLString is gone @@ -60,29 +55,11 @@ #endif // Single Precision Floating Point Routines -#ifndef fsqrtf -#define fsqrtf(x) ((F32)sqrt((F64)(x))) -#endif -#ifndef sqrtf -#define sqrtf(x) ((F32)sqrt((F64)(x))) -#endif - -#ifndef cosf -#define cosf(x) ((F32)cos((F64)(x))) -#endif -#ifndef sinf -#define sinf(x) ((F32)sin((F64)(x))) -#endif -#ifndef tanf +// (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 -#ifndef acosf -#define acosf(x) ((F32)acos((F64)(x))) -#endif - -#ifndef powf -#define powf(x,y) ((F32)pow((F64)(x),(F64)(y))) -#endif +#endif*/ const F32 GRAVITY = -9.8f; @@ -380,11 +357,14 @@ inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs) bar *= 10.f; } - foo = (F32)llround(foo * bar); + //F32 new_foo = (F32)llround(foo * bar); + // the llround() implementation sucks. Don't us it. - // shift back - foo /= bar; - return foo; + 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) @@ -518,4 +498,45 @@ 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 <class VEC_TYPE> +inline void ll_remove_outliers(std::vector<VEC_TYPE>& 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]; + + 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); + } +} + +// Include simd math header +#include "llsimdmath.h" + #endif diff --git a/indra/llmath/llmatrix3a.cpp b/indra/llmath/llmatrix3a.cpp new file mode 100644 index 0000000000..ab077abcb0 --- /dev/null +++ b/indra/llmath/llmatrix3a.cpp @@ -0,0 +1,134 @@ +/** + * @file llvector4a.cpp + * @brief SIMD vector implementation + * + * $LicenseInfo:firstyear=2010&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 "llmath.h" + +static LL_ALIGN_16(const F32 M_IDENT_3A[12]) = + { 1.f, 0.f, 0.f, 0.f, // Column 1 + 0.f, 1.f, 0.f, 0.f, // Column 2 + 0.f, 0.f, 1.f, 0.f }; // Column 3 + +extern const LLMatrix3a LL_M3A_IDENTITY = *reinterpret_cast<const LLMatrix3a*> (M_IDENT_3A); + +void LLMatrix3a::setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs ) +{ + const LLVector4a col0 = lhs.getColumn(0); + const LLVector4a col1 = lhs.getColumn(1); + const LLVector4a col2 = lhs.getColumn(2); + + for ( int i = 0; i < 3; i++ ) + { + LLVector4a xxxx = _mm_load_ss( rhs.mColumns[i].getF32ptr() ); + xxxx.splat<0>( xxxx ); + xxxx.mul( col0 ); + + { + LLVector4a yyyy = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 1 ); + yyyy.splat<0>( yyyy ); + yyyy.mul( col1 ); + xxxx.add( yyyy ); + } + + { + LLVector4a zzzz = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 2 ); + zzzz.splat<0>( zzzz ); + zzzz.mul( col2 ); + xxxx.add( zzzz ); + } + + xxxx.store4a( mColumns[i].getF32ptr() ); + } + +} + +/*static */void LLMatrix3a::batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst ) +{ + const LLVector4a col0 = xform.getColumn(0); + const LLVector4a col1 = xform.getColumn(1); + const LLVector4a col2 = xform.getColumn(2); + const LLVector4a* maxAddr = src + numVectors; + + if ( numVectors & 0x1 ) + { + LLVector4a xxxx = _mm_load_ss( (const F32*)src ); + LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 ); + LLVector4a zzzz = _mm_load_ss( (const F32*)src + 2 ); + xxxx.splat<0>( xxxx ); + yyyy.splat<0>( yyyy ); + zzzz.splat<0>( zzzz ); + xxxx.mul( col0 ); + yyyy.mul( col1 ); + zzzz.mul( col2 ); + xxxx.add( yyyy ); + xxxx.add( zzzz ); + xxxx.store4a( (F32*)dst ); + src++; + dst++; + } + + + numVectors >>= 1; + while ( src < maxAddr ) + { + _mm_prefetch( (const char*)(src + 32 ), _MM_HINT_NTA ); + _mm_prefetch( (const char*)(dst + 32), _MM_HINT_NTA ); + LLVector4a xxxx = _mm_load_ss( (const F32*)src ); + LLVector4a xxxx1= _mm_load_ss( (const F32*)(src + 1) ); + + xxxx.splat<0>( xxxx ); + xxxx1.splat<0>( xxxx1 ); + xxxx.mul( col0 ); + xxxx1.mul( col0 ); + + { + LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 ); + LLVector4a yyyy1 = _mm_load_ss( (const F32*)(src + 1) + 1); + yyyy.splat<0>( yyyy ); + yyyy1.splat<0>( yyyy1 ); + yyyy.mul( col1 ); + yyyy1.mul( col1 ); + xxxx.add( yyyy ); + xxxx1.add( yyyy1 ); + } + + { + LLVector4a zzzz = _mm_load_ss( (const F32*)(src) + 2 ); + LLVector4a zzzz1 = _mm_load_ss( (const F32*)(++src) + 2 ); + zzzz.splat<0>( zzzz ); + zzzz1.splat<0>( zzzz1 ); + zzzz.mul( col2 ); + zzzz1.mul( col2 ); + xxxx.add( zzzz ); + xxxx1.add( zzzz1 ); + } + + xxxx.store4a(dst->getF32ptr()); + src++; + dst++; + + xxxx1.store4a((F32*)dst++); + } +} diff --git a/indra/llmath/llmatrix3a.h b/indra/llmath/llmatrix3a.h new file mode 100644 index 0000000000..adb7e3389d --- /dev/null +++ b/indra/llmath/llmatrix3a.h @@ -0,0 +1,128 @@ +/** + * @file llmatrix3a.h + * @brief LLMatrix3a class header file - memory aligned and vectorized 3x3 matrix + * + * $LicenseInfo:firstyear=2010&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_LLMATRIX3A_H +#define LL_LLMATRIX3A_H + +///////////////////////////// +// LLMatrix3a, LLRotation +///////////////////////////// +// This class stores a 3x3 (technically 4x3) matrix in column-major order +///////////////////////////// +///////////////////////////// +// These classes are intentionally minimal right now. If you need additional +// functionality, please contact someone with SSE experience (e.g., Falcon or +// Huseby). +///////////////////////////// + +// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a +// rotation matrix. +class LLMatrix3a +{ +public: + + // Utility function for quickly transforming an array of LLVector4a's + // For transforming a single LLVector4a, see LLVector4a::setRotated + static void batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst ); + + // Utility function to obtain the identity matrix + static inline const LLMatrix3a& getIdentity(); + + ////////////////////////// + // Ctors + ////////////////////////// + + // Ctor + LLMatrix3a() {} + + // Ctor for setting by columns + inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 ); + + ////////////////////////// + // Get/Set + ////////////////////////// + + // Loads from an LLMatrix3 + inline void loadu(const LLMatrix3& src); + + // Set rows + inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2); + + // Set columns + inline void setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2); + + // Get the read-only access to a specified column. Valid columns are 0-2, but the + // function is unchecked. You've been warned. + inline const LLVector4a& getColumn(const U32 column) const; + + ///////////////////////// + // Matrix modification + ///////////////////////// + + // Set this matrix to the product of lhs and rhs ( this = lhs * rhs ) + void setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs ); + + // Set this matrix to the transpose of src + inline void setTranspose(const LLMatrix3a& src); + + // Set this matrix to a*w + b*(1-w) + inline void setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w); + + ///////////////////////// + // Matrix inspection + ///////////////////////// + + // Sets all 4 elements in 'dest' to the determinant of this matrix. + // If you will be using the determinant in subsequent ops with LLVector4a, use this version + inline void getDeterminant( LLVector4a& dest ) const; + + // Returns the determinant as an LLSimdScalar. Use this if you will be using the determinant + // primary for scalar operations. + inline LLSimdScalar getDeterminant() const; + + // Returns nonzero if rows 0-2 and colums 0-2 contain no NaN or INF values. Row 3 is ignored + inline LLBool32 isFinite() const; + + // Returns true if this matrix is equal to 'rhs' up to 'tolerance' + inline bool isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const; + +protected: + + LLVector4a mColumns[3]; + +}; + +class LLRotation : public LLMatrix3a +{ +public: + + LLRotation() {} + + // Returns true if this rotation is orthonormal with det ~= 1 + inline bool isOkRotation() const; +}; + +#endif diff --git a/indra/llmath/llmatrix3a.inl b/indra/llmath/llmatrix3a.inl new file mode 100644 index 0000000000..37819fea3c --- /dev/null +++ b/indra/llmath/llmatrix3a.inl @@ -0,0 +1,119 @@ +/** + * @file llmatrix3a.inl + * @brief LLMatrix3a inline definitions + * + * $LicenseInfo:firstyear=2010&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 "llmatrix3a.h" +#include "m3math.h" + +inline LLMatrix3a::LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 ) +{ + setColumns( c0, c1, c2 ); +} + +inline void LLMatrix3a::loadu(const LLMatrix3& src) +{ + mColumns[0].load3(src.mMatrix[0]); + mColumns[1].load3(src.mMatrix[1]); + mColumns[2].load3(src.mMatrix[2]); +} + +inline void LLMatrix3a::setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2) +{ + mColumns[0] = r0; + mColumns[1] = r1; + mColumns[2] = r2; + setTranspose( *this ); +} + +inline void LLMatrix3a::setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2) +{ + mColumns[0] = c0; + mColumns[1] = c1; + mColumns[2] = c2; +} + +inline void LLMatrix3a::setTranspose(const LLMatrix3a& src) +{ + const LLQuad srcCol0 = src.mColumns[0]; + const LLQuad srcCol1 = src.mColumns[1]; + const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 ); + mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] ); + mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) ); + mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) ); +} + +inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const +{ + llassert( column < 3 ); + return mColumns[column]; +} + +inline void LLMatrix3a::setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w) +{ + mColumns[0].setLerp( a.mColumns[0], b.mColumns[0], w ); + mColumns[1].setLerp( a.mColumns[1], b.mColumns[1], w ); + mColumns[2].setLerp( a.mColumns[2], b.mColumns[2], w ); +} + +inline LLBool32 LLMatrix3a::isFinite() const +{ + return mColumns[0].isFinite3() && mColumns[1].isFinite3() && mColumns[2].isFinite3(); +} + +inline void LLMatrix3a::getDeterminant( LLVector4a& dest ) const +{ + LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] ); + dest.setAllDot3( col1xcol2, mColumns[0] ); +} + +inline LLSimdScalar LLMatrix3a::getDeterminant() const +{ + LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] ); + return col1xcol2.dot3( mColumns[0] ); +} + +inline bool LLMatrix3a::isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance /*= F_APPROXIMATELY_ZERO*/ ) const +{ + return rhs.getColumn(0).equals3(mColumns[0], tolerance) + && rhs.getColumn(1).equals3(mColumns[1], tolerance) + && rhs.getColumn(2).equals3(mColumns[2], tolerance); +} + +inline const LLMatrix3a& LLMatrix3a::getIdentity() +{ + extern const LLMatrix3a LL_M3A_IDENTITY; + return LL_M3A_IDENTITY; +} + +inline bool LLRotation::isOkRotation() const +{ + LLMatrix3a transpose; transpose.setTranspose( *this ); + LLMatrix3a product; product.setMul( *this, transpose ); + + LLSimdScalar detMinusOne = getDeterminant() - 1.f; + + return product.isApproximatelyEqual( LLMatrix3a::getIdentity() ) && (detMinusOne.getAbs() < F_APPROXIMATELY_ZERO); +} + diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h new file mode 100644 index 0000000000..27cf5b79f6 --- /dev/null +++ b/indra/llmath/llmatrix4a.h @@ -0,0 +1,143 @@ +/** + * @file llmatrix4a.h + * @brief LLMatrix4a class header file - memory aligned and vectorized 4x4 matrix + * + * $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_LLMATRIX4A_H +#define LL_LLMATRIX4A_H + +#include "llvector4a.h" +#include "m4math.h" +#include "m3math.h" + +class LLMatrix4a +{ +public: + LLVector4a mMatrix[4]; + + inline void clear() + { + mMatrix[0].clear(); + mMatrix[1].clear(); + mMatrix[2].clear(); + mMatrix[3].clear(); + } + + inline void loadu(const LLMatrix4& src) + { + mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]); + mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]); + mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]); + mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]); + + } + + inline void loadu(const LLMatrix3& src) + { + mMatrix[0].load3(src.mMatrix[0]); + mMatrix[1].load3(src.mMatrix[1]); + mMatrix[2].load3(src.mMatrix[2]); + mMatrix[3].set(0,0,0,1.f); + } + + inline void add(const LLMatrix4a& rhs) + { + mMatrix[0].add(rhs.mMatrix[0]); + mMatrix[1].add(rhs.mMatrix[1]); + mMatrix[2].add(rhs.mMatrix[2]); + mMatrix[3].add(rhs.mMatrix[3]); + } + + inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2) + { + mMatrix[0] = r0; + mMatrix[1] = r1; + mMatrix[2] = r2; + } + + inline void setMul(const LLMatrix4a& m, const F32 s) + { + mMatrix[0].setMul(m.mMatrix[0], s); + mMatrix[1].setMul(m.mMatrix[1], s); + mMatrix[2].setMul(m.mMatrix[2], s); + mMatrix[3].setMul(m.mMatrix[3], s); + } + + inline void setLerp(const LLMatrix4a& a, const LLMatrix4a& b, F32 w) + { + LLVector4a d0,d1,d2,d3; + d0.setSub(b.mMatrix[0], a.mMatrix[0]); + d1.setSub(b.mMatrix[1], a.mMatrix[1]); + d2.setSub(b.mMatrix[2], a.mMatrix[2]); + d3.setSub(b.mMatrix[3], a.mMatrix[3]); + + // this = a + d*w + + d0.mul(w); + d1.mul(w); + d2.mul(w); + d3.mul(w); + + mMatrix[0].setAdd(a.mMatrix[0],d0); + mMatrix[1].setAdd(a.mMatrix[1],d1); + mMatrix[2].setAdd(a.mMatrix[2],d2); + mMatrix[3].setAdd(a.mMatrix[3],d3); + } + + inline void rotate(const LLVector4a& v, LLVector4a& res) + { + res = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); + res.mul(mMatrix[0]); + + LLVector4a y; + y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); + y.mul(mMatrix[1]); + + LLVector4a z; + z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + z.mul(mMatrix[2]); + + res.add(y); + res.add(z); + } + + inline void affineTransform(const LLVector4a& v, LLVector4a& res) + { + LLVector4a x,y,z; + + x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); + y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); + z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + + x.mul(mMatrix[0]); + y.mul(mMatrix[1]); + z.mul(mMatrix[2]); + + x.add(y); + z.add(mMatrix[3]); + res.setAdd(x,z); + } +}; + +#endif diff --git a/indra/llmath/llmodularmath.cpp b/indra/llmath/llmodularmath.cpp new file mode 100644 index 0000000000..cdc20028bf --- /dev/null +++ b/indra/llmath/llmodularmath.cpp @@ -0,0 +1,30 @@ +/** + * @file llmodularmath.cpp + * @brief LLModularMath 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" + +// implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes. +#include "llmodularmath.h" diff --git a/indra/llmath/llmodularmath.h b/indra/llmath/llmodularmath.h index 60095293c9..0d4d28fadc 100644 --- a/indra/llmath/llmodularmath.h +++ b/indra/llmath/llmodularmath.h @@ -2,31 +2,25 @@ * @file llmodularmath.h * @brief Useful modular math functions. * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index ba8776690a..e5ca47da69 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -2,31 +2,25 @@ * @file lloctree.h * @brief Octree declaration. * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -35,21 +29,20 @@ #include "lltreenode.h" #include "v3math.h" +#include "llvector4a.h" #include <vector> #include <set> -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG -#define OCT_ERRS LL_ERRS("OctreeErrors") -#else #define OCT_ERRS LL_WARNS("OctreeErrors") -#endif -#define LL_OCTREE_PARANOIA_CHECK 0 + +extern U32 gOctreeMaxCapacity; +/*#define LL_OCTREE_PARANOIA_CHECK 0 #if LL_DARWIN #define LL_OCTREE_MAX_CAPACITY 32 #else #define LL_OCTREE_MAX_CAPACITY 128 -#endif +#endif*/ template <class T> class LLOctreeNode; @@ -73,9 +66,17 @@ public: }; template <class T> +class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T> +{ +public: + virtual void traverse(const LLOctreeNode<T>* node); +}; + +template <class T> class LLOctreeNode : public LLTreeNode<T> { public: + typedef LLOctreeTraveler<T> oct_traveler; typedef LLTreeTraveler<T> tree_traveler; typedef typename std::set<LLPointer<T> > element_list; @@ -87,23 +88,30 @@ public: typedef LLOctreeNode<T> oct_node; typedef LLOctreeListener<T> oct_listener; - static const U8 OCTANT_POSITIVE_X = 0x01; - static const U8 OCTANT_POSITIVE_Y = 0x02; - static const U8 OCTANT_POSITIVE_Z = 0x04; - - LLOctreeNode( LLVector3d center, - LLVector3d size, + /*void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + }*/ + + LLOctreeNode( const LLVector4a& center, + const LLVector4a& size, BaseType* parent, U8 octant = 255) : mParent((oct_node*)parent), - mCenter(center), - mSize(size), mOctant(octant) { + mCenter = center; + mSize = size; + updateMinMax(); if ((mOctant == 255) && mParent) { - mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV); + mOctant = ((oct_node*) mParent)->getOctant(mCenter); } clearChildren(); @@ -120,40 +128,24 @@ public: } inline const BaseType* getParent() const { return mParent; } - inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; } - inline const LLVector3d& getCenter() const { return mCenter; } - inline const LLVector3d& getSize() const { return mSize; } - inline void setCenter(LLVector3d center) { mCenter = center; } - inline void setSize(LLVector3d size) { mSize = size; } - inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); } - inline U8 getOctant() const { return mOctant; } - inline void setOctant(U8 octant) { mOctant = octant; } + inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; } + inline const LLVector4a& getCenter() const { return 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 F64 pos[]) const //get the octant pos is in + U8 getOctant(const LLVector4a& pos) const //get the octant pos is in { - U8 ret = 0; - - if (pos[0] > mCenter.mdV[0]) - { - ret |= OCTANT_POSITIVE_X; - } - if (pos[1] > mCenter.mdV[1]) - { - ret |= OCTANT_POSITIVE_Y; - } - if (pos[2] > mCenter.mdV[2]) - { - ret |= OCTANT_POSITIVE_Z; - } - - return ret; + return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7); } - inline bool isInside(const LLVector3d& pos, const F64& rad) const + inline bool isInside(const LLVector4a& pos, const F32& rad) const { - return rad <= mSize.mdV[0]*2.0 && isInside(pos); + return rad <= mSize[0]*2.f && isInside(pos); } inline bool isInside(T* data) const @@ -161,30 +153,27 @@ public: return isInside(data->getPositionGroup(), data->getBinRadius()); } - bool isInside(const LLVector3d& pos) const + bool isInside(const LLVector4a& pos) const { - const F64& x = pos.mdV[0]; - const F64& y = pos.mdV[1]; - const F64& z = pos.mdV[2]; - - if (x > mMax.mdV[0] || x <= mMin.mdV[0] || - y > mMax.mdV[1] || y <= mMin.mdV[1] || - z > mMax.mdV[2] || z <= mMin.mdV[2]) + S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7; + if (gt) { return false; } - + + S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7; + if (lt) + { + return false; + } + return true; } void updateMinMax() { - for (U32 i = 0; i < 3; i++) - { - mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i]; - mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i]; - mCenter.mdV[i] = mCenter.mdV[i]; - } + mMax.setAdd(mCenter, mSize); + mMin.setSub(mCenter, mSize); } inline oct_listener* getOctListener(U32 index) @@ -197,34 +186,34 @@ public: return contains(xform->getBinRadius()); } - bool contains(F64 radius) + bool contains(F32 radius) { if (mParent == NULL) { //root node contains nothing return false; } - F64 size = mSize.mdV[0]; - F64 p_size = size * 2.0; + F32 size = mSize[0]; + F32 p_size = size * 2.f; - return (radius <= 0.001 && size <= 0.001) || + return (radius <= 0.001f && size <= 0.001f) || (radius <= p_size && radius > size); } - static void pushCenter(LLVector3d ¢er, const LLVector3d &size, const T* data) + static void pushCenter(LLVector4a ¢er, const LLVector4a &size, const T* data) { - const LLVector3d& pos = data->getPositionGroup(); - for (U32 i = 0; i < 3; i++) - { - if (pos.mdV[i] > center.mdV[i]) - { - center.mdV[i] += size.mdV[i]; - } - else - { - center.mdV[i] -= size.mdV[i]; - } - } + const LLVector4a& pos = data->getPositionGroup(); + + 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); } @@ -243,32 +232,49 @@ public: void accept(tree_traveler* visitor) const { visitor->visit(this); } void accept(oct_traveler* visitor) const { visitor->visit(this); } - oct_node* getNodeAt(const LLVector3d& pos, const F64& rad) + void validateChildMap() + { + for (U32 i = 0; i < 8; i++) + { + U8 idx = mChildMap[i]; + if (idx != 255) + { + LLOctreeNode<T>* child = mChild[idx]; + + if (child->getOctant() != i) + { + llerrs << "Invalid child map, bad octant data." << llendl; + } + + if (getOctant(child->getCenter()) != child->getOctant()) + { + llerrs << "Invalid child octant compared to position data." << llendl; + } + } + } + } + + + oct_node* getNodeAt(const LLVector4a& pos, const F32& rad) { LLOctreeNode<T>* node = this; if (node->isInside(pos, rad)) { //do a quick search by octant - U8 octant = node->getOctant(pos.mdV); - BOOL keep_going = TRUE; - + U8 octant = node->getOctant(pos); + //traverse the tree until we find a node that has no node //at the appropriate octant or is smaller than the object. //by definition, that node is the smallest node that contains // the data - while (keep_going && node->getSize().mdV[0] >= rad) + U8 next_node = node->mChildMap[octant]; + + while (next_node != 255 && node->getSize()[0] >= rad) { - keep_going = FALSE; - for (U32 i = 0; i < node->getChildCount() && !keep_going; i++) - { - if (node->getChild(i)->getOctant() == octant) - { - node = node->getChild(i); - octant = node->getOctant(pos.mdV); - keep_going = TRUE; - } - } + node = node->getChild(next_node); + octant = node->getOctant(pos); + next_node = node->mChildMap[octant]; } } else if (!node->contains(rad) && node->getParent()) @@ -283,7 +289,7 @@ public: { if (data == NULL) { - //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; return false; } LLOctreeNode<T>* parent = getOctParent(); @@ -291,10 +297,8 @@ public: //is it here? if (isInside(data->getPositionGroup())) { - if (getElementCount() < LL_OCTREE_MAX_CAPACITY && - (contains(data->getBinRadius()) || - (data->getBinRadius() > getSize().mdV[0] && - parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) + if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) || + (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) { //it belongs here #if LL_OCTREE_PARANOIA_CHECK //if this is a redundant insertion, error out (should never happen) @@ -324,16 +328,21 @@ public: } //it's here, but no kids are in the right place, make a new kid - LLVector3d center(getCenter()); - LLVector3d size(getSize()*0.5); + LLVector4a center = getCenter(); + LLVector4a size = getSize(); + size.mul(0.5f); //push center in direction of data LLOctreeNode<T>::pushCenter(center, size, data); // handle case where floating point number gets too small - if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO && - llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO && - llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO) + LLVector4a val; + val.setSub(center, getCenter()); + val.setAbs(val); + + S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7; + + if( lt == 0x7 ) { mData.insert(data); BaseType::insert(data); @@ -351,7 +360,7 @@ public: //make sure no existing node matches this position for (U32 i = 0; i < getChildCount(); i++) { - if (mChild[i]->getCenter() == center) + if (mChild[i]->getCenter().equals3(center)) { OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl; return false; @@ -369,7 +378,7 @@ public: else { //it's not in here, give it to the root - //OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl; + OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl; oct_node* node = this; @@ -443,6 +452,9 @@ public: void clearChildren() { mChild.clear(); + + U32* foo = (U32*) mChildMap; + foo[0] = foo[1] = 0xFFFFFFFF; } void validate() @@ -476,13 +488,19 @@ public: 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!" << llendl; + } + for (U32 i = 0; i < getChildCount(); i++) { - if(mChild[i]->getSize() != child->getSize()) + if(!mChild[i]->getSize().equals3(child->getSize())) { OCT_ERRS <<"Invalid octree child size." << llendl; } - if (mChild[i]->getCenter() == child->getCenter()) + if (mChild[i]->getCenter().equals3(child->getCenter())) { OCT_ERRS <<"Duplicate octree child position." << llendl; } @@ -494,6 +512,8 @@ public: } #endif + mChildMap[child->getOctant()] = (U8) mChild.size(); + mChild.push_back(child); child->setParent(this); @@ -507,7 +527,7 @@ public: } } - void removeChild(U8 index, BOOL destroy = FALSE) + void removeChild(S32 index, BOOL destroy = FALSE) { for (U32 i = 0; i < this->getListenerCount(); i++) { @@ -515,6 +535,8 @@ public: listener->handleChildRemoval(this, getChild(index)); } + + if (destroy) { mChild[index]->destroy(); @@ -522,6 +544,15 @@ public: } mChild.erase(mChild.begin() + index); + //rebuild child map + U32* foo = (U32*) mChildMap; + foo[0] = foo[1] = 0xFFFFFFFF; + + for (U32 i = 0; i < mChild.size(); ++i) + { + mChildMap[mChild[i]->getOctant()] = i; + } + checkAlive(); } @@ -548,19 +579,32 @@ public: } } - //OCT_ERRS << "Octree failed to delete requested child." << llendl; + OCT_ERRS << "Octree failed to delete requested child." << llendl; } protected: - child_list mChild; - element_list mData; + typedef enum + { + CENTER = 0, + SIZE = 1, + MAX = 2, + MIN = 3 + } eDName; + + LLVector4a mCenter; + LLVector4a mSize; + LLVector4a mMax; + LLVector4a mMin; + oct_node* mParent; - LLVector3d mCenter; - LLVector3d mSize; - LLVector3d mMax; - LLVector3d mMin; U8 mOctant; -}; + + child_list mChild; + U8 mChildMap[8]; + + element_list mData; + +}; //just like a regular node, except it might expand on insert and compress on balance template <class T> @@ -570,9 +614,9 @@ public: typedef LLOctreeNode<T> BaseType; typedef LLOctreeNode<T> oct_node; - LLOctreeRoot( LLVector3d center, - LLVector3d size, - BaseType* parent) + LLOctreeRoot(const LLVector4a& center, + const LLVector4a& size, + BaseType* parent) : BaseType(center, size, parent) { } @@ -603,6 +647,8 @@ public: //destroy child child->clearChildren(); delete child; + + return false; } return true; @@ -613,28 +659,33 @@ public: { if (data == NULL) { - //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl; + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl; return false; } if (data->getBinRadius() > 4096.0) { - //OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl; + OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl; return false; } - const F64 MAX_MAG = 1024.0*1024.0; + LLVector4a MAX_MAG; + MAX_MAG.splat(1024.f*1024.f); + + const LLVector4a& v = data->getPositionGroup(); - const LLVector3d& v = data->getPositionGroup(); - if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG && - fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG && - fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG)) + 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 !!!" << llendl; + OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl; return false; } - if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())) + if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())) { //we got it, just act like a branch oct_node* node = getNodeAt(data); @@ -650,31 +701,34 @@ public: else if (this->getChildCount() == 0) { //first object being added, just wrap it up - while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) + while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) { - LLVector3d center, size; + LLVector4a center, size; center = this->getCenter(); size = this->getSize(); LLOctreeNode<T>::pushCenter(center, size, data); this->setCenter(center); - this->setSize(size*2); + size.mul(2.f); + this->setSize(size); this->updateMinMax(); } LLOctreeNode<T>::insert(data); } else { - while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) + while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))) { //the data is outside the root node, we need to grow - LLVector3d center(this->getCenter()); - LLVector3d size(this->getSize()); + LLVector4a center(this->getCenter()); + LLVector4a size(this->getSize()); //expand this node - LLVector3d newcenter(center); + LLVector4a newcenter(center); LLOctreeNode<T>::pushCenter(newcenter, size, data); this->setCenter(newcenter); - this->setSize(size*2); + LLVector4a size2 = size; + size2.mul(2.f); + this->setSize(size2); this->updateMinMax(); //copy our children to a new branch @@ -711,4 +765,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node) traverse(node->getChild(i)); } } + +template <class T> +void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node) +{ + for (U32 i = 0; i < node->getChildCount(); i++) + { + traverse(node->getChild(i)); + } + node->accept(this); +} + #endif diff --git a/indra/llmath/llperlin.cpp b/indra/llmath/llperlin.cpp index 9293d972a4..e1da2bf92b 100644 --- a/indra/llmath/llperlin.cpp +++ b/indra/llmath/llperlin.cpp @@ -1,31 +1,25 @@ /** * @file llperlin.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llperlin.h b/indra/llmath/llperlin.h index e8815ece58..40cf19d1ec 100644 --- a/indra/llmath/llperlin.h +++ b/indra/llmath/llperlin.h @@ -1,31 +1,25 @@ /** * @file llperlin.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h index 89c6a1460f..a611894721 100644 --- a/indra/llmath/llplane.h +++ b/indra/llmath/llplane.h @@ -1,31 +1,25 @@ /** * @file llplane.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -42,19 +36,23 @@ // The plane normal = [A, B, C] // The closest approach = D / sqrt(A*A + B*B + C*C) -class LLPlane : public LLVector4 +class LLPlane { public: + + // Constructors LLPlane() {}; // no default constructor LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); } LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); } - void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); } - void setVec(const LLVector3 &p0, const LLVector3 &n) + inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); } + + // Set + inline void setVec(const LLVector3 &p0, const LLVector3 &n) { F32 d = -(p0 * n); setVec(n, d); } - void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2) + inline void setVec(const LLVector3 &p0, const LLVector3 &p1, const LLVector3 &p2) { LLVector3 u, v, w; u = p1 - p0; @@ -64,8 +62,38 @@ public: F32 d = -(w * p0); setVec(w, d); } - LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;} + + inline LLPlane& operator=(const LLVector4& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;} + + inline LLPlane& operator=(const LLVector4a& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;} + + inline void set(const LLPlane& p2) { mV = p2.mV; } + + // F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; } + + inline LLSimdScalar dot3(const LLVector4a& b) const { return mV.dot3(b); } + + // Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates + // the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead + inline F32 operator[](const S32 idx) const { return mV[idx]; } + + // preferable when index is known at compile time + template <int N> LL_FORCE_INLINE void getAt(LLSimdScalar& v) const { v = mV.getScalarAt<N>(); } + + // reset the vector to 0, 0, 0, 1 + inline void clear() { mV.set(0, 0, 0, 1); } + + inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); } + + // Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero. + inline U8 calcPlaneMask() + { + return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ; + } + +private: + LLVector4a mV; }; diff --git a/indra/llmath/llquantize.h b/indra/llmath/llquantize.h index 2192427f07..1595dbecf8 100644 --- a/indra/llmath/llquantize.h +++ b/indra/llmath/llquantize.h @@ -3,31 +3,25 @@ * @brief useful routines for quantizing floats to various length ints * and back out again * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,10 +29,16 @@ #define LL_LLQUANTIZE_H const U16 U16MAX = 65535; +LL_ALIGN_16( const F32 F_U16MAX_4A[4] ) = { 65535.f, 65535.f, 65535.f, 65535.f }; + const F32 OOU16MAX = 1.f/(F32)(U16MAX); +LL_ALIGN_16( const F32 F_OOU16MAX_4A[4] ) = { OOU16MAX, OOU16MAX, OOU16MAX, OOU16MAX }; const U8 U8MAX = 255; +LL_ALIGN_16( const F32 F_U8MAX_4A[4] ) = { 255.f, 255.f, 255.f, 255.f }; + const F32 OOU8MAX = 1.f/(F32)(U8MAX); +LL_ALIGN_16( const F32 F_OOU8MAX_4A[4] ) = { OOU8MAX, OOU8MAX, OOU8MAX, OOU8MAX }; const U8 FIRSTVALIDCHAR = 54; const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index cfd6183ec4..7381d5eb99 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -2,39 +2,34 @@ * @file llquaternion.cpp * @brief LLQuaternion class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 "llmath.h" // for F_PI //#include "vmath.h" #include "v3math.h" #include "v3dmath.h" @@ -121,7 +116,7 @@ void LLQuaternion::quantize16(F32 lower, F32 upper) mQ[VZ] = z; mQ[VS] = s; - normQuat(); + normalize(); } void LLQuaternion::quantize8(F32 lower, F32 upper) @@ -131,7 +126,7 @@ void LLQuaternion::quantize8(F32 lower, F32 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); - normQuat(); + normalize(); } // LLVector3 Magnitude and Normalization Functions @@ -346,7 +341,7 @@ const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat) // mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ); //#endif // -// normQuat(); +// normalize(); // return (*this); } diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index 5db9c5be2e..ca0dfe206b 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -2,38 +2,36 @@ * @file llquaternion.h * @brief LLQuaternion class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLQUATERNION_H #define LLQUATERNION_H -#include "llmath.h" +#include <iostream> + +#ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies +#error "Please include llmath.h first." +#endif class LLVector4; class LLVector3; @@ -469,20 +467,30 @@ inline const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b) 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) { - F32 oomag = 1.f/mag; - mQ[VX] *= oomag; - mQ[VY] *= oomag; - mQ[VZ] *= oomag; - mQ[VS] *= oomag; + // 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; @@ -499,11 +507,15 @@ inline F32 LLQuaternion::normQuat() if (mag > FP_MAG_THRESHOLD) { - F32 oomag = 1.f/mag; - mQ[VX] *= oomag; - mQ[VY] *= oomag; - mQ[VZ] *= oomag; - mQ[VS] *= oomag; + 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 { diff --git a/indra/llmath/llquaternion2.h b/indra/llmath/llquaternion2.h new file mode 100644 index 0000000000..fd9c0cf3ab --- /dev/null +++ b/indra/llmath/llquaternion2.h @@ -0,0 +1,105 @@ +/** + * @file llquaternion2.h + * @brief LLQuaternion2 class header file - SIMD-enabled quaternion class + * + * $LicenseInfo:firstyear=2010&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_QUATERNION2_H +#define LL_QUATERNION2_H + +///////////////////////////// +// LLQuaternion2 +///////////////////////////// +// This class stores a quaternion x*i + y*j + z*k + w in <x, y, z, w> order +// (i.e., w in high order element of vector) +///////////////////////////// +///////////////////////////// +// These classes are intentionally minimal right now. If you need additional +// functionality, please contact someone with SSE experience (e.g., Falcon or +// Huseby). +///////////////////////////// +#include "llquaternion.h" + +class LLQuaternion2 +{ +public: + + ////////////////////////// + // Ctors + ////////////////////////// + + // Ctor + LLQuaternion2() {} + + // Ctor from LLQuaternion + explicit LLQuaternion2( const class LLQuaternion& quat ); + + ////////////////////////// + // Get/Set + ////////////////////////// + + // Load from an LLQuaternion + inline void operator=( const LLQuaternion& quat ) + { + mQ.loadua( quat.mQ ); + } + + // Return the internal LLVector4a representation of the quaternion + inline const LLVector4a& getVector4a() const; + inline LLVector4a& getVector4aRw(); + + ///////////////////////// + // Quaternion modification + ///////////////////////// + + // Set this quaternion to the conjugate of src + inline void setConjugate(const LLQuaternion2& src); + + // Renormalizes the quaternion. Assumes it has nonzero length. + inline void normalize(); + + // Quantize this quaternion to 8 bit precision + inline void quantize8(); + + // Quantize this quaternion to 16 bit precision + inline void quantize16(); + + ///////////////////////// + // Quaternion inspection + ///////////////////////// + + // Return true if this quaternion is equal to 'rhs'. + // Note! Quaternions exhibit "double-cover", so any rotation has two equally valid + // quaternion representations and they will NOT compare equal. + inline bool equals(const LLQuaternion2& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const; + + // Return true if all components are finite and the quaternion is normalized + inline bool isOkRotation() const; + +protected: + + LLVector4a mQ; + +}; + +#endif diff --git a/indra/llmath/llquaternion2.inl b/indra/llmath/llquaternion2.inl new file mode 100644 index 0000000000..2a6987552d --- /dev/null +++ b/indra/llmath/llquaternion2.inl @@ -0,0 +1,102 @@ +/** + * @file llquaternion2.inl + * @brief LLQuaternion2 inline definitions + * + * $LicenseInfo:firstyear=2010&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 "llquaternion2.h" + +static const LLQuad LL_V4A_PLUS_ONE = {1.f, 1.f, 1.f, 1.f}; +static const LLQuad LL_V4A_MINUS_ONE = {-1.f, -1.f, -1.f, -1.f}; + +// Ctor from LLQuaternion +inline LLQuaternion2::LLQuaternion2( const LLQuaternion& quat ) +{ + mQ.set(quat.mQ[VX], quat.mQ[VY], quat.mQ[VZ], quat.mQ[VW]); +} + +////////////////////////// +// Get/Set +////////////////////////// + +// Return the internal LLVector4a representation of the quaternion +inline const LLVector4a& LLQuaternion2::getVector4a() const +{ + return mQ; +} + +inline LLVector4a& LLQuaternion2::getVector4aRw() +{ + return mQ; +} + +///////////////////////// +// Quaternion modification +///////////////////////// + +// Set this quaternion to the conjugate of src +inline void LLQuaternion2::setConjugate(const LLQuaternion2& src) +{ + static LL_ALIGN_16( const U32 F_QUAT_INV_MASK_4A[4] ) = { 0x80000000, 0x80000000, 0x80000000, 0x00000000 }; + mQ = _mm_xor_ps(src.mQ, *reinterpret_cast<const LLQuad*>(&F_QUAT_INV_MASK_4A)); +} + +// Renormalizes the quaternion. Assumes it has nonzero length. +inline void LLQuaternion2::normalize() +{ + mQ.normalize4(); +} + +// Quantize this quaternion to 8 bit precision +inline void LLQuaternion2::quantize8() +{ + mQ.quantize8( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE ); + normalize(); +} + +// Quantize this quaternion to 16 bit precision +inline void LLQuaternion2::quantize16() +{ + mQ.quantize16( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE ); + normalize(); +} + + +///////////////////////// +// Quaternion inspection +///////////////////////// + +// Return true if this quaternion is equal to 'rhs'. +// Note! Quaternions exhibit "double-cover", so any rotation has two equally valid +// quaternion representations and they will NOT compare equal. +inline bool LLQuaternion2::equals(const LLQuaternion2 &rhs, F32 tolerance/* = F_APPROXIMATELY_ZERO*/) const +{ + return mQ.equals4(rhs.mQ, tolerance); +} + +// Return true if all components are finite and the quaternion is normalized +inline bool LLQuaternion2::isOkRotation() const +{ + return mQ.isFinite4() && mQ.isNormalized4(); +} + diff --git a/indra/llmath/llrect.cpp b/indra/llmath/llrect.cpp index cba76dd211..4083c99768 100644 --- a/indra/llmath/llrect.cpp +++ b/indra/llmath/llrect.cpp @@ -1,34 +1,30 @@ /** * @file llrect.cpp + * @brief LLRect class implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" +// implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes. #include "llrect.h" diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h index 894f0a7ed0..c51e0e0ae6 100644 --- a/indra/llmath/llrect.h +++ b/indra/llmath/llrect.h @@ -2,31 +2,25 @@ * @file llrect.h * @brief A rectangle in GL coordinates, with bottom,left = 0,0 * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -42,6 +36,7 @@ template <class Type> class LLRectBase { public: + typedef Type tCoordType; Type mLeft; Type mTop; Type mRight; @@ -141,10 +136,20 @@ 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 rectInRect(const LLRectBase* rect) const + 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->mRight && rect->mLeft <= mRight && - mBottom <= rect->mTop && rect->mBottom <= mTop ; + return mLeft <= rect.mLeft + && mRight >= rect.mRight + && mBottom <= rect.mBottom + && mTop >= rect.mTop; } LLRectBase& set(Type left, Type top, Type right, Type bottom) @@ -223,26 +228,25 @@ public: return mLeft <= mRight && mBottom <= mTop; } - bool isNull() const + bool isEmpty() const { return mLeft == mRight || mBottom == mTop; } - bool notNull() const + bool notEmpty() const { - return !isNull(); + return !isEmpty(); } - LLRectBase& unionWith(const LLRectBase &other) + 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); - return *this; } - LLRectBase& intersectWith(const LLRectBase &other) + void intersectWith(const LLRectBase &other) { mLeft = llmax(mLeft, other.mLeft); mRight = llmin(mRight, other.mRight); @@ -256,7 +260,6 @@ public: { mBottom = mTop; } - return *this; } friend std::ostream &operator<<(std::ostream &s, const LLRectBase &rect) diff --git a/indra/llmath/llsdutil_math.cpp b/indra/llmath/llsdutil_math.cpp index c5176681ce..591f7fde36 100644 --- a/indra/llmath/llsdutil_math.cpp +++ b/indra/llmath/llsdutil_math.cpp @@ -4,37 +4,31 @@ * @date 2006-05-24 * @brief Implementation of classes, functions, etc, for using structured data. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" -#include "llsdutil.h" +#include "llsdutil_math.h" #include "v3math.h" #include "v4math.h" diff --git a/indra/llmath/llsdutil_math.h b/indra/llmath/llsdutil_math.h new file mode 100644 index 0000000000..0ea78cd231 --- /dev/null +++ b/indra/llmath/llsdutil_math.h @@ -0,0 +1,64 @@ +/** + * @file llsdutil_math.h + * @author Brad + * @date 2009-05-19 + * @brief Utility classes, functions, etc, for using structured data with math classes. + * + * $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$ + */ + +#ifndef LL_LLSDUTIL_MATH_H +#define LL_LLSDUTIL_MATH_H + +class LL_COMMON_API LLSD; + +// vector3 +class LLVector3; +LLSD ll_sd_from_vector3(const LLVector3& vec); +LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0); + +// vector4 +class LLVector4; +LLSD ll_sd_from_vector4(const LLVector4& vec); +LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0); + +// vector3d (double) +class LLVector3d; +LLSD ll_sd_from_vector3d(const LLVector3d& vec); +LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0); + +// vector2 +class LLVector2; +LLSD ll_sd_from_vector2(const LLVector2& vec); +LLVector2 ll_vector2_from_sd(const LLSD& sd); + +// Quaternion +class LLQuaternion; +LLSD ll_sd_from_quaternion(const LLQuaternion& quat); +LLQuaternion ll_quaternion_from_sd(const LLSD& sd); + +// color4 +class LLColor4; +LLSD ll_sd_from_color4(const LLColor4& c); +LLColor4 ll_color4_from_sd(const LLSD& sd); + +#endif // LL_LLSDUTIL_MATH_H diff --git a/indra/llmath/llsimdmath.h b/indra/llmath/llsimdmath.h new file mode 100644 index 0000000000..c7cdf7b32c --- /dev/null +++ b/indra/llmath/llsimdmath.h @@ -0,0 +1,93 @@ +/** + * @file llsimdmath.h + * @brief Common header for SIMD-based math library (llvector4a, llmatrix3a, etc.) + * + * $LicenseInfo:firstyear=2010&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_SIMD_MATH_H +#define LL_SIMD_MATH_H + +#ifndef LLMATH_H +#error "Please include llmath.h before this file." +#endif + +#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) ) +#error SSE2 not enabled. LLVector4a and related class will not compile. +#endif + +#if !LL_WINDOWS +#include <stdint.h> +#endif + +template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address) +{ + return reinterpret_cast<T*>( + (reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF); +} + +template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) +{ + return reinterpret_cast<T*>( + (reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F); +} + +#if LL_LINUX || LL_DARWIN + +#define LL_ALIGN_PREFIX(x) +#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) + +#elif LL_WINDOWS + +#define LL_ALIGN_PREFIX(x) __declspec(align(x)) +#define LL_ALIGN_POSTFIX(x) + +#else +#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined" +#endif + +#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16) + + + +#include <xmmintrin.h> +#include <emmintrin.h> + +#include "llsimdtypes.h" +#include "llsimdtypes.inl" + +class LLMatrix3a; +class LLRotation; +class LLMatrix3; + +#include "llquaternion.h" + +#include "llvector4logical.h" +#include "llvector4a.h" +#include "llmatrix3a.h" +#include "llquaternion2.h" +#include "llvector4a.inl" +#include "llmatrix3a.inl" +#include "llquaternion2.inl" + + +#endif //LL_SIMD_MATH_H diff --git a/indra/llmath/llsimdtypes.h b/indra/llmath/llsimdtypes.h new file mode 100644 index 0000000000..bd991d0e71 --- /dev/null +++ b/indra/llmath/llsimdtypes.h @@ -0,0 +1,124 @@ +/** + * @file llsimdtypes.h + * @brief Declaration of basic SIMD math related types + * + * $LicenseInfo:firstyear=2010&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_SIMD_TYPES_H +#define LL_SIMD_TYPES_H + +#ifndef LL_SIMD_MATH_H +#error "Please include llmath.h before this file." +#endif + +typedef __m128 LLQuad; + + +#if LL_WINDOWS +#pragma warning(push) +#pragma warning( disable : 4800 3 ) // Disable warning about casting int to bool for this class. +#if defined(_MSC_VER) && (_MSC_VER < 1500) +// VC++ 2005 is missing these intrinsics +// __forceinline is MSVC specific and attempts to override compiler inlining judgment. This is so +// even in debug builds this call is a NOP. +__forceinline const __m128 _mm_castsi128_ps( const __m128i a ) { return reinterpret_cast<const __m128&>(a); } +__forceinline const __m128i _mm_castps_si128( const __m128 a ) { return reinterpret_cast<const __m128i&>(a); } +#endif // _MSC_VER + +#endif // LL_WINDOWS + +class LLBool32 +{ +public: + inline LLBool32() {} + inline LLBool32(int rhs) : m_bool(rhs) {} + inline LLBool32(unsigned int rhs) : m_bool(rhs) {} + inline LLBool32(bool rhs) { m_bool = static_cast<const int>(rhs); } + inline LLBool32& operator= (bool rhs) { m_bool = (int)rhs; return *this; } + inline bool operator== (bool rhs) const { return static_cast<const bool&>(m_bool) == rhs; } + inline bool operator!= (bool rhs) const { return !operator==(rhs); } + inline operator bool() const { return static_cast<const bool&>(m_bool); } + +private: + int m_bool; +}; + +#if LL_WINDOWS +#pragma warning(pop) +#endif + +class LLSimdScalar +{ +public: + inline LLSimdScalar() {} + inline LLSimdScalar(LLQuad q) + { + mQ = q; + } + + inline LLSimdScalar(F32 f) + { + mQ = _mm_set_ss(f); + } + + static inline const LLSimdScalar& getZero() + { + extern const LLQuad F_ZERO_4A; + return reinterpret_cast<const LLSimdScalar&>(F_ZERO_4A); + } + + inline F32 getF32() const; + + inline LLBool32 isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance = F_APPROXIMATELY_ZERO) const; + + inline LLSimdScalar getAbs() const; + + inline void setMax( const LLSimdScalar& a, const LLSimdScalar& b ); + + inline void setMin( const LLSimdScalar& a, const LLSimdScalar& b ); + + inline LLSimdScalar& operator=(F32 rhs); + + inline LLSimdScalar& operator+=(const LLSimdScalar& rhs); + + inline LLSimdScalar& operator-=(const LLSimdScalar& rhs); + + inline LLSimdScalar& operator*=(const LLSimdScalar& rhs); + + inline LLSimdScalar& operator/=(const LLSimdScalar& rhs); + + inline operator LLQuad() const + { + return mQ; + } + + inline const LLQuad& getQuad() const + { + return mQ; + } + +private: + LLQuad mQ; +}; + +#endif //LL_SIMD_TYPES_H diff --git a/indra/llmath/llsimdtypes.inl b/indra/llmath/llsimdtypes.inl new file mode 100644 index 0000000000..712239e425 --- /dev/null +++ b/indra/llmath/llsimdtypes.inl @@ -0,0 +1,157 @@ +/** + * @file llsimdtypes.inl + * @brief Inlined definitions of basic SIMD math related types + * + * $LicenseInfo:firstyear=2010&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$ + */ + + + + +////////////////// +// LLSimdScalar +////////////////// + +inline LLSimdScalar operator+(const LLSimdScalar& a, const LLSimdScalar& b) +{ + LLSimdScalar t(a); + t += b; + return t; +} + +inline LLSimdScalar operator-(const LLSimdScalar& a, const LLSimdScalar& b) +{ + LLSimdScalar t(a); + t -= b; + return t; +} + +inline LLSimdScalar operator*(const LLSimdScalar& a, const LLSimdScalar& b) +{ + LLSimdScalar t(a); + t *= b; + return t; +} + +inline LLSimdScalar operator/(const LLSimdScalar& a, const LLSimdScalar& b) +{ + LLSimdScalar t(a); + t /= b; + return t; +} + +inline LLSimdScalar operator-(const LLSimdScalar& a) +{ + static LL_ALIGN_16(const U32 signMask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + return _mm_xor_ps(*reinterpret_cast<const LLQuad*>(signMask), a); +} + +inline LLBool32 operator==(const LLSimdScalar& a, const LLSimdScalar& b) +{ + return _mm_comieq_ss(a, b); +} + +inline LLBool32 operator!=(const LLSimdScalar& a, const LLSimdScalar& b) +{ + return _mm_comineq_ss(a, b); +} + +inline LLBool32 operator<(const LLSimdScalar& a, const LLSimdScalar& b) +{ + return _mm_comilt_ss(a, b); +} + +inline LLBool32 operator<=(const LLSimdScalar& a, const LLSimdScalar& b) +{ + return _mm_comile_ss(a, b); +} + +inline LLBool32 operator>(const LLSimdScalar& a, const LLSimdScalar& b) +{ + return _mm_comigt_ss(a, b); +} + +inline LLBool32 operator>=(const LLSimdScalar& a, const LLSimdScalar& b) +{ + return _mm_comige_ss(a, b); +} + +inline LLBool32 LLSimdScalar::isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance /* = F_APPROXIMATELY_ZERO */) const +{ + const LLSimdScalar tol( tolerance ); + const LLSimdScalar diff = _mm_sub_ss( mQ, rhs.mQ ); + const LLSimdScalar absDiff = diff.getAbs(); + return absDiff <= tol; +} + +inline void LLSimdScalar::setMax( const LLSimdScalar& a, const LLSimdScalar& b ) +{ + mQ = _mm_max_ss( a, b ); +} + +inline void LLSimdScalar::setMin( const LLSimdScalar& a, const LLSimdScalar& b ) +{ + mQ = _mm_min_ss( a, b ); +} + +inline LLSimdScalar& LLSimdScalar::operator=(F32 rhs) +{ + mQ = _mm_set_ss(rhs); + return *this; +} + +inline LLSimdScalar& LLSimdScalar::operator+=(const LLSimdScalar& rhs) +{ + mQ = _mm_add_ss( mQ, rhs ); + return *this; +} + +inline LLSimdScalar& LLSimdScalar::operator-=(const LLSimdScalar& rhs) +{ + mQ = _mm_sub_ss( mQ, rhs ); + return *this; +} + +inline LLSimdScalar& LLSimdScalar::operator*=(const LLSimdScalar& rhs) +{ + mQ = _mm_mul_ss( mQ, rhs ); + return *this; +} + +inline LLSimdScalar& LLSimdScalar::operator/=(const LLSimdScalar& rhs) +{ + mQ = _mm_div_ss( mQ, rhs ); + return *this; +} + +inline LLSimdScalar LLSimdScalar::getAbs() const +{ + static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }; + return _mm_and_ps( mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A)); +} + +inline F32 LLSimdScalar::getF32() const +{ + F32 ret; + _mm_store_ss(&ret, mQ); + return ret; +} diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index b260c134a7..740047b93a 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -3,31 +3,25 @@ * @author Andrew Meadows * @brief Simple line class that can compute nearest approach between two lines * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llsphere.h b/indra/llmath/llsphere.h index 58df07a567..7c60a11406 100644 --- a/indra/llmath/llsphere.h +++ b/indra/llmath/llsphere.h @@ -4,31 +4,25 @@ * @author Andrew Meadows * @brief Simple sphere implementation for basic geometric operations * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index ee9836241a..c66bc26176 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -1,31 +1,25 @@ /** * @file lltreenode.h * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -34,6 +28,9 @@ #include "stdtypes.h" #include "xform.h" +#include "llpointer.h" +#include "llrefcount.h" + #include <vector> template <class T> class LLTreeNode; diff --git a/indra/llmath/llv4math.h b/indra/llmath/llv4math.h index 5b180b3d77..5f403ba526 100644 --- a/indra/llmath/llv4math.h +++ b/indra/llmath/llv4math.h @@ -2,31 +2,25 @@ * @file llv4math.h * @brief LLV4* class header file - vector processor enabled math * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llv4matrix3.h b/indra/llmath/llv4matrix3.h index ed503e9d78..270f5d7dae 100644 --- a/indra/llmath/llv4matrix3.h +++ b/indra/llmath/llv4matrix3.h @@ -2,31 +2,25 @@ * @file llviewerjointmesh.cpp * @brief LLV4* class header file - vector processor enabled math * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llv4matrix4.h b/indra/llmath/llv4matrix4.h index 959fa34572..2eb49d9294 100644 --- a/indra/llmath/llv4matrix4.h +++ b/indra/llmath/llv4matrix4.h @@ -2,31 +2,25 @@ * @file llviewerjointmesh.cpp * @brief LLV4* class header file - vector processor enabled math * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llv4vector3.h b/indra/llmath/llv4vector3.h index a41de47e6d..a340d53f5a 100644 --- a/indra/llmath/llv4vector3.h +++ b/indra/llmath/llv4vector3.h @@ -2,31 +2,25 @@ * @file llviewerjointmesh.cpp * @brief LLV4* class header file - vector processor enabled math * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llvector4a.cpp b/indra/llmath/llvector4a.cpp new file mode 100644 index 0000000000..b66b7a7076 --- /dev/null +++ b/indra/llmath/llvector4a.cpp @@ -0,0 +1,222 @@ +/** + * @file llvector4a.cpp + * @brief SIMD vector implementation + * + * $LicenseInfo:firstyear=2010&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 "llmath.h" +#include "llquantize.h" + +extern const LLQuad F_ZERO_4A = { 0, 0, 0, 0 }; +extern const LLQuad F_APPROXIMATELY_ZERO_4A = { + F_APPROXIMATELY_ZERO, + F_APPROXIMATELY_ZERO, + F_APPROXIMATELY_ZERO, + F_APPROXIMATELY_ZERO +}; + +extern const LLVector4a LL_V4A_ZERO = reinterpret_cast<const LLVector4a&> ( F_ZERO_4A ); +extern const LLVector4a LL_V4A_EPSILON = reinterpret_cast<const LLVector4a&> ( F_APPROXIMATELY_ZERO_4A ); + +/*static */void LLVector4a::memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes) +{ + assert(src != NULL); + assert(dst != NULL); + assert(bytes > 0); + assert((bytes % sizeof(F32))== 0); + + F32* end = dst + (bytes / sizeof(F32) ); + + if (bytes > 64) + { + F32* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); + + //at least 64 (16*4) bytes before the end of the destination, switch to 16 byte copies + F32* end_64 = end-16; + + _mm_prefetch((char*)begin_64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); + + while (dst < begin_64) + { + copy4a(dst, src); + dst += 4; + src += 4; + } + + while (dst < end_64) + { + _mm_prefetch((char*)src + 512, _MM_HINT_NTA); + _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); + copy4a(dst, src); + copy4a(dst+4, src+4); + copy4a(dst+8, src+8); + copy4a(dst+12, src+12); + + dst += 16; + src += 16; + } + } + + while (dst < end) + { + copy4a(dst, src); + dst += 4; + src += 4; + } +} + +void LLVector4a::setRotated( const LLRotation& rot, const LLVector4a& vec ) +{ + const LLVector4a col0 = rot.getColumn(0); + const LLVector4a col1 = rot.getColumn(1); + const LLVector4a col2 = rot.getColumn(2); + + LLVector4a result = _mm_load_ss( vec.getF32ptr() ); + result.splat<0>( result ); + result.mul( col0 ); + + { + LLVector4a yyyy = _mm_load_ss( vec.getF32ptr() + 1 ); + yyyy.splat<0>( yyyy ); + yyyy.mul( col1 ); + result.add( yyyy ); + } + + { + LLVector4a zzzz = _mm_load_ss( vec.getF32ptr() + 2 ); + zzzz.splat<0>( zzzz ); + zzzz.mul( col2 ); + result.add( zzzz ); + } + + *this = result; +} + +void LLVector4a::setRotated( const LLQuaternion2& quat, const LLVector4a& vec ) +{ + const LLVector4a& quatVec = quat.getVector4a(); + LLVector4a temp; temp.setCross3(quatVec, vec); + temp.add( temp ); + + const LLVector4a realPart( quatVec.getScalarAt<3>() ); + LLVector4a tempTimesReal; tempTimesReal.setMul( temp, realPart ); + + mQ = vec; + add( tempTimesReal ); + + LLVector4a imagCrossTemp; imagCrossTemp.setCross3( quatVec, temp ); + add(imagCrossTemp); +} + +void LLVector4a::quantize8( const LLVector4a& low, const LLVector4a& high ) +{ + LLVector4a val(mQ); + LLVector4a delta; delta.setSub( high, low ); + + { + val.clamp(low, high); + val.sub(low); + + // 8-bit quantization means we can do with just 12 bits of reciprocal accuracy + const LLVector4a oneOverDelta = _mm_rcp_ps(delta.mQ); +// { +// static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f }; +// LLVector4a two; two.load4a( F_TWO_4A ); +// +// // Here we use _mm_rcp_ps plus one round of newton-raphson +// // We wish to find 'x' such that x = 1/delta +// // As a first approximation, we take x0 = _mm_rcp_ps(delta) +// // Then x1 = 2 * x0 - a * x0^2 or x1 = x0 * ( 2 - a * x0 ) +// // See Intel AP-803 http://ompf.org/!/Intel_application_note_AP-803.pdf +// const LLVector4a recipApprox = _mm_rcp_ps(delta.mQ); +// oneOverDelta.setMul( delta, recipApprox ); +// oneOverDelta.setSub( two, oneOverDelta ); +// oneOverDelta.mul( recipApprox ); +// } + + val.mul(oneOverDelta); + val.mul(*reinterpret_cast<const LLVector4a*>(F_U8MAX_4A)); + } + + val = _mm_cvtepi32_ps(_mm_cvtps_epi32( val.mQ )); + + { + val.mul(*reinterpret_cast<const LLVector4a*>(F_OOU8MAX_4A)); + val.mul(delta); + val.add(low); + } + + { + LLVector4a maxError; maxError.setMul(delta, *reinterpret_cast<const LLVector4a*>(F_OOU8MAX_4A)); + LLVector4a absVal; absVal.setAbs( val ); + setSelectWithMask( absVal.lessThan( maxError ), F_ZERO_4A, val ); + } +} + +void LLVector4a::quantize16( const LLVector4a& low, const LLVector4a& high ) +{ + LLVector4a val(mQ); + LLVector4a delta; delta.setSub( high, low ); + + { + val.clamp(low, high); + val.sub(low); + + // 16-bit quantization means we need a round of Newton-Raphson + LLVector4a oneOverDelta; + { + static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f }; + LLVector4a two; two.load4a( F_TWO_4A ); + + // Here we use _mm_rcp_ps plus one round of newton-raphson + // We wish to find 'x' such that x = 1/delta + // As a first approximation, we take x0 = _mm_rcp_ps(delta) + // Then x1 = 2 * x0 - a * x0^2 or x1 = x0 * ( 2 - a * x0 ) + // See Intel AP-803 http://ompf.org/!/Intel_application_note_AP-803.pdf + const LLVector4a recipApprox = _mm_rcp_ps(delta.mQ); + oneOverDelta.setMul( delta, recipApprox ); + oneOverDelta.setSub( two, oneOverDelta ); + oneOverDelta.mul( recipApprox ); + } + + val.mul(oneOverDelta); + val.mul(*reinterpret_cast<const LLVector4a*>(F_U16MAX_4A)); + } + + val = _mm_cvtepi32_ps(_mm_cvtps_epi32( val.mQ )); + + { + val.mul(*reinterpret_cast<const LLVector4a*>(F_OOU16MAX_4A)); + val.mul(delta); + val.add(low); + } + + { + LLVector4a maxError; maxError.setMul(delta, *reinterpret_cast<const LLVector4a*>(F_OOU16MAX_4A)); + LLVector4a absVal; absVal.setAbs( val ); + setSelectWithMask( absVal.lessThan( maxError ), F_ZERO_4A, val ); + } +} diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h new file mode 100644 index 0000000000..596082509d --- /dev/null +++ b/indra/llmath/llvector4a.h @@ -0,0 +1,324 @@ +/** + * @file llvector4a.h + * @brief LLVector4a class header file - memory aligned and vectorized 4 component vector + * + * $LicenseInfo:firstyear=2010&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_LLVECTOR4A_H +#define LL_LLVECTOR4A_H + + +class LLRotation; + +#include <assert.h> +#include "llpreprocessor.h" + +/////////////////////////////////// +// FIRST TIME USERS PLEASE READ +////////////////////////////////// +// This is just the beginning of LLVector4a. There are many more useful functions +// yet to be implemented. For example, setNeg to negate a vector, rotate() to apply +// a matrix rotation, various functions to manipulate only the X, Y, and Z elements +// and many others (including a whole variety of accessors). So if you don't see a +// function here that you need, please contact Falcon or someone else with SSE +// experience (Richard, I think, has some and davep has a little as of the time +// of this writing, July 08, 2010) about getting it implemented before you resort to +// LLVector3/LLVector4. +///////////////////////////////// + +class LLVector4a +{ +public: + + /////////////////////////////////// + // STATIC METHODS + /////////////////////////////////// + + // Call initClass() at startup to avoid 15,000+ cycle penalties from denormalized numbers + static void initClass() + { + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); + } + + // Return a vector of all zeros + static inline const LLVector4a& getZero() + { + extern const LLVector4a LL_V4A_ZERO; + return LL_V4A_ZERO; + } + + // Return a vector of all epsilon, where epsilon is a small float suitable for approximate equality checks + static inline const LLVector4a& getEpsilon() + { + extern const LLVector4a LL_V4A_EPSILON; + return LL_V4A_EPSILON; + } + + // Copy 16 bytes from src to dst. Source and destination must be 16-byte aligned + static inline void copy4a(F32* dst, const F32* src) + { + _mm_store_ps(dst, _mm_load_ps(src)); + } + + // Copy words 16-byte blocks from src to dst. Source and destination must not overlap. + static void memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes); + + //////////////////////////////////// + // CONSTRUCTORS + //////////////////////////////////// + + LLVector4a() + { //DO NOT INITIALIZE -- The overhead is completely unnecessary + } + + LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f) + { + set(x,y,z,w); + } + + LLVector4a(F32 x) + { + splat(x); + } + + LLVector4a(const LLSimdScalar& x) + { + splat(x); + } + + LLVector4a(LLQuad q) + { + mQ = q; + } + + //////////////////////////////////// + // LOAD/STORE + //////////////////////////////////// + + // Load from 16-byte aligned src array (preferred method of loading) + inline void load4a(const F32* src); + + // Load from unaligned src array (NB: Significantly slower than load4a) + inline void loadua(const F32* src); + + // Load only three floats beginning at address 'src'. Slowest method. + inline void load3(const F32* src); + + // Store to a 16-byte aligned memory address + inline void store4a(F32* dst) const; + + //////////////////////////////////// + // BASIC GET/SET + //////////////////////////////////// + + // Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) + inline F32* getF32ptr(); + + // Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) + inline const F32* const getF32ptr() const; + + // Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates + // the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead + inline F32 operator[](const S32 idx) const; + + // Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time. + inline LLSimdScalar getScalarAt(const S32 idx) const; + + // Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time. + template <int N> LL_FORCE_INLINE LLSimdScalar getScalarAt() const; + + // Set to an x, y, z and optional w provided + inline void set(F32 x, F32 y, F32 z, F32 w = 0.f); + + // Set to all zeros. This is preferred to using ::getZero() + inline void clear(); + + // Set all elements to 'x' + inline void splat(const F32 x); + + // Set all elements to 'x' + inline void splat(const LLSimdScalar& x); + + // Set all 4 elements to element N of src, with N known at compile time + template <int N> void splat(const LLVector4a& src); + + // Set all 4 elements to element i of v, with i NOT known at compile time + inline void splat(const LLVector4a& v, U32 i); + + // Select bits from sourceIfTrue and sourceIfFalse according to bits in mask + inline void setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse ); + + //////////////////////////////////// + // ALGEBRAIC + //////////////////////////////////// + + // Set this to the element-wise (a + b) + inline void setAdd(const LLVector4a& a, const LLVector4a& b); + + // Set this to element-wise (a - b) + inline void setSub(const LLVector4a& a, const LLVector4a& b); + + // Set this to element-wise multiply (a * b) + inline void setMul(const LLVector4a& a, const LLVector4a& b); + + // Set this to element-wise quotient (a / b) + inline void setDiv(const LLVector4a& a, const LLVector4a& b); + + // Set this to the element-wise absolute value of src + inline void setAbs(const LLVector4a& src); + + // Add to each component in this vector the corresponding component in rhs + inline void add(const LLVector4a& rhs); + + // Subtract from each component in this vector the corresponding component in rhs + inline void sub(const LLVector4a& rhs); + + // Multiply each component in this vector by the corresponding component in rhs + inline void mul(const LLVector4a& rhs); + + // Divide each component in this vector by the corresponding component in rhs + inline void div(const LLVector4a& rhs); + + // Multiply this vector by x in a scalar fashion + inline void mul(const F32 x); + + // Set this to (a x b) (geometric cross-product) + inline void setCross3(const LLVector4a& a, const LLVector4a& b); + + // Set all elements to the dot product of the x, y, and z elements in a and b + inline void setAllDot3(const LLVector4a& a, const LLVector4a& b); + + // Set all elements to the dot product of the x, y, z, and w elements in a and b + inline void setAllDot4(const LLVector4a& a, const LLVector4a& b); + + // Return the 3D dot product of this vector and b + inline LLSimdScalar dot3(const LLVector4a& b) const; + + // Return the 4D dot product of this vector and b + inline LLSimdScalar dot4(const LLVector4a& b) const; + + // Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed + // Note that this does not consider zero length vectors! + inline void normalize3(); + + // Same as normalize3() but with respect to all 4 components + inline void normalize4(); + + // Same as normalize3(), but returns length as a SIMD scalar + inline LLSimdScalar normalize3withLength(); + + // Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed + // Note that this does not consider zero length vectors! + inline void normalize3fast(); + + // Return true if this vector is normalized with respect to x,y,z up to tolerance + inline LLBool32 isNormalized3( F32 tolerance = 1e-3 ) const; + + // Return true if this vector is normalized with respect to all components up to tolerance + inline LLBool32 isNormalized4( F32 tolerance = 1e-3 ) const; + + // Set all elements to the length of vector 'v' + inline void setAllLength3( const LLVector4a& v ); + + // Get this vector's length + inline LLSimdScalar getLength3() const; + + // Set the components of this vector to the minimum of the corresponding components of lhs and rhs + inline void setMin(const LLVector4a& lhs, const LLVector4a& rhs); + + // Set the components of this vector to the maximum of the corresponding components of lhs and rhs + inline void setMax(const LLVector4a& lhs, const LLVector4a& rhs); + + // Clamps this vector to be within the component-wise range low to high (inclusive) + inline void clamp( const LLVector4a& low, const LLVector4a& high ); + + // Set this to (c * lhs) + rhs * ( 1 - c) + inline void setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c); + + // Return true (nonzero) if x, y, z (and w for Finite4) are all finite floats + inline LLBool32 isFinite3() const; + inline LLBool32 isFinite4() const; + + // Set this vector to 'vec' rotated by the LLRotation or LLQuaternion2 provided + void setRotated( const LLRotation& rot, const LLVector4a& vec ); + void setRotated( const class LLQuaternion2& quat, const LLVector4a& vec ); + + // Set this vector to 'vec' rotated by the INVERSE of the LLRotation or LLQuaternion2 provided + inline void setRotatedInv( const LLRotation& rot, const LLVector4a& vec ); + inline void setRotatedInv( const class LLQuaternion2& quat, const LLVector4a& vec ); + + // Quantize this vector to 8 or 16 bit precision + void quantize8( const LLVector4a& low, const LLVector4a& high ); + void quantize16( const LLVector4a& low, const LLVector4a& high ); + + //////////////////////////////////// + // LOGICAL + //////////////////////////////////// + // The functions in this section will compare the elements in this vector + // to those in rhs and return an LLVector4Logical with all bits set in elements + // where the comparison was true and all bits unset in elements where the comparison + // was false. See llvector4logica.h + //////////////////////////////////// + // WARNING: Other than equals3 and equals4, these functions do NOT account + // for floating point tolerance. You should include the appropriate tolerance + // in the inputs. + //////////////////////////////////// + + inline LLVector4Logical greaterThan(const LLVector4a& rhs) const; + + inline LLVector4Logical lessThan(const LLVector4a& rhs) const; + + inline LLVector4Logical greaterEqual(const LLVector4a& rhs) const; + + inline LLVector4Logical lessEqual(const LLVector4a& rhs) const; + + inline LLVector4Logical equal(const LLVector4a& rhs) const; + + // Returns true if this and rhs are componentwise equal up to the specified absolute tolerance + inline bool equals4(const LLVector4a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const; + + inline bool equals3(const LLVector4a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const; + + //////////////////////////////////// + // OPERATORS + //////////////////////////////////// + + // Do NOT add aditional operators without consulting someone with SSE experience + inline const LLVector4a& operator= ( const LLVector4a& rhs ); + + inline const LLVector4a& operator= ( const LLQuad& rhs ); + + inline operator LLQuad() const; + +private: + LLQuad mQ; +}; + +inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p) +{ + min.setMin(min, p); + max.setMax(max, p); +} + +#endif diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl new file mode 100644 index 0000000000..7ad22a5631 --- /dev/null +++ b/indra/llmath/llvector4a.inl @@ -0,0 +1,593 @@ +/** + * @file llvector4a.inl + * @brief LLVector4a inline function implementations + * + * $LicenseInfo:firstyear=2010&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$ + */ + +//////////////////////////////////// +// LOAD/STORE +//////////////////////////////////// + +// Load from 16-byte aligned src array (preferred method of loading) +inline void LLVector4a::load4a(const F32* src) +{ + mQ = _mm_load_ps(src); +} + +// Load from unaligned src array (NB: Significantly slower than load4a) +inline void LLVector4a::loadua(const F32* src) +{ + mQ = _mm_loadu_ps(src); +} + +// Load only three floats beginning at address 'src'. Slowest method. +inline void LLVector4a::load3(const F32* src) +{ + // mQ = { 0.f, src[2], src[1], src[0] } = { W, Z, Y, X } + // NB: This differs from the convention of { Z, Y, X, W } + mQ = _mm_set_ps(0.f, src[2], src[1], src[0]); +} + +// Store to a 16-byte aligned memory address +inline void LLVector4a::store4a(F32* dst) const +{ + _mm_store_ps(dst, mQ); +} + +//////////////////////////////////// +// BASIC GET/SET +//////////////////////////////////// + +// Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) +F32* LLVector4a::getF32ptr() +{ + return (F32*) &mQ; +} + +// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) +const F32* const LLVector4a::getF32ptr() const +{ + return (const F32* const) &mQ; +} + +// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates +// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead +inline F32 LLVector4a::operator[](const S32 idx) const +{ + return ((F32*)&mQ)[idx]; +} + +// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time. +inline LLSimdScalar LLVector4a::getScalarAt(const S32 idx) const +{ + // Return appropriate LLQuad. It will be cast to LLSimdScalar automatically (should be effectively a nop) + switch (idx) + { + case 0: + return mQ; + case 1: + return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(1, 1, 1, 1)); + case 2: + return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(2, 2, 2, 2)); + case 3: + default: + return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(3, 3, 3, 3)); + } +} + +// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time. +template <int N> LL_FORCE_INLINE LLSimdScalar LLVector4a::getScalarAt() const +{ + return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(N, N, N, N)); +} + +template<> LL_FORCE_INLINE LLSimdScalar LLVector4a::getScalarAt<0>() const +{ + return mQ; +} + +// Set to an x, y, z and optional w provided +inline void LLVector4a::set(F32 x, F32 y, F32 z, F32 w) +{ + mQ = _mm_set_ps(w, z, y, x); +} + +// Set to all zeros +inline void LLVector4a::clear() +{ + mQ = LLVector4a::getZero().mQ; +} + +inline void LLVector4a::splat(const F32 x) +{ + mQ = _mm_set1_ps(x); +} + +inline void LLVector4a::splat(const LLSimdScalar& x) +{ + mQ = _mm_shuffle_ps( x.getQuad(), x.getQuad(), _MM_SHUFFLE(0,0,0,0) ); +} + +// Set all 4 elements to element N of src, with N known at compile time +template <int N> void LLVector4a::splat(const LLVector4a& src) +{ + mQ = _mm_shuffle_ps(src.mQ, src.mQ, _MM_SHUFFLE(N, N, N, N) ); +} + +// Set all 4 elements to element i of v, with i NOT known at compile time +inline void LLVector4a::splat(const LLVector4a& v, U32 i) +{ + switch (i) + { + case 0: + mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(0, 0, 0, 0)); + break; + case 1: + mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(1, 1, 1, 1)); + break; + case 2: + mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(2, 2, 2, 2)); + break; + case 3: + mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(3, 3, 3, 3)); + break; + } +} + +// Select bits from sourceIfTrue and sourceIfFalse according to bits in mask +inline void LLVector4a::setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse ) +{ + // ((( sourceIfTrue ^ sourceIfFalse ) & mask) ^ sourceIfFalse ) + // E.g., sourceIfFalse = 1010b, sourceIfTrue = 0101b, mask = 1100b + // (sourceIfTrue ^ sourceIfFalse) = 1111b --> & mask = 1100b --> ^ sourceIfFalse = 0110b, + // as expected (01 from sourceIfTrue, 10 from sourceIfFalse) + // Courtesy of Mark++, http://markplusplus.wordpress.com/2007/03/14/fast-sse-select-operation/ + mQ = _mm_xor_ps( sourceIfFalse, _mm_and_ps( mask, _mm_xor_ps( sourceIfTrue, sourceIfFalse ) ) ); +} + +//////////////////////////////////// +// ALGEBRAIC +//////////////////////////////////// + +// Set this to the element-wise (a + b) +inline void LLVector4a::setAdd(const LLVector4a& a, const LLVector4a& b) +{ + mQ = _mm_add_ps(a.mQ, b.mQ); +} + +// Set this to element-wise (a - b) +inline void LLVector4a::setSub(const LLVector4a& a, const LLVector4a& b) +{ + mQ = _mm_sub_ps(a.mQ, b.mQ); +} + +// Set this to element-wise multiply (a * b) +inline void LLVector4a::setMul(const LLVector4a& a, const LLVector4a& b) +{ + mQ = _mm_mul_ps(a.mQ, b.mQ); +} + +// Set this to element-wise quotient (a / b) +inline void LLVector4a::setDiv(const LLVector4a& a, const LLVector4a& b) +{ + mQ = _mm_div_ps( a.mQ, b.mQ ); +} + +// Set this to the element-wise absolute value of src +inline void LLVector4a::setAbs(const LLVector4a& src) +{ + static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }; + mQ = _mm_and_ps(src.mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A)); +} + +// Add to each component in this vector the corresponding component in rhs +inline void LLVector4a::add(const LLVector4a& rhs) +{ + mQ = _mm_add_ps(mQ, rhs.mQ); +} + +// Subtract from each component in this vector the corresponding component in rhs +inline void LLVector4a::sub(const LLVector4a& rhs) +{ + mQ = _mm_sub_ps(mQ, rhs.mQ); +} + +// Multiply each component in this vector by the corresponding component in rhs +inline void LLVector4a::mul(const LLVector4a& rhs) +{ + mQ = _mm_mul_ps(mQ, rhs.mQ); +} + +// Divide each component in this vector by the corresponding component in rhs +inline void LLVector4a::div(const LLVector4a& rhs) +{ + // TODO: Check accuracy, maybe add divFast + mQ = _mm_div_ps(mQ, rhs.mQ); +} + +// Multiply this vector by x in a scalar fashion +inline void LLVector4a::mul(const F32 x) +{ + LLVector4a t; + t.splat(x); + + mQ = _mm_mul_ps(mQ, t.mQ); +} + +// Set this to (a x b) (geometric cross-product) +inline void LLVector4a::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] } + const LLQuad vector1 = _mm_shuffle_ps( a.mQ, a.mQ, _MM_SHUFFLE( 3, 0, 2, 1 )); + // Set vector2 = { b[W], b[Y], b[X], b[Z] } + const LLQuad vector2 = _mm_shuffle_ps( b.mQ, b.mQ, _MM_SHUFFLE( 3, 1, 0, 2 )); + // mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] } + mQ = _mm_mul_ps( vector1, vector2 ); + // vector3 = { a[W], a[Y], a[X], a[Z] } + const LLQuad vector3 = _mm_shuffle_ps( a.mQ, a.mQ, _MM_SHUFFLE( 3, 1, 0, 2 )); + // vector4 = { b[W], b[X], b[Z], b[Y] } + const LLQuad vector4 = _mm_shuffle_ps( b.mQ, b.mQ, _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] } + mQ = _mm_sub_ps( mQ, _mm_mul_ps( vector3, vector4 )); +} + +/* This function works, but may be slightly slower than the one below on older machines + inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b) + { + // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] } + const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ ); + // yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] } + const LLQuad wzxy = _mm_shuffle_ps( ab, ab, _MM_SHUFFLE(3, 2, 0, 1 )); + // xPlusY = { 2*a[W]*b[W], 2 * a[Z] * b[Z], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] } + const LLQuad xPlusY = _mm_add_ps(ab, wzxy); + // xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] } + const LLQuad xPlusYSplat = _mm_movelh_ps(xPlusY, xPlusY); + // zSplat = { a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z] } + const LLQuad zSplat = _mm_shuffle_ps( ab, ab, _MM_SHUFFLE( 2, 2, 2, 2 )); + // mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same } + mQ = _mm_add_ps(zSplat, xPlusYSplat); + }*/ + +// Set all elements to the dot product of the x, y, and z elements in a and b +inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b) +{ + // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] } + const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ ); + // yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] } + const __m128i wzxy = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE(3, 2, 0, 1 )); + // xPlusY = { 2*a[W]*b[W], 2 * a[Z] * b[Z], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] } + const LLQuad xPlusY = _mm_add_ps(ab, _mm_castsi128_ps(wzxy)); + // xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] } + const LLQuad xPlusYSplat = _mm_movelh_ps(xPlusY, xPlusY); + // zSplat = { a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z] } + const __m128i zSplat = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE( 2, 2, 2, 2 )); + // mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same } + mQ = _mm_add_ps(_mm_castsi128_ps(zSplat), xPlusYSplat); +} + +// Set all elements to the dot product of the x, y, z, and w elements in a and b +inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b) +{ + // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] } + const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ ); + // yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] } + const __m128i zwxy = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE(2, 3, 0, 1 )); + // zPlusWandXplusY = { a[W]*b[W] + a[Z]*b[Z], a[Z] * b[Z] + a[W]*b[W], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] } + const LLQuad zPlusWandXplusY = _mm_add_ps(ab, _mm_castsi128_ps(zwxy)); + // xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] } + const LLQuad xPlusYSplat = _mm_movelh_ps(zPlusWandXplusY, zPlusWandXplusY); + const LLQuad zPlusWSplat = _mm_movehl_ps(zPlusWandXplusY, zPlusWandXplusY); + + // mQ = { a[W]*b[W] + a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same } + mQ = _mm_add_ps(xPlusYSplat, zPlusWSplat); +} + +// Return the 3D dot product of this vector and b +inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const +{ + const LLQuad ab = _mm_mul_ps( mQ, b.mQ ); + const LLQuad splatY = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(1, 1, 1, 1) ) ); + const LLQuad splatZ = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(2, 2, 2, 2) ) ); + const LLQuad xPlusY = _mm_add_ps( ab, splatY ); + return _mm_add_ps( xPlusY, splatZ ); +} + +// Return the 4D dot product of this vector and b +inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const +{ + // ab = { w, z, y, x } + const LLQuad ab = _mm_mul_ps( mQ, b.mQ ); + // upperProdsInLowerElems = { y, x, y, x } + const LLQuad upperProdsInLowerElems = _mm_movehl_ps( ab, ab ); + // sumOfPairs = { w+y, z+x, 2y, 2x } + const LLQuad sumOfPairs = _mm_add_ps( upperProdsInLowerElems, ab ); + // shuffled = { z+x, z+x, z+x, z+x } + const LLQuad shuffled = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( sumOfPairs ), _MM_SHUFFLE(1, 1, 1, 1) ) ); + return _mm_add_ss( sumOfPairs, shuffled ); +} + +// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed +// Note that this does not consider zero length vectors! +inline void LLVector4a::normalize3() +{ + // lenSqrd = a dot a + LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this ); + // rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 } + const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ); + static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f }; + static const LLQuad three = {3.f, 3.f, 3.f, 3.f }; + // Now we do one round of Newton-Raphson approximation to get full accuracy + // According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a)) + // the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3)) + // w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3 + // = 0.5 * w * (3 - a*w^2) + // Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula + // which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)] + const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt ); + const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt ); + const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt ); + const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt)); + mQ = _mm_mul_ps( mQ, nrApprox ); +} + +// Normalize this vector with respect to all components. Accurate to 22 bites of precision. +// Note that this does not consider zero length vectors! +inline void LLVector4a::normalize4() +{ + // lenSqrd = a dot a + LLVector4a lenSqrd; lenSqrd.setAllDot4( *this, *this ); + // rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 } + const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ); + static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f }; + static const LLQuad three = {3.f, 3.f, 3.f, 3.f }; + // Now we do one round of Newton-Raphson approximation to get full accuracy + // According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a)) + // the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3)) + // w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3 + // = 0.5 * w * (3 - a*w^2) + // Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula + // which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)] + const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt ); + const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt ); + const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt ); + const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt)); + mQ = _mm_mul_ps( mQ, nrApprox ); +} + +// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed +// Note that this does not consider zero length vectors! +inline LLSimdScalar LLVector4a::normalize3withLength() +{ + // lenSqrd = a dot a + LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this ); + // rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 } + const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ); + static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f }; + static const LLQuad three = {3.f, 3.f, 3.f, 3.f }; + // Now we do one round of Newton-Raphson approximation to get full accuracy + // According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a)) + // the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3)) + // w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3 + // = 0.5 * w * (3 - a*w^2) + // Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula + // which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)] + const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt ); + const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt ); + const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt ); + const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt)); + mQ = _mm_mul_ps( mQ, nrApprox ); + return _mm_sqrt_ss(lenSqrd); +} + +// Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed +// Note that this does not consider zero length vectors! +inline void LLVector4a::normalize3fast() +{ + LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this ); + const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ); + mQ = _mm_mul_ps( mQ, approxRsqrt ); +} + +// Return true if this vector is normalized with respect to x,y,z up to tolerance +inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const +{ + static LL_ALIGN_16(const U32 ones[4]) = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; + LLSimdScalar tol = _mm_load_ss( &tolerance ); + tol = _mm_mul_ss( tol, tol ); + LLVector4a lenSquared; lenSquared.setAllDot3( *this, *this ); + lenSquared.sub( *reinterpret_cast<const LLVector4a*>(ones) ); + lenSquared.setAbs(lenSquared); + return _mm_comile_ss( lenSquared, tol ); +} + +// Return true if this vector is normalized with respect to all components up to tolerance +inline LLBool32 LLVector4a::isNormalized4( F32 tolerance ) const +{ + static LL_ALIGN_16(const U32 ones[4]) = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; + LLSimdScalar tol = _mm_load_ss( &tolerance ); + tol = _mm_mul_ss( tol, tol ); + LLVector4a lenSquared; lenSquared.setAllDot4( *this, *this ); + lenSquared.sub( *reinterpret_cast<const LLVector4a*>(ones) ); + lenSquared.setAbs(lenSquared); + return _mm_comile_ss( lenSquared, tol ); +} + +// Set all elements to the length of vector 'v' +inline void LLVector4a::setAllLength3( const LLVector4a& v ) +{ + LLVector4a lenSqrd; + lenSqrd.setAllDot3(v, v); + + mQ = _mm_sqrt_ps(lenSqrd.mQ); +} + +// Get this vector's length +inline LLSimdScalar LLVector4a::getLength3() const +{ + return _mm_sqrt_ss( dot3( (const LLVector4a)mQ ) ); +} + +// Set the components of this vector to the minimum of the corresponding components of lhs and rhs +inline void LLVector4a::setMin(const LLVector4a& lhs, const LLVector4a& rhs) +{ + mQ = _mm_min_ps(lhs.mQ, rhs.mQ); +} + +// Set the components of this vector to the maximum of the corresponding components of lhs and rhs +inline void LLVector4a::setMax(const LLVector4a& lhs, const LLVector4a& rhs) +{ + mQ = _mm_max_ps(lhs.mQ, rhs.mQ); +} + +// Set this to (c * lhs) + rhs * ( 1 - c) +inline void LLVector4a::setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c) +{ + LLVector4a a = lhs; + a.mul(c); + + LLVector4a b = rhs; + b.mul(1.f-c); + + setAdd(a, b); +} + +inline LLBool32 LLVector4a::isFinite3() const +{ + static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 }; + const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask); + const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV ); + const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV )); + return !equalityCheck.areAnySet( LLVector4Logical::MASK_XYZ ); +} + +inline LLBool32 LLVector4a::isFinite4() const +{ + static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 }; + const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask); + const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV ); + const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV )); + return !equalityCheck.areAnySet( LLVector4Logical::MASK_XYZW ); +} + +inline void LLVector4a::setRotatedInv( const LLRotation& rot, const LLVector4a& vec ) +{ + LLRotation inv; inv.setTranspose( rot ); + setRotated( inv, vec ); +} + +inline void LLVector4a::setRotatedInv( const LLQuaternion2& quat, const LLVector4a& vec ) +{ + LLQuaternion2 invRot; invRot.setConjugate( quat ); + setRotated(invRot, vec); +} + +inline void LLVector4a::clamp( const LLVector4a& low, const LLVector4a& high ) +{ + const LLVector4Logical highMask = greaterThan( high ); + const LLVector4Logical lowMask = lessThan( low ); + + setSelectWithMask( highMask, high, *this ); + setSelectWithMask( lowMask, low, *this ); +} + + +//////////////////////////////////// +// LOGICAL +//////////////////////////////////// +// The functions in this section will compare the elements in this vector +// to those in rhs and return an LLVector4Logical with all bits set in elements +// where the comparison was true and all bits unset in elements where the comparison +// was false. See llvector4logica.h +//////////////////////////////////// +// WARNING: Other than equals3 and equals4, these functions do NOT account +// for floating point tolerance. You should include the appropriate tolerance +// in the inputs. +//////////////////////////////////// + +inline LLVector4Logical LLVector4a::greaterThan(const LLVector4a& rhs) const +{ + return _mm_cmpgt_ps(mQ, rhs.mQ); +} + +inline LLVector4Logical LLVector4a::lessThan(const LLVector4a& rhs) const +{ + return _mm_cmplt_ps(mQ, rhs.mQ); +} + +inline LLVector4Logical LLVector4a::greaterEqual(const LLVector4a& rhs) const +{ + return _mm_cmpge_ps(mQ, rhs.mQ); +} + +inline LLVector4Logical LLVector4a::lessEqual(const LLVector4a& rhs) const +{ + return _mm_cmple_ps(mQ, rhs.mQ); +} + +inline LLVector4Logical LLVector4a::equal(const LLVector4a& rhs) const +{ + return _mm_cmpeq_ps(mQ, rhs.mQ); +} + +// Returns true if this and rhs are componentwise equal up to the specified absolute tolerance +inline bool LLVector4a::equals4(const LLVector4a& rhs, F32 tolerance ) const +{ + LLVector4a diff; diff.setSub( *this, rhs ); + diff.setAbs( diff ); + const LLQuad tol = _mm_set1_ps( tolerance ); + const LLQuad cmp = _mm_cmplt_ps( diff, tol ); + return (_mm_movemask_ps( cmp ) & LLVector4Logical::MASK_XYZW) == LLVector4Logical::MASK_XYZW; +} + +inline bool LLVector4a::equals3(const LLVector4a& rhs, F32 tolerance ) const +{ + LLVector4a diff; diff.setSub( *this, rhs ); + diff.setAbs( diff ); + const LLQuad tol = _mm_set1_ps( tolerance ); + const LLQuad t = _mm_cmplt_ps( diff, tol ); + return (_mm_movemask_ps( t ) & LLVector4Logical::MASK_XYZ) == LLVector4Logical::MASK_XYZ; + +} + +//////////////////////////////////// +// OPERATORS +//////////////////////////////////// + +// Do NOT add aditional operators without consulting someone with SSE experience +inline const LLVector4a& LLVector4a::operator= ( const LLVector4a& rhs ) +{ + mQ = rhs.mQ; + return *this; +} + +inline const LLVector4a& LLVector4a::operator= ( const LLQuad& rhs ) +{ + mQ = rhs; + return *this; +} + +inline LLVector4a::operator LLQuad() const +{ + return mQ; +} diff --git a/indra/llmath/llvector4logical.h b/indra/llmath/llvector4logical.h new file mode 100644 index 0000000000..dd66b09d43 --- /dev/null +++ b/indra/llmath/llvector4logical.h @@ -0,0 +1,124 @@ +/** + * @file llvector4logical.h + * @brief LLVector4Logical class header file - Companion class to LLVector4a for logical and bit-twiddling operations + * + * $LicenseInfo:firstyear=2010&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_VECTOR4LOGICAL_H +#define LL_VECTOR4LOGICAL_H + + +//////////////////////////// +// LLVector4Logical +//////////////////////////// +// This class is incomplete. If you need additional functionality, +// for example setting/unsetting particular elements or performing +// other boolean operations, feel free to implement. If you need +// assistance in determining the most optimal implementation, +// contact someone with SSE experience (Falcon, Richard, Davep, e.g.) +//////////////////////////// + +static LL_ALIGN_16(const U32 S_V4LOGICAL_MASK_TABLE[4*4]) = +{ + 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF +}; + +class LLVector4Logical +{ +public: + + enum { + MASK_X = 1, + MASK_Y = 1 << 1, + MASK_Z = 1 << 2, + MASK_W = 1 << 3, + MASK_XYZ = MASK_X | MASK_Y | MASK_Z, + MASK_XYZW = MASK_XYZ | MASK_W + }; + + // Empty default ctor + LLVector4Logical() {} + + LLVector4Logical( const LLQuad& quad ) + { + mQ = quad; + } + + // Create and return a mask consisting of the lowest order bit of each element + inline U32 getGatheredBits() const + { + return _mm_movemask_ps(mQ); + }; + + // Invert this mask + inline LLVector4Logical& invert() + { + static const LL_ALIGN_16(U32 allOnes[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + mQ = _mm_andnot_ps( mQ, *(LLQuad*)(allOnes) ); + return *this; + } + + inline LLBool32 areAllSet( U32 mask ) const + { + return ( getGatheredBits() & mask) == mask; + } + + inline LLBool32 areAllSet() const + { + return areAllSet( MASK_XYZW ); + } + + inline LLBool32 areAnySet( U32 mask ) const + { + return getGatheredBits() & mask; + } + + inline LLBool32 areAnySet() const + { + return areAnySet( MASK_XYZW ); + } + + inline operator LLQuad() const + { + return mQ; + } + + inline void clear() + { + mQ = _mm_setzero_ps(); + } + + template<int N> void setElement() + { + mQ = _mm_or_ps( mQ, *reinterpret_cast<const LLQuad*>(S_V4LOGICAL_MASK_TABLE + 4*N) ); + } + +private: + + LLQuad mQ; +}; + +#endif //LL_VECTOR4ALOGICAL_H diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 1250f539f5..8c81f27784 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,38 +1,37 @@ /** + * @file llvolume.cpp * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 <set> +#if !LL_WINDOWS +#include <stdint.h> +#endif #include "llerror.h" #include "llmemtype.h" @@ -43,9 +42,16 @@ #include "v4math.h" #include "m4math.h" #include "m3math.h" +#include "llmatrix3a.h" +#include "lloctree.h" #include "lldarray.h" #include "llvolume.h" +#include "llvolumeoctree.h" #include "llstl.h" +#include "llsdserialize.h" +#include "llvector4a.h" +#include "llmatrix4a.h" +#include "lltimer.h" #define DEBUG_SILHOUETTE_BINORMALS 0 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette @@ -84,6 +90,20 @@ const F32 SKEW_MIN = -0.95f; const F32 SKEW_MAX = 0.95f; const F32 SCULPT_MIN_AREA = 0.002f; +const S32 SCULPT_MIN_AREA_DETAIL = 1; + +extern BOOL gDebugGL; + +void assert_aligned(void* ptr, uintptr_t alignment) +{ +#if 0 + uintptr_t t = (uintptr_t) ptr; + if (t%alignment != 0) + { + llerrs << "Alignment check failed." << llendl; + } +#endif +} BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) { @@ -102,128 +122,262 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size) { - float fAWdU[3]; - LLVector3 dir; - LLVector3 diff; + return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV); +} + +BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size) +{ + F32 fAWdU[3]; + F32 dir[3]; + F32 diff[3]; for (U32 i = 0; i < 3; i++) { - dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]); - diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i]; - fAWdU[i] = fabsf(dir.mV[i]); - if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false; + dir[i] = 0.5f * (end[i] - start[i]); + diff[i] = (0.5f * (end[i] + start[i])) - center[i]; + fAWdU[i] = fabsf(dir[i]); + if(fabsf(diff[i])>size[i] + fAWdU[i]) return false; } float f; - f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false; - f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false; - f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false; + f = dir[1] * diff[2] - dir[2] * diff[1]; if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1]) return false; + f = dir[2] * diff[0] - dir[0] * diff[2]; if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0]) return false; + f = dir[0] * diff[1] - dir[1] * diff[0]; if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0]) return false; return true; } + // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir. // returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b, // and returns the intersection point along dir in intersection_t. // Moller-Trumbore algorithm -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided) +BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t) { - F32 u, v, t; /* find vectors for two edges sharing vert0 */ - LLVector3 edge1 = vert1 - vert0; + LLVector4a edge1; + edge1.setSub(vert1, vert0); - LLVector3 edge2 = vert2 - vert0;; + LLVector4a edge2; + edge2.setSub(vert2, vert0); /* begin calculating determinant - also used to calculate U parameter */ - LLVector3 pvec = dir % edge2; - - /* if determinant is near zero, ray lies in plane of triangle */ - F32 det = edge1 * pvec; + LLVector4a pvec; + pvec.setCross3(dir, edge2); - if (!two_sided) + /* if determinant is near zero, ray lies in plane of triangle */ + LLVector4a det; + det.setAllDot3(edge1, pvec); + + if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7) { - if (det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - /* calculate distance from vert0 to ray origin */ - LLVector3 tvec = orig - vert0; + LLVector4a tvec; + tvec.setSub(orig, vert0); /* calculate U parameter and test bounds */ - u = tvec * pvec; + LLVector4a u; + u.setAllDot3(tvec,pvec); - if (u < 0.f || u > det) + if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) && + (u.lessEqual(det).getGatheredBits() & 0x7)) { - return FALSE; + /* prepare to test V parameter */ + LLVector4a qvec; + qvec.setCross3(tvec, edge1); + + /* calculate V parameter and test bounds */ + LLVector4a v; + v.setAllDot3(dir, qvec); + + + //if (!(v < 0.f || u + v > det)) + + LLVector4a sum_uv; + sum_uv.setAdd(u, v); + + S32 v_gequal = v.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; + } } - - /* prepare to test V parameter */ - LLVector3 qvec = tvec % edge1; + } - /* calculate V parameter and test bounds */ - v = dir * qvec; - if (v < 0.f || u + v > det) - { - return FALSE; - } + return FALSE; +} - /* calculate t, scale parameters, ray intersects triangle */ - t = edge2 * qvec; - F32 inv_det = 1.0 / det; - t *= inv_det; - u *= inv_det; - v *= inv_det; - } +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; - else // two sided - { - if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO) - { - return FALSE; - } - F32 inv_det = 1.0 / det; + /* find vectors for two edges sharing vert0 */ + LLVector4a edge1; + edge1.setSub(vert1, vert0); + + + LLVector4a edge2; + edge2.setSub(vert2, vert0); - /* calculate distance from vert0 to ray origin */ - LLVector3 tvec = orig - vert0; - - /* calculate U parameter and test bounds */ - u = (tvec * pvec) * inv_det; - if (u < 0.f || u > 1.f) - { - return FALSE; - } + /* begin calculating determinant - also used to calculate U parameter */ + LLVector4a pvec; + pvec.setCross3(dir, edge2); - /* prepare to test V parameter */ - LLVector3 qvec = tvec - edge1; - - /* calculate V parameter and test bounds */ - v = (dir * qvec) * inv_det; - - if (v < 0.f || u + v > 1.f) - { - return FALSE; - } + /* 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; + } - /* calculate t, ray intersects triangle */ - t = (edge2 * qvec) * inv_det; + /* 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; - if (intersection_a != NULL) - *intersection_a = u; - if (intersection_b != NULL) - *intersection_b = v; - if (intersection_t != NULL) - *intersection_t = t; + intersection_a = u; + intersection_b = v; + intersection_t = t; return TRUE; } +//helper for non-aligned vectors +BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided) +{ + LLVector4a vert0a, vert1a, vert2a, origa, dira; + vert0a.load3(vert0.mV); + vert1a.load3(vert1.mV); + vert2a.load3(vert2.mV); + origa.load3(orig.mV); + dira.load3(dir.mV); + + if (two_sided) + { + return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, + intersection_a, intersection_b, intersection_t); + } + else + { + return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, + intersection_a, intersection_b, intersection_t); + } +} + +class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle> +{ +public: + const LLVolumeFace* mFace; + + LLVolumeOctreeRebound(const LLVolumeFace* face) + { + mFace = face; + } + + virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch) + { //this is a depth first traversal, so it's safe to assum all children have complete + //bounding data + + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); + + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + if (!branch->getData().empty()) + { //node has data, find AABB that binds data set + const LLVolumeTriangle* tri = *(branch->getData().begin()); + + //initialize min/max to first available vertex + min = *(tri->mV[0]); + max = *(tri->mV[0]); + + for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = + branch->getData().begin(); iter != branch->getData().end(); ++iter) + { //for each triangle in node + + //stretch by triangles in node + tri = *iter; + + 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->getChildren().empty()) + { //no data, but child nodes exist + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0); + + //initialize min/max to extents of first child + min = child->mExtents[0]; + max = child->mExtents[1]; + } + else + { + llerrs << "Empty leaf" << llendl; + } + + for (S32 i = 0; i < branch->getChildCount(); ++i) + { //stretch by child extents + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + min.setMin(min, child->mExtents[0]); + max.setMax(max, child->mExtents[1]); + } + + node->mBounds[0].setAdd(min, max); + node->mBounds[0].mul(0.5f); + + node->mBounds[1].setSub(max,min); + node->mBounds[1].mul(0.5f); + } +}; //------------------------------------------------------------------- // statics @@ -262,6 +416,70 @@ LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BO 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 + LLMemType m1(LLMemType::MTYPE_VOLUME); + 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 @@ -518,6 +736,117 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3 return face; } +//static +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 + LLMemType m1(LLMemType::MTYPE_VOLUME); + + if (detail < MIN_LOD) + { + detail = MIN_LOD; + } + + // Generate the face data + F32 hollow = params.getHollow(); + + S32 np = 0; + + switch (params.getCurveType() & LL_PCODE_PROFILE_MASK) + { + case LL_PCODE_PROFILE_SQUARE: + { + np = getNumNGonPoints(params, 4,-0.375, 0, 1, split); + + if (hollow) + { + np *= 2; + } + } + break; + case LL_PCODE_PROFILE_ISOTRI: + case LL_PCODE_PROFILE_RIGHTTRI: + case LL_PCODE_PROFILE_EQUALTRI: + { + np = getNumNGonPoints(params, 3,0, 0, 1, split); + + if (hollow) + { + np *= 2; + } + } + 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; + + np = getNumNGonPoints(params, sides); + + if (hollow) + { + np *= 2; + } + } + 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; + } + } + np = getNumNGonPoints(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f); + + if (hollow) + { + np *= 2; + } + + // Special case for openness of sphere + if ((params.getEnd() - params.getBegin()) < 1.f) + { + } + else if (!hollow) + { + np++; + } + } + break; + default: + break; + }; + + + return np; +} BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, @@ -979,6 +1308,32 @@ 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) { // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. @@ -1156,6 +1511,56 @@ const LLVector2 LLPathParams::getEndScale() const 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 + LLMemType m1(LLMemType::MTYPE_VOLUME); + + 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) { @@ -1672,7 +2077,13 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mFaceMask = 0x0; mDetail = detail; mSculptLevel = -2; - + mIsTetrahedron = FALSE; + mLODScaleBias.setVec(1,1,1); + mHullPoints = NULL; + mHullIndices = NULL; + mNumHullPoints = 0; + mNumHullIndices = 0; + // set defaults if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) { @@ -1687,7 +2098,8 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge mGenerateSingleFace = generate_single_face; generate(); - if (mParams.getSculptID().isNull()) + + if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE) { createVolumeFaces(); } @@ -1722,6 +2134,11 @@ LLVolume::~LLVolume() mPathp = NULL; mProfilep = NULL; mVolumeFaces.clear(); + + ll_aligned_free_16(mHullPoints); + mHullPoints = NULL; + ll_aligned_free_16(mHullIndices); + mHullIndices = NULL; } BOOL LLVolume::generate() @@ -1838,6 +2255,597 @@ BOOL LLVolume::generate() 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; + if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord) + { + if (angle_cutoff > 1.f) + { + retval = (mData[NORMAL].equals3(rhs.mData[NORMAL])); + } + 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) +{ + //input stream is now pointing at a zlib compressed block of LLSD + //decompress block + LLSD mdl; + if (!unzip_llsd(mdl, is, size)) + { + llwarns << "not a valid mesh asset!" << llendl; + return false; + } + + { + U32 face_count = mdl.size(); + + if (face_count == 0) + { //no faces unpacked, treat as failed decode + llwarns << "found no faces!" << llendl; + return false; + } + + mVolumeFaces.resize(face_count); + + for (U32 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); + memset(face.mPositions, 0, sizeof(LLVector4a)); + memset(face.mNormals, 0, sizeof(LLVector4a)); + memset(face.mTexCoords, 0, sizeof(LLVector2)); + memset(face.mIndices, 0, sizeof(U16)*3); + continue; + } + + LLSD::Binary pos = mdl[i]["Position"]; + LLSD::Binary norm = mdl[i]["Normal"]; + LLSD::Binary tc = mdl[i]["TexCoord0"]; + LLSD::Binary idx = mdl[i]["TriangleList"]; + + + + //copy out indices + face.resizeIndices(idx.size()/2); + + if (idx.empty() || face.mNumIndices < 3) + { //why is there an empty index list? + llwarns <<"Empty face present!" << llendl; + continue; + } + + U16* indices = (U16*) &(idx[0]); + U32 count = idx.size()/2; + for (U32 j = 0; j < count; ++j) + { + face.mIndices[j] = indices[j]; + } + + //copy out vertices + U32 num_verts = pos.size()/(3*2); + face.resizeVertices(num_verts); + + LLVector3 minp; + LLVector3 maxp; + LLVector2 min_tc; + LLVector2 max_tc; + + minp.setValue(mdl[i]["PositionDomain"]["Min"]); + maxp.setValue(mdl[i]["PositionDomain"]["Max"]); + LLVector4a min_pos, max_pos; + min_pos.load3(minp.mV); + max_pos.load3(maxp.mV); + + min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]); + max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]); + + LLVector4a pos_range; + pos_range.setSub(max_pos, min_pos); + LLVector2 tc_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; + } + + } + + { + 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; + } + } + + { + 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++; + } + } + + if (mdl[i].has("Weights")) + { + face.allocateWeights(num_verts); + + LLSD::Binary weights = mdl[i]["Weights"]; + + U32 idx = 0; + + U32 cur_vertex = 0; + while (idx < weights.size() && cur_vertex < num_verts) + { + const U8 END_INFLUENCES = 0xFF; + U8 joint = weights[idx++]; + + U32 cur_influence = 0; + LLVector4 wght(0,0,0,0); + + while (joint != END_INFLUENCES && idx < weights.size()) + { + U16 influence = weights[idx++]; + influence |= ((U16) weights[idx++] << 8); + + F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); + wght.mV[cur_influence++] = (F32) joint + w; + + if (cur_influence >= 4) + { + joint = END_INFLUENCES; + } + else + { + joint = weights[idx++]; + } + } + + face.mWeights[cur_vertex].loadua(wght.mV); + + cur_vertex++; + } + + if (cur_vertex != num_verts || idx != weights.size()) + { + llwarns << "Vertex weight count does not match vertex count!" << llendl; + } + + } + + // 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 + 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]); + } + } + } + } + + mSculptLevel = 0; // success! + + cacheOptimize(); + + return true; +} + +void tetrahedron_set_normal(LLVolumeFace::VertexData* cv) +{ + LLVector4a v0; + v0.setSub(cv[1].getPosition(), cv[0].getNormal()); + LLVector4a v1; + v1.setSub(cv[2].getNormal(), cv[0].getPosition()); + + cv[0].getNormal().setCross3(v0,v1); + cv[0].getNormal().normalize3fast(); + cv[1].setNormal(cv[0].getNormal()); + cv[2].setNormal(cv[1].getNormal()); +} + +BOOL LLVolume::isTetrahedron() +{ + return mIsTetrahedron; +} + +void LLVolume::makeTetrahedron() +{ + mVolumeFaces.clear(); + + LLVolumeFace face; + + F32 x = 0.25f; + LLVector4a p[] = + { //unit tetrahedron corners + LLVector4a(x,x,x), + LLVector4a(-x,-x,x), + LLVector4a(-x,x,-x), + LLVector4a(x,-x,-x) + }; + + face.mExtents[0].splat(-x); + face.mExtents[1].splat(x); + + LLVolumeFace::VertexData cv[3]; + + //set texture coordinates + cv[0].mTexCoord = LLVector2(0,0); + cv[1].mTexCoord = LLVector2(1,0); + cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3); + + + //side 1 + cv[0].setPosition(p[1]); + cv[1].setPosition(p[0]); + cv[2].setPosition(p[2]); + + tetrahedron_set_normal(cv); + + face.resizeVertices(12); + face.resizeIndices(12); + + LLVector4a* v = (LLVector4a*) face.mPositions; + LLVector4a* n = (LLVector4a*) face.mNormals; + LLVector2* tc = (LLVector2*) face.mTexCoords; + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + + //side 2 + cv[0].setPosition(p[3]); + cv[1].setPosition(p[0]); + cv[2].setPosition(p[1]); + + tetrahedron_set_normal(cv); + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + //side 3 + cv[0].setPosition(p[3]); + cv[1].setPosition(p[1]); + cv[2].setPosition(p[2]); + + tetrahedron_set_normal(cv); + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + //side 4 + cv[0].setPosition(p[2]); + cv[1].setPosition(p[0]); + cv[2].setPosition(p[3]); + + tetrahedron_set_normal(cv); + + v[0] = cv[0].getPosition(); + v[1] = cv[1].getPosition(); + v[2] = cv[2].getPosition(); + v += 3; + + n[0] = cv[0].getNormal(); + n[1] = cv[1].getNormal(); + n[2] = cv[2].getNormal(); + n += 3; + + tc[0] = cv[0].mTexCoord; + tc[1] = cv[1].mTexCoord; + tc[2] = cv[2].mTexCoord; + tc += 3; + + //set index buffer + for (U16 i = 0; i < 12; i++) + { + face.mIndices[i] = i; + } + + mVolumeFaces.push_back(face); + mSculptLevel = 0; + mIsTetrahedron = TRUE; +} + +void LLVolume::copyVolumeFaces(const LLVolume* volume) +{ + mVolumeFaces = volume->mVolumeFaces; + mSculptLevel = 0; + mIsTetrahedron = FALSE; +} + +void LLVolume::cacheOptimize() +{ + for (S32 i = 0; i < mVolumeFaces.size(); ++i) + { + mVolumeFaces[i].cacheOptimize(); + } +} + + +S32 LLVolume::getNumFaces() const +{ + U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK); + + if (sculpt_type == LL_SCULPT_TYPE_MESH) + { + return LL_SCULPT_MESH_MAX_FACES; + } + + return (S32)mProfilep->mFaces.size(); +} + void LLVolume::createVolumeFaces() { @@ -1863,6 +2871,11 @@ void LLVolume::createVolumeFaces() LLProfile::Face& face = mProfilep->mFaces[i]; vf.mBeginS = face.mIndex; vf.mNumS = face.mCount; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } + vf.mBeginT = 0; vf.mNumT= getPath().mPath.size(); vf.mID = i; @@ -1906,6 +2919,10 @@ void LLVolume::createVolumeFaces() if (face.mFlat && vf.mNumS > 2) { //flat inner faces have to copy vert normals vf.mNumS = vf.mNumS*2; + if (vf.mNumS < 0) + { + llerrs << "Volume face corruption detected." << llendl; + } } } else @@ -2182,7 +3199,7 @@ void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32 ratio = (F32) width / (F32) height; - s = (S32)fsqrtf(((F32)vertices / ratio)); + s = (S32)(F32) sqrt(((F32)vertices / ratio)); s = llmax(s, 4); // no degenerate sizes, please t = vertices / s; @@ -2230,10 +3247,18 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, if (!data_is_empty) { sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type); - - if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) + + // don't test lowest LOD to support legacy content DEV-33670 + if (mDetail > SCULPT_MIN_AREA_DETAIL) { - data_is_empty = TRUE; + F32 area = sculptGetSurfaceArea(); + + const F32 SCULPT_MAX_AREA = 32.f; + + if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA) + { + data_is_empty = TRUE; + } } } @@ -2271,6 +3296,16 @@ BOOL LLVolume::isFlat(S32 face) } +bool LLVolumeParams::isSculpt() const +{ + return mSculptID.notNull(); +} + +bool LLVolumeParams::isMeshSculpt() const +{ + return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH); +} + bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const { return ( (getPathParams() == params.getPathParams()) && @@ -2304,7 +3339,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams ¶ms) const return mSculptID < params.mSculptID; } - return mSculptType < params.mSculptType; @@ -3305,6 +4339,23 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const return index; } +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 + 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::getNumTriangleIndices() const { BOOL profile_open = getProfile().isOpen(); @@ -3362,28 +4413,62 @@ S32 LLVolume::getNumTriangleIndices() const return count; } + +S32 LLVolume::getNumTriangles() const +{ + U32 triangle_count = 0; + + for (S32 i = 0; i < getNumVolumeFaces(); ++i) + { + triangle_count += getVolumeFace(i).mNumIndices/3; + } + + return triangle_count; +} + + //----------------------------------------------------------------------------- // generateSilhouetteVertices() //----------------------------------------------------------------------------- void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<LLVector3> &normals, - std::vector<S32> &segments, - const LLVector3& obj_cam_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat) + const LLVector3& obj_cam_vec_in, + const LLMatrix4& mat_in, + const LLMatrix3& norm_mat_in, + S32 face_mask) { LLMemType m1(LLMemType::MTYPE_VOLUME); - + + LLMatrix4a mat; + mat.loadu(mat_in); + + LLMatrix4a norm_mat; + norm_mat.loadu(norm_mat_in); + + LLVector4a obj_cam_vec; + obj_cam_vec.load3(obj_cam_vec_in.mV); + vertices.clear(); normals.clear(); - segments.clear(); + if ((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) { - const LLVolumeFace& face = *iter; + LLVolumeFace& face = *iter; + if (!(face_mask & (0x1 << cur_index++)) || + face.mNumIndices == 0 || face.mEdge.empty()) + { + continue; + } + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { } @@ -3396,7 +4481,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, #if DEBUG_SILHOUETTE_EDGE_MAP //for each triangle - U32 count = face.mIndices.size(); + U32 count = face.mNumIndices; for (U32 j = 0; j < count/3; j++) { //get vertices S32 v1 = face.mIndices[j*3+0]; @@ -3404,9 +4489,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, S32 v3 = face.mIndices[j*3+2]; //get current face center - LLVector3 cCenter = (face.mVertices[v1].mPosition + - face.mVertices[v2].mPosition + - face.mVertices[v3].mPosition) / 3.0f; + LLVector3 cCenter = (face.mVertices[v1].getPosition() + + face.mVertices[v2].getPosition() + + face.mVertices[v3].getPosition()) / 3.0f; //for each edge for (S32 k = 0; k < 3; k++) { @@ -3424,9 +4509,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, v3 = face.mIndices[nIndex*3+2]; //get neighbor face center - LLVector3 nCenter = (face.mVertices[v1].mPosition + - face.mVertices[v2].mPosition + - face.mVertices[v3].mPosition) / 3.0f; + LLVector3 nCenter = (face.mVertices[v1].getPosition() + + face.mVertices[v2].getPosition() + + face.mVertices[v3].getPosition()) / 3.0f; //draw line vertices.push_back(cCenter); @@ -3449,15 +4534,15 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, #elif DEBUG_SILHOUETTE_NORMALS //for each vertex - for (U32 j = 0; j < face.mVertices.size(); j++) { - vertices.push_back(face.mVertices[j].mPosition); - vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f); + for (U32 j = 0; j < face.mNumVertices; j++) { + vertices.push_back(face.mVertices[j].getPosition()); + vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f); normals.push_back(LLVector3(0,0,1)); normals.push_back(LLVector3(0,0,1)); segments.push_back(vertices.size()); #if DEBUG_SILHOUETTE_BINORMALS - vertices.push_back(face.mVertices[j].mPosition); - vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f); + vertices.push_back(face.mVertices[j].getPosition()); + vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f); normals.push_back(LLVector3(0,0,1)); normals.push_back(LLVector3(0,0,1)); segments.push_back(vertices.size()); @@ -3475,26 +4560,36 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, //for each triangle std::vector<U8> fFacing; - vector_append(fFacing, face.mIndices.size()/3); - for (U32 j = 0; j < face.mIndices.size()/3; j++) + vector_append(fFacing, face.mNumIndices/3); + + LLVector4a* v = (LLVector4a*) face.mPositions; + LLVector4a* n = (LLVector4a*) face.mNormals; + + for (U32 j = 0; j < face.mNumIndices/3; j++) { //approximate normal S32 v1 = face.mIndices[j*3+0]; S32 v2 = face.mIndices[j*3+1]; S32 v3 = face.mIndices[j*3+2]; - LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % - (face.mVertices[v2].mPosition - face.mVertices[v3].mPosition); - - if (norm.magVecSquared() < 0.00000001f) + LLVector4a c1,c2; + c1.setSub(v[v1], v[v2]); + c2.setSub(v[v2], v[v3]); + + LLVector4a norm; + + norm.setCross3(c1, c2); + + if (norm.dot3(norm) < 0.00000001f) { fFacing[j] = AWAY | TOWARDS; } else { //get view vector - LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition); - bool away = view * norm > 0.0f; + LLVector4a view; + view.setSub(obj_cam_vec, v[v1]); + bool away = view.dot3(norm) > 0.0f; if (away) { fFacing[j] = AWAY; @@ -3507,7 +4602,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, } //for each triangle - for (U32 j = 0; j < face.mIndices.size()/3; j++) + for (U32 j = 0; j < face.mNumIndices/3; j++) { if (fFacing[j] == (AWAY | TOWARDS)) { //this is a degenerate triangle @@ -3540,17 +4635,21 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, S32 v1 = face.mIndices[j*3+k]; S32 v2 = face.mIndices[j*3+((k+1)%3)]; - vertices.push_back(face.mVertices[v1].mPosition*mat); - LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat; - norm1.normVec(); - normals.push_back(norm1); + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); + + norm_mat.rotate(n[v1], t); - vertices.push_back(face.mVertices[v2].mPosition*mat); - LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat; - norm2.normVec(); - normals.push_back(norm2); + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); - segments.push_back(vertices.size()); + 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])); } } } @@ -3563,6 +4662,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) { + LLVector4a starta, enda; + starta.load3(start.mV); + enda.load3(end.mV); + + return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal); + +} + + +S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face, + LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +{ S32 hit_face = -1; S32 start_face; @@ -3571,7 +4683,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, if (face == -1) // ALL_SIDES { start_face = 0; - end_face = getNumFaces() - 1; + end_face = getNumVolumeFaces() - 1; } else { @@ -3579,16 +4691,23 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, end_face = face; } - LLVector3 dir = end - start; + LLVector4a dir; + dir.setSub(end, start); F32 closest_t = 2.f; // must be larger than 1 + end_face = llmin(end_face, getNumVolumeFaces()-1); + for (S32 i = start_face; i <= end_face; i++) { - const LLVolumeFace &face = getVolumeFace((U32)i); + LLVolumeFace &face = mVolumeFaces[i]; + + LLVector4a box_center; + box_center.setAdd(face.mExtents[0], face.mExtents[1]); + box_center.mul(0.5f); - LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f; - LLVector3 box_size = face.mExtents[1] - face.mExtents[0]; + LLVector4a box_size; + box_size.setSub(face.mExtents[1], face.mExtents[0]); if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) { @@ -3596,56 +4715,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, { genBinormals(i); } - - for (U32 tri = 0; tri < face.mIndices.size()/3; tri++) - { - S32 index1 = face.mIndices[tri*3+0]; - S32 index2 = face.mIndices[tri*3+1]; - S32 index3 = face.mIndices[tri*3+2]; - F32 a, b, t; + if (!face.mOctree) + { + face.createOctree(); + } - if (LLTriangleRayIntersect(face.mVertices[index1].mPosition, - face.mVertices[index2].mPosition, - face.mVertices[index3].mPosition, - start, dir, &a, &b, &t, FALSE)) - { - if ((t >= 0.f) && // if hit is after start - (t <= 1.f) && // and before end - (t < closest_t)) // and this hit is closer - { - closest_t = t; - hit_face = i; + //LLVector4a* p = (LLVector4a*) face.mPositions; - if (intersection != NULL) - { - *intersection = start + dir * closest_t; - } - - if (tex_coord != NULL) + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal); + intersect.traverse(face.mOctree); + if (intersect.mHitFace) { - *tex_coord = ((1.f - a - b) * face.mVertices[index1].mTexCoord + - a * face.mVertices[index2].mTexCoord + - b * face.mVertices[index3].mTexCoord); - - } - - if (normal != NULL) - { - *normal = ((1.f - a - b) * face.mVertices[index1].mNormal + - a * face.mVertices[index2].mNormal + - b * face.mVertices[index3].mNormal); - } - - if (bi_normal != NULL) - { - *bi_normal = ((1.f - a - b) * face.mVertices[index1].mBinormal + - a * face.mVertices[index2].mBinormal + - b * face.mVertices[index3].mBinormal); - } - - } - } + hit_face = i; } } } @@ -3811,6 +4893,7 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices, // Generate the vertex mapping and the list of vertices without // duplicates. This will crash if there are no vertices. + llassert(num_input_vertices > 0); // check for no vertices! S32 *vertex_mapping = new S32[num_input_vertices]; LLVector3 *new_vertices = new LLVector3[num_input_vertices]; LLVertexIndexPair *prev_pairp = NULL; @@ -4092,11 +5175,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const return TRUE; } +LLSD LLVolumeParams::sculptAsLLSD() const +{ + LLSD sd = LLSD(); + sd["id"] = getSculptID(); + sd["type"] = getSculptType(); + + return sd; +} + +bool LLVolumeParams::sculptFromLLSD(LLSD& sd) +{ + setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger()); + return true; +} + LLSD LLVolumeParams::asLLSD() const { LLSD sd = LLSD(); sd["path"] = mPathParams; sd["profile"] = mProfileParams; + sd["sculpt"] = sculptAsLLSD(); + return sd; } @@ -4104,6 +5204,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd) { mPathParams.fromLLSD(sd["path"]); mProfileParams.fromLLSD(sd["profile"]); + sculptFromLLSD(sd["sculpt"]); + return true; } @@ -4146,6 +5248,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity // for collison purposes BOOL LLVolumeParams::isConvex() const { + if (!getSculptID().isNull()) + { + // can't determine, be safe and say no: + return FALSE; + } + F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); F32 hollow = mProfileParams.getHollow(); @@ -4262,7 +5370,7 @@ LLFaceID LLVolume::generateFaceMask() } break; default: - llerrs << "Unknown profile!" << llendl + llerrs << "Unknown profile!" << llendl; break; } @@ -4386,22 +5494,812 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep) return s; } +LLVolumeFace::LLVolumeFace() : + mID(0), + mTypeMask(0), + mBeginS(0), + mBeginT(0), + mNumS(0), + mNumT(0), + mNumVertices(0), + mNumIndices(0), + mPositions(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL), + mIndices(NULL), + mWeights(NULL), + mOctree(NULL) +{ + mExtents = (LLVector4a*) ll_aligned_malloc_16(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), + mNumIndices(0), + mPositions(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL), + mIndices(NULL), + mWeights(NULL), + mOctree(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(); + + LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a)); + + 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); + LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); + LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); + + + if (src.mBinormals) + { + allocateBinormals(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size); + } + else + { + ll_aligned_free_16(mBinormals); + mBinormals = NULL; + } + + if (src.mWeights) + { + allocateWeights(src.mNumVertices); + LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); + } + else + { + ll_aligned_free_16(mWeights); + mWeights = NULL; + } + } + + if (mNumIndices) + { + S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF; + + LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); + } + + //delete + return *this; +} + +LLVolumeFace::~LLVolumeFace() +{ + ll_aligned_free_16(mExtents); + mExtents = NULL; + + freeData(); +} + +void LLVolumeFace::freeData() +{ + ll_aligned_free_16(mPositions); + mPositions = NULL; + ll_aligned_free_16( mNormals); + mNormals = NULL; + ll_aligned_free_16(mTexCoords); + mTexCoords = NULL; + ll_aligned_free_16(mIndices); + mIndices = NULL; + ll_aligned_free_16(mBinormals); + mBinormals = NULL; + ll_aligned_free_16(mWeights); + mWeights = NULL; + + delete mOctree; + mOctree = NULL; +} BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) { + //tree for this face is no longer valid + delete mOctree; + mOctree = NULL; + + BOOL ret = FALSE ; if (mTypeMask & CAP_MASK) { - return createCap(volume, partial_build); + ret = createCap(volume, partial_build); } else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) { - return createSide(volume, partial_build); + ret = createSide(volume, partial_build); } else { llerrs << "Unknown/uninitialized face type!" << llendl; - return FALSE; } + + //update the range of the texture coordinates + if(ret) + { + mTexCoordExtents[0].setVec(1.f, 1.f) ; + mTexCoordExtents[1].setVec(0.f, 0.f) ; + + for(U32 i = 0 ; i < mNumVertices ; i++) + { + if(mTexCoordExtents[0].mV[0] > mTexCoords[i].mV[0]) + { + mTexCoordExtents[0].mV[0] = mTexCoords[i].mV[0] ; + } + if(mTexCoordExtents[1].mV[0] < mTexCoords[i].mV[0]) + { + mTexCoordExtents[1].mV[0] = mTexCoords[i].mV[0] ; + } + + if(mTexCoordExtents[0].mV[1] > mTexCoords[i].mV[1]) + { + mTexCoordExtents[0].mV[1] = mTexCoords[i].mV[1] ; + } + if(mTexCoordExtents[1].mV[1] < mTexCoords[i].mV[1]) + { + mTexCoordExtents[1].mV[1] = mTexCoords[i].mV[1] ; + } + } + mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ; + mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ; + mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ; + mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ; + } + + return ret ; +} + +void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv) +{ + cv.setPosition(mPositions[index]); + cv.setNormal(mNormals[index]); + cv.mTexCoord = mTexCoords[index]; +} + +bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const +{ + return getPosition().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::optimize(F32 angle_cutoff) +{ + LLVolumeFace new_face; + + //map of points to vector of vertices at that point + VertexMapData::PointMap point_map; + + //remove redundant vertices + for (U32 i = 0; i < mNumIndices; ++i) + { + U16 index = mIndices[i]; + + LLVolumeFace::VertexData cv; + getVertexData(index, cv); + + BOOL found = FALSE; + VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); + if (point_iter != point_map.end()) + { //duplicate point might exist + for (U32 j = 0; j < point_iter->second.size(); ++j) + { + LLVolumeFace::VertexData& tv = (point_iter->second)[j]; + if (tv.compareNormal(cv, angle_cutoff)) + { + found = TRUE; + new_face.pushIndex((point_iter->second)[j].mIndex); + break; + } + } + } + + if (!found) + { + new_face.pushVertex(cv); + U16 index = (U16) new_face.mNumVertices-1; + new_face.pushIndex(index); + + VertexMapData d; + d.setPosition(cv.getPosition()); + d.mTexCoord = cv.mTexCoord; + d.setNormal(cv.getNormal()); + d.mIndex = index; + if (point_iter != point_map.end()) + { + point_iter->second.push_back(d); + } + else + { + point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); + } + } + } + + swapData(new_face); +} + +class LLVCacheTriangleData; + +class LLVCacheVertexData +{ +public: + S32 mIdx; + S32 mCacheTag; + F32 mScore; + U32 mActiveTriangles; + std::vector<LLVCacheTriangleData*> mTriangles; + + LLVCacheVertexData() + { + mCacheTag = -1; + mScore = 0.f; + mActiveTriangles = 0; + mIdx = -1; + } +}; + +class LLVCacheTriangleData +{ +public: + bool mActive; + F32 mScore; + LLVCacheVertexData* mVertex[3]; + + LLVCacheTriangleData() + { + mActive = true; + mScore = 0.f; + mVertex[0] = mVertex[1] = mVertex[2] = NULL; + } + + void complete() + { + mActive = false; + for (S32 i = 0; i < 3; ++i) + { + if (mVertex[i]) + { + llassert_always(mVertex[i]->mActiveTriangles > 0); + mVertex[i]->mActiveTriangles--; + } + } + } + + bool operator<(const LLVCacheTriangleData& rhs) const + { //highest score first + return rhs.mScore < mScore; + } +}; + +const F32 FindVertexScore_CacheDecayPower = 1.5f; +const F32 FindVertexScore_LastTriScore = 0.75f; +const F32 FindVertexScore_ValenceBoostScale = 2.0f; +const F32 FindVertexScore_ValenceBoostPower = 0.5f; +const U32 MaxSizeVertexCache = 32; + +F32 find_vertex_score(LLVCacheVertexData& data) +{ + if (data.mActiveTriangles == 0) + { //no triangle references this vertex + return -1.f; + } + + F32 score = 0.f; + + 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 + F32 scaler = 1.f/(MaxSizeVertexCache-3); + score = 1.f-((cache_idx-3)*scaler); + score = powf(score, FindVertexScore_CacheDecayPower); + } + } + + //bonus points for having low valence + F32 valence_boost = powf(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() + { + for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) + { //trailing 3 vertices aren't actually in the cache for scoring purposes + if (mCache[i]) + { + mCache[i]->mCacheTag = -1; + } + } + + for (U32 i = 0; i < MaxSizeVertexCache; ++i) + { //update scores of vertices in cache + if (mCache[i]) + { + mCache[i]->mScore = find_vertex_score(*(mCache[i])); + llassert_always(mCache[i]->mCacheTag == i); + } + } + + mBestTriangle = NULL; + //update triangle scores + for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) + { + if (mCache[i]) + { + for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j) + { + LLVCacheTriangleData* tri = mCache[i]->mTriangles[j]; + if (tri->mActive) + { + tri->mScore = tri->mVertex[0]->mScore; + tri->mScore += tri->mVertex[1]->mScore; + tri->mScore += tri->mVertex[2]->mScore; + + if (!mBestTriangle || mBestTriangle->mScore < tri->mScore) + { + mBestTriangle = tri; + } + } + } + } + } + + //knock trailing 3 vertices off the cache + for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) + { + if (mCache[i]) + { + llassert_always(mCache[i]->mCacheTag == -1); + mCache[i] = NULL; + } + } + } +}; + + +void LLVolumeFace::cacheOptimize() +{ //optimize for vertex cache according to Forsyth method: + // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html + + LLVCacheLRU cache; + + if (mNumVertices < 3) + { //nothing to do + return; + } + + //mapping of vertices to triangles and indices + std::vector<LLVCacheVertexData> vertex_data; + + //mapping of triangles do vertices + std::vector<LLVCacheTriangleData> triangle_data; + + triangle_data.resize(mNumIndices/3); + vertex_data.resize(mNumVertices); + + for (U32 i = 0; i < mNumIndices; i++) + { //populate vertex data and triangle data arrays + U16 idx = mIndices[i]; + U32 tri_idx = i/3; + + vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); + vertex_data[idx].mIdx = idx; + triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]); + } + + /*F32 pre_acmr = 1.f; + //measure cache misses from before rebuild + { + LLVCacheFIFO test_cache; + for (U32 i = 0; i < mNumIndices; ++i) + { + test_cache.addVertex(&vertex_data[mIndices[i]]); + } + + for (U32 i = 0; i < mNumVertices; i++) + { + vertex_data[i].mCacheTag = -1; + } + + pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3); + }*/ + + for (U32 i = 0; i < mNumVertices; i++) + { //initialize score values (no cache -- might try a fifo cache here) + vertex_data[i].mScore = find_vertex_score(vertex_data[i]); + vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size(); + + for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j) + { + vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore; + } + } + + //sort triangle data by score + std::sort(triangle_data.begin(), triangle_data.end()); + + std::vector<U16> new_indices; + + LLVCacheTriangleData* tri; + + //prime pump by adding first triangle to cache; + tri = &(triangle_data[0]); + cache.addTriangle(tri); + new_indices.push_back(tri->mVertex[0]->mIdx); + new_indices.push_back(tri->mVertex[1]->mIdx); + new_indices.push_back(tri->mVertex[2]->mIdx); + tri->complete(); + + U32 breaks = 0; + for (U32 i = 1; i < mNumIndices/3; ++i) + { + cache.updateScores(); + tri = cache.mBestTriangle; + if (!tri) + { + breaks++; + for (U32 j = 0; j < triangle_data.size(); ++j) + { + if (triangle_data[j].mActive) + { + tri = &(triangle_data[j]); + break; + } + } + } + + cache.addTriangle(tri); + new_indices.push_back(tri->mVertex[0]->mIdx); + new_indices.push_back(tri->mVertex[1]->mIdx); + new_indices.push_back(tri->mVertex[2]->mIdx); + tri->complete(); + } + + for (U32 i = 0; i < mNumIndices; ++i) + { + mIndices[i] = new_indices[i]; + } + + /*F32 post_acmr = 1.f; + //measure cache misses from after rebuild + { + LLVCacheFIFO test_cache; + for (U32 i = 0; i < mNumVertices; i++) + { + vertex_data[i].mCacheTag = -1; + } + + for (U32 i = 0; i < mNumIndices; ++i) + { + test_cache.addVertex(&vertex_data[mIndices[i]]); + } + + post_acmr = (F32) test_cache.mMisses/(mNumIndices/3); + }*/ + + //optimize for pre-TnL cache + + //allocate space for new buffer + S32 num_verts = mNumVertices; + LLVector4a* pos = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + LLVector4a* norm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size); + + LLVector4a* wght = NULL; + if (mWeights) + { + wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + } + + LLVector4a* binorm = NULL; + if (mBinormals) + { + binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + } + + //allocate mapping of old indices to new indices + std::vector<S32> new_idx; + new_idx.resize(mNumVertices, -1); + + S32 cur_idx = 0; + for (U32 i = 0; i < mNumIndices; ++i) + { + U16 idx = mIndices[i]; + if (new_idx[idx] == -1) + { //this vertex hasn't been added yet + new_idx[idx] = cur_idx; + + //copy vertex data + pos[cur_idx] = mPositions[idx]; + norm[cur_idx] = mNormals[idx]; + tc[cur_idx] = mTexCoords[idx]; + if (mWeights) + { + wght[cur_idx] = mWeights[idx]; + } + if (mBinormals) + { + binorm[cur_idx] = mBinormals[idx]; + } + + cur_idx++; + } + } + + for (U32 i = 0; i < mNumIndices; ++i) + { + mIndices[i] = new_idx[mIndices[i]]; + } + + ll_aligned_free_16(mPositions); + ll_aligned_free_16(mNormals); + ll_aligned_free_16(mTexCoords); + ll_aligned_free_16(mWeights); + ll_aligned_free_16(mBinormals); + + mPositions = pos; + mNormals = norm; + mTexCoords = tc; + mWeights = wght; + mBinormals = binorm; + + //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); + //llinfos << result << llendl; + +} + +void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) +{ + if (mOctree) + { + return; + } + + mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL); + new LLVolumeOctreeListener(mOctree); + + for (U32 i = 0; i < mNumIndices; i+= 3) + { //for each triangle + LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle(); + + const LLVector4a& v0 = mPositions[mIndices[i]]; + const LLVector4a& v1 = mPositions[mIndices[i+1]]; + const LLVector4a& v2 = mPositions[mIndices[i+2]]; + + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = mIndices[i]; + tri->mIndex[1] = mIndices[i+1]; + tri->mIndex[2] = mIndices[i+2]; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max,min); + + tri->mRadius = size.getLength3().getF32() * 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::swapData(LLVolumeFace& rhs) +{ + llswap(rhs.mPositions, mPositions); + llswap(rhs.mNormals, mNormals); + llswap(rhs.mBinormals, mBinormals); + llswap(rhs.mTexCoords, mTexCoords); + llswap(rhs.mIndices,mIndices); + llswap(rhs.mNumVertices, mNumVertices); + llswap(rhs.mNumIndices, mNumIndices); } void LerpPlanarVertex(LLVolumeFace::VertexData& v0, @@ -4411,10 +6309,21 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, F32 coef01, F32 coef02) { - vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02); + + LLVector4a lhs; + lhs.setSub(v1.getPosition(), v0.getPosition()); + lhs.mul(coef01); + LLVector4a rhs; + rhs.setSub(v2.getPosition(), v0.getPosition()); + rhs.mul(coef02); + + rhs.add(lhs); + rhs.add(v0.getPosition()); + + vout.setPosition(rhs); + vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02); - vout.mNormal = v0.mNormal; - vout.mBinormal = v0.mBinormal; + vout.setNormal(v0.getNormal()); } BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) @@ -4434,90 +6343,134 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) num_vertices = (grid_size+1)*(grid_size+1); num_indices = quad_count * 4; - LLVector3& min = mExtents[0]; - LLVector3& max = mExtents[1]; + LLVector4a& min = mExtents[0]; + LLVector4a& max = mExtents[1]; S32 offset = 0; if (mTypeMask & TOP_MASK) + { offset = (max_t-1) * max_s; + } else + { offset = mBeginS; + } - VertexData corners[4]; - VertexData baseVert; - for(int t = 0; t < 4; t++){ - corners[t].mPosition = mesh[offset + (grid_size*t)].mPos; - corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; - corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; - } - baseVert.mNormal = - ((corners[1].mPosition-corners[0].mPosition) % - (corners[2].mPosition-corners[1].mPosition)); - baseVert.mNormal.normVec(); - if(!(mTypeMask & TOP_MASK)){ - baseVert.mNormal *= -1.0f; - }else{ - //Swap the UVs on the U(X) axis for top face - LLVector2 swap; - swap = corners[0].mTexCoord; - corners[0].mTexCoord=corners[3].mTexCoord; - corners[3].mTexCoord=swap; - swap = corners[1].mTexCoord; - corners[1].mTexCoord=corners[2].mTexCoord; - corners[2].mTexCoord=swap; - } - baseVert.mBinormal = calc_binormal_from_triangle( - corners[0].mPosition, corners[0].mTexCoord, - corners[1].mPosition, corners[1].mTexCoord, - corners[2].mPosition, corners[2].mTexCoord); - for(int t = 0; t < 4; t++){ - corners[t].mBinormal = baseVert.mBinormal; - corners[t].mNormal = baseVert.mNormal; - } - mHasBinormals = TRUE; - - if (partial_build) { - mVertices.clear(); - } + VertexData corners[4]; + VertexData baseVert; + for(S32 t = 0; t < 4; t++) + { + corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV); + corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; + corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; + } - S32 vtop = mVertices.size(); - for(int gx = 0;gx<grid_size+1;gx++){ - for(int gy = 0;gy<grid_size+1;gy++){ - VertexData newVert; - LerpPlanarVertex( - corners[0], - corners[1], - corners[3], - newVert, - (F32)gx/(F32)grid_size, - (F32)gy/(F32)grid_size); - mVertices.push_back(newVert); + { + LLVector4a lhs; + lhs.setSub(corners[1].getPosition(), corners[0].getPosition()); + LLVector4a rhs; + rhs.setSub(corners[2].getPosition(), corners[1].getPosition()); + baseVert.getNormal().setCross3(lhs, rhs); + baseVert.getNormal().normalize3fast(); + } - if (gx == 0 && gy == 0) - { - min = max = newVert.mPosition; - } - else + if(!(mTypeMask & TOP_MASK)) + { + baseVert.getNormal().mul(-1.0f); + } + else + { + //Swap the UVs on the U(X) axis for top face + LLVector2 swap; + swap = corners[0].mTexCoord; + corners[0].mTexCoord=corners[3].mTexCoord; + corners[3].mTexCoord=swap; + swap = corners[1].mTexCoord; + corners[1].mTexCoord=corners[2].mTexCoord; + corners[2].mTexCoord=swap; + } + + LLVector4a binormal; + + calc_binormal_from_triangle( binormal, + corners[0].getPosition(), corners[0].mTexCoord, + corners[1].getPosition(), corners[1].mTexCoord, + corners[2].getPosition(), corners[2].mTexCoord); + + binormal.normalize3fast(); + + S32 size = (grid_size+1)*(grid_size+1); + resizeVertices(size); + allocateBinormals(size); + + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + LLVector4a* binorm = (LLVector4a*) mBinormals; + LLVector2* tc = (LLVector2*) mTexCoords; + + for(int gx = 0;gx<grid_size+1;gx++) + { + for(int gy = 0;gy<grid_size+1;gy++) { - update_min_max(min,max,newVert.mPosition); + VertexData newVert; + LerpPlanarVertex( + corners[0], + corners[1], + corners[3], + newVert, + (F32)gx/(F32)grid_size, + (F32)gy/(F32)grid_size); + + *pos++ = newVert.getPosition(); + *norm++ = baseVert.getNormal(); + *tc++ = newVert.mTexCoord; + *binorm++ = binormal; + + if (gx == 0 && gy == 0) + { + min = newVert.getPosition(); + max = min; + } + else + { + min.setMin(min, newVert.getPosition()); + max.setMax(max, newVert.getPosition()); + } } } - } - mCenter = (min + max) * 0.5f; + mCenter->setAdd(min, max); + mCenter->mul(0.5f); + } if (!partial_build) { - int idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - for(int gx = 0;gx<grid_size;gx++){ - for(int gy = 0;gy<grid_size;gy++){ - if (mTypeMask & TOP_MASK){ - for(int i=5;i>=0;i--)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); - }else{ - for(int i=0;i<6;i++)mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]); + resizeIndices(grid_size*grid_size*6); + + U16* out = mIndices; + + S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; + for(S32 gx = 0;gx<grid_size;gx++) + { + + for(S32 gy = 0;gy<grid_size;gy++) + { + if (mTypeMask & TOP_MASK) + { + for(S32 i=5;i>=0;i--) + { + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } } - } + else + { + for(S32 i=0;i<6;i++) + { + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } + } + } } } @@ -4548,17 +6501,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) num_vertices = profile.size(); num_indices = (profile.size() - 2)*3; - mVertices.resize(num_vertices); + if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) + { + resizeVertices(num_vertices+1); + allocateBinormals(num_vertices+1); - if (!partial_build) + if (!partial_build) + { + resizeIndices(num_indices+3); + } + } + else { - mIndices.resize(num_indices); + resizeVertices(num_vertices); + allocateBinormals(num_vertices); + + if (!partial_build) + { + resizeIndices(num_indices); + } } S32 max_s = volume->getProfile().getTotal(); S32 max_t = volume->getPath().mPath.size(); - mCenter.clearVec(); + mCenter->clear(); S32 offset = 0; if (mTypeMask & TOP_MASK) @@ -4576,82 +6543,91 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) LLVector2 cuv; LLVector2 min_uv, max_uv; - LLVector3& min = mExtents[0]; - LLVector3& max = mExtents[1]; + LLVector4a& min = mExtents[0]; + LLVector4a& max = mExtents[1]; + + LLVector2* tc = (LLVector2*) mTexCoords; + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + LLVector4a* binorm = (LLVector4a*) mBinormals; // Copy the vertices into the array for (S32 i = 0; i < num_vertices; i++) { if (mTypeMask & TOP_MASK) { - mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; - mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f; + tc[i].mV[0] = profile[i].mV[0]+0.5f; + tc[i].mV[1] = profile[i].mV[1]+0.5f; } else { // Mirror for underside. - mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f; - mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1]; + tc[i].mV[0] = profile[i].mV[0]+0.5f; + tc[i].mV[1] = 0.5f - profile[i].mV[1]; } - mVertices[i].mPosition = mesh[i + offset].mPos; + pos[i].load3(mesh[i + offset].mPos.mV); if (i == 0) { - min = max = mVertices[i].mPosition; - min_uv = max_uv = mVertices[i].mTexCoord; + max = pos[i]; + min = max; + min_uv = max_uv = tc[i]; } else { - update_min_max(min,max, mVertices[i].mPosition); - update_min_max(min_uv, max_uv, mVertices[i].mTexCoord); + update_min_max(min,max,pos[i]); + update_min_max(min_uv, max_uv, tc[i]); } } - mCenter = (min+max)*0.5f; + mCenter->setAdd(min, max); + mCenter->mul(0.5f); + cuv = (min_uv + max_uv)*0.5f; - LLVector3 binormal = calc_binormal_from_triangle( - mCenter, cuv, - mVertices[0].mPosition, mVertices[0].mTexCoord, - mVertices[1].mPosition, mVertices[1].mTexCoord); - binormal.normVec(); + LLVector4a binormal; + calc_binormal_from_triangle(binormal, + *mCenter, cuv, + pos[0], tc[0], + pos[1], tc[1]); + binormal.normalize3fast(); + + LLVector4a normal; + LLVector4a d0, d1; + - LLVector3 d0; - LLVector3 d1; - LLVector3 normal; + d0.setSub(*mCenter, pos[0]); + d1.setSub(*mCenter, pos[1]); - d0 = mCenter-mVertices[0].mPosition; - d1 = mCenter-mVertices[1].mPosition; + if (mTypeMask & TOP_MASK) + { + normal.setCross3(d0, d1); + } + else + { + normal.setCross3(d1, d0); + } - normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0); - normal.normVec(); + normal.normalize3fast(); VertexData vd; - vd.mPosition = mCenter; - vd.mNormal = normal; - vd.mBinormal = binormal; + vd.setPosition(*mCenter); vd.mTexCoord = cuv; if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) { - mVertices.push_back(vd); + pos[num_vertices] = *mCenter; + tc[num_vertices] = cuv; num_vertices++; - if (!partial_build) - { - vector_append(mIndices, 3); - } } - for (S32 i = 0; i < num_vertices; i++) { - mVertices[i].mBinormal = binormal; - mVertices[i].mNormal = normal; + binorm[i].load4a(binormal.getF32ptr()); + norm[i].load4a(normal.getF32ptr()); } - mHasBinormals = TRUE; - if (partial_build) { return TRUE; @@ -4868,59 +6844,25 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) else { // Not hollow, generate the triangle fan. + U16 v1 = 2; + U16 v2 = 1; + if (mTypeMask & TOP_MASK) { - if (mTypeMask & OPEN_MASK) - { - // SOLID OPEN TOP - // Generate indices - // This is a tri-fan, so we reuse the same first point for all triangles. - for (S32 i = 0; i < (num_vertices - 2); i++) - { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i; - mIndices[3*i+2] = i + 1; - } - } - else - { - // SOLID CLOSED TOP - for (S32 i = 0; i < (num_vertices - 2); i++) - { - //MSMSM fix these caps but only for the un-cut case - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i; - mIndices[3*i+2] = i + 1; - } - } + v1 = 1; + v2 = 2; } - else + + for (S32 i = 0; i < (num_vertices - 2); i++) { - if (mTypeMask & OPEN_MASK) - { - // SOLID OPEN BOTTOM - // Generate indices - // This is a tri-fan, so we reuse the same first point for all triangles. - for (S32 i = 0; i < (num_vertices - 2); i++) - { - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i + 1; - mIndices[3*i+2] = i; - } - } - else - { - // SOLID CLOSED BOTTOM - for (S32 i = 0; i < (num_vertices - 2); i++) - { - //MSMSM fix these caps but only for the un-cut case - mIndices[3*i] = num_vertices - 1; - mIndices[3*i+1] = i + 1; - mIndices[3*i+2] = i; - } - } + mIndices[3*i] = num_vertices - 1; + mIndices[3*i+v1] = i; + mIndices[3*i+v2] = i + 1; } + + } + return TRUE; } @@ -4928,44 +6870,267 @@ void LLVolumeFace::createBinormals() { LLMemType m1(LLMemType::MTYPE_VOLUME); - if (!mHasBinormals) + if (!mBinormals) { + allocateBinormals(mNumVertices); + //generate binormals - for (U32 i = 0; i < mIndices.size()/3; i++) + LLVector4a* pos = mPositions; + LLVector2* tc = (LLVector2*) mTexCoords; + LLVector4a* binorm = (LLVector4a*) mBinormals; + + LLVector4a* end = mBinormals+mNumVertices; + while (binorm < end) + { + (*binorm++).clear(); + } + + binorm = mBinormals; + + for (U32 i = 0; i < mNumIndices/3; i++) { //for each triangle - const VertexData& v0 = mVertices[mIndices[i*3+0]]; - const VertexData& v1 = mVertices[mIndices[i*3+1]]; - const VertexData& v2 = mVertices[mIndices[i*3+2]]; + const U16& i0 = mIndices[i*3+0]; + const U16& i1 = mIndices[i*3+1]; + const U16& i2 = mIndices[i*3+2]; //calculate binormal - LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord, - v1.mPosition, v1.mTexCoord, - v2.mPosition, v2.mTexCoord); + LLVector4a binormal; + calc_binormal_from_triangle(binormal, + pos[i0], tc[i0], + pos[i1], tc[i1], + pos[i2], tc[i2]); - for (U32 j = 0; j < 3; j++) - { //add triangle normal to vertices - mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum; - } + + //add triangle normal to vertices + binorm[i0].add(binormal); + binorm[i1].add(binormal); + binorm[i2].add(binormal); //even out quad contributions if (i % 2 == 0) { - mVertices[mIndices[i*3+2]].mBinormal += binorm; + binorm[i2].add(binormal); } else { - mVertices[mIndices[i*3+1]].mBinormal += binorm; + binorm[i1].add(binormal); } } //normalize binormals - for (U32 i = 0; i < mVertices.size(); i++) + for (U32 i = 0; i < mNumVertices; i++) { - mVertices[i].mBinormal.normVec(); - mVertices[i].mNormal.normVec(); + binorm[i].normalize3fast(); + //bump map/planar projection code requires normals to be normalized + mNormals[i].normalize3fast(); } + } +} + +void LLVolumeFace::resizeVertices(S32 num_verts) +{ + ll_aligned_free_16(mPositions); + ll_aligned_free_16(mNormals); + ll_aligned_free_16(mBinormals); + ll_aligned_free_16(mTexCoords); + + mBinormals = NULL; - mHasBinormals = TRUE; + if (num_verts) + { + mPositions = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + assert_aligned(mPositions, 16); + mNormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + assert_aligned(mNormals, 16); + + //pad texture coordinate block end to allow for QWORD reads + S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; + mTexCoords = (LLVector2*) ll_aligned_malloc_16(size); + assert_aligned(mTexCoords, 16); + } + else + { + mPositions = NULL; + mNormals = NULL; + mTexCoords = NULL; + } + + mNumVertices = num_verts; +} + +void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) +{ + pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord); +} + +void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc) +{ + S32 new_verts = mNumVertices+1; + S32 new_size = new_verts*16; +// S32 old_size = mNumVertices*16; + + //positions + mPositions = (LLVector4a*) realloc(mPositions, new_size); + + //normals + mNormals = (LLVector4a*) realloc(mNormals, new_size); + + //tex coords + new_size = ((new_verts*8)+0xF) & ~0xF; + mTexCoords = (LLVector2*) realloc(mTexCoords, new_size); + + + //just clear binormals + ll_aligned_free_16(mBinormals); + mBinormals = NULL; + + mPositions[mNumVertices] = pos; + mNormals[mNumVertices] = norm; + mTexCoords[mNumVertices] = tc; + + mNumVertices++; +} + +void LLVolumeFace::allocateBinormals(S32 num_verts) +{ + ll_aligned_free_16(mBinormals); + mBinormals = (LLVector4a*) ll_aligned_malloc_16(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::resizeIndices(S32 num_indices) +{ + ll_aligned_free_16(mIndices); + + if (num_indices) + { + //pad index block end to allow for QWORD reads + S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; + + mIndices = (U16*) ll_aligned_malloc_16(size); + } + else + { + mIndices = NULL; + } + + mNumIndices = num_indices; +} + +void LLVolumeFace::pushIndex(const U16& idx) +{ + S32 new_count = mNumIndices + 1; + S32 new_size = ((new_count*2)+0xF) & ~0xF; + + S32 old_size = ((mNumIndices*2)+0xF) & ~0xF; + if (new_size != old_size) + { + mIndices = (U16*) realloc(mIndices, new_size); + } + + mIndices[mNumIndices++] = idx; +} + +void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& 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]; + } +} + +void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) +{ + U16 offset = mNumVertices; + + S32 new_count = face.mNumVertices + mNumVertices; + + if (new_count > 65536) + { + llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl; + } + + if (face.mNumVertices == 0) + { + llerrs << "Cannot append empty face." << llendl; + } + + //allocate new buffer space + mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a)); + assert_aligned(mPositions, 16); + mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a)); + assert_aligned(mNormals, 16); + mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF); + assert_aligned(mTexCoords, 16); + + mNumVertices = new_count; + + //get destination address of appended face + LLVector4a* dst_pos = mPositions+offset; + LLVector2* dst_tc = mTexCoords+offset; + LLVector4a* dst_norm = mNormals+offset; + + //get source addresses of appended face + const LLVector4a* src_pos = face.mPositions; + const LLVector2* src_tc = face.mTexCoords; + const LLVector4a* src_norm = face.mNormals; + + //load aligned matrices + LLMatrix4a mat, norm_mat; + mat.loadu(mat_in); + norm_mat.loadu(norm_mat_in); + + for (U32 i = 0; i < face.mNumVertices; ++i) + { + //transform appended face position and store + mat.affineTransform(src_pos[i], dst_pos[i]); + + //transform appended face normal and store + norm_mat.rotate(src_norm[i], dst_norm[i]); + dst_norm[i].normalize3fast(); + + //copy appended face texture coordinate + dst_tc[i] = src_tc[i]; + + if (offset == 0 && i == 0) + { //initialize bounding box + mExtents[0] = mExtents[1] = dst_pos[i]; + } + else + { + //stretch bounding box + update_min_max(mExtents[0], mExtents[1], dst_pos[i]); + } + } + + + new_count = mNumIndices + face.mNumIndices; + + //allocate new index buffer + mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF); + + //get destination address into new index buffer + U16* dst_idx = mIndices+mNumIndices; + mNumIndices = new_count; + + for (U32 i = 0; i < face.mNumIndices; ++i) + { //copy indices, offsetting by old vertex count + dst_idx[i] = face.mIndices[i]+offset; } } @@ -4995,24 +7160,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) num_vertices = mNumS*mNumT; num_indices = (mNumS-1)*(mNumT-1)*6; - mVertices.resize(num_vertices); - if (!partial_build) { - mIndices.resize(num_indices); - mEdge.resize(num_indices); - } - else - { - mHasBinormals = FALSE; - } - + resizeVertices(num_vertices); + resizeIndices(num_indices); - LLVector3& face_min = mExtents[0]; - LLVector3& face_max = mExtents[1]; - - mCenter.clearVec(); + if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + mEdge.resize(num_indices); + } + } + LLVector4a* pos = (LLVector4a*) mPositions; + LLVector4a* norm = (LLVector4a*) mNormals; + LLVector2* tc = (LLVector2*) mTexCoords; S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; @@ -5063,30 +7224,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) i = mBeginS + s + max_s*t; } - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - - if (cur_vertex == 0) - { - face_min = face_max = mesh[i].mPos; - } - else - { - update_min_max(face_min, face_max, mesh[i].mPos); - } - + norm[cur_vertex].clear(); cur_vertex++; if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) { - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); + + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); + norm[cur_vertex].clear(); + cur_vertex++; } } @@ -5104,19 +7255,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) i = mBeginS + s + max_s*t; ss = profile[mBeginS + s].mV[2] - begin_stex; - mVertices[cur_vertex].mPosition = mesh[i].mPos; - mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt); - - mVertices[cur_vertex].mNormal = LLVector3(0,0,0); - mVertices[cur_vertex].mBinormal = LLVector3(0,0,0); - - update_min_max(face_min,face_max,mesh[i].mPos); - + pos[cur_vertex].load3(mesh[i].mPos.mV); + tc[cur_vertex] = LLVector2(ss,tt); + norm[cur_vertex].clear(); + cur_vertex++; } } - mCenter = (face_min + face_max) * 0.5f; + + //get bounding box for this side + LLVector4a& face_min = mExtents[0]; + LLVector4a& face_max = mExtents[1]; + mCenter->clear(); + + face_min = face_max = pos[0]; + + for (U32 i = 1; i < mNumVertices; ++i) + { + update_min_max(face_min, face_max, pos[i]); + } + + mCenter->setAdd(face_min, face_max); + mCenter->mul(0.5f); S32 cur_index = 0; S32 cur_edge = 0; @@ -5179,49 +7340,58 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) } } + //clear normals + for (U32 i = 0; i < mNumVertices; i++) + { + mNormals[i].clear(); + } + //generate normals - for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle - { - const S32 i0 = mIndices[i*3+0]; - const S32 i1 = mIndices[i*3+1]; - const S32 i2 = mIndices[i*3+2]; - const VertexData& v0 = mVertices[i0]; - const VertexData& v1 = mVertices[i1]; - const VertexData& v2 = mVertices[i2]; - - //calculate triangle normal - LLVector3 norm = (v0.mPosition-v1.mPosition) % (v0.mPosition-v2.mPosition); + for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle + { + const U16* idx = &(mIndices[i*3]); + - for (U32 j = 0; j < 3; j++) - { //add triangle normal to vertices - const S32 idx = mIndices[i*3+j]; - mVertices[idx].mNormal += norm; // * (weight_sum - d[j])/weight_sum; - } + LLVector4a* v[] = + { pos+idx[0], pos+idx[1], pos+idx[2] }; + + LLVector4a* n[] = + { norm+idx[0], norm+idx[1], norm+idx[2] }; + + //calculate triangle normal + LLVector4a a, b, c; + + a.setSub(*v[0], *v[1]); + b.setSub(*v[0], *v[2]); + c.setCross3(a,b); + n[0]->add(c); + n[1]->add(c); + n[2]->add(c); + //even out quad contributions - if ((i & 1) == 0) - { - mVertices[i2].mNormal += norm; - } - else - { - mVertices[i1].mNormal += norm; - } + n[i%2+1]->add(c); } // adjust normals based on wrapping and stitching - BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f); - BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f); + LLVector4a top; + top.setSub(pos[0], pos[mNumS*(mNumT-2)]); + BOOL s_bottom_converges = (top.dot3(top) < 0.000001f); + + top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]); + BOOL s_top_converges = (top.dot3(top) < 0.000001f); + if (sculpt_stitching == LL_SCULPT_TYPE_NONE) // logic for non-sculpt volumes { if (volume->getPath().isOpen() == FALSE) { //wrap normals on T for (S32 i = 0; i < mNumS; i++) { - LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; - mVertices[i].mNormal = norm; - mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; } } @@ -5229,9 +7399,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //wrap normals on S for (S32 i = 0; i < mNumT; i++) { - LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; - mVertices[mNumS * i].mNormal = norm; - mVertices[mNumS * i+mNumS-1].mNormal = norm; + LLVector4a n; + n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); + norm[mNumS * i] = n; + norm[mNumS * i+mNumS-1] = n; } } @@ -5242,7 +7413,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //all lower S have same normal for (S32 i = 0; i < mNumT; i++) { - mVertices[mNumS*i].mNormal = LLVector3(1,0,0); + norm[mNumS*i].set(1,0,0); } } @@ -5250,12 +7421,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { //all upper S have same normal for (S32 i = 0; i < mNumT; i++) { - mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0); + norm[mNumS*i+mNumS-1].set(-1,0,0); } } } } - else // logic for sculpt volumes { BOOL average_poles = FALSE; @@ -5278,30 +7448,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { // average normals for north pole - LLVector3 average(0.0, 0.0, 0.0); + LLVector4a average; + average.clear(); + for (S32 i = 0; i < mNumS; i++) { - average += mVertices[i].mNormal; + average.add(norm[i]); } // set average for (S32 i = 0; i < mNumS; i++) { - mVertices[i].mNormal = average; + norm[i] = average; } // average normals for south pole - average = LLVector3(0.0, 0.0, 0.0); + average.clear(); + for (S32 i = 0; i < mNumS; i++) { - average += mVertices[i + mNumS * (mNumT - 1)].mNormal; + average.add(norm[i + mNumS * (mNumT - 1)]); } // set average for (S32 i = 0; i < mNumS; i++) { - mVertices[i + mNumS * (mNumT - 1)].mNormal = average; + norm[i + mNumS * (mNumT - 1)] = average; } } @@ -5311,23 +7484,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { for (S32 i = 0; i < mNumT; i++) { - LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal; - mVertices[mNumS * i].mNormal = norm; - mVertices[mNumS * i+mNumS-1].mNormal = norm; + LLVector4a n; + n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]); + norm[mNumS * i] = n; + norm[mNumS * i+mNumS-1] = n; } } - - if (wrap_t) { for (S32 i = 0; i < mNumS; i++) { - LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal; - mVertices[i].mNormal = norm; - mVertices[mNumS*(mNumT-1)+i].mNormal = norm; + LLVector4a n; + n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]); + norm[i] = n; + norm[mNumS*(mNumT-1)+i] = n; } - } } @@ -5337,41 +7509,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) // Finds binormal based on three vertices with texture coordinates. // Fills in dummy values if the triangle has degenerate texture coordinates. -LLVector3 calc_binormal_from_triangle( - const LLVector3& pos0, +void calc_binormal_from_triangle(LLVector4a& binormal, + + const LLVector4a& pos0, const LLVector2& tex0, - const LLVector3& pos1, + const LLVector4a& pos1, const LLVector2& tex1, - const LLVector3& pos2, + const LLVector4a& pos2, const LLVector2& tex2) { - LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] ); - LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] ); - LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] ); + LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] ); - LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] ); - LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] ); - LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] ); + LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] ); - LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] ); - LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] ); - LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] ); + LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] ); - LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2); - LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2); - LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2); + LLVector4a lhs, rhs; + + LLVector4a r0; + lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2); + r0.setCross3(lhs, rhs); + + LLVector4a r1; + lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2); + r1.setCross3(lhs, rhs); + + LLVector4a r2; + lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2); + r2.setCross3(lhs, rhs); - if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] ) + if( r0[VX] && r1[VX] && r2[VX] ) { - LLVector3 binormal( - -r0.mV[VZ] / r0.mV[VX], - -r1.mV[VZ] / r1.mV[VX], - -r2.mV[VZ] / r2.mV[VX]); + binormal.set( + -r0[VZ] / r0[VX], + -r1[VZ] / r1[VX], + -r2[VZ] / r2[VX]); // binormal.normVec(); - return binormal; } else { - return LLVector3( 0, 1 , 0 ); + binormal.set( 0, 1 , 0 ); } } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index af46da05d8..f67f8f644d 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -2,31 +2,25 @@ * @file llvolume.h * @brief LLVolume base class. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -40,8 +34,13 @@ class LLPathParams; class LLVolumeParams; class LLProfile; class LLPath; + +template <class T> class LLOctreeNode; + +class LLVector4a; class LLVolumeFace; class LLVolume; +class LLVolumeTriangle; #include "lldarray.h" #include "lluuid.h" @@ -49,6 +48,8 @@ class LLVolume; //#include "vmath.h" #include "v2math.h" #include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" #include "llquaternion.h" #include "llstrider.h" #include "v4coloru.h" @@ -183,12 +184,14 @@ const U8 LL_SCULPT_TYPE_SPHERE = 1; const U8 LL_SCULPT_TYPE_TORUS = 2; const U8 LL_SCULPT_TYPE_PLANE = 3; const U8 LL_SCULPT_TYPE_CYLINDER = 4; - -const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER; +const U8 LL_SCULPT_TYPE_MESH = 5; +const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | + LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; const U8 LL_SCULPT_FLAG_INVERT = 64; const U8 LL_SCULPT_FLAG_MIRROR = 128; +const S32 LL_SCULPT_MESH_MAX_FACES = 8; class LLProfileParams { @@ -575,6 +578,9 @@ public: BOOL importLegacyStream(std::istream& input_stream); BOOL exportLegacyStream(std::ostream& output_stream) const; + LLSD sculptAsLLSD() const; + bool sculptFromLLSD(LLSD& sd); + LLSD asLLSD() const; operator LLSD() const { return asLLSD(); } bool fromLLSD(LLSD& sd); @@ -634,7 +640,8 @@ public: 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) @@ -683,6 +690,9 @@ public: 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; } @@ -707,6 +717,7 @@ public: protected: void genNormals(const LLProfileParams& params); + 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); @@ -749,6 +760,9 @@ public: 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); @@ -785,29 +799,88 @@ public: class LLVolumeFace { public: - LLVolumeFace() : - mID(0), - mTypeMask(0), - mHasBinormals(FALSE), - mBeginS(0), - mBeginT(0), - mNumS(0), - mNumT(0) + class VertexData { - } + enum + { + POSITION = 0, + NORMAL = 1 + }; + + private: + void init(); + public: + VertexData(); + VertexData(const VertexData& rhs); + const VertexData& operator=(const VertexData& rhs); + + ~VertexData(); + LLVector4a& getPosition(); + LLVector4a& getNormal(); + const LLVector4a& getPosition() const; + const LLVector4a& getNormal() const; + void setPosition(const LLVector4a& pos); + void setNormal(const LLVector4a& norm); + + + LLVector2 mTexCoord; + + bool operator<(const VertexData& rhs) const; + bool operator==(const VertexData& rhs) const; + bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const; + + private: + LLVector4a* mData; + }; + + LLVolumeFace(); + LLVolumeFace(const LLVolumeFace& src); + LLVolumeFace& operator=(const LLVolumeFace& rhs); + + ~LLVolumeFace(); +private: + void freeData(); +public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); void createBinormals(); + + void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); - class VertexData + void resizeVertices(S32 num_verts); + void allocateBinormals(S32 num_verts); + void allocateWeights(S32 num_verts); + void resizeIndices(S32 num_indices); + void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx); + + void pushVertex(const VertexData& cv); + void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc); + void pushIndex(const U16& idx); + + void swapData(LLVolumeFace& rhs); + + void getVertexData(U16 indx, LLVolumeFace::VertexData& cv); + + class VertexMapData : public LLVolumeFace::VertexData { public: - LLVector3 mPosition; - LLVector3 mNormal; - LLVector3 mBinormal; - LLVector2 mTexCoord; + U16 mIndex; + + bool operator==(const LLVolumeFace::VertexData& rhs) const; + + struct ComparePosition + { + bool operator()(const LLVector3& a, const LLVector3& b) const; + }; + + typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap; }; + void optimize(F32 angle_cutoff = 2.f); + void cacheOptimize(); + + void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f)); + enum { SINGLE_MASK = 0x0001, @@ -826,21 +899,35 @@ public: public: S32 mID; U32 mTypeMask; - LLVector3 mCenter; - BOOL mHasBinormals; - + // Only used for INNER/OUTER faces S32 mBeginS; S32 mBeginT; S32 mNumS; S32 mNumT; - LLVector3 mExtents[2]; //minimum and maximum point of face + LLVector4a* mExtents; //minimum and maximum point of face + LLVector4a* mCenter; + LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. + + S32 mNumVertices; + S32 mNumIndices; + + LLVector4a* mPositions; + LLVector4a* mNormals; + LLVector4a* mBinormals; + LLVector2* mTexCoords; + U16* mIndices; - std::vector<VertexData> mVertices; - std::vector<U16> mIndices; std::vector<S32> mEdge; + //list of skin weights for rigged volumes + // format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight> + // mWeights.size() should be empty or match mVertices.size() + LLVector4a* mWeights; + + LLOctreeNode<LLVolumeTriangle>* mOctree; + private: BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE); @@ -851,8 +938,7 @@ class LLVolume : public LLRefCount { friend class LLVolumeLODGroup; -private: - LLVolume(const LLVolume&); // Don't implement +protected: ~LLVolume(); // use unref public: @@ -874,7 +960,7 @@ public: U8 getProfileType() const { return mParams.getProfileParams().getCurveType(); } U8 getPathType() const { return mParams.getPathParams().getCurveType(); } - S32 getNumFaces() const { return (S32)mProfilep->mFaces.size(); } + S32 getNumFaces() const; S32 getNumVolumeFaces() const { return mVolumeFaces.size(); } F32 getDetail() const { return mDetail; } const LLVolumeParams& getParams() const { return mParams; } @@ -896,15 +982,22 @@ public: BOOL isUnique() const { return mUnique; } S32 getSculptLevel() const { return mSculptLevel; } - + void setSculptLevel(S32 level) { mSculptLevel = level; } + S32 *getTriangleIndices(U32 &num_indices) const; // returns number of triangle indeces required for path/profile mesh S32 getNumTriangleIndices() const; + static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts); - void generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<LLVector3> &normals, std::vector<S32> &segments, const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat); + S32 getNumTriangles() const; + + void generateSilhouetteVertices(std::vector<LLVector3> &vertices, + std::vector<LLVector3> &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. @@ -916,6 +1009,13 @@ public: LLVector3* normal = NULL, // return the surface normal at the intersection point LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point ); + + S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face = 1, + LLVector3* intersection = NULL, + LLVector2* tex_coord = NULL, + LLVector3* normal = NULL, + LLVector3* bi_normal = NULL); // The following cleans up vertices and triangles, // getting rid of degenerate triangles and duplicate vertices, @@ -937,11 +1037,14 @@ public: 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 - + 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); + void copyVolumeFaces(const LLVolume* volume); + void cacheOptimize(); + private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); F32 sculptGetSurfaceArea(); @@ -952,35 +1055,56 @@ private: protected: BOOL generate(); void createVolumeFaces(); +public: + virtual bool unpackVolumeFaces(std::istream& is, S32 size); + + virtual void makeTetrahedron(); + virtual BOOL isTetrahedron(); protected: BOOL mUnique; F32 mDetail; S32 mSculptLevel; + BOOL mIsTetrahedron; LLVolumeParams mParams; LLPath *mPathp; LLProfile *mProfilep; std::vector<Point> mMesh; - + BOOL mGenerateSingleFace; typedef std::vector<LLVolumeFace> face_list_t; face_list_t mVolumeFaces; + +public: + LLVector4a* mHullPoints; + U16* mHullIndices; + S32 mNumHullPoints; + S32 mNumHullIndices; }; std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); -LLVector3 calc_binormal_from_triangle( - const LLVector3& pos0, +void calc_binormal_from_triangle( + LLVector4a& binormal, + const LLVector4a& pos0, const LLVector2& tex0, - const LLVector3& pos1, + const LLVector4a& pos1, const LLVector2& tex1, - const LLVector3& pos2, + const LLVector4a& pos2, const LLVector2& tex2); +BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size); BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); +BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size); + BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided); + F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided); + +BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t); +BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, + F32& intersection_a, F32& intersection_b, F32& intersection_t); diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 53641fceab..c60b750088 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -1,31 +1,25 @@ /** * @file llvolumemgr.cpp * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -320,7 +314,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) { llassert_always(mLODRefs[i] > 0); mLODRefs[i]--; -#if 1 // SJB: Possible opt: keep other lods around +#if 0 // SJB: Possible opt: keep other lods around if (!mLODRefs[i]) { mVolumeLODs[i] = NULL; @@ -375,6 +369,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail) return mDetailScales[detail]; } +S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail) +{ + for (S32 i = 1; i < 4; i++) + { + if (mDetailScales[i] > detail) + { + return i-1; + } + } + + return 3; +} + F32 LLVolumeLODGroup::dump() { F32 usage = 0.f; diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index a78ea76a1a..c75906f675 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -2,31 +2,25 @@ * @file llvolumemgr.h * @brief LLVolumeMgr class. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,6 +53,7 @@ public: static S32 getDetailFromTan(const F32 tan_angle); static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher); static F32 getVolumeScaleFromDetail(const S32 detail); + static S32 getVolumeDetailFromScale(F32 scale); LLVolume* refLOD(const S32 detail); BOOL derefLOD(LLVolume *volumep); diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp new file mode 100644 index 0000000000..b5a935c2b5 --- /dev/null +++ b/indra/llmath/llvolumeoctree.cpp @@ -0,0 +1,256 @@ +/** + + * @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) ? false : true; +} + + +LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node) +{ + node->addListener(this); +} + +LLVolumeOctreeListener::~LLVolumeOctreeListener() +{ + +} + +void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent, + LLOctreeNode<LLVolumeTriangle>* child) +{ + new LLVolumeOctreeListener(child); +} + + +LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, + const LLVolumeFace* face, F32* closest_t, + LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) + : mFace(face), + mStart(start), + mDir(dir), + mIntersection(intersection), + mTexCoord(tex_coord), + mNormal(normal), + mBinormal(bi_normal), + mClosestT(closest_t), + mHitFace(false) +{ + mEnd.setAdd(mStart, mDir); +} + +void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>* node) +{ + LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0); + + /*const F32* start = mStart.getF32(); + const F32* end = mEnd.getF32(); + const F32* center = vl->mBounds[0].getF32(); + const F32* size = vl->mBounds[1].getF32();*/ + + //if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1])) + if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr())) + { + node->accept(this); + for (S32 i = 0; i < node->getChildCount(); ++i) + { + traverse(node->getChild(i)); + } + } +} + +void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node) +{ + for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = + node->getData().begin(); iter != node->getData().end(); ++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->set(intersect.getF32ptr()); + } + + + if (mTexCoord != NULL) + { + LLVector2* tc = (LLVector2*) mFace->mTexCoords; + *mTexCoord = ((1.f - a - b) * tc[tri->mIndex[0]] + + a * tc[tri->mIndex[1]] + + b * tc[tri->mIndex[2]]); + + } + + if (mNormal != NULL) + { + LLVector4* norm = (LLVector4*) mFace->mNormals; + + *mNormal = ((1.f - a - b) * LLVector3(norm[tri->mIndex[0]]) + + a * LLVector3(norm[tri->mIndex[1]]) + + b * LLVector3(norm[tri->mIndex[2]])); + } + + if (mBinormal != NULL) + { + LLVector4* binormal = (LLVector4*) mFace->mBinormals; + *mBinormal = ((1.f - a - b) * LLVector3(binormal[tri->mIndex[0]]) + + a * LLVector3(binormal[tri->mIndex[1]]) + + b * LLVector3(binormal[tri->mIndex[2]])); + } + } + } + } +} + +const LLVector4a& LLVolumeTriangle::getPositionGroup() const +{ + return mPositionGroup; +} + +const F32& LLVolumeTriangle::getBinRadius() const +{ + return mRadius; +} + + +//TEST CODE + +void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch) +{ + LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); + + //make sure bounds matches extents + LLVector4a& min = node->mExtents[0]; + LLVector4a& max = node->mExtents[1]; + + LLVector4a& center = node->mBounds[0]; + LLVector4a& size = node->mBounds[1]; + + LLVector4a test_min, test_max; + test_min.setSub(center, size); + test_max.setAdd(center, size); + + if (!test_min.equals3(min, 0.001f) || + !test_max.equals3(max, 0.001f)) + { + llerrs << "Bad bounding box data found." << llendl; + } + + test_min.sub(LLVector4a(0.001f)); + test_max.add(LLVector4a(0.001f)); + + for (U32 i = 0; i < branch->getChildCount(); ++i) + { + LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0); + + //make sure all children fit inside this node + if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) || + child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ)) + { + llerrs << "Child protrudes from bounding box." << llendl; + } + } + + //children fit, check data + for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); + iter != branch->getData().end(); ++iter) + { + const LLVolumeTriangle* tri = *iter; + + //validate triangle + for (U32 i = 0; i < 3; i++) + { + if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) || + tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ)) + { + llerrs << "Triangle protrudes from node." << llendl; + } + } + } +} + + diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h new file mode 100644 index 0000000000..688d91dc40 --- /dev/null +++ b/indra/llmath/llvolumeoctree.h @@ -0,0 +1,134 @@ +/** + * @file llvolumeoctree.h + * @brief LLVolume octree classes. + * + * $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_OCTREE_H +#define LL_LLVOLUME_OCTREE_H + +#include "linden_common.h" +#include "llmemory.h" + +#include "lloctree.h" +#include "llvolume.h" +#include "llvector4a.h" + +class LLVolumeTriangle : public LLRefCount +{ +public: + LLVolumeTriangle() + { + + } + + LLVolumeTriangle(const LLVolumeTriangle& rhs) + { + *this = rhs; + } + + const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + + ~LLVolumeTriangle() + { + + } + + LLVector4a mPositionGroup; + + const LLVector4a* mV[3]; + U16 mIndex[3]; + + F32 mRadius; + + virtual const LLVector4a& getPositionGroup() const; + virtual const F32& getBinRadius() const; +}; + +class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle> +{ +public: + + LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node); + ~LLVolumeOctreeListener(); + + LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs) + { + *this = rhs; + } + + const LLVolumeOctreeListener& operator=(const LLVolumeOctreeListener& rhs) + { + llerrs << "Illegal operation!" << llendl; + return *this; + } + + //LISTENER FUNCTIONS + virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent, + LLOctreeNode<LLVolumeTriangle>* child); + virtual void handleStateChange(const LLTreeNode<LLVolumeTriangle>* node) { } + virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle>* parent, + const LLOctreeNode<LLVolumeTriangle>* child) { } + virtual void handleInsertion(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { } + virtual void handleRemoval(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { } + virtual void handleDestruction(const LLTreeNode<LLVolumeTriangle>* node) { } + + +public: + LLVector4a mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects) + LLVector4a mExtents[2]; // extents (min, max) of this node and all its children +}; + +class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle> +{ +public: + const LLVolumeFace* mFace; + LLVector4a mStart; + LLVector4a mDir; + LLVector4a mEnd; + LLVector3* mIntersection; + LLVector2* mTexCoord; + LLVector3* mNormal; + LLVector3* mBinormal; + F32* mClosestT; + bool mHitFace; + + LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, + const LLVolumeFace* face, F32* closest_t, + LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal); + + void traverse(const LLOctreeNode<LLVolumeTriangle>* node); + + virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node); +}; + +class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle> +{ + virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch); +}; + +#endif diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index 1b878c8f4d..802ddb9e57 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -2,31 +2,25 @@ * @file m3math.cpp * @brief LLMatrix3 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index 3ac963e5aa..2be5452f8d 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -2,31 +2,25 @@ * @file m3math.h * @brief LLMatrix3 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 59a0bc2335..bad4deb4de 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -2,31 +2,25 @@ * @file m4math.cpp * @brief LLMatrix4 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -221,8 +215,33 @@ const LLMatrix4& LLMatrix4::transpose() F32 LLMatrix4::determinant() const { - llerrs << "Not implemented!" << llendl; - return 0.f; + F32 value = + mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][0] - + mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][0] - + mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][0] + + mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][0] + + mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][0] - + mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][0] - + mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][1] + + mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][1] + + mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][1] - + mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][1] - + mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][1] + + mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][1] + + mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][2] - + mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][2] - + mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][2] + + mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][2] + + mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][2] - + mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][2] - + mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][3] + + mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][3] + + mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][3] - + mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][3] - + mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][3] + + mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][3]; + + return value; } // Only works for pure orthonormal, homogeneous transform matrices. @@ -428,6 +447,17 @@ const LLMatrix4& LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector return (*this); } +const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale) +{ + setIdentity(); + + mMatrix[VX][VX] = scale.mV[VX]; + mMatrix[VY][VY] = scale.mV[VY]; + mMatrix[VZ][VZ] = scale.mV[VZ]; + + return (*this); +} + const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos) { F32 sx, sy, sz; @@ -648,63 +678,6 @@ const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 & // LLMatrix4 Operators - -/* Not implemented to help enforce code consistency with the syntax of - row-major notation. This is a Good Thing. -LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b) -{ - // Operate "to the right" on column-vector b - LLVector4 vec; - vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + - a.mMatrix[VY][VX] * b.mV[VY] + - a.mMatrix[VZ][VX] * b.mV[VZ] + - a.mMatrix[VW][VX] * b.mV[VW]; - - vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] + - a.mMatrix[VY][VY] * b.mV[VY] + - a.mMatrix[VZ][VY] * b.mV[VZ] + - a.mMatrix[VW][VY] * b.mV[VW]; - - vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] + - a.mMatrix[VY][VZ] * b.mV[VY] + - a.mMatrix[VZ][VZ] * b.mV[VZ] + - a.mMatrix[VW][VZ] * b.mV[VW]; - - vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] + - a.mMatrix[VY][VW] * b.mV[VY] + - a.mMatrix[VZ][VW] * b.mV[VZ] + - a.mMatrix[VW][VW] * b.mV[VW]; - return vec; -} -*/ - -// Operates "to the left" on row-vector a -// -// This used to be in the header file but was not actually inlined in practice. -// When avatar vertex programs are off, this function is a hot spot in profiles -// due to software skinning in LLViewerJointMesh::updateGeometry(). JC -LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b) -{ - // This is better than making a temporary LLVector3. This eliminates an - // unnecessary LLVector3() constructor and also helps the compiler to - // realize that the output floats do not alias the input floats, hence - // eliminating redundant loads of a.mV[0], etc. JC - return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] + - a.mV[VY] * b.mMatrix[VY][VX] + - a.mV[VZ] * b.mMatrix[VZ][VX] + - 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] + - 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] + - b.mMatrix[VW][VZ]); -} - LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b) { // Operate "to the left" on row-vector a @@ -800,6 +773,23 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b) return FALSE; } +bool operator<(const LLMatrix4& a, const LLMatrix4 &b) +{ + U32 i, j; + for (i = 0; i < NUM_VALUES_IN_MAT4; i++) + { + for (j = 0; j < NUM_VALUES_IN_MAT4; j++) + { + if (a.mMatrix[i][j] != b.mMatrix[i][j]) + { + return a.mMatrix[i][j] < b.mMatrix[i][j]; + } + } + } + + return false; +} + const LLMatrix4& operator*=(LLMatrix4 &a, F32 k) { U32 i, j; @@ -839,4 +829,54 @@ std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a) 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] = data[0].asReal(); + mMatrix[0][1] = data[1].asReal(); + mMatrix[0][2] = data[2].asReal(); + mMatrix[0][3] = data[3].asReal(); + + mMatrix[1][0] = data[4].asReal(); + mMatrix[1][1] = data[5].asReal(); + mMatrix[1][2] = data[6].asReal(); + mMatrix[1][3] = data[7].asReal(); + + mMatrix[2][0] = data[8].asReal(); + mMatrix[2][1] = data[9].asReal(); + mMatrix[2][2] = data[10].asReal(); + mMatrix[2][3] = data[11].asReal(); + + mMatrix[3][0] = data[12].asReal(); + mMatrix[3][1] = data[13].asReal(); + mMatrix[3][2] = data[14].asReal(); + mMatrix[3][3] = data[15].asReal(); +} + diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index 58c9c09d7f..a7dce10397 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -2,31 +2,25 @@ * @file m4math.h * @brief LLMatrix4 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -125,6 +119,8 @@ public: ~LLMatrix4(void); // Destructor + LLSD getValue() const; + void setValue(const LLSD&); ////////////////////////////// // @@ -138,6 +134,7 @@ public: // various useful matrix functions const LLMatrix4& setIdentity(); // Load identity matrix + bool isIdentity() const; const LLMatrix4& setZero(); // Clears matrix to all zeros. const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z) @@ -159,6 +156,7 @@ public: const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos); // Set with Quaternion and position + const LLMatrix4& initScale(const LLVector3 &scale); // Set all const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos); @@ -225,17 +223,15 @@ public: // Operators // -// Not implemented to enforce code that agrees with symbolic syntax -// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b - -// friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b + // friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b - friend LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b + friend const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b); // Rotates a but does not translate friend LLVector3 rotate_vector(const LLVector3 &a, const LLMatrix4 &b); // Rotates a but does not translate friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b); // Return a == b friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b); // Return a != b + friend bool operator<(const LLMatrix4 &a, const LLMatrix4& b); // Return a < b friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b); // Return a + b friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b); // Return a - b @@ -269,6 +265,30 @@ inline const LLMatrix4& LLMatrix4::setIdentity() return (*this); } +inline bool LLMatrix4::isIdentity() const +{ + return + mMatrix[0][0] == 1.f && + mMatrix[0][1] == 0.f && + mMatrix[0][2] == 0.f && + mMatrix[0][3] == 0.f && + + mMatrix[1][0] == 0.f && + mMatrix[1][1] == 1.f && + mMatrix[1][2] == 0.f && + mMatrix[1][3] == 0.f && + + mMatrix[2][0] == 0.f && + mMatrix[2][1] == 0.f && + mMatrix[2][2] == 1.f && + 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; +} + /* inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b) @@ -353,7 +373,31 @@ inline const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b) return a; } -#endif - +// Operates "to the left" on row-vector a +// +// When avatar vertex programs are off, this function is a hot spot in profiles +// due to software skinning in LLViewerJointMesh::updateGeometry(). JC +inline const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b) +{ + // This is better than making a temporary LLVector3. This eliminates an + // unnecessary LLVector3() constructor and also helps the compiler to + // realize that the output floats do not alias the input floats, hence + // eliminating redundant loads of a.mV[0], etc. JC + return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] + + a.mV[VY] * b.mMatrix[VY][VX] + + a.mV[VZ] * b.mMatrix[VZ][VX] + + 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] + + 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] + + b.mMatrix[VW][VZ]); +} +#endif diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index a5eb0d2682..f38fe49bcb 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -2,31 +2,25 @@ * @file raytrace.cpp * @brief Functions called by box object scripts. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index b433e1769c..2d32af0c86 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -2,31 +2,25 @@ * @file raytrace.h * @brief Ray intersection tests for primitives. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/tests/llbbox_test.cpp b/indra/llmath/tests/llbbox_test.cpp new file mode 100644 index 0000000000..fd0dbb58fc --- /dev/null +++ b/indra/llmath/tests/llbbox_test.cpp @@ -0,0 +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<LLBBoxData> 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/llbboxlocal_test.cpp b/indra/llmath/tests/llbboxlocal_test.cpp new file mode 100644 index 0000000000..f31e4126c4 --- /dev/null +++ b/indra/llmath/tests/llbboxlocal_test.cpp @@ -0,0 +1,232 @@ +/** + * @file llbboxlocal_test.cpp + * @author Martin Reddy + * @date 2009-06-25 + * @brief Test for llbboxlocal.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 "../llbboxlocal.h" + +namespace tut +{ + struct LLBBoxLocalData + { + }; + + typedef test_group<LLBBoxLocalData> factory; + typedef factory::object object; +} + +namespace +{ + tut::factory llbboxlocal_test_factory("LLBBoxLocal"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + // + // test the default constructor + // + + LLBBoxLocal bbox1; + + ensure_equals("Default bbox min", bbox1.getMin(), LLVector3(0.0f, 0.0f, 0.0f)); + ensure_equals("Default bbox max", bbox1.getMax(), LLVector3(0.0f, 0.0f, 0.0f)); + } + + template<> template<> + void object::test<2>() + { + // + // test the non-default constructor + // + + LLBBoxLocal bbox2(LLVector3(-1.0f, -2.0f, 0.0f), LLVector3(1.0f, 2.0f, 3.0f)); + + ensure_equals("Custom bbox min", bbox2.getMin(), LLVector3(-1.0f, -2.0f, 0.0f)); + ensure_equals("Custom bbox max", bbox2.getMax(), LLVector3(1.0f, 2.0f, 3.0f)); + } + + template<> template<> + void object::test<3>() + { + // + // test the setMin() + // + // N.B. no validation is currently performed to ensure that the min + // and max vectors are actually the min/max values. + // + + LLBBoxLocal bbox2; + bbox2.setMin(LLVector3(1.0f, 2.0f, 3.0f)); + + ensure_equals("Custom bbox min (2)", bbox2.getMin(), LLVector3(1.0f, 2.0f, 3.0f)); + } + + template<> template<> + void object::test<4>() + { + // + // test the setMax() + // + // N.B. no validation is currently performed to ensure that the min + // and max vectors are actually the min/max values. + // + + LLBBoxLocal bbox2; + bbox2.setMax(LLVector3(10.0f, 20.0f, 30.0f)); + + ensure_equals("Custom bbox max (2)", bbox2.getMax(), LLVector3(10.0f, 20.0f, 30.0f)); + } + + template<> template<> + void object::test<5>() + { + // + // test the getCenter() method + // + + ensure_equals("Default bbox center", LLBBoxLocal().getCenter(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBoxLocal bbox1(LLVector3(-1.0f, -1.0f, -1.0f), LLVector3(0.0f, 0.0f, 0.0f)); + + ensure_equals("Custom bbox center", bbox1.getCenter(), LLVector3(-0.5f, -0.5f, -0.5f)); + + LLBBoxLocal bbox2(LLVector3(0.0f, 0.0f, 0.0f), LLVector3(-1.0f, -1.0f, -1.0f)); + + ensure_equals("Invalid bbox center", bbox2.getCenter(), LLVector3(-0.5f, -0.5f, -0.5f)); + } + + template<> template<> + void object::test<6>() + { + // + // test the getExtent() method + // + + LLBBoxLocal bbox2(LLVector3(0.0f, 0.0f, 0.0f), LLVector3(-1.0f, -1.0f, -1.0f)); + + ensure_equals("Default bbox extent", LLBBoxLocal().getExtent(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBoxLocal bbox3(LLVector3(-1.0f, -1.0f, -1.0f), LLVector3(1.0f, 2.0f, 0.0f)); + + ensure_equals("Custom bbox extent", bbox3.getExtent(), LLVector3(2.0f, 3.0f, 1.0f)); + } + + template<> template<> + void object::test<7>() + { + // + // test the addPoint() method + // + // N.B. if you create an empty bbox and then add points, + // the vector (0, 0, 0) will always be part of the bbox. + // (Fixing this would require adding a bool to the class size). + // + + LLBBoxLocal bbox1; + bbox1.addPoint(LLVector3(-1.0f, -2.0f, -3.0f)); + bbox1.addPoint(LLVector3(3.0f, 4.0f, 5.0f)); + + ensure_equals("Custom BBox center (1)", bbox1.getCenter(), LLVector3(1.0f, 1.0f, 1.0f)); + ensure_equals("Custom BBox min (1)", bbox1.getMin(), LLVector3(-1.0f, -2.0f, -3.0f)); + ensure_equals("Custom BBox max (1)", bbox1.getMax(), LLVector3(3.0f, 4.0f, 5.0f)); + + bbox1.addPoint(LLVector3(0.0f, 0.0f, 0.0f)); + bbox1.addPoint(LLVector3(1.0f, 2.0f, 3.0f)); + bbox1.addPoint(LLVector3(2.0f, 2.0f, 2.0f)); + + ensure_equals("Custom BBox center (2)", bbox1.getCenter(), LLVector3(1.0f, 1.0f, 1.0f)); + ensure_equals("Custom BBox min (2)", bbox1.getMin(), LLVector3(-1.0f, -2.0f, -3.0f)); + ensure_equals("Custom BBox max (2)", bbox1.getMax(), LLVector3(3.0f, 4.0f, 5.0f)); + + bbox1.addPoint(LLVector3(5.0f, 5.0f, 5.0f)); + + ensure_equals("Custom BBox center (3)", bbox1.getCenter(), LLVector3(2.0f, 1.5f, 1.0f)); + ensure_equals("Custom BBox min (3)", bbox1.getMin(), LLVector3(-1.0f, -2.0f, -3.0f)); + ensure_equals("Custom BBox max (3)", bbox1.getMax(), LLVector3(5.0f, 5.0f, 5.0f)); + } + + template<> template<> + void object::test<8>() + { + // + // test the addBBox() methods + // + // N.B. if you create an empty bbox and then add points, + // the vector (0, 0, 0) will always be part of the bbox. + // (Fixing this would require adding a bool to the class size). + // + + LLBBoxLocal bbox2(LLVector3(1.0f, 1.0f, 1.0f), LLVector3(2.0f, 2.0f, 2.0f)); + bbox2.addBBox(LLBBoxLocal(LLVector3(1.5f, 1.5f, 1.5f), LLVector3(3.0f, 3.0f, 3.0f))); + + ensure_equals("Custom BBox center (4)", bbox2.getCenter(), LLVector3(2.0f, 2.0f, 2.0f)); + ensure_equals("Custom BBox min (4)", bbox2.getMin(), LLVector3(1.0f, 1.0f, 1.0f)); + ensure_equals("Custom BBox max (4)", bbox2.getMax(), LLVector3(3.0f, 3.0f, 3.0f)); + + bbox2.addBBox(LLBBoxLocal(LLVector3(-1.0f, -1.0f, -1.0f), LLVector3(0.0f, 0.0f, 0.0f))); + + ensure_equals("Custom BBox center (5)", bbox2.getCenter(), LLVector3(1.0f, 1.0f, 1.0f)); + ensure_equals("Custom BBox min (5)", bbox2.getMin(), LLVector3(-1.0f, -1.0f, -1.0f)); + ensure_equals("Custom BBox max (5)", bbox2.getMax(), LLVector3(3.0f, 3.0f, 3.0f)); + } + + template<> template<> + void object::test<9>() + { + // + // test the expand() method + // + + LLBBoxLocal bbox1; + bbox1.expand(0.0f); + + ensure_equals("Zero-expanded Default BBox center", bbox1.getCenter(), LLVector3(0.0f, 0.0f, 0.0f)); + + LLBBoxLocal bbox2(LLVector3(1.0f, 2.0f, 3.0f), LLVector3(3.0f, 4.0f, 5.0f)); + bbox2.expand(0.0f); + + ensure_equals("Zero-expanded BBox center", bbox2.getCenter(), LLVector3(2.0f, 3.0f, 4.0f)); + ensure_equals("Zero-expanded BBox min", bbox2.getMin(), LLVector3(1.0f, 2.0f, 3.0f)); + ensure_equals("Zero-expanded BBox max", bbox2.getMax(), LLVector3(3.0f, 4.0f, 5.0f)); + + bbox2.expand(0.5f); + + ensure_equals("Positive-expanded BBox center", bbox2.getCenter(), LLVector3(2.0f, 3.0f, 4.0f)); + ensure_equals("Positive-expanded BBox min", bbox2.getMin(), LLVector3(0.5f, 1.5f, 2.5f)); + ensure_equals("Positive-expanded BBox max", bbox2.getMax(), LLVector3(3.5f, 4.5f, 5.5f)); + + bbox2.expand(-1.0f); + + ensure_equals("Negative-expanded BBox center", bbox2.getCenter(), LLVector3(2.0f, 3.0f, 4.0f)); + ensure_equals("Negative-expanded BBox min", bbox2.getMin(), LLVector3(1.5f, 2.5f, 3.5f)); + ensure_equals("Negative-expanded BBox max", bbox2.getMax(), LLVector3(2.5f, 3.5f, 4.5f)); + } +} diff --git a/indra/llmath/tests/llmodularmath_test.cpp b/indra/llmath/tests/llmodularmath_test.cpp new file mode 100644 index 0000000000..063d3ef79f --- /dev/null +++ b/indra/llmath/tests/llmodularmath_test.cpp @@ -0,0 +1,76 @@ +/** + * @file modularmath_test.cpp + * @author babbage + * @date 2008-09 + * @brief llmodularmath tests + * + * $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 "../llmodularmath.h" + +#include "../test/lltut.h" + +namespace tut +{ + struct modularmath_data + { + }; + typedef test_group<modularmath_data> modularmath_test; + typedef modularmath_test::object modularmath_object; + tut::modularmath_test modularmath_testcase("LLModularMath"); + + template<> template<> + void modularmath_object::test<1>() + { + // lhs < rhs + const U32 lhs = 0x000001; + const U32 rhs = 0xFFFFFF; + const U32 width = 24; + U32 result = LLModularMath::subtract<width>(lhs, rhs); + ensure_equals("diff(0x000001, 0xFFFFFF, 24)", result, 2); + } + + template<> template<> + void modularmath_object::test<2>() + { + // lhs > rhs + const U32 lhs = 0x000002; + const U32 rhs = 0x000001; + const U32 width = 24; + U32 result = LLModularMath::subtract<width>(lhs, rhs); + ensure_equals("diff(0x000002, 0x000001, 24)", result, 1); + } + + template<> template<> + void modularmath_object::test<3>() + { + // lhs == rhs + const U32 lhs = 0xABCDEF; + const U32 rhs = 0xABCDEF; + const U32 width = 24; + U32 result = LLModularMath::subtract<width>(lhs, rhs); + ensure_equals("diff(0xABCDEF, 0xABCDEF, 24)", result, 0); + } +} diff --git a/indra/llmath/tests/llquaternion_test.cpp b/indra/llmath/tests/llquaternion_test.cpp new file mode 100644 index 0000000000..e69010b2d6 --- /dev/null +++ b/indra/llmath/tests/llquaternion_test.cpp @@ -0,0 +1,660 @@ +/** + * @file llquaternion_test.cpp + * @author Adroit + * @date 2007-03 + * @brief Test cases of llquaternion.h + * + * $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 "../v4math.h" +#include "../v3math.h" +#include "../v3dmath.h" +#include "../m4math.h" +#include "../m3math.h" +#include "../llquaternion.h" + +namespace tut +{ + struct llquat_test + { + }; + typedef test_group<llquat_test> llquat_test_t; + typedef llquat_test_t::object llquat_test_object_t; + tut::llquat_test_t tut_llquat_test("LLQuaternion"); + + //test case for LLQuaternion::LLQuaternion(void) fn. + template<> template<> + void llquat_test_object_t::test<1>() + { + LLQuaternion llquat; + ensure("LLQuaternion::LLQuaternion() failed", 0.f == llquat.mQ[0] && + 0.f == llquat.mQ[1] && + 0.f == llquat.mQ[2] && + 1.f == llquat.mQ[3]); + } + + //test case for explicit LLQuaternion(const LLMatrix4 &mat) fn. + template<> template<> + void llquat_test_object_t::test<2>() + { + LLMatrix4 llmat; + LLVector4 vector1(2.0f, 1.0f, 3.0f, 6.0f); + LLVector4 vector2(5.0f, 6.0f, 0.0f, 1.0f); + LLVector4 vector3(2.0f, 1.0f, 2.0f, 9.0f); + LLVector4 vector4(3.0f, 8.0f, 1.0f, 5.0f); + + llmat.initRows(vector1, vector2, vector3, vector4); + ensure("explicit LLQuaternion(const LLMatrix4 &mat) failed", 2.0f == llmat.mMatrix[0][0] && + 1.0f == llmat.mMatrix[0][1] && + 3.0f == llmat.mMatrix[0][2] && + 6.0f == llmat.mMatrix[0][3] && + 5.0f == llmat.mMatrix[1][0] && + 6.0f == llmat.mMatrix[1][1] && + 0.0f == llmat.mMatrix[1][2] && + 1.0f == llmat.mMatrix[1][3] && + 2.0f == llmat.mMatrix[2][0] && + 1.0f == llmat.mMatrix[2][1] && + 2.0f == llmat.mMatrix[2][2] && + 9.0f == llmat.mMatrix[2][3] && + 3.0f == llmat.mMatrix[3][0] && + 8.0f == llmat.mMatrix[3][1] && + 1.0f == llmat.mMatrix[3][2] && + 5.0f == llmat.mMatrix[3][3]); + } + + template<> template<> + void llquat_test_object_t::test<3>() + { + LLMatrix3 llmat; + + LLVector3 vect1(3.4028234660000000f , 234.56f, 4234.442234f); + LLVector3 vect2(741.434f, 23.00034f, 6567.223423f); + LLVector3 vect3(566.003034f, 12.98705f, 234.764423f); + llmat.setRows(vect1, vect2, vect3); + + ensure("LLMatrix3::setRows fn failed.", 3.4028234660000000f == llmat.mMatrix[0][0] && + 234.56f == llmat.mMatrix[0][1] && + 4234.442234f == llmat.mMatrix[0][2] && + 741.434f == llmat.mMatrix[1][0] && + 23.00034f == llmat.mMatrix[1][1] && + 6567.223423f == llmat.mMatrix[1][2] && + 566.003034f == llmat.mMatrix[2][0] && + 12.98705f == llmat.mMatrix[2][1] && + 234.764423f == llmat.mMatrix[2][2]); + } + + //test case for LLQuaternion(F32 x, F32 y, F32 z, F32 w), setQuatInit() and normQuat() fns. + template<> template<> + void llquat_test_object_t::test<4>() + { + F32 x_val = 3.0f; + F32 y_val = 2.0f; + F32 z_val = 6.0f; + F32 w_val = 1.0f; + + LLQuaternion res_quat; + res_quat.setQuatInit(x_val, y_val, z_val, w_val); + res_quat.normQuat(); + + ensure("LLQuaternion::normQuat() fn failed", + is_approx_equal(0.42426407f, res_quat.mQ[0]) && + is_approx_equal(0.28284273f, res_quat.mQ[1]) && + is_approx_equal(0.84852815f, res_quat.mQ[2]) && + is_approx_equal(0.14142136f, res_quat.mQ[3])); + + x_val = 0.0f; + y_val = 0.0f; + z_val = 0.0f; + w_val = 0.0f; + + res_quat.setQuatInit(x_val, y_val, z_val, w_val); + res_quat.normQuat(); + + ensure("LLQuaternion::normQuat() fn. failed.", + is_approx_equal(0.0f, res_quat.mQ[0]) && + is_approx_equal(0.0f, res_quat.mQ[1]) && + is_approx_equal(0.0f, res_quat.mQ[2]) && + is_approx_equal(1.0f, res_quat.mQ[3])); + + + ensure("LLQuaternion::normQuat() fn. failed.", + is_approx_equal(0.0f, res_quat.mQ[0]) && + is_approx_equal(0.0f, res_quat.mQ[1]) && + is_approx_equal(0.0f, res_quat.mQ[2]) && + is_approx_equal(1.0f, res_quat.mQ[3])); + } + + //test case for conjQuat() and transQuat() fns. + template<> template<> + void llquat_test_object_t::test<5>() + { + F32 x_val = 3.0f; + F32 y_val = 2.0f; + F32 z_val = 6.0f; + F32 w_val = 1.0f; + + LLQuaternion res_quat; + LLQuaternion result, result1; + result1 = result = res_quat.setQuatInit(x_val, y_val, z_val, w_val); + + result.conjQuat(); + result1.transQuat(); + + ensure("LLQuaternion::conjQuat and LLQuaternion::transQuat failed ", + is_approx_equal(result1.mQ[0], result.mQ[0]) && + is_approx_equal(result1.mQ[1], result.mQ[1]) && + is_approx_equal(result1.mQ[2], result.mQ[2])); + + } + + //test case for dot(const LLQuaternion &a, const LLQuaternion &b) fn. + template<> template<> + void llquat_test_object_t::test<6>() + { + LLQuaternion quat1(3.0f, 2.0f, 6.0f, 0.0f), quat2(1.0f, 1.0f, 1.0f, 1.0f); + ensure("1. The two values are different", llround(12.000000f, 2) == llround(dot(quat1, quat2), 2)); + + LLQuaternion quat0(3.0f, 9.334f, 34.5f, 23.0f), quat(34.5f, 23.23f, 2.0f, 45.5f); + ensure("2. The two values are different", llround(1435.828807f, 2) == llround(dot(quat0, quat), 2)); + } + + //test case for LLQuaternion &LLQuaternion::constrain(F32 radians) fn. + template<> template<> + void llquat_test_object_t::test<7>() + { + F32 radian = 60.0f; + LLQuaternion quat(3.0f, 2.0f, 6.0f, 0.0f); + LLQuaternion quat1; + quat1 = quat.constrain(radian); + ensure("1. LLQuaternion::constrain(F32 radians) failed", + is_approx_equal_fraction(-0.423442f, quat1.mQ[0], 8) && + is_approx_equal_fraction(-0.282295f, quat1.mQ[1], 8) && + is_approx_equal_fraction(-0.846884f, quat1.mQ[2], 8) && + is_approx_equal_fraction(0.154251f, quat1.mQ[3], 8)); + + + radian = 30.0f; + LLQuaternion quat0(37.50f, 12.0f, 86.023f, 40.32f); + quat1 = quat0.constrain(radian); + + ensure("2. LLQuaternion::constrain(F32 radians) failed", + is_approx_equal_fraction(37.500000f, quat1.mQ[0], 8) && + is_approx_equal_fraction(12.0000f, quat1.mQ[1], 8) && + is_approx_equal_fraction(86.0230f, quat1.mQ[2], 8) && + is_approx_equal_fraction(40.320000f, quat1.mQ[3], 8)); + } + + template<> template<> + void llquat_test_object_t::test<8>() + { + F32 value1 = 15.0f; + LLQuaternion quat1(1.0f, 2.0f, 4.0f, 1.0f); + LLQuaternion quat2(4.0f, 3.0f, 6.5f, 9.7f); + LLQuaternion res_lerp, res_slerp, res_nlerp; + + //test case for lerp(F32 t, const LLQuaternion &q) fn. + res_lerp = lerp(value1, quat1); + ensure("1. LLQuaternion lerp(F32 t, const LLQuaternion &q) failed", + is_approx_equal_fraction(0.181355f, res_lerp.mQ[0], 16) && + is_approx_equal_fraction(0.362711f, res_lerp.mQ[1], 16) && + is_approx_equal_fraction(0.725423f, res_lerp.mQ[2], 16) && + is_approx_equal_fraction(0.556158f, res_lerp.mQ[3], 16)); + + //test case for lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q) fn. + res_lerp = lerp(value1, quat1, quat2); + ensure("2. LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q) failed", + is_approx_equal_fraction(0.314306f, res_lerp.mQ[0], 16) && + is_approx_equal_fraction(0.116156f, res_lerp.mQ[1], 16) && + is_approx_equal_fraction(0.283559f, res_lerp.mQ[2], 16) && + is_approx_equal_fraction(0.898506f, res_lerp.mQ[3], 16)); + + //test case for slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b ) fn. + res_slerp = slerp(value1, quat1, quat2); + ensure("3. LLQuaternion slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b) failed", + is_approx_equal_fraction(46.000f, res_slerp.mQ[0], 16) && + is_approx_equal_fraction(17.00f, res_slerp.mQ[1], 16) && + is_approx_equal_fraction(41.5f, res_slerp.mQ[2], 16) && + is_approx_equal_fraction(131.5f, res_slerp.mQ[3], 16)); + + //test case for nlerp(F32 t, const LLQuaternion &a, const LLQuaternion &b) fn. + res_nlerp = nlerp(value1, quat1, quat2); + ensure("4. LLQuaternion nlerp(F32 t, const LLQuaternion &a, const LLQuaternion &b) failed", + is_approx_equal_fraction(0.314306f, res_nlerp.mQ[0], 16) && + is_approx_equal_fraction(0.116157f, res_nlerp.mQ[1], 16) && + is_approx_equal_fraction(0.283559f, res_nlerp.mQ[2], 16) && + is_approx_equal_fraction(0.898506f, res_nlerp.mQ[3], 16)); + + //test case for nlerp(F32 t, const LLQuaternion &q) fn. + res_slerp = slerp(value1, quat1); + ensure("5. LLQuaternion slerp(F32 t, const LLQuaternion &q) failed", + is_approx_equal_fraction(1.0f, res_slerp.mQ[0], 16) && + is_approx_equal_fraction(2.0f, res_slerp.mQ[1], 16) && + is_approx_equal_fraction(4.0000f, res_slerp.mQ[2], 16) && + is_approx_equal_fraction(1.000f, res_slerp.mQ[3], 16)); + + LLQuaternion quat3(2.0f, 1.0f, 5.5f, 10.5f); + LLQuaternion res_nlerp1; + value1 = 100.0f; + res_nlerp1 = nlerp(value1, quat3); + ensure("6. LLQuaternion nlerp(F32 t, const LLQuaternion &q) failed", + is_approx_equal_fraction(0.268245f, res_nlerp1.mQ[0], 16) && is_approx_equal_fraction(0.134122f, res_nlerp1.mQ[1], 2) && + is_approx_equal_fraction(0.737673f, res_nlerp1.mQ[2], 16) && + is_approx_equal_fraction(0.604892f, res_nlerp1.mQ[3], 16)); + + //test case for lerp(F32 t, const LLQuaternion &q) fn. + res_lerp = lerp(value1, quat2); + ensure("7. LLQuaternion lerp(F32 t, const LLQuaternion &q) failed", + is_approx_equal_fraction(0.404867f, res_lerp.mQ[0], 16) && + is_approx_equal_fraction(0.303650f, res_lerp.mQ[1], 16) && + is_approx_equal_fraction(0.657909f, res_lerp.mQ[2], 16) && + is_approx_equal_fraction(0.557704f, res_lerp.mQ[3], 16)); + + } + + template<> template<> + void llquat_test_object_t::test<9>() + { + //test case for LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b) fn + LLQuaternion quat1(1.0f, 2.5f, 3.5f, 5.5f); + LLQuaternion quat2(4.0f, 3.0f, 5.0f, 1.0f); + LLQuaternion result = quat1 * quat2; + ensure("1. LLQuaternion Operator* failed", (21.0f == result.mQ[0]) && + (10.0f == result.mQ[1]) && + (38.0f == result.mQ[2]) && + (-23.5f == result.mQ[3])); + + LLQuaternion quat3(2341.340f, 2352.345f, 233.25f, 7645.5f); + LLQuaternion quat4(674.067f, 893.0897f, 578.0f, 231.0f); + result = quat3 * quat4; + ensure("2. LLQuaternion Operator* failed", (4543086.5f == result.mQ[0]) && + (8567578.0f == result.mQ[1]) && + (3967591.25f == result.mQ[2]) && + is_approx_equal(-2047783.25f, result.mQ[3])); + + //inline LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b)fn. + result = quat1 + quat2; + ensure("3. LLQuaternion operator+ failed", (5.0f == result.mQ[0]) && + (5.5f == result.mQ[1]) && + (8.5f == result.mQ[2]) && + (6.5f == result.mQ[3])); + + result = quat3 + quat4; + ensure( + "4. LLQuaternion operator+ failed", + is_approx_equal(3015.407227f, result.mQ[0]) && + is_approx_equal(3245.434570f, result.mQ[1]) && + (811.25f == result.mQ[2]) && + (7876.5f == result.mQ[3])); + + //inline LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b) fn + result = quat1 - quat2; + ensure( + "5. LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b) failed", + (-3.0f == result.mQ[0]) && + (-0.5f == result.mQ[1]) && + (-1.5f == result.mQ[2]) && + (4.5f == result.mQ[3])); + + result = quat3 - quat4; + ensure( + "6. LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b) failed", + is_approx_equal(1667.273071f, result.mQ[0]) && + is_approx_equal(1459.255249f, result.mQ[1]) && + (-344.75f == result.mQ[2]) && + (7414.50f == result.mQ[3])); + } + + //test case for LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) fn. + template<> template<> + void llquat_test_object_t::test<10>() + { + LLVector4 vect(12.0f, 5.0f, 60.0f, 75.1f); + LLQuaternion quat(2323.034f, 23.5f, 673.23f, 57667.5f); + LLVector4 result = vect * quat; + ensure( + "1. LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) failed", + is_approx_equal(39928406016.0f, result.mV[0]) && + // gcc on x86 actually gives us more precision than we were expecting, verified with -ffloat-store - we forgive this + (1457802240.0f >= result.mV[1]) && // gcc+x86+linux + (1457800960.0f <= result.mV[1]) && // elsewhere + is_approx_equal(200580612096.0f, result.mV[2]) && + (75.099998f == result.mV[3])); + + LLVector4 vect1(22.0f, 45.0f, 40.0f, 78.1f); + LLQuaternion quat1(2.034f, 45.5f, 37.23f, 7.5f); + result = vect1 * quat1; + ensure( + "2. LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) failed", + is_approx_equal(-58153.5390f, result.mV[0]) && + (183787.8125f == result.mV[1]) && + (116864.164063f == result.mV[2]) && + (78.099998f == result.mV[3])); + } + + //test case for LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) fn. + template<> template<> + void llquat_test_object_t::test<11>() + { + LLVector3 vect(12.0f, 5.0f, 60.0f); + LLQuaternion quat(23.5f, 6.5f, 3.23f, 56.5f); + LLVector3 result = vect * quat; + ensure( + "1. LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) failed", + is_approx_equal(97182.953125f,result.mV[0]) && + is_approx_equal(-135405.640625f, result.mV[1]) && + is_approx_equal(162986.140f, result.mV[2])); + + LLVector3 vect1(5.0f, 40.0f, 78.1f); + LLQuaternion quat1(2.034f, 45.5f, 37.23f, 7.5f); + result = vect1 * quat1; + ensure( + "2. LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) failed", + is_approx_equal(33217.703f, result.mV[0]) && + is_approx_equal(295383.8125f, result.mV[1]) && + is_approx_equal(84718.140f, result.mV[2])); + } + + //test case for LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot) fn. + template<> template<> + void llquat_test_object_t::test<12>() + { + LLVector3d vect(-2.0f, 5.0f, -6.0f); + LLQuaternion quat(-3.5f, 4.5f, 3.5f, 6.5f); + LLVector3d result = vect * quat; + ensure( + "1. LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot) failed ", + (-633.0f == result.mdV[0]) && + (-300.0f == result.mdV[1]) && + (-36.0f == result.mdV[2])); + + LLVector3d vect1(5.0f, -4.5f, 8.21f); + LLQuaternion quat1(2.0f, 4.5f, -7.2f, 9.5f); + result = vect1 * quat1; + ensure( + "2. LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot) failed", + is_approx_equal_fraction(-120.29f, (F32) result.mdV[0], 8) && + is_approx_equal_fraction(-1683.958f, (F32) result.mdV[1], 8) && + is_approx_equal_fraction(516.56f, (F32) result.mdV[2], 8)); + + LLVector3d vect2(2.0f, 3.5f, 1.1f); + LLQuaternion quat2(1.0f, 4.0f, 2.0f, 5.0f); + result = vect2 * quat2; + ensure( + "3. LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot) failed", + is_approx_equal_fraction(18.400001f, (F32) result.mdV[0], 8) && + is_approx_equal_fraction(188.6f, (F32) result.mdV[1], 8) && + is_approx_equal_fraction(32.20f, (F32) result.mdV[2], 8)); + } + + //test case for inline LLQuaternion operator-(const LLQuaternion &a) fn. + template<> template<> + void llquat_test_object_t::test<13>() + { + LLQuaternion quat(23.5f, 34.5f, 16723.4f, 324.7f); + LLQuaternion result = -quat; + ensure( + "1. LLQuaternion operator-(const LLQuaternion &a) failed", + (-23.5f == result.mQ[0]) && + (-34.5f == result.mQ[1]) && + (-16723.4f == result.mQ[2]) && + (-324.7f == result.mQ[3])); + + LLQuaternion quat1(-3.5f, -34.5f, -16.4f, -154.7f); + result = -quat1; + ensure( + "2. LLQuaternion operator-(const LLQuaternion &a) failed.", + (3.5f == result.mQ[0]) && + (34.5f == result.mQ[1]) && + (16.4f == result.mQ[2]) && + (154.7f == result.mQ[3])); + } + + //test case for inline LLQuaternion operator*(F32 a, const LLQuaternion &q) and + //inline LLQuaternion operator*(F32 a, const LLQuaternion &q) fns. + template<> template<> + void llquat_test_object_t::test<14>() + { + LLQuaternion quat_value(9.0f, 8.0f, 7.0f, 6.0f); + F32 a =3.5f; + LLQuaternion result = a * quat_value; + LLQuaternion result1 = quat_value * a; + + ensure( + "1. LLQuaternion operator* failed", + (result.mQ[0] == result1.mQ[0]) && + (result.mQ[1] == result1.mQ[1]) && + (result.mQ[2] == result1.mQ[2]) && + (result.mQ[3] == result1.mQ[3])); + + + LLQuaternion quat_val(9454.0f, 43568.3450f, 456343247.0343f, 2346.03434f); + a =-3324.3445f; + result = a * quat_val; + result1 = quat_val * a; + + ensure( + "2. LLQuaternion operator* failed", + (result.mQ[0] == result1.mQ[0]) && + (result.mQ[1] == result1.mQ[1]) && + (result.mQ[2] == result1.mQ[2]) && + (result.mQ[3] == result1.mQ[3])); + } + + template<> template<> + void llquat_test_object_t::test<15>() + { + // test cases for inline LLQuaternion operator~(const LLQuaternion &a) + LLQuaternion quat_val(2323.634f, -43535.4f, 3455.88f, -32232.45f); + LLQuaternion result = ~quat_val; + ensure( + "1. LLQuaternion operator~(const LLQuaternion &a) failed ", + (-2323.634f == result.mQ[0]) && + (43535.4f == result.mQ[1]) && + (-3455.88f == result.mQ[2]) && + (-32232.45f == result.mQ[3])); + + //test case for inline bool LLQuaternion::operator==(const LLQuaternion &b) const + LLQuaternion quat_val1(2323.634f, -43535.4f, 3455.88f, -32232.45f); + LLQuaternion quat_val2(2323.634f, -43535.4f, 3455.88f, -32232.45f); + ensure( + "2. LLQuaternion::operator==(const LLQuaternion &b) failed", + quat_val1 == quat_val2); + } + + template<> template<> + void llquat_test_object_t::test<16>() + { + //test case for inline bool LLQuaternion::operator!=(const LLQuaternion &b) const + LLQuaternion quat_val1(2323.634f, -43535.4f, 3455.88f, -32232.45f); + LLQuaternion quat_val2(0, -43535.4f, 3455.88f, -32232.45f); + ensure("LLQuaternion::operator!=(const LLQuaternion &b) failed", quat_val1 != quat_val2); + } + + template<> template<> + void llquat_test_object_t::test<17>() + { + //test case for LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) + F32 x = 2.0f; + F32 y = 1.0f; + F32 z = 3.0f; + + LLQuaternion result = mayaQ(x, y, z, LLQuaternion::XYZ); + ensure( + "1. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for XYZ", + is_approx_equal_fraction(0.0172174f, result.mQ[0], 16) && + is_approx_equal_fraction(0.009179f, result.mQ[1], 16) && + is_approx_equal_fraction(0.026020f, result.mQ[2], 16) && + is_approx_equal_fraction(0.999471f, result.mQ[3], 16)); + + LLQuaternion result1 = mayaQ(x, y, z, LLQuaternion::YZX); + ensure( + "2. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for XYZ", + is_approx_equal_fraction(0.017217f, result1.mQ[0], 16) && + is_approx_equal_fraction(0.008265f, result1.mQ[1], 16) && + is_approx_equal_fraction(0.026324f, result1.mQ[2], 16) && + is_approx_equal_fraction(0.999471f, result1.mQ[3], 16)); + + LLQuaternion result2 = mayaQ(x, y, z, LLQuaternion::ZXY); + ensure( + "3. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for ZXY", + is_approx_equal_fraction(0.017674f, result2.mQ[0], 16) && + is_approx_equal_fraction(0.008265f, result2.mQ[1], 16) && + is_approx_equal_fraction(0.026020f, result2.mQ[2], 16) && + is_approx_equal_fraction(0.999471f, result2.mQ[3], 16)); + + LLQuaternion result3 = mayaQ(x, y, z, LLQuaternion::XZY); + ensure( + "4. TLLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for XZY", + is_approx_equal_fraction(0.017674f, result3.mQ[0], 16) && + is_approx_equal_fraction(0.009179f, result3.mQ[1], 16) && + is_approx_equal_fraction(0.026020f, result3.mQ[2], 16) && + is_approx_equal_fraction(0.999463f, result3.mQ[3], 16)); + + LLQuaternion result4 = mayaQ(x, y, z, LLQuaternion::YXZ); + ensure( + "5. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for YXZ", + is_approx_equal_fraction(0.017217f, result4.mQ[0], 16) && + is_approx_equal_fraction(0.009179f, result4.mQ[1], 16) && + is_approx_equal_fraction(0.026324f, result4.mQ[2], 16) && + is_approx_equal_fraction(0.999463f, result4.mQ[3], 16)); + + LLQuaternion result5 = mayaQ(x, y, z, LLQuaternion::ZYX); + ensure( + "6. LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order) failed for ZYX", + is_approx_equal_fraction(0.017674f, result5.mQ[0], 16) && + is_approx_equal_fraction(0.008265f, result5.mQ[1], 16) && + is_approx_equal_fraction(0.026324f, result5.mQ[2], 16) && + is_approx_equal_fraction(0.999463f, result5.mQ[3], 16)); + } + + template<> template<> + void llquat_test_object_t::test<18>() + { + // test case for friend std::ostream& operator<<(std::ostream &s, const LLQuaternion &a) fn + LLQuaternion a(1.0f, 1.0f, 1.0f, 1.0f); + std::ostringstream result_value; + result_value << a; + ensure_equals("1. Operator << failed", result_value.str(), "{ 1, 1, 1, 1 }"); + + LLQuaternion b(-31.034f, 231.2340f, 3451.344320f, -341.0f); + std::ostringstream result_value1; + result_value1 << b; + ensure_equals("2. Operator << failed", result_value1.str(), "{ -31.034, 231.234, 3451.34, -341 }"); + + LLQuaternion c(1.0f, 2.2f, 3.3f, 4.4f); + result_value << c; + ensure_equals("3. Operator << failed", result_value.str(), "{ 1, 1, 1, 1 }{ 1, 2.2, 3.3, 4.4 }"); + + } + + template<> template<> + void llquat_test_object_t::test<19>() + { + //test case for const char *OrderToString( const LLQuaternion::Order order ) fn + const char* result = OrderToString(LLQuaternion::XYZ); + ensure("1. OrderToString failed for XYZ", (0 == strcmp("XYZ", result))); + + result = OrderToString(LLQuaternion::YZX); + ensure("2. OrderToString failed for YZX", (0 == strcmp("YZX", result))); + + result = OrderToString(LLQuaternion::ZXY); + ensure( + "3. OrderToString failed for ZXY", + (0 == strcmp("ZXY", result)) && + (0 != strcmp("XYZ", result)) && + (0 != strcmp("YXZ", result)) && + (0 != strcmp("ZYX", result)) && + (0 != strcmp("XYZ", result))); + + result = OrderToString(LLQuaternion::XZY); + ensure("4. OrderToString failed for XZY", (0 == strcmp("XZY", result))); + + result = OrderToString(LLQuaternion::ZYX); + ensure("5. OrderToString failed for ZYX", (0 == strcmp("ZYX", result))); + + result = OrderToString(LLQuaternion::YXZ); + ensure("6.OrderToString failed for YXZ", (0 == strcmp("YXZ", result))); + } + + template<> template<> + void llquat_test_object_t::test<20>() + { + //test case for LLQuaternion::Order StringToOrder( const char *str ) fn + int result = StringToOrder("XYZ"); + ensure("1. LLQuaternion::Order StringToOrder(const char *str ) failed for XYZ", 0 == result); + + result = StringToOrder("YZX"); + ensure("2. LLQuaternion::Order StringToOrder(const char *str) failed for YZX", 1 == result); + + result = StringToOrder("ZXY"); + ensure("3. LLQuaternion::Order StringToOrder(const char *str) failed for ZXY", 2 == result); + + result = StringToOrder("XZY"); + ensure("4. LLQuaternion::Order StringToOrder(const char *str) failed for XZY", 3 == result); + + result = StringToOrder("YXZ"); + ensure("5. LLQuaternion::Order StringToOrder(const char *str) failed for YXZ", 4 == result); + + result = StringToOrder("ZYX"); + ensure("6. LLQuaternion::Order StringToOrder(const char *str) failed for ZYX", 5 == result); + + } + + template<> template<> + void llquat_test_object_t::test<21>() + { + //void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const fn + F32 angle_value = 90.0f; + LLVector3 vect(12.0f, 4.0f, 1.0f); + LLQuaternion llquat(angle_value, vect); + llquat.getAngleAxis(&angle_value, vect); + ensure( + "LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) failed", + is_approx_equal_fraction(2.035406f, angle_value, 16) && + is_approx_equal_fraction(0.315244f, vect.mV[1], 16) && + is_approx_equal_fraction(0.078811f, vect.mV[2], 16) && + is_approx_equal_fraction(0.945733f, vect.mV[0], 16)); + } + + template<> template<> + void llquat_test_object_t::test<22>() + { + //test case for void LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const fn + F32 roll = -12.0f; + F32 pitch = -22.43f; + F32 yaw = 11.0f; + + LLQuaternion llquat; + llquat.getEulerAngles(&roll, &pitch, &yaw); + ensure( + "LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) failed", + is_approx_equal(0.000f, llquat.mQ[0]) && + is_approx_equal(0.000f, llquat.mQ[1]) && + is_approx_equal(0.000f, llquat.mQ[2]) && + is_approx_equal(1.000f, llquat.mQ[3])); + } + +} diff --git a/indra/llmath/tests/llrect_test.cpp b/indra/llmath/tests/llrect_test.cpp new file mode 100644 index 0000000000..d740173e69 --- /dev/null +++ b/indra/llmath/tests/llrect_test.cpp @@ -0,0 +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<LLRectData> 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/m3math_test.cpp b/indra/llmath/tests/m3math_test.cpp new file mode 100644 index 0000000000..1ca2b005d9 --- /dev/null +++ b/indra/llmath/tests/m3math_test.cpp @@ -0,0 +1,332 @@ +/** + * @file m3math_test.cpp + * @author Adroit + * @date 2007-03 + * @brief Test cases of m3math.h + * + * $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 "../m3math.h" +#include "../v3math.h" +#include "../v4math.h" +#include "../m4math.h" +#include "../llquaternion.h" +#include "../v3dmath.h" + +#include "../test/lltut.h" + +#if LL_WINDOWS +// disable unreachable code warnings caused by usage of skip. +#pragma warning(disable: 4702) +#endif + +#if LL_WINDOWS +// disable unreachable code warnings caused by usage of skip. +#pragma warning(disable: 4702) +#endif + +namespace tut +{ + struct m3math_test + { + }; + typedef test_group<m3math_test> m3math_test_t; + typedef m3math_test_t::object m3math_test_object_t; + tut::m3math_test_t tut_m3math_test("m3math_h"); + + //test case for setIdentity() fn. + template<> template<> + void m3math_test_object_t::test<1>() + { + LLMatrix3 llmat3_obj; + llmat3_obj.setIdentity(); + ensure("LLMatrix3::setIdentity failed", 1.f == llmat3_obj.mMatrix[0][0] && + 0.f == llmat3_obj.mMatrix[0][1] && + 0.f == llmat3_obj.mMatrix[0][2] && + 0.f == llmat3_obj.mMatrix[1][0] && + 1.f == llmat3_obj.mMatrix[1][1] && + 0.f == llmat3_obj.mMatrix[1][2] && + 0.f == llmat3_obj.mMatrix[2][0] && + 0.f == llmat3_obj.mMatrix[2][1] && + 1.f == llmat3_obj.mMatrix[2][2]); + } + + //test case for LLMatrix3& setZero() fn. + template<> template<> + void m3math_test_object_t::test<2>() + { + LLMatrix3 llmat3_obj(30, 1, 2, 3); + llmat3_obj.setZero(); + + ensure("LLMatrix3::setZero failed", 0.f == llmat3_obj.setZero().mMatrix[0][0] && + 0.f == llmat3_obj.setZero().mMatrix[0][1] && + 0.f == llmat3_obj.setZero().mMatrix[0][2] && + 0.f == llmat3_obj.setZero().mMatrix[1][0] && + 0.f == llmat3_obj.setZero().mMatrix[1][1] && + 0.f == llmat3_obj.setZero().mMatrix[1][2] && + 0.f == llmat3_obj.setZero().mMatrix[2][0] && + 0.f == llmat3_obj.setZero().mMatrix[2][1] && + 0.f == llmat3_obj.setZero().mMatrix[2][2]); + } + + //test case for setRows(const LLVector3 &x_axis, const LLVector3 &y_axis, const LLVector3 &z_axis) fns. + template<> template<> + void m3math_test_object_t::test<3>() + { + LLMatrix3 llmat3_obj; + LLVector3 vect1(2, 1, 4); + LLVector3 vect2(3, 5, 7); + LLVector3 vect3(6, 9, 7); + llmat3_obj.setRows(vect1, vect2, vect3); + ensure("LLVector3::setRows failed ", 2 == llmat3_obj.mMatrix[0][0] && + 1 == llmat3_obj.mMatrix[0][1] && + 4 == llmat3_obj.mMatrix[0][2] && + 3 == llmat3_obj.mMatrix[1][0] && + 5 == llmat3_obj.mMatrix[1][1] && + 7 == llmat3_obj.mMatrix[1][2] && + 6 == llmat3_obj.mMatrix[2][0] && + 9 == llmat3_obj.mMatrix[2][1] && + 7 == llmat3_obj.mMatrix[2][2]); + } + + //test case for getFwdRow(), getLeftRow(), getUpRow() fns. + template<> template<> + void m3math_test_object_t::test<4>() + { + LLMatrix3 llmat3_obj; + LLVector3 vect1(2, 1, 4); + LLVector3 vect2(3, 5, 7); + LLVector3 vect3(6, 9, 7); + llmat3_obj.setRows(vect1, vect2, vect3); + + ensure("LLVector3::getFwdRow failed ", vect1 == llmat3_obj.getFwdRow()); + ensure("LLVector3::getLeftRow failed ", vect2 == llmat3_obj.getLeftRow()); + ensure("LLVector3::getUpRow failed ", vect3 == llmat3_obj.getUpRow()); + } + + //test case for operator*(const LLMatrix3 &a, const LLMatrix3 &b) + template<> template<> + void m3math_test_object_t::test<5>() + { + LLMatrix3 llmat_obj1; + LLMatrix3 llmat_obj2; + LLMatrix3 llmat_obj3; + + LLVector3 llvec1(1, 3, 5); + LLVector3 llvec2(3, 6, 1); + LLVector3 llvec3(4, 6, 9); + + LLVector3 llvec4(1, 1, 5); + LLVector3 llvec5(3, 6, 8); + LLVector3 llvec6(8, 6, 2); + + LLVector3 llvec7(0, 0, 0); + LLVector3 llvec8(0, 0, 0); + LLVector3 llvec9(0, 0, 0); + + llmat_obj1.setRows(llvec1, llvec2, llvec3); + llmat_obj2.setRows(llvec4, llvec5, llvec6); + llmat_obj3.setRows(llvec7, llvec8, llvec9); + llmat_obj3 = llmat_obj1 * llmat_obj2; + ensure("LLMatrix3::operator*(const LLMatrix3 &a, const LLMatrix3 &b) failed", + 50 == llmat_obj3.mMatrix[0][0] && + 49 == llmat_obj3.mMatrix[0][1] && + 39 == llmat_obj3.mMatrix[0][2] && + 29 == llmat_obj3.mMatrix[1][0] && + 45 == llmat_obj3.mMatrix[1][1] && + 65 == llmat_obj3.mMatrix[1][2] && + 94 == llmat_obj3.mMatrix[2][0] && + 94 == llmat_obj3.mMatrix[2][1] && + 86 == llmat_obj3.mMatrix[2][2]); + } + + + //test case for operator*(const LLVector3 &a, const LLMatrix3 &b) + template<> template<> + void m3math_test_object_t::test<6>() + { + + LLMatrix3 llmat_obj1; + + LLVector3 llvec(1, 3, 5); + LLVector3 res_vec(0, 0, 0); + LLVector3 llvec1(1, 3, 5); + LLVector3 llvec2(3, 6, 1); + LLVector3 llvec3(4, 6, 9); + + llmat_obj1.setRows(llvec1, llvec2, llvec3); + res_vec = llvec * llmat_obj1; + + LLVector3 expected_result(30, 51, 53); + + ensure("LLMatrix3::operator*(const LLVector3 &a, const LLMatrix3 &b) failed", res_vec == expected_result); + } + + //test case for operator*(const LLVector3d &a, const LLMatrix3 &b) + template<> template<> + void m3math_test_object_t::test<7>() + { + LLMatrix3 llmat_obj1; + LLVector3d llvec3d1; + LLVector3d llvec3d2(0, 3, 4); + + LLVector3 llvec1(1, 3, 5); + LLVector3 llvec2(3, 2, 1); + LLVector3 llvec3(4, 6, 0); + + llmat_obj1.setRows(llvec1, llvec2, llvec3); + llvec3d1 = llvec3d2 * llmat_obj1; + + LLVector3d expected_result(25, 30, 3); + + ensure("LLMatrix3::operator*(const LLVector3 &a, const LLMatrix3 &b) failed", llvec3d1 == expected_result); + } + + // test case for operator==(const LLMatrix3 &a, const LLMatrix3 &b) + template<> template<> + void m3math_test_object_t::test<8>() + { + LLMatrix3 llmat_obj1; + LLMatrix3 llmat_obj2; + + LLVector3 llvec1(1, 3, 5); + LLVector3 llvec2(3, 6, 1); + LLVector3 llvec3(4, 6, 9); + + llmat_obj1.setRows(llvec1, llvec2, llvec3); + llmat_obj2.setRows(llvec1, llvec2, llvec3); + ensure("LLMatrix3::operator==(const LLMatrix3 &a, const LLMatrix3 &b) failed", llmat_obj1 == llmat_obj2); + + llmat_obj2.setRows(llvec2, llvec2, llvec3); + ensure("LLMatrix3::operator!=(const LLMatrix3 &a, const LLMatrix3 &b) failed", llmat_obj1 != llmat_obj2); + } + + //test case for quaternion() fn. + template<> template<> + void m3math_test_object_t::test<9>() + { + LLMatrix3 llmat_obj1; + LLQuaternion llmat_quat; + + LLVector3 llmat1(2.0f, 1.0f, 6.0f); + LLVector3 llmat2(1.0f, 1.0f, 3.0f); + LLVector3 llmat3(1.0f, 7.0f, 5.0f); + + llmat_obj1.setRows(llmat1, llmat2, llmat3); + llmat_quat = llmat_obj1.quaternion(); + ensure("LLMatrix3::quaternion failed ", is_approx_equal(-0.66666669f, llmat_quat.mQ[0]) && + is_approx_equal(-0.83333337f, llmat_quat.mQ[1]) && + is_approx_equal(0.0f, llmat_quat.mQ[2]) && + is_approx_equal(1.5f, llmat_quat.mQ[3])); + } + + //test case for transpose() fn. + template<> template<> + void m3math_test_object_t::test<10>() + { + LLMatrix3 llmat_obj; + + LLVector3 llvec1(1, 2, 3); + LLVector3 llvec2(3, 2, 1); + LLVector3 llvec3(2, 2, 2); + + llmat_obj.setRows(llvec1, llvec2, llvec3); + llmat_obj.transpose(); + + LLVector3 resllvec1(1, 3, 2); + LLVector3 resllvec2(2, 2, 2); + LLVector3 resllvec3(3, 1, 2); + LLMatrix3 expectedllmat_obj; + expectedllmat_obj.setRows(resllvec1, resllvec2, resllvec3); + + ensure("LLMatrix3::transpose failed ", llmat_obj == expectedllmat_obj); + } + + //test case for determinant() fn. + template<> template<> + void m3math_test_object_t::test<11>() + { + LLMatrix3 llmat_obj1; + + LLVector3 llvec1(1, 2, 3); + LLVector3 llvec2(3, 2, 1); + LLVector3 llvec3(2, 2, 2); + llmat_obj1.setRows(llvec1, llvec2, llvec3); + ensure("LLMatrix3::determinant failed ", 0.0f == llmat_obj1.determinant()); + } + + //test case for orthogonalize() fn. + template<> template<> + void m3math_test_object_t::test<12>() + { + LLMatrix3 llmat_obj; + + LLVector3 llvec1(1, 4, 3); + LLVector3 llvec2(1, 2, 0); + LLVector3 llvec3(2, 4, 2); + + skip("This test fails depending on architecture. Need to fix comparison operation, is_approx_equal, to work on more than one platform."); + + llmat_obj.setRows(llvec1, llvec2, llvec3); + llmat_obj.orthogonalize(); + + ensure("LLMatrix3::orthogonalize failed ", + is_approx_equal(0.19611614f, llmat_obj.mMatrix[0][0]) && + is_approx_equal(0.78446454f, llmat_obj.mMatrix[0][1]) && + is_approx_equal(0.58834841f, llmat_obj.mMatrix[0][2]) && + is_approx_equal(0.47628204f, llmat_obj.mMatrix[1][0]) && + is_approx_equal(0.44826545f, llmat_obj.mMatrix[1][1]) && + is_approx_equal(-0.75644795f, llmat_obj.mMatrix[1][2]) && + is_approx_equal(-0.85714286f, llmat_obj.mMatrix[2][0]) && + is_approx_equal(0.42857143f, llmat_obj.mMatrix[2][1]) && + is_approx_equal(-0.28571429f, llmat_obj.mMatrix[2][2])); + } + + //test case for adjointTranspose() fn. + template<> template<> + void m3math_test_object_t::test<13>() + { + LLMatrix3 llmat_obj; + + LLVector3 llvec1(3, 2, 1); + LLVector3 llvec2(6, 2, 1); + LLVector3 llvec3(3, 6, 8); + + llmat_obj.setRows(llvec1, llvec2, llvec3); + llmat_obj.adjointTranspose(); + + ensure("LLMatrix3::adjointTranspose failed ", 10 == llmat_obj.mMatrix[0][0] && + -45 == llmat_obj.mMatrix[1][0] && + 30 == llmat_obj.mMatrix[2][0] && + -10 == llmat_obj.mMatrix[0][1] && + 21 == llmat_obj.mMatrix[1][1] && + -12 == llmat_obj.mMatrix[2][1] && + 0 == llmat_obj.mMatrix[0][2] && + 3 == llmat_obj.mMatrix[1][2] && + -6 == llmat_obj.mMatrix[2][2]); + } + + /* TBD: Need to add test cases for getEulerAngles() and setRot() functions */ +} diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp new file mode 100644 index 0000000000..91a2e6c009 --- /dev/null +++ b/indra/llmath/tests/mathmisc_test.cpp @@ -0,0 +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_data> 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 = llround(val); + ensure("float llround value 1", (430903 == val1)); + val = -430903.9f; + val1 = llround(val); + ensure("float llround value 2", (-430904 == val1)); + } + + template<> template<> + void math_object::test<9>() + { + F32 val = 430905.2654f, nearest = 100.f; + val = llround(val, nearest); + ensure("float llround value 1", (430900 == val)); + val = -430905.2654f, nearest = 10.f; + val = llround(val, nearest); + ensure("float llround value 1", (-430910 == val)); + } + + template<> template<> + void math_object::test<10>() + { + F64 val = 430905.2654, nearest = 100.0; + val = llround(val, nearest); + ensure("double llround value 1", (430900 == val)); + val = -430905.2654, nearest = 10.0; + val = llround(val, nearest); + ensure("double llround 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_data> 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_data> 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_data> 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_data> 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 new file mode 100644 index 0000000000..4d6a2eca93 --- /dev/null +++ b/indra/llmath/tests/v2math_test.cpp @@ -0,0 +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_data> 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 new file mode 100644 index 0000000000..29d1c483ab --- /dev/null +++ b/indra/llmath/tests/v3color_test.cpp @@ -0,0 +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_data> 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 new file mode 100644 index 0000000000..20b26faa12 --- /dev/null +++ b/indra/llmath/tests/v3dmath_test.cpp @@ -0,0 +1,526 @@ +/** + * @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_data> 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); + ensure("2:angle_between: Fail ", (angle == angle2)); +#endif + } +} diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp new file mode 100644 index 0000000000..df7a77002f --- /dev/null +++ b/indra/llmath/tests/v3math_test.cpp @@ -0,0 +1,567 @@ +/** + * @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_data> 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])); + } +} diff --git a/indra/llmath/tests/v4color_test.cpp b/indra/llmath/tests/v4color_test.cpp new file mode 100644 index 0000000000..d7eec3c87f --- /dev/null +++ b/indra/llmath/tests/v4color_test.cpp @@ -0,0 +1,359 @@ +/** + * @file v4color_test.cpp + * @author Adroit + * @date 2007-03 + * @brief v4color 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 "../v4coloru.h" +#include "llsd.h" +#include "../v3color.h" +#include "../v4color.h" + + +namespace tut +{ + struct v4color_data + { + }; + typedef test_group<v4color_data> v4color_test; + typedef v4color_test::object v4color_object; + tut::v4color_test v4color_testcase("v4color_h"); + + template<> template<> + 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]))); + + 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]))); + + 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]))); + + 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]))); + + 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]))); + + LLSD sd = llcolor4d.getValue(); + LLColor4 llcolor4e(sd); + ensure_equals("6:LLColor4:(LLSD) failed ", llcolor4d, llcolor4e); + + U8 r1 = 0xF2, g1 = 0xFA, b1 = 0xBF; + LLColor4U color4u(r1,g1,b1); + 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]))); + } + + template<> template<> + void v4color_object::test<2>() + { + LLColor4 llcolor(1.0, 2.0, 3.0, 4.0); + LLSD llsd = llcolor.getValue(); + LLColor4 llcolor4(llsd), llcolor4a; + llcolor4a.setValue(llsd); + ensure("setValue: failed", (llcolor4 == llcolor4a)); + LLSD sd = llcolor4a.getValue(); + LLColor4 llcolor4b(sd); + ensure("getValue: Failed ", (llcolor4b == llcolor4a)); + } + + template<> template<> + void v4color_object::test<3>() + { + 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]))); + + 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]))); + } + + template<> template<> + void v4color_object::test<4>() + { + 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]))); + + 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]))); + + LLColor4 llcolor4a; + llcolor4a.setVec(llcolor4); + ensure_equals("3:setVec:Fail to set the values ", llcolor4a,llcolor4); + + 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]))); + + 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]))); + + 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]))); + + 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]))); + } + + template<> template<> + void v4color_object::test<5>() + { + F32 alpha = 0xAF; + LLColor4 llcolor4; + llcolor4.setAlpha(alpha); + ensure("setAlpha:Fail to initialize ", (alpha == llcolor4.mV[VW])); + } + + template<> template<> + void v4color_object::test<6>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF; + LLColor4 llcolor4(r,g,b); + ensure("magVecSquared:Fail ", is_approx_equal(llcolor4.magVecSquared(), (r*r + g*g + b*b))); + ensure("magVec:Fail ", is_approx_equal(llcolor4.magVec(), (F32) sqrt(r*r + g*g + b*b))); + } + + template<> template<> + void v4color_object::test<7>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF; + LLColor4 llcolor4(r,g,b); + F32 vecMag = llcolor4.normVec(); + F32 mag = (F32) sqrt(r*r + g*g + b*b); + F32 oomag = 1.f / mag; + F32 val1 = r * oomag, val2 = g * oomag, val3 = b * oomag; + ensure("1:normVec failed ", (is_approx_equal(val1, llcolor4.mV[0]) && is_approx_equal(val2, llcolor4.mV[1]) && is_approx_equal(val3, llcolor4.mV[2]) && is_approx_equal(vecMag, mag))); + } + + template<> template<> + void v4color_object::test<8>() + { + LLColor4 llcolor4; + ensure("1:isOpaque failed ",(1 == llcolor4.isOpaque())); + F32 r = 0x20, g = 0xFFFF, b = 0xFF,a = 1.f; + llcolor4.setVec(r,g,b,a); + ensure("2:isOpaque failed ",(1 == llcolor4.isOpaque())); + a = 2.f; + llcolor4.setVec(r,g,b,a); + ensure("3:isOpaque failed ",(0 == llcolor4.isOpaque())); + } + + template<> template<> + void v4color_object::test<9>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF; + LLColor4 llcolor4(r,g,b); + ensure("1:operator [] failed",( r == llcolor4[0])); + ensure("2:operator [] failed",( g == llcolor4[1])); + ensure("3:operator [] failed",( b == llcolor4[2])); + + r = 0xA20, g = 0xFBFF, b = 0xFFF; + llcolor4.setVec(r,g,b); + F32 &ref1 = llcolor4[0]; + ensure("4:operator [] failed",( ref1 == llcolor4[0])); + F32 &ref2 = llcolor4[1]; + ensure("5:operator [] failed",( ref2 == llcolor4[1])); + F32 &ref3 = llcolor4[2]; + ensure("6:operator [] failed",( ref3 == llcolor4[2])); + } + + template<> template<> + void v4color_object::test<10>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF; + 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]))); + LLSD sd = llcolor4a.getValue(); + llcolor4b = LLColor4(sd); + ensure_equals("Operator= LLSD:Fail ", llcolor4a, llcolor4b); + } + + template<> template<> + void v4color_object::test<11>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF; + std::ostringstream stream1, stream2; + LLColor4 llcolor4a(r,g,b),llcolor4b; + stream1 << llcolor4a; + llcolor4b.setVec(r,g,b); + stream2 << llcolor4b; + ensure("operator << failed ", (stream1.str() == stream2.str())); + } + + template<> template<> + void v4color_object::test<12>() + { + F32 r1 = 0x20, g1 = 0xFFFF, b1 = 0xFF; + 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]))); + + 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]))); + } + + template<> template<> + void v4color_object::test<13>() + { + F32 r1 = 0x20, g1 = 0xFFFF, b1 = 0xFF; + 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]))); + + 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]))); + } + + template<> template<> + void v4color_object::test<14>() + { + F32 r1 = 0x20, g1 = 0xFFFF, b1 = 0xFF; + 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]))); + + 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]))); + 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]))); + + 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]))); + + 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]))); + } + + template<> template<> + void v4color_object::test<15>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF,a = 0x30; + 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]))); + + 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]))); + + llcolor4a %= div; + ensure("operator%=:Fail ", (is_approx_equal(a*div,llcolor4a.mV[VW]))); + } + + template<> template<> + void v4color_object::test<16>() + { + F32 r = 0x20, g = 0xFFFF, b = 0xFF,a = 0x30; + LLColor4 llcolor4a(r,g,b,a),llcolor4b; + llcolor4b = llcolor4a; + ensure("1:operator== failed to ensure the equality ", (llcolor4b == llcolor4a)); + F32 r1 = 0x2, g1 = 0xFF, b1 = 0xFA; + LLColor3 llcolor3(r1,g1,b1); + llcolor4b = llcolor3; + ensure("2:operator== failed to ensure the equality ", (llcolor4b == llcolor3)); + ensure("2:operator!= failed to ensure the equality ", (llcolor4a != llcolor3)); + } + + template<> template<> + void v4color_object::test<17>() + { + 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]))); + llcolor4b = vec3to4(llcolor3); + ensure_equals("vec3to4:Fail to convert vec3 to vec4 ", llcolor4b, llcolor4a); + } + + template<> template<> + void v4color_object::test<18>() + { + F32 r1 = 0x20, g1 = 0xFFFF, b1 = 0xFF, val = 0x20; + 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]))); + } + + template<> template<> + void v4color_object::test<19>() + { + F32 r = 12.0f, g = -2.3f, b = 1.32f, a = 5.0f; + LLColor4 llcolor4a(r,g,b,a),llcolor4b; + std::string color("red"); + LLColor4::parseColor(color, &llcolor4b); + ensure_equals("1:parseColor() failed to parse the color value ", llcolor4b, LLColor4::red); + + color = "12.0, -2.3, 1.32, 5.0"; + LLColor4::parseColor(color, &llcolor4b); + llcolor4a = llcolor4a * (1.f / 255.f); + ensure_equals("2:parseColor() failed to parse the color value ", llcolor4a,llcolor4b); + + color = "yellow5"; + llcolor4a.setVec(r,g,b); + LLColor4::parseColor(color, &llcolor4a); + ensure_equals("3:parseColor() failed to parse the color value ", llcolor4a, LLColor4::yellow5); + } + + template<> template<> + void v4color_object::test<20>() + { + F32 r = 12.0f, g = -2.3f, b = 1.32f, a = 5.0f; + LLColor4 llcolor4a(r,g,b,a),llcolor4b; + std::string color("12.0, -2.3, 1.32, 5.0"); + LLColor4::parseColor4(color, &llcolor4b); + ensure_equals("parseColor4() failed to parse the color value ", llcolor4a, llcolor4b); + } +} diff --git a/indra/llmath/tests/v4coloru_test.cpp b/indra/llmath/tests/v4coloru_test.cpp new file mode 100644 index 0000000000..128f6f3564 --- /dev/null +++ b/indra/llmath/tests/v4coloru_test.cpp @@ -0,0 +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_data> 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)llround(r * fVal) == llcolor4u1.mV[VX]) && (U8)llround(g * fVal) == llcolor4u1.mV[VY] + && ((U8)llround(b * fVal) == llcolor4u1.mV[VZ])&& ((U8)llround(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 = llround(r * color_scale_factor); + S32 g2 = llround(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 new file mode 100644 index 0000000000..191ac864df --- /dev/null +++ b/indra/llmath/tests/v4math_test.cpp @@ -0,0 +1,382 @@ +/** + * @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_data> 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); + ensure("lerp failed", ((val1 ==vec4b.mV[VX])&& (val2 ==vec4b.mV[VY]) && (val3 ==vec4b.mV[VZ])&& (val4 ==vec4b.mV[VW]))); + } + + 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 new file mode 100644 index 0000000000..49870eef3c --- /dev/null +++ b/indra/llmath/tests/xform_test.cpp @@ -0,0 +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> 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 555e1f92bb..a0cd642853 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -2,31 +2,25 @@ * @file v2math.cpp * @brief LLVector2 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -92,7 +86,7 @@ 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 fsqrtf( x*x + y*y ); + return (F32) sqrt( x*x + y*y ); } F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b) @@ -115,3 +109,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u) a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u, a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u ); } + +LLSD LLVector2::getValue() const +{ + LLSD ret; + ret[0] = mV[0]; + ret[1] = mV[1]; + return ret; +} + +void LLVector2::setValue(LLSD& sd) +{ + mV[0] = (F32) sd[0].asReal(); + mV[1] = (F32) sd[1].asReal(); +} + diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index 9fef8851cc..8d5db96f5e 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -2,31 +2,25 @@ * @file v2math.h * @brief LLVector2 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -66,10 +60,15 @@ class LLVector2 void set(const LLVector2 &vec); // Sets LLVector2 to vec void set(const F32 *vec); // Sets LLVector2 to vec + LLSD getValue() const; + void setValue(LLSD& sd); + void setVec(F32 x, F32 y); // deprecated void setVec(const LLVector2 &vec); // deprecated void setVec(const F32 *vec); // deprecated + 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 @@ -215,11 +214,12 @@ inline void LLVector2::setVec(const F32 *vec) mV[VY] = vec[VY]; } + // LLVector2 Magnitude and Normalization Functions inline F32 LLVector2::length(void) const { - return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); } inline F32 LLVector2::lengthSquared(void) const @@ -229,7 +229,7 @@ inline F32 LLVector2::lengthSquared(void) const inline F32 LLVector2::normalize(void) { - F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); F32 oomag; if (mag > FP_MAG_THRESHOLD) @@ -247,10 +247,16 @@ inline F32 LLVector2::normalize(void) return (mag); } +// checker +inline bool LLVector2::isFinite() const +{ + return (llfinite(mV[VX]) && llfinite(mV[VY])); +} + // deprecated inline F32 LLVector2::magVec(void) const { - return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); } // deprecated @@ -262,7 +268,7 @@ inline F32 LLVector2::magVecSquared(void) const // deprecated inline F32 LLVector2::normVec(void) { - F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]); F32 oomag; if (mag > FP_MAG_THRESHOLD) diff --git a/indra/llmath/v3color.cpp b/indra/llmath/v3color.cpp index e76607a91f..d38f48b11e 100644 --- a/indra/llmath/v3color.cpp +++ b/indra/llmath/v3color.cpp @@ -2,31 +2,25 @@ * @file v3color.cpp * @brief LLColor3 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -56,9 +50,7 @@ LLColor3::LLColor3(const LLVector4 &a) LLColor3::LLColor3(const LLSD &sd) { - mV[0] = (F32) sd[0].asReal(); - mV[1] = (F32) sd[1].asReal(); - mV[2] = (F32) sd[2].asReal(); + setValue(sd); } const LLColor3& LLColor3::operator=(const LLColor4 &a) diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 1915d80502..56cb2ae73e 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -2,31 +2,25 @@ * @file v3color.h * @brief LLColor3 class header file. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -284,7 +278,7 @@ inline F32 LLColor3::brightness(void) const inline F32 LLColor3::length(void) const { - return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); } inline F32 LLColor3::lengthSquared(void) const @@ -294,7 +288,7 @@ inline F32 LLColor3::lengthSquared(void) const inline F32 LLColor3::normalize(void) { - F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); F32 oomag; if (mag) @@ -310,7 +304,7 @@ inline F32 LLColor3::normalize(void) // deprecated inline F32 LLColor3::magVec(void) const { - return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); } // deprecated @@ -322,7 +316,7 @@ inline F32 LLColor3::magVecSquared(void) const // deprecated inline F32 LLColor3::normVec(void) { - F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); F32 oomag; if (mag) @@ -444,7 +438,7 @@ inline F32 distVec(const LLColor3 &a, const LLColor3 &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 fsqrtf( x*x + y*y + z*z ); + return (F32) sqrt( x*x + y*y + z*z ); } inline F32 distVec_squared(const LLColor3 &a, const LLColor3 &b) diff --git a/indra/llmath/v3dmath.cpp b/indra/llmath/v3dmath.cpp index 2bcbf632b1..a50cb3c6ca 100644 --- a/indra/llmath/v3dmath.cpp +++ b/indra/llmath/v3dmath.cpp @@ -2,31 +2,25 @@ * @file v3dmath.cpp * @brief LLVector3d class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 6ab31e8a41..578dcdc8ea 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -2,31 +2,25 @@ * @file v3dmath.h * @brief High precision 3 dimensional vector. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -240,7 +234,7 @@ inline const LLVector3d& LLVector3d::setVec(const F64 *vec) inline F64 LLVector3d::normVec(void) { - F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); + F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); F64 oomag; if (mag > FP_MAG_THRESHOLD) @@ -262,7 +256,7 @@ inline F64 LLVector3d::normVec(void) inline F64 LLVector3d::normalize(void) { - F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); + F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); F64 oomag; if (mag > FP_MAG_THRESHOLD) @@ -286,7 +280,7 @@ inline F64 LLVector3d::normalize(void) inline F64 LLVector3d::magVec(void) const { - return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); + return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); } inline F64 LLVector3d::magVecSquared(void) const @@ -296,7 +290,7 @@ inline F64 LLVector3d::magVecSquared(void) const inline F64 LLVector3d::length(void) const { - return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); + return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]); } inline F64 LLVector3d::lengthSquared(void) const @@ -406,7 +400,7 @@ 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 fsqrtf( x*x + y*y + z*z ); + return (F32) sqrt( x*x + y*y + z*z ); } inline F64 dist_vec_squared(const LLVector3d &a, const LLVector3d &b) diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index f392ac448b..e7107dee16 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -2,31 +2,25 @@ * @file v3math.cpp * @brief LLVector3 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -140,6 +134,21 @@ BOOL LLVector3::clampLength( F32 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 @@ -185,14 +194,6 @@ void LLVector3::snap(S32 sig_digits) mV[VZ] = snap_to_sig_figs(mV[VZ], sig_digits); } - -std::ostream& operator<<(std::ostream& s, const LLVector3 &a) -{ - s << "{ " << a.mV[VX] << ", " << a.mV[VY] << ", " << a.mV[VZ] << " }"; - return s; -} - - const LLVector3& LLVector3::rotVec(const LLMatrix3 &mat) { *this = *this * mat; @@ -205,6 +206,28 @@ const LLVector3& LLVector3::rotVec(const LLQuaternion &q) return *this; } +const LLVector3& LLVector3::transVec(const LLMatrix4& mat) +{ + setVec( + mV[VX] * mat.mMatrix[VX][VX] + + mV[VY] * mat.mMatrix[VX][VY] + + mV[VZ] * mat.mMatrix[VX][VZ] + + mat.mMatrix[VX][VW], + + mV[VX] * mat.mMatrix[VY][VX] + + mV[VY] * mat.mMatrix[VY][VY] + + mV[VZ] * mat.mMatrix[VY][VZ] + + mat.mMatrix[VY][VW], + + mV[VX] * mat.mMatrix[VZ][VX] + + mV[VY] * mat.mMatrix[VZ][VY] + + mV[VZ] * mat.mMatrix[VZ][VZ] + + mat.mMatrix[VZ][VW]); + + return *this; +} + + const LLVector3& LLVector3::rotVec(F32 angle, const LLVector3 &vec) { if ( !vec.isExactlyZero() && angle ) diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 805d7e6384..0432aeba4c 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -2,31 +2,25 @@ * @file v3math.h * @brief LLVector3 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,6 +34,7 @@ class LLVector2; class LLVector4; class LLMatrix3; +class LLMatrix4; class LLVector3d; class LLQuaternion; @@ -75,6 +70,7 @@ class LLVector3 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 @@ -115,6 +111,7 @@ class LLVector3 const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q + const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v) const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec @@ -162,6 +159,8 @@ F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance betwe 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 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 inline LLVector3::LLVector3(void) @@ -280,7 +279,7 @@ inline void LLVector3::setVec(const F32 *vec) inline F32 LLVector3::normalize(void) { - F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); F32 oomag; if (mag > FP_MAG_THRESHOLD) @@ -303,7 +302,7 @@ inline F32 LLVector3::normalize(void) // deprecated inline F32 LLVector3::normVec(void) { - F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); F32 oomag; if (mag > FP_MAG_THRESHOLD) @@ -327,7 +326,7 @@ inline F32 LLVector3::normVec(void) inline F32 LLVector3::length(void) const { - return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); } inline F32 LLVector3::lengthSquared(void) const @@ -337,7 +336,7 @@ inline F32 LLVector3::lengthSquared(void) const inline F32 LLVector3::magVec(void) const { - return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); + return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); } inline F32 LLVector3::magVecSquared(void) const @@ -409,8 +408,8 @@ 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]))); + || ((a.mV[1] == b.mV[1]) + && a.mV[2] < b.mV[2])))); } inline const LLVector3& operator+=(LLVector3 &a, const LLVector3 &b) @@ -471,7 +470,7 @@ 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 fsqrtf( x*x + y*y + z*z ); + return (F32) sqrt( x*x + y*y + z*z ); } inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b) @@ -496,6 +495,17 @@ inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b) return project_axis * (a * project_axis); } +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( @@ -529,6 +539,21 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos) } } +inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos) +{ + for (U32 i = 0; i < 3; i++) + { + if (min.mV[i] > pos[i]) + { + min.mV[i] = pos[i]; + } + if (max.mV[i] < pos[i]) + { + max.mV[i] = pos[i]; + } + } +} + inline F32 angle_between(const LLVector3& a, const LLVector3& b) { LLVector3 an = a; @@ -556,4 +581,10 @@ inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) 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 219b06ec74..81ac62be56 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -2,31 +2,25 @@ * @file v4color.cpp * @brief LLColor4 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index d6fbdec61e..b047f86e6e 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -2,31 +2,25 @@ * @file v4color.h * @brief LLColor4 class header file. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -114,6 +108,7 @@ class LLColor4 const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4 + bool operator<(const LLColor4& rhs) const; friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b @@ -391,7 +386,7 @@ inline const LLColor4& LLColor4::setAlpha(F32 a) inline F32 LLColor4::length(void) const { - return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); } inline F32 LLColor4::lengthSquared(void) const @@ -401,7 +396,7 @@ inline F32 LLColor4::lengthSquared(void) const inline F32 LLColor4::normalize(void) { - F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); F32 oomag; if (mag) @@ -417,7 +412,7 @@ inline F32 LLColor4::normalize(void) // deprecated inline F32 LLColor4::magVec(void) const { - return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); } // deprecated @@ -429,7 +424,7 @@ inline F32 LLColor4::magVecSquared(void) const // deprecated inline F32 LLColor4::normVec(void) { - F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); F32 oomag; if (mag) @@ -595,6 +590,23 @@ inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u) a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u); } +inline bool LLColor4::operator<(const LLColor4& rhs) const +{ + if (mV[0] != rhs.mV[0]) + { + return mV[0] < rhs.mV[0]; + } + if (mV[1] != rhs.mV[1]) + { + return mV[1] < rhs.mV[1]; + } + if (mV[2] != rhs.mV[2]) + { + return mV[2] < rhs.mV[2]; + } + + return mV[3] < rhs.mV[3]; +} void LLColor4::clamp() { diff --git a/indra/llmath/v4coloru.cpp b/indra/llmath/v4coloru.cpp index 061b4970f7..f1a2518cf3 100644 --- a/indra/llmath/v4coloru.cpp +++ b/indra/llmath/v4coloru.cpp @@ -2,31 +2,25 @@ * @file v4coloru.cpp * @brief LLColor4U class implementation. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index 4ec5a345eb..12da7e2dd7 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -2,31 +2,25 @@ * @file v4coloru.h * @brief The LLColor4U class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -300,7 +294,7 @@ inline const LLColor4U& LLColor4U::setAlpha(U8 a) inline F32 LLColor4U::length(void) const { - return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); + return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); } inline F32 LLColor4U::lengthSquared(void) const @@ -311,7 +305,7 @@ inline F32 LLColor4U::lengthSquared(void) const // deprecated inline F32 LLColor4U::magVec(void) const { - return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); + return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] ); } // deprecated diff --git a/indra/llmath/v4math.cpp b/indra/llmath/v4math.cpp index b938480dd9..2782cf2966 100644 --- a/indra/llmath/v4math.cpp +++ b/indra/llmath/v4math.cpp @@ -2,31 +2,25 @@ * @file v4math.cpp * @brief LLVector4 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 4c82e6b629..623c8b2003 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -2,31 +2,25 @@ * @file v4math.h * @brief LLVector4 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -321,7 +315,7 @@ inline void LLVector4::setVec(const F32 *vec) inline F32 LLVector4::length(void) const { - return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); } inline F32 LLVector4::lengthSquared(void) const @@ -331,7 +325,7 @@ inline F32 LLVector4::lengthSquared(void) const inline F32 LLVector4::magVec(void) const { - return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); } inline F32 LLVector4::magVecSquared(void) const @@ -463,7 +457,7 @@ inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u) inline F32 LLVector4::normalize(void) { - F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); F32 oomag; if (mag > FP_MAG_THRESHOLD) @@ -486,7 +480,7 @@ inline F32 LLVector4::normalize(void) // deprecated inline F32 LLVector4::normVec(void) { - F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); F32 oomag; if (mag > FP_MAG_THRESHOLD) diff --git a/indra/llmath/xform.cpp b/indra/llmath/xform.cpp index ce6f756ab9..b75aec6a27 100644 --- a/indra/llmath/xform.cpp +++ b/indra/llmath/xform.cpp @@ -1,31 +1,25 @@ /** * @file xform.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,6 +36,11 @@ LLXform::~LLXform() { } +// Link optimization - don't inline these llwarns +void LLXform::warn(const char* const msg) +{ + llwarns << msg << llendl; +} LLXform* LLXform::getRoot() const { diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 5b7b1900bc..1b50749b3e 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -1,31 +1,25 @@ /** * @file xform.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,11 +32,11 @@ 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 = 10.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 - class LLXform { protected: @@ -107,6 +101,12 @@ public: 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. llwarns causes inline LLError::CallSite + // static objects that make more work for the linker. + // Avoid inline llwarns by calling this function. + void warn(const char* const msg); void setChanged(const U32 bits) { mChanged |= bits; } BOOL isChanged() const { return mChanged; } @@ -173,7 +173,7 @@ BOOL LLXform::setParent(LLXform* parent) { if (cur_par == this) { - //llwarns << "LLXform::setParent Creating loop when setting parent!" << llendl; + //warn("LLXform::setParent Creating loop when setting parent!"); return FALSE; } cur_par = cur_par->mParent; @@ -191,7 +191,7 @@ void LLXform::setPosition(const LLVector3& pos) else { mPosition.clearVec(); - llwarns << "Non Finite in LLXform::setPosition(LLVector3)" << llendl; + warn("Non Finite in LLXform::setPosition(LLVector3)"); } } @@ -203,7 +203,7 @@ void LLXform::setPosition(const F32 x, const F32 y, const F32 z) else { mPosition.clearVec(); - llwarns << "Non Finite in LLXform::setPosition(F32,F32,F32)" << llendl; + warn("Non Finite in LLXform::setPosition(F32,F32,F32)"); } } @@ -215,7 +215,7 @@ void LLXform::setPositionX(const F32 x) else { mPosition.mV[VX] = 0.f; - llwarns << "Non Finite in LLXform::setPositionX" << llendl; + warn("Non Finite in LLXform::setPositionX"); } } @@ -227,7 +227,7 @@ void LLXform::setPositionY(const F32 y) else { mPosition.mV[VY] = 0.f; - llwarns << "Non Finite in LLXform::setPositionY" << llendl; + warn("Non Finite in LLXform::setPositionY"); } } @@ -239,7 +239,7 @@ void LLXform::setPositionZ(const F32 z) else { mPosition.mV[VZ] = 0.f; - llwarns << "Non Finite in LLXform::setPositionZ" << llendl; + warn("Non Finite in LLXform::setPositionZ"); } } @@ -249,7 +249,7 @@ void LLXform::addPosition(const LLVector3& pos) if (pos.isFinite()) mPosition += pos; else - llwarns << "Non Finite in LLXform::addPosition" << llendl; + warn("Non Finite in LLXform::addPosition"); } void LLXform::setScale(const LLVector3& scale) @@ -260,7 +260,7 @@ void LLXform::setScale(const LLVector3& scale) else { mScale.setVec(1.f, 1.f, 1.f); - llwarns << "Non Finite in LLXform::setScale" << llendl; + warn("Non Finite in LLXform::setScale"); } } void LLXform::setScale(const F32 x, const F32 y, const F32 z) @@ -271,7 +271,7 @@ void LLXform::setScale(const F32 x, const F32 y, const F32 z) else { mScale.setVec(1.f, 1.f, 1.f); - llwarns << "Non Finite in LLXform::setScale" << llendl; + warn("Non Finite in LLXform::setScale"); } } void LLXform::setRotation(const LLQuaternion& rot) @@ -282,7 +282,7 @@ void LLXform::setRotation(const LLQuaternion& rot) else { mRotation.loadIdentity(); - llwarns << "Non Finite in LLXform::setRotation" << llendl; + warn("Non Finite in LLXform::setRotation"); } } void LLXform::setRotation(const F32 x, const F32 y, const F32 z) @@ -295,7 +295,7 @@ void LLXform::setRotation(const F32 x, const F32 y, const F32 z) else { mRotation.loadIdentity(); - llwarns << "Non Finite in LLXform::setRotation" << llendl; + warn("Non Finite in LLXform::setRotation"); } } void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) @@ -308,7 +308,7 @@ void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) else { mRotation.loadIdentity(); - llwarns << "Non Finite in LLXform::setRotation" << llendl; + warn("Non Finite in LLXform::setRotation"); } } |