#include "ContactCache.h"
ContactCache *currentContactCache = 0;
inline void ContactCacheStarted_CB(btPersistentManifold* const &manifold) {
currentContactCache->contactStarted(manifold);
}
inline void ContactCacheEnded_CB(btPersistentManifold* const &manifold) {
currentContactCache->contactEnded(manifold);
}
struct ContactPair {
const btCollisionObject *object0;
const btCollisionObject *object1;
float time;
ContactPair() : object0(0), object1(0), time(0) {}
ContactPair(const ContactPair &rhs) : object0(rhs.object0), object1(rhs.object1), time(rhs.time) {}
ContactPair(const btCollisionObject* const &object0, const btCollisionObject* const &object1, const float &time) : object0(object0), object1(object1), time(time) {}
ContactPair &operator=(const ContactPair &rhs) {
object0 = rhs.object0;
object1 = rhs.object1;
time = rhs.time;
return *this;
}
inline bool operator==(const ContactPair &rhs) const {
return ((rhs.object0 == object0) && (rhs.object1 == object1)) || ((rhs.object0 == object1) && (rhs.object1 == object0));
}
inline bool operator<(const ContactPair &rhs) const {
if (*this == rhs)
return false;
return object0 < rhs.object0;
}
inline bool equals(const btCollisionObject* const &obj0, const btCollisionObject* const &obj1) const {
return ((obj0 == object0) && (obj1 == object1)) || ((obj0 == object1) && (obj1 == object0));
}
};
ContactCache::ContactCache(bool dummy)
: events(0), cacheTime(0.2f), filter(true) {}
ContactCache::~ContactCache() {
disable();
}
void ContactCache::setEvents(const int &events) {
this->events = events;
}
void ContactCache::enable() {
currentContactCache = this;
gContactStartedCallback = ContactCacheStarted_CB;
gContactEndedCallback = ContactCacheEnded_CB;
}
void ContactCache::disable() {
if (currentContactCache == this) {
currentContactCache = 0;
if (gContactStartedCallback == ContactCacheStarted_CB)
gContactStartedCallback = 0;
if (gContactEndedCallback == ContactCacheEnded_CB)
gContactEndedCallback = 0;
}
}
bool ContactCache::isEnabled() {
return (currentContactCache == this) && (gContactStartedCallback == ContactCacheStarted_CB) && (gContactEndedCallback == ContactCacheEnded_CB);
}
void ContactCache::clear() {
cache.clear();
}
void ContactCache::update(float delta) {
for (int i = cache.size() - 1; i >= 0; --i) {
ContactPair &pair = cache.at(i);
if ((pair.time -= delta) < 0) {
const btCollisionObject* const &object0 = pair.object0;
const btCollisionObject* const &object1 = pair.object1;
const bool match0 = gdxCheckFilter(object0, object1);
const bool match1 = gdxCheckFilter(object1, object0);
if (!filter || match0 || match1)
onContactEnded(object0, match0, object1, match1);
cache.swap(i, cache.size()-1);
cache.pop_back();
}
}
}
int ContactCache::indexOf(const btCollisionObject* const &obj0, const btCollisionObject* const &obj1) {
for (int i = cache.size() - 1; i >= 0; --i) {
ContactPair &pair = cache.at(i);
if (pair.equals(obj0, obj1))
return i;
}
return -1;
}
void ContactCache::contactStarted(btPersistentManifold* manifold) {
const bool match0 = gdxCheckFilter(manifold->getBody0(), manifold->getBody1());
const bool match1 = gdxCheckFilter(manifold->getBody1(), manifold->getBody0());
if (filter && !match0 && !match1)
return;
const int idx = indexOf(manifold->getBody0(), manifold->getBody1());
if (idx >= 0) {
cache.swap(idx, cache.size()-1);
cache.pop_back();
}
else
onContactStarted(manifold, match0, match1);
}
void ContactCache::contactEnded(btPersistentManifold* manifold) {
const bool match0 = gdxCheckFilter(manifold->getBody0(), manifold->getBody1());
const bool match1 = gdxCheckFilter(manifold->getBody1(), manifold->getBody0());
if (filter && !match0 && !match1)
return;
const int idx = indexOf(manifold->getBody0(), manifold->getBody1());
if (idx >= 0)
cache[idx].time = cacheTime;
else
cache.push_back(ContactPair(manifold->getBody0(), manifold->getBody1(), cacheTime));
}