aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h437
1 files changed, 437 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h b/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h
new file mode 100644
index 00000000..2596785f
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV4_Common.h
@@ -0,0 +1,437 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Include Guard
+#ifndef GU_BV4_COMMON_H
+#define GU_BV4_COMMON_H
+
+#include "foundation/PxMat44.h"
+#include "GuBox.h"
+#include "GuSphere.h"
+#include "GuCapsule.h"
+#include "GuSIMDHelpers.h"
+
+#define BV4_ALIGN16(x) PX_ALIGN_PREFIX(16) x PX_ALIGN_SUFFIX(16)
+
+namespace physx
+{
+namespace Gu
+{
+ enum QueryModifierFlag
+ {
+ QUERY_MODIFIER_ANY_HIT = (1<<0),
+ QUERY_MODIFIER_DOUBLE_SIDED = (1<<1),
+ QUERY_MODIFIER_MESH_BOTH_SIDES = (1<<2)
+ };
+
+ template<class ParamsT>
+ PX_FORCE_INLINE void setupParamsFlags(ParamsT* PX_RESTRICT params, PxU32 flags)
+ {
+ params->mBackfaceCulling = (flags & (QUERY_MODIFIER_DOUBLE_SIDED|QUERY_MODIFIER_MESH_BOTH_SIDES)) ? 0 : 1u;
+ params->mEarlyExit = flags & QUERY_MODIFIER_ANY_HIT;
+ }
+
+ enum HitCode
+ {
+ HIT_NONE = 0, //!< No hit
+ HIT_CONTINUE = 1, //!< Hit found, but keep looking for closer one
+ HIT_EXIT = 2 //!< Hit found, you can early-exit (raycast any)
+ };
+
+ class RaycastHitInternal : public physx::shdfnd::UserAllocated
+ {
+ public:
+ PX_FORCE_INLINE RaycastHitInternal() {}
+ PX_FORCE_INLINE ~RaycastHitInternal() {}
+
+ float mDistance;
+ PxU32 mTriangleID;
+ };
+
+ class SweepHit : public physx::shdfnd::UserAllocated
+ {
+ public:
+ PX_FORCE_INLINE SweepHit() {}
+ PX_FORCE_INLINE ~SweepHit() {}
+
+ PxU32 mTriangleID; //!< Index of touched face
+ float mDistance; //!< Impact distance
+
+ PxVec3 mPos;
+ PxVec3 mNormal;
+ };
+
+ typedef HitCode (*MeshRayCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, float dist, float u, float v);
+ typedef bool (*MeshOverlapCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* vertexIndices);
+ typedef bool (*MeshSweepCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, /*const PxU32* vertexIndices,*/ float& dist);
+ typedef bool (*SweepUnlimitedCallback) (void* userData, const SweepHit& hit);
+
+ template<class ParamsT>
+ PX_FORCE_INLINE void reportUnlimitedCallbackHit(ParamsT* PX_RESTRICT params, const SweepHit& hit)
+ {
+ // PT: we can't reuse the MeshSweepCallback here since it's designed for doing the sweep test inside the callback
+ // (in the user's code) rather than inside the traversal code. So we use the SweepUnlimitedCallback instead to
+ // report the already fully computed hit to users.
+ // PT: TODO: this may not be very efficient, since computing the full hit is expensive. If we use this codepath
+ // to implement the Epic Tweak, the resulting code will not be optimal.
+ (params->mCallback)(params->mUserData, hit);
+
+ // PT: the existing traversal code already shrunk the ray. For real "sweep all" calls we must undo that by reseting the max dist.
+ // (params->mStabbedFace.mDistance is used in computeImpactDataX code, so we need it before that point - we can't simply avoid
+ // modifying this value before this point).
+ if(!params->mNodeSorting)
+ params->mStabbedFace.mDistance = params->mMaxDist;
+ }
+
+ PX_FORCE_INLINE void invertPRMatrix(PxMat44* PX_RESTRICT dest, const PxMat44* PX_RESTRICT src)
+ {
+ const float m30 = src->column3.x;
+ const float m31 = src->column3.y;
+ const float m32 = src->column3.z;
+
+ const float m00 = src->column0.x;
+ const float m01 = src->column0.y;
+ const float m02 = src->column0.z;
+
+ dest->column0.x = m00;
+ dest->column1.x = m01;
+ dest->column2.x = m02;
+ dest->column3.x = -(m30*m00 + m31*m01 + m32*m02);
+
+ const float m10 = src->column1.x;
+ const float m11 = src->column1.y;
+ const float m12 = src->column1.z;
+
+ dest->column0.y = m10;
+ dest->column1.y = m11;
+ dest->column2.y = m12;
+ dest->column3.y = -(m30*m10 + m31*m11 + m32*m12);
+
+ const float m20 = src->column2.x;
+ const float m21 = src->column2.y;
+ const float m22 = src->column2.z;
+
+ dest->column0.z = m20;
+ dest->column1.z = m21;
+ dest->column2.z = m22;
+ dest->column3.z = -(m30*m20 + m31*m21 + m32*m22);
+
+ dest->column0.w = 0.0f;
+ dest->column1.w = 0.0f;
+ dest->column2.w = 0.0f;
+ dest->column3.w = 1.0f;
+ }
+
+ PX_FORCE_INLINE void invertBoxMatrix(PxMat33& m, PxVec3& t, const Gu::Box& box)
+ {
+ const float m30 = box.center.x;
+ const float m31 = box.center.y;
+ const float m32 = box.center.z;
+
+ const float m00 = box.rot.column0.x;
+ const float m01 = box.rot.column0.y;
+ const float m02 = box.rot.column0.z;
+
+ m.column0.x = m00;
+ m.column1.x = m01;
+ m.column2.x = m02;
+ t.x = -(m30*m00 + m31*m01 + m32*m02);
+
+ const float m10 = box.rot.column1.x;
+ const float m11 = box.rot.column1.y;
+ const float m12 = box.rot.column1.z;
+
+ m.column0.y = m10;
+ m.column1.y = m11;
+ m.column2.y = m12;
+ t.y = -(m30*m10 + m31*m11 + m32*m12);
+
+ const float m20 = box.rot.column2.x;
+ const float m21 = box.rot.column2.y;
+ const float m22 = box.rot.column2.z;
+
+ m.column0.z = m20;
+ m.column1.z = m21;
+ m.column2.z = m22;
+ t.z = -(m30*m20 + m31*m21 + m32*m22);
+ }
+
+#ifdef GU_BV4_USE_SLABS
+ // PT: this class moved here to make things compile with pedantic compilers.
+ struct BVDataSwizzled : public physx::shdfnd::UserAllocated
+ {
+ #ifdef GU_BV4_QUANTIZED_TREE
+ struct Data
+ {
+ PxI16 mMin; //!< Quantized min
+ PxI16 mMax; //!< Quantized max
+ };
+
+ Data mX[4];
+ Data mY[4];
+ Data mZ[4];
+ #else
+ float mMinX[4];
+ float mMinY[4];
+ float mMinZ[4];
+ float mMaxX[4];
+ float mMaxY[4];
+ float mMaxZ[4];
+ #endif
+ PxU32 mData[4];
+
+ PX_FORCE_INLINE PxU32 isLeaf(PxU32 i) const { return mData[i]&1; }
+ PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return mData[i]>>1; }
+ PX_FORCE_INLINE PxU32 getChildOffset(PxU32 i) const { return mData[i]>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
+ PX_FORCE_INLINE PxU32 getChildType(PxU32 i) const { return (mData[i]>>1)&3; }
+ PX_FORCE_INLINE PxU32 getChildData(PxU32 i) const { return mData[i]; }
+ PX_FORCE_INLINE PxU32 decodePNSNoShift(PxU32 i) const { return mData[i]; }
+ };
+#else
+ #define SSE_CONST4(name, val) static const __declspec(align(16)) PxU32 name[4] = { (val), (val), (val), (val) }
+ #define SSE_CONST(name) *(const __m128i *)&name
+ #define SSE_CONSTF(name) *(const __m128 *)&name
+#endif
+
+ PX_FORCE_INLINE PxU32 getNbPrimitives(PxU32& primIndex)
+ {
+ PxU32 NbToGo = (primIndex & 15)-1;
+ primIndex>>=4;
+ return NbToGo;
+ }
+
+ template<class ParamsT>
+ PX_FORCE_INLINE void setupMeshPointersAndQuantizedCoeffs(ParamsT* PX_RESTRICT params, const SourceMesh* PX_RESTRICT mesh, const BV4Tree* PX_RESTRICT tree)
+ {
+ params->mTris32 = mesh->getTris32();
+ params->mTris16 = mesh->getTris16();
+ params->mVerts = mesh->getVerts();
+
+#ifdef GU_BV4_QUANTIZED_TREE
+ V4StoreA_Safe(V4LoadU_Safe(&tree->mCenterOrMinCoeff.x), &params->mCenterOrMinCoeff_PaddedAligned.x);
+ V4StoreA_Safe(V4LoadU_Safe(&tree->mExtentsOrMaxCoeff.x), &params->mExtentsOrMaxCoeff_PaddedAligned.x);
+#else
+ PX_UNUSED(tree);
+#endif
+ }
+
+ PX_FORCE_INLINE void rotateBox(Gu::Box& dst, const PxMat44& m, const Gu::Box& src)
+ {
+ // The extents remain constant
+ dst.extents = src.extents;
+ // The center gets x-formed
+ dst.center = m.transform(src.center);
+ // Combine rotations
+ // PT: TODO: revisit.. this is awkward... grab 3x3 part of 4x4 matrix (TA34704)
+ const PxMat33 tmp( PxVec3(m.column0.x, m.column0.y, m.column0.z),
+ PxVec3(m.column1.x, m.column1.y, m.column1.z),
+ PxVec3(m.column2.x, m.column2.y, m.column2.z));
+ dst.rot = tmp * src.rot;
+ }
+
+ PX_FORCE_INLINE PxVec3 inverseRotate(const PxMat44* PX_RESTRICT src, const PxVec3& p)
+ {
+ const float m00 = src->column0.x;
+ const float m01 = src->column0.y;
+ const float m02 = src->column0.z;
+
+ const float m10 = src->column1.x;
+ const float m11 = src->column1.y;
+ const float m12 = src->column1.z;
+
+ const float m20 = src->column2.x;
+ const float m21 = src->column2.y;
+ const float m22 = src->column2.z;
+
+ return PxVec3( m00*p.x + m01*p.y + m02*p.z,
+ m10*p.x + m11*p.y + m12*p.z,
+ m20*p.x + m21*p.y + m22*p.z);
+ }
+
+ PX_FORCE_INLINE PxVec3 inverseTransform(const PxMat44* PX_RESTRICT src, const PxVec3& p)
+ {
+ const float m30 = src->column3.x;
+ const float m31 = src->column3.y;
+ const float m32 = src->column3.z;
+
+ const float m00 = src->column0.x;
+ const float m01 = src->column0.y;
+ const float m02 = src->column0.z;
+
+ const float m10 = src->column1.x;
+ const float m11 = src->column1.y;
+ const float m12 = src->column1.z;
+
+ const float m20 = src->column2.x;
+ const float m21 = src->column2.y;
+ const float m22 = src->column2.z;
+
+ return PxVec3( m00*p.x + m01*p.y + m02*p.z -(m30*m00 + m31*m01 + m32*m02),
+ m10*p.x + m11*p.y + m12*p.z -(m30*m10 + m31*m11 + m32*m12),
+ m20*p.x + m21*p.y + m22*p.z -(m30*m20 + m31*m21 + m32*m22));
+ }
+
+ PX_FORCE_INLINE void computeLocalRay(PxVec3& localDir, PxVec3& localOrigin, const PxVec3& dir, const PxVec3& origin, const PxMat44* PX_RESTRICT worldm_Aligned)
+ {
+ if(worldm_Aligned)
+ {
+ localDir = inverseRotate(worldm_Aligned, dir);
+ localOrigin = inverseTransform(worldm_Aligned, origin);
+ }
+ else
+ {
+ localDir = dir;
+ localOrigin = origin;
+ }
+ }
+
+ PX_FORCE_INLINE void computeLocalSphere(float& radius2, PxVec3& local_center, const Sphere& sphere, const PxMat44* PX_RESTRICT worldm_Aligned)
+ {
+ radius2 = sphere.radius * sphere.radius;
+ if(worldm_Aligned)
+ {
+ local_center = inverseTransform(worldm_Aligned, sphere.center);
+ }
+ else
+ {
+ local_center = sphere.center;
+ }
+ }
+
+ PX_FORCE_INLINE void computeLocalCapsule(Capsule& localCapsule, const Capsule& capsule, const PxMat44* PX_RESTRICT worldm_Aligned)
+ {
+ localCapsule.radius = capsule.radius;
+ if(worldm_Aligned)
+ {
+ localCapsule.p0 = inverseTransform(worldm_Aligned, capsule.p0);
+ localCapsule.p1 = inverseTransform(worldm_Aligned, capsule.p1);
+ }
+ else
+ {
+ localCapsule.p0 = capsule.p0;
+ localCapsule.p1 = capsule.p1;
+ }
+ }
+
+ PX_FORCE_INLINE void computeLocalBox(Gu::Box& dst, const Gu::Box& src, const PxMat44* PX_RESTRICT worldm_Aligned)
+ {
+ if(worldm_Aligned)
+ {
+ PxMat44 invWorldM;
+ invertPRMatrix(&invWorldM, worldm_Aligned);
+
+ rotateBox(dst, invWorldM, src);
+ }
+ else
+ {
+ dst = src; // PT: TODO: check asm for operator= (TA34704)
+ }
+ }
+
+ template<class ImpactFunctionT, class ShapeT, class ParamsT>
+ static PX_FORCE_INLINE bool computeImpactDataT(const ShapeT& shape, const PxVec3& dir, SweepHit* PX_RESTRICT hit, const ParamsT* PX_RESTRICT params, const PxMat44* PX_RESTRICT worldm, bool isDoubleSided, bool meshBothSides)
+ {
+ if(params->mStabbedFace.mTriangleID==PX_INVALID_U32)
+ return false; // We didn't touch any triangle
+
+ if(hit)
+ {
+ const float t = params->mStabbedFace.mDistance;
+ hit->mTriangleID = params->mStabbedFace.mTriangleID;
+ hit->mDistance = t;
+
+ if(t==0.0f)
+ {
+ hit->mPos = PxVec3(0.0f);
+ hit->mNormal = -dir;
+ }
+ else
+ {
+ // PT: TODO: we shouldn't compute impact in world space, and in fact moving this to local space is necessary if we want to reuse this for box-sweeps (TA34704)
+ TrianglePadded WP;
+ if(worldm)
+ {
+ WP.verts[0] = worldm->transform(params->mP0);
+ WP.verts[1] = worldm->transform(params->mP1);
+ WP.verts[2] = worldm->transform(params->mP2);
+ }
+ else
+ {
+ WP.verts[0] = params->mP0;
+ WP.verts[1] = params->mP1;
+ WP.verts[2] = params->mP2;
+ }
+
+ PxVec3 impactNormal;
+ ImpactFunctionT::computeImpact(hit->mPos, impactNormal, shape, dir, t, WP);
+
+ // PT: by design, returned normal is opposed to the sweep direction.
+ if(shouldFlipNormal(impactNormal, meshBothSides, isDoubleSided, params->mBestTriNormal, dir))
+ impactNormal = -impactNormal;
+
+ hit->mNormal = impactNormal;
+ }
+ }
+ return true;
+ }
+
+ // PT: we don't create a structure for small meshes with just a few triangles. We use brute-force tests on these.
+ template<class LeafFunction_AnyT, class LeafFunction_ClosestT, class ParamsT>
+ static void doBruteForceTests(PxU32 nbTris, ParamsT* PX_RESTRICT params)
+ {
+ PX_ASSERT(nbTris<16);
+ if(params->mEarlyExit)
+ LeafFunction_AnyT::doLeafTest(params, nbTris);
+ else
+ LeafFunction_ClosestT::doLeafTest(params, nbTris);
+ }
+
+#if PX_INTEL_FAMILY
+#ifndef GU_BV4_USE_SLABS
+ template<class ParamsT>
+ PX_FORCE_INLINE void setupRayData(ParamsT* PX_RESTRICT params, float max_dist, const PxVec3& origin, const PxVec3& dir)
+ {
+ const float Half = 0.5f*max_dist;
+ const FloatV HalfV = FLoad(Half);
+ const Vec4V DataV = V4Scale(V4LoadU(&dir.x), HalfV);
+ const Vec4V Data2V = V4Add(V4LoadU(&origin.x), DataV);
+ const PxU32 MaskI = 0x7fffffff;
+ const Vec4V FDirV = _mm_and_ps(_mm_load1_ps((float*)&MaskI), DataV);
+ V4StoreA_Safe(DataV, &params->mData_PaddedAligned.x);
+ V4StoreA_Safe(Data2V, &params->mData2_PaddedAligned.x);
+ V4StoreA_Safe(FDirV, &params->mFDir_PaddedAligned.x);
+ }
+#endif
+#endif
+
+}
+}
+
+#endif // GU_BV4_COMMON_H