13BoxColUnit::BoxColUnit() : m_pos(
nullptr), m_radius(0.0f), m_range(0.0f), m_userData(
nullptr) {}
16BoxColUnit::~BoxColUnit() =
default;
19void BoxColUnit::init(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
const BoxColFlag &flag,
23 m_range = radius + maxSpeed;
25 m_flag.
setBit(eBoxColFlag::Active);
26 m_userData = userData;
27 m_xMax = pos->x + m_range;
28 m_xMin = pos->x - m_range;
32void BoxColUnit::makeInactive() {
33 m_flag.
resetBit(eBoxColFlag::Active);
37void BoxColUnit::resize(f32 radius, f32 maxSpeed) {
39 m_range = radius + maxSpeed;
44void BoxColUnit::reinsert() {
45 BoxColManager::Instance()->reinsertUnit(
this);
49void BoxColUnit::search(
const BoxColFlag &flag) {
50 BoxColManager::Instance()->search(
this, flag);
56 constexpr f32 SPATIAL_BOUND = 999999.9f;
58 static const EGG::Vector3f upperBound(SPATIAL_BOUND, SPATIAL_BOUND, SPATIAL_BOUND);
59 static const EGG::Vector3f lowerBound(-SPATIAL_BOUND, -SPATIAL_BOUND, -SPATIAL_BOUND);
74BoxColManager::~BoxColManager() {
77 WARN(
"BoxColManager instance not explicitly handled!");
82void BoxColManager::clear() {
83 m_nextObjectID = MAX_UNIT_COUNT;
84 m_nextDrivableID = MAX_UNIT_COUNT;
86 m_cacheQueryUnit =
nullptr;
87 m_cacheRadius = -1.0f;
98 int activeUnitIdx = 0;
101 if (unit.m_flag.offBit(eBoxColFlag::Active)) {
107 unit.m_xMax = unit.m_pos->x + unit.m_range;
108 unit.m_xMin = unit.m_pos->x - unit.m_range;
109 m_highPoints[unit.m_highPointIdx].z = unit.m_pos->z + unit.m_range;
110 m_lowPoints[unit.m_lowPointIdx].z = unit.m_pos->z - unit.m_range;
117 if (++activeUnitIdx >= m_unitCount) {
127 for (
size_t i = 1; i < static_cast<size_t>(m_unitCount); ++i) {
132 std::swap(upper, lower);
136 ++upperLow.highPoint;
137 --lowerLow.highPoint;
142 u8 &nextMinLowPoint = upper.minLowPoint;
143 if (nextMinLowPoint == lower.lowPoint) {
146 }
while (
m_lowPoints[nextMinLowPoint].highPoint < j);
149 lower.minLowPoint = std::min(lower.minLowPoint, upper.lowPoint);
154 for (
size_t i = 1; i < static_cast<size_t>(m_unitCount); ++i) {
159 std::swap(upper, lower);
167 if (upper.highPoint > lower.highPoint) {
168 int k = upper.highPoint;
170 while (k > lower.highPoint &&
m_highPoints[k].minLowPoint == j - 1) {
174 int k = lower.highPoint;
176 while (k > upper.highPoint &&
m_highPoints[k].minLowPoint == j) {
190ObjectDrivable *BoxColManager::getNextDrivable() {
191 return reinterpret_cast<ObjectDrivable *
>(
getNextImpl(m_nextDrivableID, eBoxColFlag::Drivable));
195void BoxColManager::resetIterators() {
197 iterate(m_nextObjectID, eBoxColFlag::Object);
199 m_nextDrivableID = -1;
200 iterate(m_nextDrivableID, eBoxColFlag::Drivable);
204BoxColUnit *BoxColManager::insertDriver(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
205 bool alwaysRecalc, Kart::KartObject *kartObject) {
206 BoxColFlag flag = BoxColFlag(eBoxColFlag::Driver);
212 return insert(radius, maxSpeed, pos, flag, kartObject);
216BoxColUnit *BoxColManager::insertObject(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
217 bool alwaysRecalc,
void *userData) {
218 BoxColFlag flag = BoxColFlag(eBoxColFlag::Object);
224 return insert(radius, maxSpeed, pos, flag, userData);
228BoxColUnit *BoxColManager::insertDrivable(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
229 bool alwaysRecalc,
void *userData) {
230 BoxColFlag flag = BoxColFlag(eBoxColFlag::Drivable);
236 return insert(radius, maxSpeed, pos, flag, userData);
240void BoxColManager::reinsertUnit(
BoxColUnit *unit) {
241 f32 radius = unit->m_radius;
242 f32 maxSpeed = unit->m_range - radius;
243 const EGG::Vector3f *pos = unit->m_pos;
244 BoxColFlag flag = unit->m_flag;
245 void *userData = unit->m_userData;
248 insert(radius, maxSpeed, pos, BoxColFlag(), userData)->m_flag = flag;
252void BoxColManager::remove(
BoxColUnit *&unit) {
253 if (!unit || unit->m_flag.offBit(eBoxColFlag::Active)) {
257 int highPointIdx = unit->m_highPointIdx;
258 int lowPointIdx = unit->m_lowPointIdx;
261 for (
int i = highPointIdx; i < m_unitCount - 1; ++i) {
268 if (high.minLowPoint > lowPointIdx) {
274 for (
int i = lowPointIdx; i < m_unitCount - 1; ++i) {
281 if (low.highPoint >= highPointIdx) {
285 int minLowPoint =
m_highPoints[low.highPoint].minLowPoint;
287 if (minLowPoint != lowPointIdx) {
291 for (BoxColLowPoint *pLowPoint = &
m_lowPoints[minLowPoint];
292 pLowPoint->highPoint < low.highPoint; ++minLowPoint) {
299 unit->makeInactive();
302 m_nextUnitID = nextID;
308void BoxColManager::search(
BoxColUnit *unit,
const BoxColFlag &flag) {
309 searchImpl(unit, flag);
314void BoxColManager::search(f32 radius,
const EGG::Vector3f &pos,
const BoxColFlag &flag) {
315 searchImpl(radius, pos, flag);
320bool BoxColManager::isSphereInSpatialCache(f32 radius,
const EGG::Vector3f &pos,
321 const BoxColFlag &flag)
const {
322 if (m_cacheRadius == -1.0f) {
326 if (!m_cacheFlag.onAll(flag)) {
330 f32 radiusDiff = m_cacheRadius - radius;
331 EGG::Vector3f posDiff = pos - m_cachePoint;
333 return EGG::Mathf::abs(posDiff.x) <= radiusDiff && EGG::Mathf::abs(posDiff.z) <= radiusDiff;
339 s_instance = EGG::egg_new<BoxColManager>();
344void BoxColManager::DestroyInstance() {
346 auto *instance = s_instance;
347 s_instance =
nullptr;
348 EGG::egg_delete(instance);
357 if (
id == MAX_UNIT_COUNT) {
364 return unit->m_userData;
368void BoxColManager::iterate(s32 &iter,
const BoxColFlag &flag) {
369 while (++iter < m_maxID) {
370 if (
m_units[iter]->m_flag.on(flag)) {
375 iter = MAX_UNIT_COUNT;
379BoxColUnit *BoxColManager::insert(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
380 const BoxColFlag &flag,
void *userData) {
381 if (m_unitCount >=
static_cast<s32
>(MAX_UNIT_COUNT)) {
385 s32 unitID = m_nextUnitID;
387 unit.init(radius, maxSpeed, pos, flag, userData);
389 f32 range = radius + maxSpeed;
390 f32 zHigh = pos->z + range;
391 f32 zLow = pos->z - range;
393 if (m_unitCount == 0) {
409 int highPointIdx = 0;
414 int highSearch = highPointIdx + i;
415 int lowSearch = lowPointIdx + i;
417 if (highSearch <= m_unitCount && zHigh >
m_highPoints[highSearch - 1].z) {
418 highPointIdx = highSearch;
421 if (lowSearch <= m_unitCount && zLow >
m_lowPoints[lowSearch - 1].z) {
422 lowPointIdx = lowSearch;
432 unit.m_highPointIdx = highPointIdx;
433 unit.m_lowPointIdx = lowPointIdx;
436 for (
int i = m_unitCount; i > highPointIdx; --i) {
444 if (high.minLowPoint >= lowPointIdx) {
453 if (highPointIdx == m_unitCount ||
m_highPoints[highPointIdx + 1].minLowPoint > lowPointIdx) {
456 for (
int i = highPointIdx - 1; i >= 0 &&
m_highPoints[i].minLowPoint > lowPointIdx; --i) {
464 for (
int i = m_unitCount; i > lowPointIdx; --i) {
481void BoxColManager::searchImpl(
BoxColUnit *unit,
const BoxColFlag &flag) {
482 if (unit->m_flag.offBit(eBoxColFlag::Active)) {
486 int highPointIdx = unit->m_highPointIdx;
487 int lowPointIdx = unit->m_lowPointIdx;
488 int origLowPointIdx = unit->m_lowPointIdx;
493 f32 xMax = unit->m_xMax;
494 f32 xMin = unit->m_xMin;
496 const EGG::Vector3f *pos = unit->m_pos;
497 f32 radius = unit->m_radius;
499 f32 zHigh = pos->z + radius;
500 f32 zLow = pos->z - radius;
501 f32 xHigh = pos->x + radius;
502 f32 xLow = pos->x - radius;
504 int maxIdx = m_unitCount - 1;
507 m_cacheQueryUnit = unit;
508 m_cacheRadius = -1.0f;
511 for (; highPointIdx > 7 &&
m_highPoints[highPointIdx - 8].z >= lowZPos;) {
515 for (; highPointIdx > 0 &&
m_highPoints[highPointIdx - 1].z >= lowZPos;) {
519 for (; lowPointIdx < maxIdx - 7 &&
m_lowPoints[lowPointIdx + 8].z <= highZPos;) {
523 for (; lowPointIdx < maxIdx &&
m_lowPoints[lowPointIdx + 1].z <= highZPos;) {
527 u8 minLowPoint =
m_highPoints[highPointIdx].minLowPoint;
529 for (
int i = lowPointIdx; i >= minLowPoint; --i, --lowPointIdx) {
532 if (low.highPoint >= highPointIdx && lowPointIdx != origLowPointIdx) {
535 if (lowUnit.m_xMax < xMin || lowUnit.m_xMin > xMax) {
543 f32 radius = lowUnit.m_radius;
544 if (lowUnit.m_pos->z + radius < zLow || lowUnit.m_pos->z - radius > zHigh) {
548 if (lowUnit.m_pos->x + radius < xLow || lowUnit.m_pos->x - radius > xHigh) {
554 if (m_maxID == MAX_UNIT_COUNT) {
559 if (lowPointIdx == 0) {
566void BoxColManager::searchImpl(f32 radius,
const EGG::Vector3f &pos,
const BoxColFlag &flag) {
568 int highPointIdx = 0;
570 f32 zHigh = pos.z + radius;
571 f32 zLow = pos.z - radius;
572 f32 xHigh = pos.x + radius;
573 f32 xLow = pos.x - radius;
576 m_cacheQueryUnit =
nullptr;
578 m_cacheRadius = radius;
581 int i = m_unitCount - 1;
583 int highSearch = highPointIdx + i;
584 int lowSearch = lowPointIdx + i;
585 if (highSearch <= m_unitCount && zLow >
m_highPoints[highSearch - 1].z) {
586 highPointIdx = highSearch;
589 if (lowSearch <= m_unitCount && zHigh >=
m_lowPoints[lowSearch].z) {
590 lowPointIdx = lowSearch;
600 u8 minLowPoint =
m_highPoints[highPointIdx].minLowPoint;
602 for (i = lowPointIdx; i >= minLowPoint; --i, --lowPointIdx) {
604 if (low.highPoint >= highPointIdx) {
607 if (unit.m_xMax < xLow || unit.m_xMin > xHigh) {
617 if (m_maxID == MAX_UNIT_COUNT) {
622 if (lowPointIdx == 0) {