mirror of https://github.com/axmolengine/axmol.git
279 lines
9.3 KiB
C
279 lines
9.3 KiB
C
|
// MIT License
|
||
|
|
||
|
// Copyright (c) 2019 Erin Catto
|
||
|
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
// of this software and associated documentation files (the "Software"), to deal
|
||
|
// in the Software without restriction, including without limitation the rights
|
||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
// copies of the Software, and to permit persons to whom the Software is
|
||
|
// furnished to do so, subject to the following conditions:
|
||
|
|
||
|
// The above copyright notice and this permission notice shall be included in all
|
||
|
// copies or substantial portions of the Software.
|
||
|
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
|
// SOFTWARE.
|
||
|
|
||
|
#ifndef B2_COLLISION_H
|
||
|
#define B2_COLLISION_H
|
||
|
|
||
|
#include <limits.h>
|
||
|
|
||
|
#include "b2_api.h"
|
||
|
#include "b2_math.h"
|
||
|
|
||
|
/// @file
|
||
|
/// Structures and functions used for computing contact points, distance
|
||
|
/// queries, and TOI queries.
|
||
|
|
||
|
class b2Shape;
|
||
|
class b2CircleShape;
|
||
|
class b2EdgeShape;
|
||
|
class b2PolygonShape;
|
||
|
|
||
|
const uint8 b2_nullFeature = UCHAR_MAX;
|
||
|
|
||
|
/// The features that intersect to form the contact point
|
||
|
/// This must be 4 bytes or less.
|
||
|
struct B2_API b2ContactFeature
|
||
|
{
|
||
|
enum Type
|
||
|
{
|
||
|
e_vertex = 0,
|
||
|
e_face = 1
|
||
|
};
|
||
|
|
||
|
uint8 indexA; ///< Feature index on shapeA
|
||
|
uint8 indexB; ///< Feature index on shapeB
|
||
|
uint8 typeA; ///< The feature type on shapeA
|
||
|
uint8 typeB; ///< The feature type on shapeB
|
||
|
};
|
||
|
|
||
|
/// Contact ids to facilitate warm starting.
|
||
|
union B2_API b2ContactID
|
||
|
{
|
||
|
b2ContactFeature cf;
|
||
|
uint32 key; ///< Used to quickly compare contact ids.
|
||
|
};
|
||
|
|
||
|
/// A manifold point is a contact point belonging to a contact
|
||
|
/// manifold. It holds details related to the geometry and dynamics
|
||
|
/// of the contact points.
|
||
|
/// The local point usage depends on the manifold type:
|
||
|
/// -e_circles: the local center of circleB
|
||
|
/// -e_faceA: the local center of cirlceB or the clip point of polygonB
|
||
|
/// -e_faceB: the clip point of polygonA
|
||
|
/// This structure is stored across time steps, so we keep it small.
|
||
|
/// Note: the impulses are used for internal caching and may not
|
||
|
/// provide reliable contact forces, especially for high speed collisions.
|
||
|
struct B2_API b2ManifoldPoint
|
||
|
{
|
||
|
b2Vec2 localPoint; ///< usage depends on manifold type
|
||
|
float normalImpulse; ///< the non-penetration impulse
|
||
|
|
||
|
#ifdef ENABLE_FRICTION
|
||
|
float tangentImpulse; ///< the friction impulse
|
||
|
#endif // ENABLE_FRICTION
|
||
|
|
||
|
b2ContactID id; ///< uniquely identifies a contact point between two shapes
|
||
|
};
|
||
|
|
||
|
/// A manifold for two touching convex shapes.
|
||
|
/// Box2D supports multiple types of contact:
|
||
|
/// - clip point versus plane with radius
|
||
|
/// - point versus point with radius (circles)
|
||
|
/// The local point usage depends on the manifold type:
|
||
|
/// -e_circles: the local center of circleA
|
||
|
/// -e_faceA: the center of faceA
|
||
|
/// -e_faceB: the center of faceB
|
||
|
/// Similarly the local normal usage:
|
||
|
/// -e_circles: not used
|
||
|
/// -e_faceA: the normal on polygonA
|
||
|
/// -e_faceB: the normal on polygonB
|
||
|
/// We store contacts in this way so that position correction can
|
||
|
/// account for movement, which is critical for continuous physics.
|
||
|
/// All contact scenarios must be expressed in one of these types.
|
||
|
/// This structure is stored across time steps, so we keep it small.
|
||
|
struct B2_API b2Manifold
|
||
|
{
|
||
|
enum Type
|
||
|
{
|
||
|
e_circles,
|
||
|
e_faceA,
|
||
|
e_faceB
|
||
|
};
|
||
|
|
||
|
b2ManifoldPoint points[b2_maxManifoldPoints]; ///< the points of contact
|
||
|
b2Vec2 localNormal; ///< not use for Type::e_points
|
||
|
b2Vec2 localPoint; ///< usage depends on manifold type
|
||
|
Type type;
|
||
|
int32 pointCount; ///< the number of manifold points
|
||
|
};
|
||
|
|
||
|
/// This is used to compute the current state of a contact manifold.
|
||
|
struct B2_API b2WorldManifold
|
||
|
{
|
||
|
/// Evaluate the manifold with supplied transforms. This assumes
|
||
|
/// modest motion from the original state. This does not change the
|
||
|
/// point count, impulses, etc. The radii must come from the shapes
|
||
|
/// that generated the manifold.
|
||
|
void Initialize(const b2Manifold* manifold,
|
||
|
const b2Transform& xfA, float radiusA,
|
||
|
const b2Transform& xfB, float radiusB);
|
||
|
|
||
|
b2Vec2 normal; ///< world vector pointing from A to B
|
||
|
b2Vec2 points[b2_maxManifoldPoints]; ///< world contact point (point of intersection)
|
||
|
float separations[b2_maxManifoldPoints]; ///< a negative value indicates overlap, in meters
|
||
|
};
|
||
|
|
||
|
/// This is used for determining the state of contact points.
|
||
|
enum b2PointState
|
||
|
{
|
||
|
b2_nullState, ///< point does not exist
|
||
|
b2_addState, ///< point was added in the update
|
||
|
b2_persistState, ///< point persisted across the update
|
||
|
b2_removeState ///< point was removed in the update
|
||
|
};
|
||
|
|
||
|
/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
|
||
|
/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
|
||
|
B2_API void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
|
||
|
const b2Manifold* manifold1, const b2Manifold* manifold2);
|
||
|
|
||
|
/// Used for computing contact manifolds.
|
||
|
struct B2_API b2ClipVertex
|
||
|
{
|
||
|
b2Vec2 v;
|
||
|
b2ContactID id;
|
||
|
};
|
||
|
|
||
|
/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
|
||
|
struct B2_API b2RayCastInput
|
||
|
{
|
||
|
b2Vec2 p1, p2;
|
||
|
float maxFraction;
|
||
|
};
|
||
|
|
||
|
/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
|
||
|
/// come from b2RayCastInput.
|
||
|
struct B2_API b2RayCastOutput
|
||
|
{
|
||
|
b2Vec2 normal;
|
||
|
float fraction;
|
||
|
};
|
||
|
|
||
|
/// An axis aligned bounding box.
|
||
|
struct B2_API b2AABB {
|
||
|
/// Verify that the bounds are sorted.
|
||
|
bool IsValid() const;
|
||
|
|
||
|
/// Get the center of the AABB.
|
||
|
b2Vec2 GetCenter() const {
|
||
|
return 0.5f * (lowerBound + upperBound);
|
||
|
}
|
||
|
|
||
|
/// Get the extents of the AABB (half-widths).
|
||
|
b2Vec2 GetExtents() const {
|
||
|
return 0.5f * (upperBound - lowerBound);
|
||
|
}
|
||
|
|
||
|
/// Get the perimeter length
|
||
|
float GetPerimeter() const {
|
||
|
float wx = upperBound.x - lowerBound.x;
|
||
|
float wy = upperBound.y - lowerBound.y;
|
||
|
return 2.0f * (wx + wy);
|
||
|
}
|
||
|
|
||
|
/// Get the perimeter length
|
||
|
float GetArea() const {
|
||
|
float wx = upperBound.x - lowerBound.x;
|
||
|
float wy = upperBound.y - lowerBound.y;
|
||
|
return wx * wy;
|
||
|
}
|
||
|
|
||
|
/// Combine an AABB into this one.
|
||
|
void Combine(const b2AABB& aabb) {
|
||
|
lowerBound = b2Min(lowerBound, aabb.lowerBound);
|
||
|
upperBound = b2Max(upperBound, aabb.upperBound);
|
||
|
}
|
||
|
|
||
|
/// Combine two AABBs into this one.
|
||
|
void Combine(const b2AABB& aabb1, const b2AABB& aabb2) {
|
||
|
lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);
|
||
|
upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);
|
||
|
}
|
||
|
|
||
|
/// Does this aabb contain the provided AABB.
|
||
|
bool Contains(const b2AABB& aabb) const {
|
||
|
// use & instead of && to prevent short-circuit
|
||
|
return (lowerBound.x <= aabb.lowerBound.x)
|
||
|
& (lowerBound.y <= aabb.lowerBound.y)
|
||
|
& (aabb.upperBound.x <= upperBound.x)
|
||
|
& (aabb.upperBound.y <= upperBound.y);
|
||
|
}
|
||
|
|
||
|
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;
|
||
|
|
||
|
b2Vec2 lowerBound; ///< the lower vertex
|
||
|
b2Vec2 upperBound; ///< the upper vertex
|
||
|
};
|
||
|
|
||
|
/// Compute the collision manifold between two circles.
|
||
|
B2_API void b2CollideCircles(b2Manifold* manifold,
|
||
|
const b2CircleShape* circleA, const b2Transform& xfA,
|
||
|
const b2CircleShape* circleB, const b2Transform& xfB);
|
||
|
|
||
|
/// Compute the collision manifold between a polygon and a circle.
|
||
|
B2_API void b2CollidePolygonAndCircle(b2Manifold* manifold,
|
||
|
const b2PolygonShape* polygonA, const b2Transform& xfA,
|
||
|
const b2CircleShape* circleB, const b2Transform& xfB);
|
||
|
|
||
|
/// Compute the collision manifold between two polygons.
|
||
|
B2_API void b2CollidePolygons(b2Manifold* manifold,
|
||
|
const b2PolygonShape* polygonA, const b2Transform& xfA,
|
||
|
const b2PolygonShape* polygonB, const b2Transform& xfB);
|
||
|
|
||
|
/// Compute the collision manifold between an edge and a circle.
|
||
|
B2_API void b2CollideEdgeAndCircle(b2Manifold* manifold,
|
||
|
const b2EdgeShape* polygonA, const b2Transform& xfA,
|
||
|
const b2CircleShape* circleB, const b2Transform& xfB);
|
||
|
|
||
|
/// Compute the collision manifold between an edge and a polygon.
|
||
|
B2_API void b2CollideEdgeAndPolygon(b2Manifold* manifold,
|
||
|
const b2EdgeShape* edgeA, const b2Transform& xfA,
|
||
|
const b2PolygonShape* circleB, const b2Transform& xfB);
|
||
|
|
||
|
/// Clipping for contact manifolds.
|
||
|
B2_API int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
|
||
|
const b2Vec2& normal, float offset, int32 vertexIndexA);
|
||
|
|
||
|
/// Determine if two generic shapes overlap.
|
||
|
B2_API bool b2TestOverlap( const b2Shape* shapeA,
|
||
|
const b2Shape* shapeB,
|
||
|
const b2Transform& xfA, const b2Transform& xfB);
|
||
|
|
||
|
// ---------------- Inline Functions ------------------------------------------
|
||
|
|
||
|
inline bool b2AABB::IsValid() const {
|
||
|
return upperBound.x >= lowerBound.x
|
||
|
&& upperBound.y >= lowerBound.y
|
||
|
&& lowerBound.IsValid()
|
||
|
&& upperBound.IsValid();
|
||
|
}
|
||
|
|
||
|
inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b) {
|
||
|
// use & instead of && to prevent short-circuit
|
||
|
return (a.upperBound.x >= b.lowerBound.x)
|
||
|
& (a.lowerBound.x <= b.upperBound.x)
|
||
|
& (a.upperBound.y >= b.lowerBound.y)
|
||
|
& (a.lowerBound.y <= b.upperBound.y);
|
||
|
}
|
||
|
|
||
|
#endif
|