mirror of https://github.com/axmolengine/axmol.git
338 lines
9.4 KiB
C
338 lines
9.4 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_CONTACT_H
|
||
|
#define B2_CONTACT_H
|
||
|
|
||
|
#include "b2_api.h"
|
||
|
#include "b2_collision.h"
|
||
|
#include "b2_fixture.h"
|
||
|
#include "b2_math.h"
|
||
|
#include "b2_shape.h"
|
||
|
|
||
|
class b2Body;
|
||
|
class b2Contact;
|
||
|
class b2Fixture;
|
||
|
class b2World;
|
||
|
class b2BlockAllocator;
|
||
|
class b2StackAllocator;
|
||
|
class b2ContactListener;
|
||
|
|
||
|
/// Friction mixing law. The idea is to allow either fixture to drive the friction to zero.
|
||
|
/// For example, anything slides on ice.
|
||
|
inline float b2MixFriction(float friction1, float friction2) {
|
||
|
return b2Sqrt(friction1 * friction2);
|
||
|
}
|
||
|
|
||
|
/// Restitution mixing law. The idea is allow for anything to bounce off an inelastic surface.
|
||
|
/// For example, a superball bounces on anything.
|
||
|
inline float b2MixRestitution(float restitution1, float restitution2) {
|
||
|
return restitution1 > restitution2 ? restitution1 : restitution2;
|
||
|
}
|
||
|
|
||
|
typedef void b2EvaluateFunction(b2Manifold* manifold,
|
||
|
const b2Shape* shapeA, const b2Transform& xfA,
|
||
|
const b2Shape* shapeB, const b2Transform& xfB);
|
||
|
|
||
|
/// Restitution mixing law. This picks the lowest value.
|
||
|
inline float b2MixRestitutionThreshold(float threshold1, float threshold2)
|
||
|
{
|
||
|
return threshold1 < threshold2 ? threshold1 : threshold2;
|
||
|
}
|
||
|
|
||
|
/// The class manages contact between two shapes. A contact exists for each overlapping
|
||
|
/// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
|
||
|
/// that has no contact points.
|
||
|
class B2_API b2Contact
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
/// Get the contact manifold. Do not modify the manifold unless you understand the
|
||
|
/// internals of Box2D.
|
||
|
b2Manifold* GetManifold();
|
||
|
const b2Manifold* GetManifold() const;
|
||
|
|
||
|
/// Get the world manifold.
|
||
|
void GetWorldManifold(b2WorldManifold* worldManifold) const;
|
||
|
|
||
|
/// Is this contact touching?
|
||
|
bool IsTouching() const;
|
||
|
|
||
|
/// Enable/disable this contact. This can be used inside the pre-solve
|
||
|
/// contact listener. The contact is only disabled for the current
|
||
|
/// time step (or sub-step in continuous collisions).
|
||
|
void SetEnabled(bool flag);
|
||
|
|
||
|
/// Has this contact been disabled?
|
||
|
bool IsEnabled() const;
|
||
|
|
||
|
/// Get the next contact in the world's contact list.
|
||
|
b2Contact* GetNext();
|
||
|
const b2Contact* GetNext() const;
|
||
|
|
||
|
/// Get fixture A in this contact.
|
||
|
b2Fixture* GetFixtureA();
|
||
|
const b2Fixture* GetFixtureA() const;
|
||
|
|
||
|
/// Get fixture B in this contact.
|
||
|
b2Fixture* GetFixtureB();
|
||
|
const b2Fixture* GetFixtureB() const;
|
||
|
|
||
|
#ifdef ENABLE_FRICTION
|
||
|
/// Override the default friction mixture. You can call this in b2ContactListener::PreSolve.
|
||
|
/// This value persists until set or reset.
|
||
|
void SetFriction(float friction);
|
||
|
|
||
|
/// Get the friction.
|
||
|
float GetFriction() const;
|
||
|
|
||
|
/// Reset the friction mixture to the default value.
|
||
|
void ResetFriction();
|
||
|
#endif // ENABLE_FRICTION
|
||
|
|
||
|
#ifdef ENABLE_RESTITUTION
|
||
|
/// Override the default restitution mixture. You can call this in b2ContactListener::PreSolve.
|
||
|
/// The value persists until you set or reset.
|
||
|
void SetRestitution(float restitution);
|
||
|
|
||
|
/// Get the restitution.
|
||
|
float GetRestitution() const;
|
||
|
|
||
|
/// Reset the restitution to the default value.
|
||
|
void ResetRestitution();
|
||
|
|
||
|
/// Override the default restitution velocity threshold mixture. You can call this in b2ContactListener::PreSolve.
|
||
|
/// The value persists until you set or reset.
|
||
|
void SetRestitutionThreshold(float threshold);
|
||
|
|
||
|
/// Get the restitution threshold.
|
||
|
float GetRestitutionThreshold() const;
|
||
|
|
||
|
/// Reset the restitution threshold to the default value.
|
||
|
void ResetRestitutionThreshold();
|
||
|
#endif // ENABLE_RESTITUTION
|
||
|
|
||
|
#ifdef ENABLE_TANGENT_SPEED
|
||
|
/// Set the desired tangent speed for a conveyor belt behavior. In meters per second.
|
||
|
void SetTangentSpeed(float speed);
|
||
|
|
||
|
/// Get the desired tangent speed. In meters per second.
|
||
|
float GetTangentSpeed() const;
|
||
|
#endif // ENABLE_TANGENT_SPEED
|
||
|
|
||
|
/// Evaluate this contact with your own manifold and transforms.
|
||
|
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
|
||
|
|
||
|
protected:
|
||
|
friend class b2ContactManager;
|
||
|
friend class b2World;
|
||
|
friend class b2TOIMinHeap;
|
||
|
friend class b2TOIQueryWrapper;
|
||
|
friend class b2ContactSolver;
|
||
|
friend class b2Body;
|
||
|
friend class b2Fixture;
|
||
|
|
||
|
// Flags stored in m_flags
|
||
|
enum {
|
||
|
// Used when crawling contact graph when forming islands.
|
||
|
e_islandFlag = 0x0001,
|
||
|
|
||
|
// This contact has persisted from the previous step
|
||
|
e_persistFlag = 0x0002,
|
||
|
|
||
|
// This contact needs filtering because a fixture filter was changed.
|
||
|
e_filterFlag = 0x0004,
|
||
|
|
||
|
// Set when the shapes are touching.
|
||
|
e_touchingFlag = 0x0008,
|
||
|
|
||
|
// This contact can be disabled (by user)
|
||
|
e_enabledFlag = 0x0010,
|
||
|
|
||
|
// This bullet contact had a TOI event
|
||
|
e_bulletHitFlag = 0x0020
|
||
|
};
|
||
|
|
||
|
/// Flag this contact for filtering. Filtering will occur the next time step.
|
||
|
void FlagForFiltering();
|
||
|
|
||
|
static bool InitializeRegisters();
|
||
|
static b2Contact* Create(b2Fixture* fixtureA, b2Fixture* fixtureB, b2BlockAllocator* allocator);
|
||
|
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
|
||
|
|
||
|
b2Contact(b2Fixture* fixtureA, b2Fixture* fixtureB, b2EvaluateFunction* evaluateFunction);
|
||
|
|
||
|
void Update(b2ContactListener* listener);
|
||
|
|
||
|
float CalculateTOI();
|
||
|
|
||
|
static b2EvaluateFunction* functions[b2Shape::e_typeCount][b2Shape::e_typeCount];
|
||
|
|
||
|
b2EvaluateFunction* m_evaluateFunction;
|
||
|
|
||
|
// World pool and list pointers.
|
||
|
b2Contact* m_prev;
|
||
|
b2Contact* m_next;
|
||
|
|
||
|
b2Fixture* m_fixtureA;
|
||
|
b2Fixture* m_fixtureB;
|
||
|
|
||
|
b2Manifold m_manifold;
|
||
|
|
||
|
uint32 m_flags;
|
||
|
|
||
|
int32 m_toiIndex;
|
||
|
|
||
|
#ifdef ENABLE_FRICTION
|
||
|
float m_friction;
|
||
|
#endif // ENABLE_FRICTION
|
||
|
|
||
|
#ifdef ENABLE_RESTITUTION
|
||
|
float m_restitution;
|
||
|
float m_restitutionThreshold;
|
||
|
#endif // ENABLE_RESTITUTION
|
||
|
|
||
|
#ifdef ENABLE_TANGENT_SPEED
|
||
|
float m_tangentSpeed;
|
||
|
#endif // ENABLE_TANGENT_SPEED
|
||
|
};
|
||
|
|
||
|
inline b2Manifold* b2Contact::GetManifold() {
|
||
|
return &m_manifold;
|
||
|
}
|
||
|
|
||
|
inline const b2Manifold* b2Contact::GetManifold() const {
|
||
|
return &m_manifold;
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const {
|
||
|
const b2Body* bodyA = m_fixtureA->GetBody();
|
||
|
const b2Body* bodyB = m_fixtureB->GetBody();
|
||
|
const b2Shape* shapeA = m_fixtureA->GetShape();
|
||
|
const b2Shape* shapeB = m_fixtureB->GetShape();
|
||
|
|
||
|
worldManifold->Initialize(&m_manifold, bodyA->GetTransform(), shapeA->m_radius, bodyB->GetTransform(), shapeB->m_radius);
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::SetEnabled(bool flag) {
|
||
|
if (flag) {
|
||
|
m_flags |= e_enabledFlag;
|
||
|
} else {
|
||
|
m_flags &= ~e_enabledFlag;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline bool b2Contact::IsEnabled() const {
|
||
|
return (m_flags & e_enabledFlag) == e_enabledFlag;
|
||
|
}
|
||
|
|
||
|
inline bool b2Contact::IsTouching() const {
|
||
|
return (m_flags & e_touchingFlag) == e_touchingFlag;
|
||
|
}
|
||
|
|
||
|
inline b2Contact* b2Contact::GetNext() {
|
||
|
return m_next;
|
||
|
}
|
||
|
|
||
|
inline const b2Contact* b2Contact::GetNext() const {
|
||
|
return m_next;
|
||
|
}
|
||
|
|
||
|
inline b2Fixture* b2Contact::GetFixtureA() {
|
||
|
return m_fixtureA;
|
||
|
}
|
||
|
|
||
|
inline const b2Fixture* b2Contact::GetFixtureA() const {
|
||
|
return m_fixtureA;
|
||
|
}
|
||
|
|
||
|
inline b2Fixture* b2Contact::GetFixtureB() {
|
||
|
return m_fixtureB;
|
||
|
}
|
||
|
|
||
|
inline const b2Fixture* b2Contact::GetFixtureB() const {
|
||
|
return m_fixtureB;
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::FlagForFiltering() {
|
||
|
m_flags |= e_filterFlag;
|
||
|
}
|
||
|
|
||
|
#ifdef ENABLE_FRICTION
|
||
|
inline void b2Contact::SetFriction(float friction) {
|
||
|
m_friction = friction;
|
||
|
}
|
||
|
|
||
|
inline float b2Contact::GetFriction() const {
|
||
|
return m_friction;
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::ResetFriction() {
|
||
|
m_friction = b2MixFriction(m_fixtureA->m_friction, m_fixtureB->m_friction);
|
||
|
}
|
||
|
#endif // ENABLE_FRICTION
|
||
|
|
||
|
#ifdef ENABLE_RESTITUTION
|
||
|
inline void b2Contact::SetRestitution(float restitution) {
|
||
|
m_restitution = restitution;
|
||
|
}
|
||
|
|
||
|
inline float b2Contact::GetRestitution() const {
|
||
|
return m_restitution;
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::ResetRestitution() {
|
||
|
m_restitution = b2MixRestitution(m_fixtureA->m_restitution, m_fixtureB->m_restitution);
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::SetRestitutionThreshold(float threshold)
|
||
|
{
|
||
|
m_restitutionThreshold = threshold;
|
||
|
}
|
||
|
|
||
|
inline float b2Contact::GetRestitutionThreshold() const
|
||
|
{
|
||
|
return m_restitutionThreshold;
|
||
|
}
|
||
|
|
||
|
inline void b2Contact::ResetRestitutionThreshold()
|
||
|
{
|
||
|
m_restitutionThreshold = b2MixRestitutionThreshold(m_fixtureA->m_restitutionThreshold, m_fixtureB->m_restitutionThreshold);
|
||
|
}
|
||
|
#endif // ENABLE_RESTITUTION
|
||
|
|
||
|
#ifdef ENABLE_TANGENT_SPEED
|
||
|
inline void b2Contact::SetTangentSpeed(float speed) {
|
||
|
m_tangentSpeed = speed;
|
||
|
}
|
||
|
|
||
|
inline float b2Contact::GetTangentSpeed() const {
|
||
|
return m_tangentSpeed;
|
||
|
}
|
||
|
#endif // ENABLE_TANGENT_SPEED
|
||
|
|
||
|
inline void b2Contact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB) {
|
||
|
m_evaluateFunction(manifold, m_fixtureA->GetShape(), xfA, m_fixtureB->GetShape(), xfB);
|
||
|
}
|
||
|
|
||
|
#endif
|