Revision control

++ // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
++ // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
++ // SPDX-FileCopyrightText: Copyright (c) 2008-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
++ // SPDX-License-Identifier: Apache-2.0
++
++ #include "geometry/PxSphereGeometry.h"
++ #include "geometry/PxCustomGeometry.h"
++ #include "geometry/PxConvexCoreGeometry.h"
++ #include "geometry/PxHeightFieldGeometry.h"
++ #include "GuSweepTests.h"
++ #include "GuVecCapsule.h"
++ #include "GuVecBox.h"
++ #include "GuVecTriangle.h"
++ #include "GuSweepTriangleUtils.h"
++ #include "GuInternal.h"
++ #include "GuGJKRaycast.h"
++ #include "GuConvexGeometry.h"
++ #include "GuConvexSupport.h"
++ #include "GuMidphaseInterface.h"
++ #include "geometry/PxGjkQuery.h"
++ #include "GuHeightField.h"
++ #include "GuEntityReport.h"
++ #include "GuHeightFieldUtil.h"
++
++ using namespace physx;
++ using namespace Gu;
++ using namespace Cm;
++ using namespace aos;
++
++ //#define USE_VIRTUAL_GJK
++ #ifdef USE_VIRTUAL_GJK
++ static bool virtualGjkRaycastPenetration(const GjkConvex& a, const GjkConvex& b, const Vec3VArg initialDir, const FloatVArg initialLambda, const Vec3VArg s, const Vec3VArg r, FloatV& lambda,
++ Vec3V& normal, Vec3V& closestA, const PxReal _inflation, const bool initialOverlap)
++ {
++ return gjkRaycastPenetration<GjkConvex, GjkConvex >(a, b, initialDir, initialLambda, s, r, lambda, normal, closestA, _inflation, initialOverlap);
++ }
++ #endif
++
++ bool sweepCapsule_BoxGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(threadContext);
++
++ using namespace aos;
++ PX_ASSERT(geom.getType() == PxGeometryType::eBOX);
++ const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom);
++
++ const FloatV zero = FZero();
++ const Vec3V zeroV = V3Zero();
++ const Vec3V boxExtents0 = V3LoadU(boxGeom.halfExtents);
++ const FloatV dist = FLoad(distance);
++ const Vec3V worldDir = V3LoadU(unitDir);
++
++ const PxTransformV capPos = loadTransformU(capsulePose_);
++ const PxTransformV boxPos = loadTransformU(pose);
++
++ const PxMatTransformV aToB(boxPos.transformInv(capPos));
++
++ const FloatV capsuleHalfHeight = FLoad(capsuleGeom_.halfHeight);
++ const FloatV capsuleRadius = FLoad(lss.radius);
++
++ BoxV box(zeroV, boxExtents0);
++ CapsuleV capsule(aToB.p, aToB.rotate(V3Scale(V3UnitX(), capsuleHalfHeight)), capsuleRadius);
++
++ const Vec3V dir = boxPos.rotateInv(V3Neg(V3Scale(worldDir, dist)));
++
++ const bool isMtd = hitFlags & PxHitFlag::eMTD;
++ FloatV toi = FMax();
++ Vec3V closestA, normal;//closestA and normal is in the local space of box
++ const LocalConvex<CapsuleV> convexA(capsule);
++ const LocalConvex<BoxV> convexB(box);
++ const Vec3V initialSearchDir = V3Sub(capsule.getCenter(), box.getCenter());
++ #ifdef USE_VIRTUAL_GJK
++ if(!virtualGjkRaycastPenetration(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, lss.radius + inflation, isMtd))
++ return false;
++ #else
++ if(!gjkRaycastPenetration<LocalConvex<CapsuleV>, LocalConvex<BoxV> >(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, lss.radius + inflation, isMtd))
++ return false;
++ #endif
++ sweepHit.flags = PxHitFlag::eNORMAL;
++
++ if(FAllGrtrOrEq(zero, toi))
++ {
++ //initial overlap
++ if(isMtd)
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const Vec3V worldPointA = boxPos.transform(closestA);
++ const Vec3V destNormal = boxPos.rotate(normal);
++ const FloatV length = toi;
++ const Vec3V destWorldPointA = V3NegScaleSub(destNormal, length, worldPointA);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ V3StoreU(destNormal, sweepHit.normal);
++ FStore(length, &sweepHit.distance);
++ }
++ else
++ {
++ sweepHit.distance = 0.0f;
++ sweepHit.normal = -unitDir;
++ }
++ }
++ else
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const Vec3V worldPointA = boxPos.transform(closestA);
++ const Vec3V destNormal = boxPos.rotate(normal);
++ const FloatV length = FMul(dist, toi);
++ const Vec3V destWorldPointA = V3ScaleAdd(worldDir, length, worldPointA);
++ V3StoreU(destNormal, sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ return true;
++ }
++
++ bool sweepBox_SphereGeom(GU_BOX_SWEEP_FUNC_PARAMS)
++ {
++ PX_ASSERT(geom.getType() == PxGeometryType::eSPHERE);
++ PX_UNUSED(threadContext);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(boxGeom_);
++
++ const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom);
++
++ const FloatV zero = FZero();
++ const Vec3V zeroV = V3Zero();
++ const Vec3V boxExtents = V3LoadU(box.extents);
++ const FloatV worldDist = FLoad(distance);
++ const Vec3V unitDirV = V3LoadU(unitDir);
++
++ const FloatV sphereRadius = FLoad(sphereGeom.radius);
++
++ const PxTransformV spherePos = loadTransformU(pose);
++ const PxTransformV boxPos = loadTransformU(boxPose_);
++
++ const PxMatTransformV aToB(boxPos.transformInv(spherePos));
++
++ const BoxV boxV(zeroV, boxExtents);
++ const CapsuleV capsuleV(aToB.p, sphereRadius);
++
++ //transform into b space
++ const Vec3V dir = boxPos.rotateInv(V3Scale(unitDirV, worldDist));
++
++ const bool isMtd = hitFlags & PxHitFlag::eMTD;
++ FloatV toi;
++ Vec3V closestA, normal;//closestA and normal is in the local space of box
++ const Vec3V initialSearchDir = V3Sub(capsuleV.getCenter(), boxV.getCenter());
++ const LocalConvex<CapsuleV> convexA(capsuleV);
++ const LocalConvex<BoxV> convexB(boxV);
++ #ifdef USE_VIRTUAL_GJK
++ if(!virtualGjkRaycastPenetration(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, sphereGeom.radius+inflation, isMtd))
++ return false;
++ #else
++ if(!gjkRaycastPenetration<LocalConvex<CapsuleV>, LocalConvex<BoxV> >(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, sphereGeom.radius+inflation, isMtd))
++ return false;
++ #endif
++ sweepHit.flags = PxHitFlag::eNORMAL;
++
++ //initial overlap
++ if(FAllGrtrOrEq(zero, toi))
++ {
++ if(isMtd)
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const Vec3V destWorldPointA = boxPos.transform(closestA);
++ const Vec3V destNormal = V3Neg(boxPos.rotate(normal));
++ const FloatV length = toi;
++ V3StoreU(destNormal, sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ else
++ {
++ sweepHit.distance = 0.0f;
++ sweepHit.normal = -unitDir;
++ }
++ }
++ else
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const Vec3V destWorldPointA = boxPos.transform(closestA);
++ const Vec3V destNormal = V3Neg(boxPos.rotate(normal));
++ const FloatV length = FMul(worldDist, toi);
++ V3StoreU(destNormal, sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ return true;
++ }
++
++ bool sweepBox_CapsuleGeom(GU_BOX_SWEEP_FUNC_PARAMS)
++ {
++ using namespace aos;
++ PX_ASSERT(geom.getType() == PxGeometryType::eCAPSULE);
++ PX_UNUSED(threadContext);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(boxGeom_);
++
++ const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom);
++
++ const FloatV capsuleHalfHeight = FLoad(capsuleGeom.halfHeight);
++ const FloatV capsuleRadius = FLoad(capsuleGeom.radius);
++
++ const FloatV zero = FZero();
++ const Vec3V zeroV = V3Zero();
++ const Vec3V boxExtents = V3LoadU(box.extents);
++ const FloatV worldDist = FLoad(distance);
++ const Vec3V unitDirV = V3LoadU(unitDir);
++
++ const PxTransformV capPos = loadTransformU(pose);
++ const PxTransformV boxPos = loadTransformU(boxPose_);
++
++ const PxMatTransformV aToB(boxPos.transformInv(capPos));
++
++ const BoxV boxV(zeroV, boxExtents);
++ const CapsuleV capsuleV(aToB.p, aToB.rotate(V3Scale(V3UnitX(), capsuleHalfHeight)), capsuleRadius);
++
++ //transform into b space
++ const Vec3V dir = boxPos.rotateInv(V3Scale(unitDirV, worldDist));
++
++ const bool isMtd = hitFlags & PxHitFlag::eMTD;
++ FloatV toi;
++ Vec3V closestA, normal;//closestA and normal is in the local space of box
++ const Vec3V initialSearchDir = V3Sub(capsuleV.getCenter(), boxV.getCenter());
++ const LocalConvex<CapsuleV> convexA(capsuleV);
++ const LocalConvex<BoxV> convexB(boxV);
++ #ifdef USE_VIRTUAL_GJK
++ if(!virtualGjkRaycastPenetration(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, capsuleGeom.radius+inflation, isMtd))
++ return false;
++ #else
++ if(!gjkRaycastPenetration<LocalConvex<CapsuleV>, LocalConvex<BoxV> >(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, capsuleGeom.radius+inflation, isMtd))
++ return false;
++ #endif
++ sweepHit.flags = PxHitFlag::eNORMAL;
++
++ //initial overlap
++ if(FAllGrtrOrEq(zero, toi))
++ {
++ if(isMtd)
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ //initial overlap is toi < 0
++ const FloatV length = toi;
++ const Vec3V destWorldPointA = boxPos.transform(closestA);
++ const Vec3V destNormal = boxPos.rotate(normal);
++ V3StoreU(V3Neg(destNormal), sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ else
++ {
++ sweepHit.distance = 0.0f;
++ sweepHit.normal = -unitDir;
++ }
++ return true;
++ }
++ else
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const Vec3V destWorldPointA = boxPos.transform(closestA);
++ const Vec3V destNormal = boxPos.rotate(normal);
++ const FloatV length = FMul(worldDist, toi);
++ V3StoreU(V3Neg(destNormal), sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ return true;
++ }
++
++ bool sweepBox_BoxGeom(GU_BOX_SWEEP_FUNC_PARAMS)
++ {
++ PX_ASSERT(geom.getType() == PxGeometryType::eBOX);
++ PX_UNUSED(threadContext);
++ PX_UNUSED(boxGeom_);
++
++ const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom);
++
++ const FloatV zero = FZero();
++ const Vec3V zeroV = V3Zero();
++ const Vec3V boxExtents0 = V3LoadU(boxGeom.halfExtents);
++ const Vec3V boxExtents1 = V3LoadU(box.extents);
++ const FloatV worldDist = FLoad(distance);
++ const Vec3V unitDirV = V3LoadU(unitDir);
++
++ const PxTransformV boxTrans0 = loadTransformU(pose);
++ const PxTransformV boxTrans1 = loadTransformU(boxPose_);
++
++ const PxMatTransformV aToB(boxTrans1.transformInv(boxTrans0));
++
++ const BoxV box0(zeroV, boxExtents0);
++ const BoxV box1(zeroV, boxExtents1);
++
++ //transform into b space
++ const Vec3V dir = boxTrans1.rotateInv(V3Scale(unitDirV, worldDist));
++ const bool isMtd = hitFlags & PxHitFlag::eMTD;
++ FloatV toi;
++ Vec3V closestA, normal;//closestA and normal is in the local space of box
++ const RelativeConvex<BoxV> convexA(box0, aToB);
++ const LocalConvex<BoxV> convexB(box1);
++ #ifdef USE_VIRTUAL_GJK
++ if(!virtualGjkRaycastPenetration(convexA, convexB, aToB.p, zero, zeroV, dir, toi, normal, closestA, inflation, isMtd))
++ return false;
++ #else
++ if(!gjkRaycastPenetration<RelativeConvex<BoxV>, LocalConvex<BoxV> >(convexA, convexB, aToB.p, zero, zeroV, dir, toi, normal, closestA, inflation, isMtd))
++ return false;
++ #endif
++ sweepHit.flags = PxHitFlag::eNORMAL;
++ if(FAllGrtrOrEq(zero, toi))
++ {
++ if(isMtd)
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const FloatV length = toi;
++ const Vec3V destWorldPointA = boxTrans1.transform(closestA);
++ const Vec3V destNormal = V3Normalize(boxTrans1.rotate(normal));
++ V3StoreU(V3Neg(destNormal), sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ else
++ {
++ sweepHit.distance = 0.0f;
++ sweepHit.normal = -unitDir;
++ }
++ }
++ else
++ {
++ sweepHit.flags |= PxHitFlag::ePOSITION;
++ const Vec3V destWorldPointA = boxTrans1.transform(closestA);
++ const Vec3V destNormal = V3Normalize(boxTrans1.rotate(normal));
++ const FloatV length = FMul(worldDist, toi);
++ V3StoreU(V3Neg(destNormal), sweepHit.normal);
++ V3StoreU(destWorldPointA, sweepHit.position);
++ FStore(length, &sweepHit.distance);
++ }
++ return true;
++ }
++
++ bool Gu::sweepBoxTriangles(GU_SWEEP_TRIANGLES_FUNC_PARAMS(PxBoxGeometry))
++ {
++ PX_UNUSED(hitFlags);
++
++ if(!nbTris)
++ return false;
++
++ const bool meshBothSides = hitFlags & PxHitFlag::eMESH_BOTH_SIDES;
++ const bool doBackfaceCulling = !doubleSided && !meshBothSides;
++
++ Box box;
++ buildFrom(box, pose.p, geom.halfExtents, pose.q);
++
++ PxGeomSweepHit sweepHit;
++ // Move to AABB space
++ PxMat34 worldToBox;
++ computeWorldToBoxMatrix(worldToBox, box);
++
++ const PxVec3 localDir = worldToBox.rotate(unitDir);
++ const PxVec3 localMotion = localDir * distance;
++
++ const Vec3V base0 = V3LoadU(worldToBox.m.column0);
++ const Vec3V base1 = V3LoadU(worldToBox.m.column1);
++ const Vec3V base2 = V3LoadU(worldToBox.m.column2);
++ const Mat33V matV(base0, base1, base2);
++ const Vec3V p = V3LoadU(worldToBox.p);
++ const PxMatTransformV worldToBoxV(p, matV);
++
++ const FloatV zero = FZero();
++ const Vec3V zeroV = V3Zero();
++ const Vec3V boxExtents = V3LoadU(box.extents);
++ const Vec3V boxDir = V3LoadU(localDir);
++ const FloatV inflationV = FLoad(inflation);
++ const Vec3V absBoxDir = V3Abs(boxDir);
++ const FloatV boxRadiusV = FAdd(V3Dot(absBoxDir, boxExtents), inflationV);
++ BoxV boxV(zeroV, boxExtents);
++
++ #if PX_DEBUG
++ PxU32 totalTestsExpected = nbTris;
++ PxU32 totalTestsReal = 0;
++ PX_UNUSED(totalTestsExpected);
++ PX_UNUSED(totalTestsReal);
++ #endif
++
++ Vec3V boxLocalMotion = V3LoadU(localMotion);
++ Vec3V minClosestA = zeroV, minNormal = zeroV;
++ PxU32 minTriangleIndex = 0;
++ PxVec3 bestTriNormal(0.0f);
++ FloatV dist = FLoad(distance);
++
++ const PxTransformV boxPos = loadTransformU(pose);
++
++ bool status = false;
++
++ const PxU32 idx = cachedIndex ? *cachedIndex : 0;
++
++ for(PxU32 ii=0;ii<nbTris;ii++)
++ {
++ const PxU32 triangleIndex = getTriangleIndex(ii, idx);
++
++ const Vec3V localV0 = V3LoadU(triangles[triangleIndex].verts[0]);
++ const Vec3V localV1 = V3LoadU(triangles[triangleIndex].verts[1]);
++ const Vec3V localV2 = V3LoadU(triangles[triangleIndex].verts[2]);
++
++ const Vec3V triV0 = worldToBoxV.transform(localV0);
++ const Vec3V triV1 = worldToBoxV.transform(localV1);
++ const Vec3V triV2 = worldToBoxV.transform(localV2);
++
++ const Vec3V triNormal = V3Cross(V3Sub(triV2, triV1),V3Sub(triV0, triV1));
++
++ if(doBackfaceCulling && FAllGrtrOrEq(V3Dot(triNormal, boxLocalMotion), zero)) // backface culling
++ continue;
++
++ const FloatV dp0 = V3Dot(triV0, boxDir);
++ const FloatV dp1 = V3Dot(triV1, boxDir);
++ const FloatV dp2 = V3Dot(triV2, boxDir);
++
++ const FloatV dp = FMin(dp0, FMin(dp1, dp2));
++
++ const Vec3V dpV = V3Merge(dp0, dp1, dp2);
++
++ const FloatV temp1 = FAdd(boxRadiusV, dist);
++ const BoolV con0 = FIsGrtr(dp, temp1);
++ const BoolV con1 = V3IsGrtr(zeroV, dpV);
++
++ if(BAllEqTTTT(BOr(con0, con1)))
++ continue;
++
++ #if PX_DEBUG
++ totalTestsReal++;
++ #endif
++
++ TriangleV triangleV(triV0, triV1, triV2);
++
++ FloatV lambda;
++ Vec3V closestA, normal;//closestA and normal is in the local space of convex hull
++ const LocalConvex<TriangleV> convexA(triangleV);
++ const LocalConvex<BoxV> convexB(boxV);
++ const Vec3V initialSearchDir = V3Sub(triangleV.getCenter(), boxV.getCenter());
++ #ifdef USE_VIRTUAL_GJK
++ if(virtualGjkRaycastPenetration(convexA, convexB, initialSearchDir, zero, zeroV, boxLocalMotion, lambda, normal, closestA, inflation, false))
++ #else
++ if(gjkRaycastPenetration<LocalConvex<TriangleV>, LocalConvex<BoxV> >(convexA, convexB, initialSearchDir, zero, zeroV, boxLocalMotion, lambda, normal, closestA, inflation, false))
++ #endif
++ {
++ //hitCount++;
++
++ if(FAllGrtrOrEq(zero, lambda))
++ {
++ hit.distance = 0.0f;
++ hit.faceIndex = triangleIndex;
++ hit.normal = -unitDir;
++ hit.flags = PxHitFlag::eNORMAL;
++ return true;
++ }
++
++ dist = FMul(dist, lambda);
++ boxLocalMotion = V3Scale(boxDir, dist);
++ minClosestA = closestA;
++ minNormal = normal;
++ minTriangleIndex = triangleIndex;
++ V3StoreU(triNormal, bestTriNormal);
++ status = true;
++ if(hitFlags & PxHitFlag::eANY_HIT)
++ break;
++ }
++ }
++
++ if(!status)
++ return false;
++
++ hit.faceIndex = minTriangleIndex;
++ const Vec3V destNormal = V3Neg(V3Normalize(boxPos.rotate(minNormal)));
++ const Vec3V destWorldPointA = boxPos.transform(minClosestA);
++ V3StoreU(destNormal, hit.normal);
++ V3StoreU(destWorldPointA, hit.position);
++ FStore(dist, &hit.distance);
++
++ // PT: by design, returned normal is opposed to the sweep direction.
++ if(shouldFlipNormal(hit.normal, meshBothSides, doubleSided, bestTriNormal, unitDir))
++ hit.normal = -hit.normal;
++
++ hit.flags = PxHitFlag::ePOSITION|PxHitFlag::eNORMAL;
++ return true;
++ }
++
++ bool sweepCapsule_SphereGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_PlaneGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_CapsuleGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_BoxGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_BoxGeom_Precise (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_ConvexGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_MeshGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++ bool sweepCapsule_HeightFieldGeom (GU_CAPSULE_SWEEP_FUNC_PARAMS);
++
++ bool sweepBox_SphereGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_SphereGeom_Precise (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_PlaneGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_CapsuleGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_CapsuleGeom_Precise (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_BoxGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_BoxGeom_Precise (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_ConvexGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_MeshGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_HeightFieldGeom (GU_BOX_SWEEP_FUNC_PARAMS);
++ bool sweepBox_HeightFieldGeom_Precise(GU_BOX_SWEEP_FUNC_PARAMS);
++
++ bool sweepConvex_SphereGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_PlaneGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_CapsuleGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_BoxGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_ConvexCoreGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_ConvexGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_MeshGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++ bool sweepConvex_HeightFieldGeom (GU_CONVEX_SWEEP_FUNC_PARAMS);
++
++ static bool sweepCapsule_InvalidGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(capsuleGeom_);
++ PX_UNUSED(capsulePose_);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(lss);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++ return false;
++ }
++
++ static bool sweepBox_InvalidGeom(GU_BOX_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(boxPose_);
++ PX_UNUSED(boxGeom_);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(box);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++ return false;
++ }
++
++ static bool sweepConvexCore_InvalidGeom(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++ return false;
++ }
++
++ static bool sweepConvex_InvalidGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++ return false;
++ }
++
++ static bool sweepCapsule_CustomGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(lss);
++ if(geom.getType() == PxGeometryType::eCUSTOM)
++ return static_cast<const PxCustomGeometry&>(geom).callbacks->sweep(unitDir, distance, geom, pose, capsuleGeom_, capsulePose_, sweepHit, hitFlags, inflation, threadContext);
++ return false;
++ }
++
++ static bool sweepBox_CustomGeom(GU_BOX_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(box);
++ if(geom.getType() == PxGeometryType::eCUSTOM)
++ return static_cast<const PxCustomGeometry&>(geom).callbacks->sweep(unitDir, distance, geom, pose, boxGeom_, boxPose_, sweepHit, hitFlags, inflation, threadContext);
++ return false;
++ }
++
++ static bool sweepConvexCore_CustomGeom(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ if (geom.getType() == PxGeometryType::eCUSTOM)
++ return static_cast<const PxCustomGeometry&>(geom).callbacks->sweep(unitDir, distance, geom, pose, convexGeom, convexPose, sweepHit, hitFlags, inflation, threadContext);
++ return false;
++ }
++
++ static bool sweepConvex_CustomGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
++ {
++ if(geom.getType() == PxGeometryType::eCUSTOM)
++ return static_cast<const PxCustomGeometry&>(geom).callbacks->sweep(unitDir, distance, geom, pose, convexGeom, convexPose, sweepHit, hitFlags, inflation, threadContext);
++ return false;
++ }
++
++ static bool sweepCapsule_ConvexCoreGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(capsuleGeom_);
++ PX_UNUSED(capsulePose_);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(lss);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ struct CapsuleSupport : PxGjkQuery::Support
++ {
++ PxCapsuleGeometry capsule;
++ CapsuleSupport(const PxCapsuleGeometry& c)
++ : capsule(c) {}
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return capsule.radius; }
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return PxVec3(PxSign(dir.x) * capsule.halfHeight, 0, 0); }
++ };
++
++ struct ConvexCoreSupport : PxGjkQuery::Support
++ {
++ Gu::ConvexShape shape;
++ ConvexCoreSupport(const PxConvexCoreGeometry& g)
++ { Gu::makeConvexShape(g, PxTransform(PxIdentity), shape); }
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return shape.margin; }
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return shape.supportLocal(dir); }
++ };
++
++ const PxConvexCoreGeometry& convex = static_cast<const PxConvexCoreGeometry&>(geom);
++ if (convex.isValid())
++ {
++ PxBounds3 bounds = Gu::computeBounds(convex, pose);
++ bounds.include(Gu::computeBounds(capsuleGeom_, capsulePose_));
++ PxReal wiseDist = PxMin(distance, bounds.getDimensions().magnitude());
++ PxReal t;
++ PxVec3 n, p;
++ if (PxGjkQuery::sweep(ConvexCoreSupport(convex), CapsuleSupport(capsuleGeom_), pose, capsulePose_, unitDir, wiseDist, t, n, p))
++ {
++ PxGeomSweepHit& hit = sweepHit;
++ hit.distance = t;
++ hit.position = p;
++ hit.normal = n;
++ hit.flags |= PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
++ return 1;
++ }
++ }
++
++ return 0;
++ }
++
++ static bool sweepBox_ConvexCoreGeom(GU_BOX_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(boxPose_);
++ PX_UNUSED(boxGeom_);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(box);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ struct BoxSupport : PxGjkQuery::Support
++ {
++ PxBoxGeometry box;
++ BoxSupport(const PxBoxGeometry& b)
++ : box(b) {}
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return 0; }
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return PxVec3(PxSign(dir.x) * box.halfExtents.x,
++ PxSign(dir.y) * box.halfExtents.y, PxSign(dir.z) * box.halfExtents.z); }
++ };
++
++ struct ConvexCoreSupport : PxGjkQuery::Support
++ {
++ Gu::ConvexShape shape;
++ ConvexCoreSupport(const PxConvexCoreGeometry& g)
++ { Gu::makeConvexShape(g, PxTransform(PxIdentity), shape); }
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return shape.margin; }
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return shape.supportLocal(dir); }
++ };
++
++ const PxConvexCoreGeometry& convex = static_cast<const PxConvexCoreGeometry&>(geom);
++ if (convex.isValid())
++ {
++ PxBounds3 bounds = Gu::computeBounds(convex, pose);
++ bounds.include(Gu::computeBounds(boxGeom_, boxPose_));
++ PxReal wiseDist = PxMin(distance, bounds.getDimensions().magnitude());
++ PxReal t;
++ PxVec3 n, p;
++ if (PxGjkQuery::sweep(ConvexCoreSupport(convex), BoxSupport(boxGeom_), pose, boxPose_, unitDir, wiseDist, t, n, p))
++ {
++ PxGeomSweepHit& hit = sweepHit;
++ hit.distance = t;
++ hit.position = p;
++ hit.normal = n;
++ hit.flags |= PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
++ return 1;
++ }
++ }
++
++ return 0;
++ }
++
++ static bool sweepConvexCore_Plane(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ PxPlane plane = getPlane(pose);
++
++ Gu::ConvexShape shape;
++ Gu::makeConvexShape(convexGeom, convexPose, shape);
++ shape.margin += inflation;
++
++ PxVec3 closestPoint = shape.support(-plane.n);
++ PxReal closestDist = plane.distance(closestPoint);
++
++ sweepHit.faceIndex = 0xffffffff;
++
++ if (closestDist <= 0)
++ {
++ if (hitFlags & PxHitFlag::eMTD)
++ {
++ sweepHit.flags = PxHitFlag::eNORMAL | PxHitFlag::ePOSITION;
++ sweepHit.distance = closestDist;
++ sweepHit.normal = plane.n;
++ sweepHit.position = closestPoint + plane.n * closestDist;
++ return true;
++ }
++ else if (!(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP))
++ {
++ sweepHit.flags = PxHitFlag::eNORMAL;
++ sweepHit.distance = 0.0f;
++ sweepHit.normal = -unitDir;
++ return true;
++ }
++ }
++
++ PxReal dirDotNorm = unitDir.dot(plane.n);
++
++ const PxReal dotEps = 1e-5f;
++ if (dirDotNorm < -dotEps)
++ {
++ PxReal hitDistance = closestDist / -dirDotNorm;
++ if (hitDistance < distance)
++ {
++ sweepHit.flags = PxHitFlag::eNORMAL | PxHitFlag::ePOSITION;
++ sweepHit.distance = hitDistance;
++ sweepHit.normal = plane.n;
++ sweepHit.position = closestPoint + unitDir * hitDistance;
++ return true;
++ }
++ }
++
++ return false;
++ }
++
++ static bool sweepConvexCore_Convex(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ bool res = false;
++ switch (geom.getType())
++ {
++ case PxGeometryType::eSPHERE:
++ res = sweepCapsule_ConvexCoreGeom(convexGeom, convexPose, PxCapsuleGeometry(static_cast<const PxSphereGeometry&>(geom).radius, 0),
++ pose, Gu::Capsule(), -unitDir, distance, sweepHit, hitFlags, inflation, threadContext);
++ break;
++ case PxGeometryType::eCAPSULE:
++ res = sweepCapsule_ConvexCoreGeom(convexGeom, convexPose, static_cast<const PxCapsuleGeometry&>(geom), pose,
++ Gu::Capsule(), -unitDir, distance, sweepHit, hitFlags, inflation, threadContext);
++ break;
++ case PxGeometryType::eBOX:
++ res = sweepBox_ConvexCoreGeom(convexGeom, convexPose, static_cast<const PxBoxGeometry&>(geom), pose,
++ Gu::Box(), -unitDir, distance, sweepHit, hitFlags, inflation, threadContext);
++ break;
++ case PxGeometryType::eCONVEXMESH:
++ res = sweepConvex_ConvexCoreGeom(convexGeom, convexPose, static_cast<const PxConvexMeshGeometry&>(geom), pose,
++ -unitDir, distance, sweepHit, hitFlags, inflation, threadContext);
++ break;
++ default:
++ PX_ASSERT(0);
++ }
++
++ if (res)
++ {
++ if (sweepHit.flags & PxHitFlag::eNORMAL)
++ sweepHit.normal = -sweepHit.normal;
++
++ if (sweepHit.flags & PxHitFlag::ePOSITION)
++ sweepHit.position += unitDir * sweepHit.distance;
++ }
++
++ return res;
++ }
++
++ static bool sweepConvexCore_ConvexCore(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ struct ConvexCoreSupport : PxGjkQuery::Support
++ {
++ Gu::ConvexShape shape;
++ ConvexCoreSupport(const PxConvexCoreGeometry& g)
++ { Gu::makeConvexShape(g, PxTransform(PxIdentity), shape); }
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return shape.margin; }
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return shape.supportLocal(dir); }
++ };
++
++ const PxConvexCoreGeometry& convex = static_cast<const PxConvexCoreGeometry&>(geom);
++ if (convex.isValid())
++ {
++ PxBounds3 bounds = Gu::computeBounds(convex, pose);
++ bounds.include(Gu::computeBounds(convexGeom, convexPose));
++ PxReal wiseDist = PxMin(distance, bounds.getDimensions().magnitude());
++ PxReal t;
++ PxVec3 n, p;
++ if (PxGjkQuery::sweep(ConvexCoreSupport(convex), ConvexCoreSupport(convexGeom), pose, convexPose, unitDir, wiseDist, t, n, p))
++ {
++ PxGeomSweepHit& hit = sweepHit;
++ hit.distance = t;
++ hit.position = p;
++ hit.normal = n;
++ hit.flags |= PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
++ return true;
++ }
++ }
++
++ return false;
++ }
++
++ static bool sweepConvexCore_MeshGeom(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ struct TriSupport : PxGjkQuery::Support
++ {
++ PxVec3 v0, v1, v2;
++
++ TriSupport(const PxVec3& _v0, const PxVec3& _v1, const PxVec3& _v2)
++ : v0(_v0), v1(_v1), v2(_v2) {}
++
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return 0; }
++
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { PxReal d0 = dir.dot(v0), d1 = dir.dot(v1), d2 = dir.dot(v2);
++ return (d0 > d1 && d0 > d2) ? v0 : (d1 > d2) ? v1 : v2; }
++ };
++
++ struct ConvexCoreSupport : PxGjkQuery::Support
++ {
++ Gu::ConvexShape shape;
++ PxReal inflation;
++
++ ConvexCoreSupport(const PxConvexCoreGeometry& g, PxReal inf)
++ : inflation(inf)
++ { Gu::makeConvexShape(g, PxTransform(PxIdentity), shape); }
++
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return shape.margin + inflation; }
++
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return shape.supportLocal(dir); }
++ };
++
++ struct Callback : MeshHitCallback<PxGeomRaycastHit>
++ {
++ ConvexCoreSupport convexSupport;
++ PxTransform convexPose;
++ PxVec3 unitDir;
++ PxReal maxDist;
++
++ PxGeomSweepHit closestHit;
++
++ Callback(const PxConvexCoreGeometry& geom, const PxTransform& pose, const PxVec3& dir, PxReal dist, PxReal inf)
++ :
++ MeshHitCallback<PxGeomRaycastHit>(CallbackMode::eMULTIPLE),
++ convexSupport(geom, inf), convexPose(pose), unitDir(dir), maxDist(dist)
++ {
++ closestHit.distance = FLT_MAX;
++ }
++
++ virtual PxAgain processHit(const PxGeomRaycastHit& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal&, const PxU32*) PX_OVERRIDE
++ {
++ PxReal t; PxVec3 n, p;
++ TriSupport triSupport(v0, v1, v2);
++ if (PxGjkQuery::sweep(triSupport, convexSupport, PxTransform(PxIdentity), convexPose, unitDir, maxDist, t, n, p))
++ {
++ if (t < closestHit.distance)
++ {
++ closestHit.distance = t;
++ closestHit.position = p;
++ closestHit.normal = n;
++ closestHit.faceIndex = hit.faceIndex;
++ }
++ }
++ return true;
++ }
++ };
++
++ const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom);
++ const TriangleMesh* meshData = _getMeshData(meshGeom);
++ const bool doubleSided = (meshGeom.meshFlags & PxMeshGeometryFlag::eDOUBLE_SIDED) || (hitFlags & PxHitFlag::eMESH_BOTH_SIDES);
++
++ PxTransform localPose = pose.transformInv(convexPose);
++ PxVec3 localDir = pose.transformInv(unitDir);
++ PxBounds3 bounds = Gu::computeBounds(convexGeom, localPose);
++ bounds.include(Gu::computeBounds(convexGeom, PxTransform(localPose.p + localDir * distance, localPose.q)));
++
++ Box queryBox;
++ queryBox.extents = bounds.getExtents() + PxVec3(inflation);
++ queryBox.center = bounds.getCenter();
++ queryBox.rot = PxMat33(PxIdentity);
++
++ Callback callback(convexGeom, localPose, localDir, distance, inflation);
++ Midphase::intersectOBB(meshData, queryBox, callback, doubleSided);
++
++ if (callback.closestHit.distance <= distance)
++ {
++ PxGeomSweepHit& hit = sweepHit;
++ hit.distance = callback.closestHit.distance;
++ hit.position = pose.transform(callback.closestHit.position);
++ hit.normal = pose.rotate(callback.closestHit.normal);
++ hit.faceIndex = callback.closestHit.faceIndex;
++ hit.flags |= PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX;
++ return true;
++ }
++
++ return false;
++ }
++
++ bool sweepConvexCore_HeightFieldGeom(GU_CONVEXCORE_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ struct TriSupport : PxGjkQuery::Support
++ {
++ PxVec3 v0, v1, v2;
++
++ TriSupport(const PxVec3& _v0, const PxVec3& _v1, const PxVec3& _v2)
++ : v0(_v0), v1(_v1), v2(_v2) {}
++
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return 0; }
++
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { PxReal d0 = dir.dot(v0), d1 = dir.dot(v1), d2 = dir.dot(v2);
++ return (d0 > d1 && d0 > d2) ? v0 : (d1 > d2) ? v1 : v2; }
++ };
++
++ struct ConvexCoreSupport : PxGjkQuery::Support
++ {
++ Gu::ConvexShape shape;
++ PxReal inflation;
++
++ ConvexCoreSupport(const PxConvexCoreGeometry& g, PxReal inf)
++ : inflation(inf)
++ { Gu::makeConvexShape(g, PxTransform(PxIdentity), shape); }
++
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return shape.margin + inflation; }
++
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return shape.supportLocal(dir); }
++ };
++
++ struct Callback : Gu::OverlapReport
++ {
++ ConvexCoreSupport convexSupport;
++ PxTransform convexPose;
++ PxVec3 unitDir;
++ PxReal maxDist;
++ const Gu::HeightFieldUtil mHfUtil;
++ const PxTransform& mHFPose;
++
++ PxGeomSweepHit closestHit;
++
++ Callback(const PxConvexCoreGeometry& geom, const PxTransform& pose, const PxVec3& dir, PxReal dist, PxReal inf, const PxHeightFieldGeometry& hfGeom, const PxTransform& hfPose)
++ : convexSupport(geom, inf), convexPose(pose), unitDir(dir), maxDist(dist), mHfUtil(hfGeom), mHFPose(hfPose)
++ {
++ closestHit.distance = FLT_MAX;
++ }
++
++ virtual bool reportTouchedTris(PxU32 nb, const PxU32* indices) PX_OVERRIDE
++ {
++ while(nb--)
++ {
++ const PxU32 triangleIndex = *indices++;
++
++ PxTrianglePadded currentTriangle;
++ mHfUtil.getTriangle(mHFPose, currentTriangle, NULL, NULL, triangleIndex, false, false);
++
++ const PxVec3& v0 = currentTriangle.verts[0];
++ const PxVec3& v1 = currentTriangle.verts[1];
++ const PxVec3& v2 = currentTriangle.verts[2];
++
++ PxReal t; PxVec3 n, p;
++ TriSupport triSupport(v0, v1, v2);
++ if (PxGjkQuery::sweep(triSupport, convexSupport, PxTransform(PxIdentity), convexPose, unitDir, maxDist, t, n, p))
++ {
++ if (t < closestHit.distance)
++ {
++ closestHit.distance = t;
++ closestHit.position = p;
++ closestHit.normal = n;
++ closestHit.faceIndex = triangleIndex;
++ }
++ }
++ }
++ return true;
++ }
++ };
++
++ const PxHeightFieldGeometry& hfGeom = static_cast<const PxHeightFieldGeometry&>(geom);
++ const HeightField* hf = static_cast<const HeightField*>(hfGeom.heightField);
++ if(!hf)
++ return false;
++
++ PxTransform localPose = pose.transformInv(convexPose);
++ PxVec3 localDir = pose.rotateInv(unitDir);
++ PxBounds3 bounds = Gu::computeBounds(convexGeom, localPose);
++ bounds.include(Gu::computeBounds(convexGeom, PxTransform(localPose.p + localDir * distance, localPose.q)));
++
++ Callback callback(convexGeom, localPose, localDir, distance, inflation, hfGeom, pose);
++ callback.mHfUtil.overlapAABBTriangles(bounds, callback, 4);
++
++ if (callback.closestHit.distance <= distance)
++ {
++ PxGeomSweepHit& hit = sweepHit;
++ hit.distance = callback.closestHit.distance;
++ hit.position = pose.transform(callback.closestHit.position);
++ hit.normal = pose.rotate(callback.closestHit.normal);
++ hit.faceIndex = callback.closestHit.faceIndex;
++ hit.flags |= PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX;
++ return true;
++ }
++
++ return false;
++ }
++
++ bool sweepConvex_ConvexCoreGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
++ {
++ PX_UNUSED(threadContext);
++ PX_UNUSED(geom);
++ PX_UNUSED(pose);
++ PX_UNUSED(convexGeom);
++ PX_UNUSED(convexPose);
++ PX_UNUSED(unitDir);
++ PX_UNUSED(distance);
++ PX_UNUSED(sweepHit);
++ PX_UNUSED(hitFlags);
++ PX_UNUSED(inflation);
++
++ struct ConvexSupport : PxGjkQuery::Support
++ {
++ PxConvexMeshGeometry convex;
++ PxReal inflation;
++
++ ConvexSupport(const PxConvexMeshGeometry& c, PxReal inf)
++ : convex(c), inflation(inf) {}
++
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return inflation; }
++
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ {
++ PxVec3 d = convex.scale.rotation.rotateInv(convex.scale.rotation.rotate(dir)
++ .multiply(convex.scale.scale));
++
++ const PxVec3* verts = convex.convexMesh->getVertices();
++ int count = int(convex.convexMesh->getNbVertices());
++ float maxDot = -FLT_MAX;
++ int index = -1;
++ for (int i = 0; i < count; ++i)
++ {
++ float dot = verts[i].dot(d);
++ if (dot > maxDot)
++ {
++ maxDot = dot;
++ index = i;
++ }
++ }
++
++ if (index == -1)
++ return PxVec3(0);
++
++ return convex.scale.rotation.rotateInv(convex.scale.rotation.rotate(verts[index])
++ .multiply(convex.scale.scale));
++ }
++ };
++
++ struct ConvexCoreSupport : PxGjkQuery::Support
++ {
++ Gu::ConvexShape shape;
++ ConvexCoreSupport(const PxConvexCoreGeometry& g)
++ { Gu::makeConvexShape(g, PxTransform(PxIdentity), shape); }
++ virtual PxReal getMargin() const PX_OVERRIDE
++ { return shape.margin; }
++ virtual PxVec3 supportLocal(const PxVec3& dir) const PX_OVERRIDE
++ { return shape.supportLocal(dir); }
++ };
++
++ const PxConvexCoreGeometry& convex = static_cast<const PxConvexCoreGeometry&>(geom);
++ if (convex.isValid())
++ {
++ PxBounds3 bounds = Gu::computeBounds(convex, pose);
++ bounds.include(Gu::computeBounds(convexGeom, convexPose));
++ PxReal wiseDist = PxMin(distance, bounds.getDimensions().magnitude());
++ PxReal t;
++ PxVec3 n, p;
++ if (PxGjkQuery::sweep(ConvexCoreSupport(convex), ConvexSupport(convexGeom, inflation), pose,
++ convexPose, unitDir, wiseDist, t, n, p))
++ {
++ PxGeomSweepHit& hit = sweepHit;
++ hit.distance = t;
++ hit.position = p;
++ hit.normal = n;
++ hit.flags |= PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
++ return true;
++ }
++ }
++
++ return false;
++ }
++
++ Gu::GeomSweepFuncs gGeomSweepFuncs =
++ {
++ {
++ sweepCapsule_SphereGeom,
++ sweepCapsule_PlaneGeom,
++ sweepCapsule_CapsuleGeom,
++ sweepCapsule_BoxGeom,
++ sweepCapsule_ConvexCoreGeom,
++ sweepCapsule_ConvexGeom,
++ sweepCapsule_InvalidGeom,
++ sweepCapsule_InvalidGeom,
++ sweepCapsule_MeshGeom,
++ sweepCapsule_HeightFieldGeom,
++ sweepCapsule_CustomGeom
++ },
++ {
++ sweepCapsule_SphereGeom,
++ sweepCapsule_PlaneGeom,
++ sweepCapsule_CapsuleGeom,
++ sweepCapsule_BoxGeom_Precise,
++ sweepCapsule_ConvexCoreGeom,
++ sweepCapsule_ConvexGeom,
++ sweepCapsule_InvalidGeom,
++ sweepCapsule_InvalidGeom,
++ sweepCapsule_MeshGeom ,
++ sweepCapsule_HeightFieldGeom,
++ sweepCapsule_CustomGeom
++ },
++ {
++ sweepBox_SphereGeom,
++ sweepBox_PlaneGeom,
++ sweepBox_CapsuleGeom,
++ sweepBox_BoxGeom,
++ sweepBox_ConvexCoreGeom,
++ sweepBox_ConvexGeom,
++ sweepBox_InvalidGeom,
++ sweepBox_InvalidGeom,
++ sweepBox_MeshGeom,
++ sweepBox_HeightFieldGeom,
++ sweepBox_CustomGeom
++ },
++ {
++ sweepBox_SphereGeom_Precise,
++ sweepBox_PlaneGeom,
++ sweepBox_CapsuleGeom_Precise,
++ sweepBox_BoxGeom_Precise,
++ sweepBox_ConvexCoreGeom,
++ sweepBox_ConvexGeom,
++ sweepBox_InvalidGeom,
++ sweepBox_InvalidGeom,
++ sweepBox_MeshGeom,
++ sweepBox_HeightFieldGeom_Precise,
++ sweepBox_CustomGeom
++ },
++ {
++ sweepConvexCore_Convex, // 0
++ sweepConvexCore_Plane, // 1
++ sweepConvexCore_Convex, // 2
++ sweepConvexCore_Convex, // 3
++ sweepConvexCore_ConvexCore, // 4
++ sweepConvexCore_Convex, // 5
++ sweepConvexCore_InvalidGeom, // 6
++ sweepConvexCore_InvalidGeom, // 7
++ sweepConvexCore_MeshGeom, // 8
++ sweepConvexCore_HeightFieldGeom,// 9
++ sweepConvexCore_CustomGeom // 10
++ },
++ {
++ sweepConvex_SphereGeom, // 0
++ sweepConvex_PlaneGeom, // 1
++ sweepConvex_CapsuleGeom, // 2
++ sweepConvex_BoxGeom, // 3
++ sweepConvex_ConvexCoreGeom, // 4
++ sweepConvex_ConvexGeom, // 5
++ sweepConvex_InvalidGeom, // 6
++ sweepConvex_InvalidGeom, // 7
++ sweepConvex_MeshGeom, // 8
++ sweepConvex_HeightFieldGeom,// 9
++ sweepConvex_CustomGeom // 10
++ }
++ };
++
++ PX_PHYSX_COMMON_API const GeomSweepFuncs& Gu::getSweepFuncTable()
++ {
++ return gGeomSweepFuncs;
++ }
++