botw/src/KingSystem/Physics/System/physContactLayerCollisionIn...

118 lines
4.1 KiB
C++

#include "KingSystem/Physics/System/physContactLayerCollisionInfoGroup.h"
#include "KingSystem/Physics/System/physContactLayerCollisionInfo.h"
#include "KingSystem/Physics/System/physSystem.h"
namespace ksys::phys {
ContactLayerCollisionInfoGroup::ContactLayerCollisionInfoGroup(ContactLayer layer,
const sead::SafeString& name)
: sead::INamable(name), mLayer(layer) {}
ContactLayerCollisionInfoGroup::~ContactLayerCollisionInfoGroup() = default;
ContactLayerCollisionInfoGroup* ContactLayerCollisionInfoGroup::make(sead::Heap* heap,
ContactLayer layer,
int capacity,
const sead::SafeString& name) {
return System::instance()->makeContactLayerCollisionInfoGroup(heap, layer, capacity, name);
}
void ContactLayerCollisionInfoGroup::free(ContactLayerCollisionInfoGroup* group) {
System::instance()->freeContactLayerCollisionInfoGroup(group);
}
void ContactLayerCollisionInfoGroup::init(sead::Heap* heap, int capacity) {
mCollisionInfoInstances.allocBuffer(capacity, heap);
mLayers.allocBufferAssert(capacity, heap);
}
void ContactLayerCollisionInfoGroup::finalize() {
mCollisionInfoInstances.freeBuffer();
mLayers.freeBuffer();
}
// NON_MATCHING: trivial reordering
void ContactLayerCollisionInfoGroup::addLayer(ContactLayer layer) {
auto& info = mLayers[mCollisionInfoInstances.size()];
info.layer = layer;
info.layer_gt = mLayer > layer;
info.layer_le = !info.layer_gt;
auto* collision_info = System::instance()->trackLayerPair(mLayer, layer);
mCollisionInfoInstances.pushBack(collision_info);
}
void ContactLayerCollisionInfoGroup::ensureLayersAreTracked() {
for (int i = 0; i < mCollisionInfoInstances.size(); ++i) {
System::instance()->trackLayerPair(mLayer, mLayers[i].layer);
}
}
ContactLayerCollisionInfoGroup::CollidingBodiesIterator::CollidingBodiesIterator(
const ContactLayerCollisionInfoGroup* group, int index, IsStart start)
: mGroup(group), mInfoIndex(index) {
if (!bool(start))
return;
initIterator(group);
// If there is no colliding body, turn this iterator into an end iterator.
if (!mCollidingBodiesEntry) {
mInfo = nullptr;
mInfoIndex = group->mCollisionInfoInstances.size();
}
}
ContactLayerCollisionInfoGroup::CollidingBodiesIterator::~CollidingBodiesIterator() {
if (mInfo)
mInfo->unlock();
}
void ContactLayerCollisionInfoGroup::CollidingBodiesIterator::initIterator(
const ContactLayerCollisionInfoGroup* group) {
for (mInfoIndex = 0; mInfoIndex < group->mCollisionInfoInstances.size(); ++mInfoIndex) {
mInfo = group->mCollisionInfoInstances[mInfoIndex];
if (!mInfo)
continue;
mInfo->lock();
mCollidingBodiesEntry = mInfo->getCollidingBodies().front();
if (mCollidingBodiesEntry) {
// Keep the ContactLayerCollisionInfo locked.
break;
}
// Otherwise, unlock the current ContactLayerCollisionInfo and try the next one.
mInfo->unlock();
}
}
ContactLayerCollisionInfoGroup::CollidingBodiesIterator&
ContactLayerCollisionInfoGroup::CollidingBodiesIterator::operator++() {
auto* group = mGroup;
mCollidingBodiesEntry = mInfo->getCollidingBodies().next(mCollidingBodiesEntry);
if (mCollidingBodiesEntry)
return *this;
// If we reached the last entry in the current ContactLayerCollisionInfo,
// move on to the next one.
++mInfoIndex;
for (; mInfoIndex < group->mCollisionInfoInstances.size(); ++mInfoIndex) {
auto* next_info = group->mCollisionInfoInstances[mInfoIndex];
if (!next_info)
continue;
mInfo->unlock();
mInfo = next_info;
mInfo->lock();
mCollidingBodiesEntry = mInfo->getCollidingBodies().front();
if (mCollidingBodiesEntry)
break;
}
return *this;
}
} // namespace ksys::phys