11BoxColUnit::BoxColUnit() : m_pos(
nullptr), m_radius(0.0f), m_range(0.0f), m_userData(
nullptr) {}
14BoxColUnit::~BoxColUnit() =
default;
21 m_range = radius + maxSpeed;
23 m_flag.
setBit(eBoxColFlag::Active);
24 m_userData = userData;
25 m_xMax = pos->x + m_range;
26 m_xMin = pos->x - m_range;
30void BoxColUnit::makeInactive() {
31 m_flag.
resetBit(eBoxColFlag::Active);
35void BoxColUnit::resize(f32 radius, f32 maxSpeed) {
37 m_range = radius + maxSpeed;
42void BoxColUnit::reinsert() {
43 BoxColManager::Instance()->reinsertUnit(
this);
47void BoxColUnit::search(
const BoxColFlag &flag) {
48 BoxColManager::Instance()->search(
this, flag);
54 constexpr f32 SPATIAL_BOUND = 999999.9f;
56 static const EGG::Vector3f upperBound(SPATIAL_BOUND, SPATIAL_BOUND, SPATIAL_BOUND);
57 static const EGG::Vector3f lowerBound(-SPATIAL_BOUND, -SPATIAL_BOUND, -SPATIAL_BOUND);
72BoxColManager::~BoxColManager() {
75 WARN(
"BoxColManager instance not explicitly handled!");
80void BoxColManager::clear() {
81 m_nextObjectID = MAX_UNIT_COUNT;
82 m_nextDrivableID = MAX_UNIT_COUNT;
84 m_cacheQueryUnit =
nullptr;
85 m_cacheRadius = -1.0f;
96 int activeUnitIdx = 0;
99 if (unit.m_flag.offBit(eBoxColFlag::Active)) {
105 unit.m_xMax = unit.m_pos->x + unit.m_range;
106 unit.m_xMin = unit.m_pos->x - unit.m_range;
107 m_highPoints[unit.m_highPointIdx].z = unit.m_pos->z + unit.m_range;
108 m_lowPoints[unit.m_lowPointIdx].z = unit.m_pos->z - unit.m_range;
115 if (++activeUnitIdx >= m_unitCount) {
125 for (
size_t i = 1; i < static_cast<size_t>(m_unitCount); ++i) {
130 std::swap(upper, lower);
134 ++upperLow.highPoint;
135 --lowerLow.highPoint;
140 u8 &nextMinLowPoint = upper.minLowPoint;
141 if (nextMinLowPoint == lower.lowPoint) {
144 }
while (
m_lowPoints[nextMinLowPoint].highPoint < j);
147 lower.minLowPoint = std::min(lower.minLowPoint, upper.lowPoint);
152 for (
size_t i = 1; i < static_cast<size_t>(m_unitCount); ++i) {
157 std::swap(upper, lower);
165 if (upper.highPoint > lower.highPoint) {
166 int k = upper.highPoint;
168 while (k > lower.highPoint &&
m_highPoints[k].minLowPoint == j - 1) {
172 int k = lower.highPoint;
174 while (k > upper.highPoint &&
m_highPoints[k].minLowPoint == j) {
188ObjectDrivable *BoxColManager::getNextDrivable() {
189 return reinterpret_cast<ObjectDrivable *
>(
getNextImpl(m_nextDrivableID, eBoxColFlag::Drivable));
193void BoxColManager::resetIterators() {
195 iterate(m_nextObjectID, eBoxColFlag::Object);
197 m_nextDrivableID = -1;
198 iterate(m_nextDrivableID, eBoxColFlag::Drivable);
202BoxColUnit *BoxColManager::insertDriver(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
204 BoxColFlag flag = BoxColFlag(eBoxColFlag::Driver);
210 return insert(radius, maxSpeed, pos, flag, kartObject);
214BoxColUnit *BoxColManager::insertObject(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
215 bool alwaysRecalc,
void *userData) {
216 BoxColFlag flag = BoxColFlag(eBoxColFlag::Object);
222 return insert(radius, maxSpeed, pos, flag, userData);
226BoxColUnit *BoxColManager::insertDrivable(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
227 bool alwaysRecalc,
void *userData) {
228 BoxColFlag flag = BoxColFlag(eBoxColFlag::Drivable);
234 return insert(radius, maxSpeed, pos, flag, userData);
238void BoxColManager::reinsertUnit(BoxColUnit *unit) {
239 f32 radius = unit->m_radius;
240 f32 maxSpeed = unit->m_range - radius;
242 BoxColFlag flag = unit->m_flag;
243 void *userData = unit->m_userData;
246 insert(radius, maxSpeed, pos, BoxColFlag(), userData)->m_flag = flag;
250void BoxColManager::remove(BoxColUnit *&unit) {
251 if (!unit || unit->m_flag.offBit(eBoxColFlag::Active)) {
255 int highPointIdx = unit->m_highPointIdx;
256 int lowPointIdx = unit->m_lowPointIdx;
259 for (
int i = highPointIdx; i < m_unitCount - 1; ++i) {
266 if (high.minLowPoint > lowPointIdx) {
272 for (
int i = lowPointIdx; i < m_unitCount - 1; ++i) {
279 if (low.highPoint >= highPointIdx) {
283 int minLowPoint =
m_highPoints[low.highPoint].minLowPoint;
285 if (minLowPoint != lowPointIdx) {
289 for (BoxColLowPoint *pLowPoint = &
m_lowPoints[minLowPoint];
290 pLowPoint->highPoint < low.highPoint; ++minLowPoint) {
297 unit->makeInactive();
300 m_nextUnitID = nextID;
306void BoxColManager::search(BoxColUnit *unit,
const BoxColFlag &flag) {
307 searchImpl(unit, flag);
312void BoxColManager::search(f32 radius,
const EGG::Vector3f &pos,
const BoxColFlag &flag) {
313 searchImpl(radius, pos, flag);
318bool BoxColManager::isSphereInSpatialCache(f32 radius,
const EGG::Vector3f &pos,
319 const BoxColFlag &flag)
const {
320 if (m_cacheRadius == -1.0f) {
324 if (!m_cacheFlag.
onAll(flag)) {
328 f32 radiusDiff = m_cacheRadius - radius;
331 return EGG::Mathf::abs(posDiff.x) <= radiusDiff && EGG::Mathf::abs(posDiff.z) <= radiusDiff;
335BoxColManager *BoxColManager::CreateInstance() {
342void BoxColManager::DestroyInstance() {
344 auto *instance = s_instance;
345 s_instance =
nullptr;
349BoxColManager *BoxColManager::Instance() {
355 if (
id == MAX_UNIT_COUNT) {
362 return unit->m_userData;
366void BoxColManager::iterate(
s32 &iter,
const BoxColFlag &flag) {
367 while (++iter < m_maxID) {
368 if (
m_units[iter]->m_flag.on(flag)) {
373 iter = MAX_UNIT_COUNT;
377BoxColUnit *BoxColManager::insert(f32 radius, f32 maxSpeed,
const EGG::Vector3f *pos,
378 const BoxColFlag &flag,
void *userData) {
379 if (m_unitCount >=
static_cast<s32
>(MAX_UNIT_COUNT)) {
383 s32 unitID = m_nextUnitID;
385 unit.init(radius, maxSpeed, pos, flag, userData);
387 f32 range = radius + maxSpeed;
388 f32 zHigh = pos->z + range;
389 f32 zLow = pos->z - range;
391 if (m_unitCount == 0) {
407 int highPointIdx = 0;
412 int highSearch = highPointIdx + i;
413 int lowSearch = lowPointIdx + i;
415 if (highSearch <= m_unitCount && zHigh >
m_highPoints[highSearch - 1].z) {
416 highPointIdx = highSearch;
419 if (lowSearch <= m_unitCount && zLow >
m_lowPoints[lowSearch - 1].z) {
420 lowPointIdx = lowSearch;
430 unit.m_highPointIdx = highPointIdx;
431 unit.m_lowPointIdx = lowPointIdx;
434 for (
int i = m_unitCount; i > highPointIdx; --i) {
442 if (high.minLowPoint >= lowPointIdx) {
451 if (highPointIdx == m_unitCount ||
m_highPoints[highPointIdx + 1].minLowPoint > lowPointIdx) {
454 for (
int i = highPointIdx - 1; i >= 0 &&
m_highPoints[i].minLowPoint > lowPointIdx; --i) {
462 for (
int i = m_unitCount; i > lowPointIdx; --i) {
479void BoxColManager::searchImpl(BoxColUnit *unit,
const BoxColFlag &flag) {
480 if (unit->m_flag.offBit(eBoxColFlag::Active)) {
484 int highPointIdx = unit->m_highPointIdx;
485 int lowPointIdx = unit->m_lowPointIdx;
486 int origLowPointIdx = unit->m_lowPointIdx;
491 f32 xMax = unit->m_xMax;
492 f32 xMin = unit->m_xMin;
495 f32 radius = unit->m_radius;
497 f32 zHigh = pos->z + radius;
498 f32 zLow = pos->z - radius;
499 f32 xHigh = pos->x + radius;
500 f32 xLow = pos->x - radius;
502 int maxIdx = m_unitCount - 1;
505 m_cacheQueryUnit = unit;
506 m_cacheRadius = -1.0f;
509 for (; highPointIdx > 7 &&
m_highPoints[highPointIdx - 8].z >= lowZPos;) {
513 for (; highPointIdx > 0 &&
m_highPoints[highPointIdx - 1].z >= lowZPos;) {
517 for (; lowPointIdx < maxIdx - 7 &&
m_lowPoints[lowPointIdx + 8].z <= highZPos;) {
521 for (; lowPointIdx < maxIdx &&
m_lowPoints[lowPointIdx + 1].z <= highZPos;) {
525 u8 minLowPoint =
m_highPoints[highPointIdx].minLowPoint;
527 for (
int i = lowPointIdx; i >= minLowPoint; --i, --lowPointIdx) {
530 if (low.highPoint >= highPointIdx && lowPointIdx != origLowPointIdx) {
533 if (lowUnit.m_xMax < xMin || lowUnit.m_xMin > xMax) {
541 f32 radius = lowUnit.m_radius;
542 if (lowUnit.m_pos->z + radius < zLow || lowUnit.m_pos->z - radius > zHigh) {
546 if (lowUnit.m_pos->x + radius < xLow || lowUnit.m_pos->x - radius > xHigh) {
552 if (m_maxID == MAX_UNIT_COUNT) {
557 if (lowPointIdx == 0) {
564void BoxColManager::searchImpl(f32 radius,
const EGG::Vector3f &pos,
const BoxColFlag &flag) {
566 int highPointIdx = 0;
568 f32 zHigh = pos.z + radius;
569 f32 zLow = pos.z - radius;
570 f32 xHigh = pos.x + radius;
571 f32 xLow = pos.x - radius;
574 m_cacheQueryUnit =
nullptr;
576 m_cacheRadius = radius;
579 int i = m_unitCount - 1;
581 int highSearch = highPointIdx + i;
582 int lowSearch = lowPointIdx + i;
583 if (highSearch <= m_unitCount && zLow >
m_highPoints[highSearch - 1].z) {
584 highPointIdx = highSearch;
587 if (lowSearch <= m_unitCount && zHigh >=
m_lowPoints[lowSearch].z) {
588 lowPointIdx = lowSearch;
598 u8 minLowPoint =
m_highPoints[highPointIdx].minLowPoint;
600 for (i = lowPointIdx; i >= minLowPoint; --i, --lowPointIdx) {
602 if (low.highPoint >= highPointIdx) {
605 if (unit.m_xMax < xLow || unit.m_xMin > xHigh) {
615 if (m_maxID == MAX_UNIT_COUNT) {
620 if (lowPointIdx == 0) {
626BoxColManager *BoxColManager::s_instance =
nullptr;