diff --git a/source/game/field/CollisionDirector.cc b/source/game/field/CollisionDirector.cc index e95712f2..dfa124c1 100644 --- a/source/game/field/CollisionDirector.cc +++ b/source/game/field/CollisionDirector.cc @@ -4,14 +4,14 @@ namespace Field { /// @addr{0x8078E4F0} void CollisionDirector::checkCourseColNarrScLocal(f32 radius, const EGG::Vector3f &pos, - KCLTypeMask mask, u32 /*unused*/) { + KCLTypeMask mask, u32 /*timeOffset*/) { CourseColMgr::Instance()->scaledNarrowScopeLocal(1.0f, radius, nullptr, pos, mask); } /// @addr{0x8078F500} bool CollisionDirector::checkSphereFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, CourseColMgr::CollisionInfo *pInfo, - KCLTypeMask *pFlagsOut, u32 /*start*/) { + KCLTypeMask *pFlagsOut, u32 /*timeOffset*/) { if (pInfo) { pInfo->bbox.min = EGG::Vector3f::zero; pInfo->bbox.max = EGG::Vector3f::zero; @@ -57,7 +57,7 @@ bool CollisionDirector::checkSphereFull(f32 radius, const EGG::Vector3f &v0, /// @addr{0x8078F784} bool CollisionDirector::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, CourseColMgr::CollisionInfo *pInfo, - KCLTypeMask *pFlagsOut, u32 /*param_8*/) { + KCLTypeMask *pFlagsOut, u32 /*timeOffset*/) { if (pInfo) { pInfo->bbox.setZero(); pInfo->_50 = -std::numeric_limits::min(); @@ -101,11 +101,11 @@ bool CollisionDirector::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, } /// @addr{0x807901F0} -bool CollisionDirector::checkSphereCachedPartial(const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CourseColMgr::CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 radius) { - if (colInfo) { - colInfo->bbox.setZero(); +bool CollisionDirector::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask typeMask, + CourseColMgr::CollisionInfoPartial *info, KCLTypeMask *typeMaskOut, u32 /*timeOffset*/) { + if (info) { + info->bbox.setZero(); } if (typeMaskOut) { @@ -119,12 +119,12 @@ bool CollisionDirector::checkSphereCachedPartial(const EGG::Vector3f &pos, noBounceInfo->dist = std::numeric_limits::min(); } - bool hasCourseCol = courseColMgr->checkSphereCachedPartial(nullptr, pos, prevPos, typeMask, - colInfo, typeMaskOut, 1.0f, radius); + bool hasCourseCol = courseColMgr->checkSphereCachedPartial(1.0f, radius, nullptr, pos, prevPos, + typeMask, info, typeMaskOut); if (hasCourseCol) { - if (colInfo) { - colInfo->tangentOff = colInfo->bbox.min + colInfo->bbox.max; + if (info) { + info->tangentOff = info->bbox.min + info->bbox.max; } if (noBounceInfo) { @@ -138,11 +138,11 @@ bool CollisionDirector::checkSphereCachedPartial(const EGG::Vector3f &pos, } /// @addr{0x807903BC} -bool CollisionDirector::checkSphereCachedPartialPush(const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CourseColMgr::CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 radius, u32 /*start*/) { - if (colInfo) { - colInfo->bbox.setZero(); +bool CollisionDirector::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask typeMask, + CourseColMgr::CollisionInfoPartial *info, KCLTypeMask *typeMaskOut, u32 /*timeOffset*/) { + if (info) { + info->bbox.setZero(); } if (typeMaskOut) { @@ -156,8 +156,8 @@ bool CollisionDirector::checkSphereCachedPartialPush(const EGG::Vector3f &pos, noBounceInfo->dist = std::numeric_limits::min(); } - bool hasCourseCol = courseColMgr->checkSphereCachedPartialPush(nullptr, pos, prevPos, typeMask, - colInfo, typeMaskOut, 1.0f, radius); + bool hasCourseCol = courseColMgr->checkSphereCachedPartialPush(1.0f, radius, nullptr, pos, + prevPos, typeMask, info, typeMaskOut); courseColMgr->clearNoBounceWallInfo(); @@ -165,9 +165,9 @@ bool CollisionDirector::checkSphereCachedPartialPush(const EGG::Vector3f &pos, } /// @addr{0x807907F8} -bool CollisionDirector::checkSphereCachedFullPush(const EGG::Vector3f &pos, +bool CollisionDirector::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CourseColMgr::CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 radius, u32 /*start*/) { + KCLTypeMask *typeMaskOut, u32 /*timeOffset*/) { if (colInfo) { colInfo->bbox.min.setZero(); colInfo->bbox.max.setZero(); @@ -188,8 +188,8 @@ bool CollisionDirector::checkSphereCachedFullPush(const EGG::Vector3f &pos, info->dist = std::numeric_limits::min(); } - bool hasCourseCol = courseColMgr->checkSphereCachedFullPush(nullptr, pos, prevPos, typeMask, - colInfo, typeMaskOut, 1.0f, radius); + bool hasCourseCol = courseColMgr->checkSphereCachedFullPush(1.0f, radius, nullptr, pos, prevPos, + typeMask, colInfo, typeMaskOut); if (hasCourseCol) { if (colInfo) { diff --git a/source/game/field/CollisionDirector.hh b/source/game/field/CollisionDirector.hh index 481fb81f..29ed4429 100644 --- a/source/game/field/CollisionDirector.hh +++ b/source/game/field/CollisionDirector.hh @@ -21,24 +21,24 @@ public: }; void checkCourseColNarrScLocal(f32 radius, const EGG::Vector3f &pos, KCLTypeMask mask, - u32 /*unused*/); + u32 timeOffset); [[nodiscard]] bool checkSphereFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, CourseColMgr::CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, - u32 /*start*/); + u32 timeOffset); [[nodiscard]] bool checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, CourseColMgr::CollisionInfo *pInfo, - KCLTypeMask *pFlagsOut, u32 /*start*/); + KCLTypeMask *pFlagsOut, u32 timeOffset); - [[nodiscard]] bool checkSphereCachedPartial(const EGG::Vector3f &pos, + [[nodiscard]] bool checkSphereCachedPartial(f32 radius, const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, - CourseColMgr::CollisionInfo *colInfo, KCLTypeMask *typeMaskOut, f32 radius); - [[nodiscard]] bool checkSphereCachedPartialPush(const EGG::Vector3f &pos, + CourseColMgr::CollisionInfoPartial *info, KCLTypeMask *typeMaskOut, u32 timeOffset); + [[nodiscard]] bool checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, - CourseColMgr::CollisionInfo *colInfo, KCLTypeMask *typeMaskOut, f32 radius, u32 start); - [[nodiscard]] bool checkSphereCachedFullPush(const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, - CourseColMgr::CollisionInfo *colInfo, KCLTypeMask *typeMaskOut, f32 radius, u32 start); + CourseColMgr::CollisionInfoPartial *info, KCLTypeMask *typeMaskOut, u32 timeOffset); + [[nodiscard]] bool checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CourseColMgr::CollisionInfo *info, + KCLTypeMask *typeMaskOut, u32 timeOffset); void resetCollisionEntries(KCLTypeMask *ptr); void pushCollisionEntry(f32 dist, KCLTypeMask *typeMask, KCLTypeMask kclTypeBit, u16 attribute); diff --git a/source/game/field/CourseColMgr.cc b/source/game/field/CourseColMgr.cc index cfe89ad2..7450b624 100644 --- a/source/game/field/CourseColMgr.cc +++ b/source/game/field/CourseColMgr.cc @@ -26,48 +26,234 @@ void CourseColMgr::scaledNarrowScopeLocal(f32 scale, f32 radius, KColData *data, data->narrowScopeLocal(pos / scale, radius / scale, mask); } +/// @addr{0x807C2A60} +bool CourseColMgr::checkPointPartial(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithPartialInfo(data, &KColData::checkPointCollision, info, maskOut); + } + + return doCheckMaskOnly(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C2DA0} +bool CourseColMgr::checkPointPartialPush(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithPartialInfoPush(data, &KColData::checkPointCollision, info, maskOut); + } + return doCheckMaskOnlyPush(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C30E0} +bool CourseColMgr::checkPointFull(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithFullInfo(data, &KColData::checkPointCollision, info, maskOut); + } + return doCheckMaskOnly(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C3554} +bool CourseColMgr::checkPointFullPush(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithFullInfoPush(data, &KColData::checkPointCollision, info, maskOut); + } + return doCheckMaskOnlyPush(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C39C8} +bool CourseColMgr::checkSpherePartial(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupSphere(radius, v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithPartialInfo(data, &KColData::checkSphereCollision, info, maskOut); + } + return doCheckMaskOnly(data, &KColData::checkSphereCollision, maskOut); +} + +/// @addr{0x807C3B5C} +bool CourseColMgr::checkSpherePartialPush(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupSphere(radius, v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithPartialInfoPush(data, &KColData::checkSphereCollision, info, maskOut); + } + return doCheckMaskOnlyPush(data, &KColData::checkSphereCollision, maskOut); +} + /// @addr{0x807C3CF0} bool CourseColMgr::checkSphereFull(f32 scalar, f32 radius, KColData *data, const EGG::Vector3f &v0, - const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *info, - KCLTypeMask *kcl_flags_out) { + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) { if (!data) { data = m_data; } m_kclScale = scalar; - EGG::Vector3f scaled_position = v0 / scalar; - EGG::Vector3f vStack88 = v1 / scalar; - data->lookupSphere(radius, scaled_position, vStack88, flags); + + data->lookupSphere(radius, v0 / scalar, v1 / scalar, mask); if (info) { - return doCheckWithFullInfo(data, &KColData::checkSphereCollision, info, kcl_flags_out); + return doCheckWithFullInfo(data, &KColData::checkSphereCollision, info, maskOut); } - return false; // doCheckMaskOnly(data, &KColData::checkSphereCollision, kcl_flags_out); + return doCheckMaskOnly(data, &KColData::checkSphereCollision, maskOut); } /// @addr{0x807C3E84} bool CourseColMgr::checkSphereFullPush(f32 scalar, f32 radius, KColData *data, - const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *info, - KCLTypeMask *kcl_flags_out) { + const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfo *info, + KCLTypeMask *maskOut) { if (!data) { data = m_data; } m_kclScale = scalar; - EGG::Vector3f scaled_position = v0 / scalar; - EGG::Vector3f vStack88 = v1 / scalar; - data->lookupSphere(radius, scaled_position, vStack88, flags); + + data->lookupSphere(radius, v0 / scalar, v1 / scalar, mask); if (info) { - return doCheckWithFullInfoPush(data, &KColData::checkSphereCollision, info, kcl_flags_out); + return doCheckWithFullInfoPush(data, &KColData::checkSphereCollision, info, maskOut); } - return doCheckMaskOnlyPush(data, &KColData::checkSphereCollision, kcl_flags_out); + return doCheckMaskOnlyPush(data, &KColData::checkSphereCollision, maskOut); +} + +/// @addr{0x807C4018} +bool CourseColMgr::checkPointCachedPartial(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithPartialInfo(data, &KColData::checkPointCollision, info, maskOut); + } + return doCheckMaskOnly(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C41A4} +bool CourseColMgr::checkPointCachedPartialPush(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + if (data->prismCache(0) == 0) { + return false; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (info) { + return doCheckWithPartialInfoPush(data, &KColData::checkPointCollision, info, maskOut); + } + return doCheckMaskOnlyPush(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C4330} +bool CourseColMgr::checkPointCachedFull(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfo *pInfo, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + if (data->prismCache(0) == 0) { + return false; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (pInfo) { + return doCheckWithFullInfo(data, &KColData::checkPointCollision, pInfo, maskOut); + } + return doCheckMaskOnly(data, &KColData::checkPointCollision, maskOut); +} + +/// @addr{0x807C44BC} +bool CourseColMgr::checkPointCachedFullPush(f32 scale, KColData *data, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask mask, CollisionInfo *pInfo, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + if (data->prismCache(0) == 0) { + return false; + } + + m_kclScale = scale; + + data->lookupPoint(v0 / scale, v1 / scale, mask); + + if (pInfo) { + return doCheckWithFullInfoPush(data, &KColData::checkPointCollision, pInfo, maskOut); + } + return doCheckMaskOnlyPush(data, &KColData::checkPointCollision, maskOut); } /// @addr{0x807C4648} -bool CourseColMgr::checkSphereCachedPartial(KColData *data, const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 scale, f32 radius) { +bool CourseColMgr::checkSphereCachedPartial(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut) { if (!data) { data = m_data; } @@ -78,20 +264,19 @@ bool CourseColMgr::checkSphereCachedPartial(KColData *data, const EGG::Vector3f m_kclScale = scale; - data->lookupSphereCached(pos / scale, prevPos / scale, typeMask, radius / scale); + data->lookupSphereCached(pos / scale, prevPos / scale, mask, radius / scale); - if (colInfo) { - return doCheckWithPartialInfo(data, &KColData::checkSphereCollision, colInfo, typeMaskOut); + if (info) { + return doCheckWithPartialInfo(data, &KColData::checkSphereCollision, info, maskOut); } - // Not required atm - return false; + return doCheckMaskOnly(data, &KColData::checkSphereCollision, maskOut); } /// @addr{0x807C47F0} -bool CourseColMgr::checkSphereCachedPartialPush(KColData *data, const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 scale, f32 radius) { +bool CourseColMgr::checkSphereCachedPartialPush(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut) { if (!data) { data = m_data; } @@ -102,20 +287,42 @@ bool CourseColMgr::checkSphereCachedPartialPush(KColData *data, const EGG::Vecto m_kclScale = scale; - data->lookupSphereCached(pos / scale, prevPos / scale, typeMask, radius / scale); + data->lookupSphereCached(pos / scale, prevPos / scale, mask, radius / scale); - if (colInfo) { - return doCheckWithPartialInfoPush(data, &KColData::checkSphereCollision, colInfo, - typeMaskOut); + if (info) { + return doCheckWithPartialInfoPush(data, &KColData::checkSphereCollision, info, maskOut); } - return doCheckMaskOnlyPush(data, &KColData::checkSphereCollision, typeMaskOut); + return doCheckMaskOnlyPush(data, &KColData::checkSphereCollision, maskOut); +} + +/// @addr{0x807C4998} +bool CourseColMgr::checkSphereCachedFull(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfo *pInfo, KCLTypeMask *maskOut) { + if (!data) { + data = m_data; + } + + if (data->prismCache(0) == 0) { + return false; + } + + m_kclScale = scale; + + data->lookupSphereCached(pos / scale, prevPos / scale, mask, radius / scale); + + if (pInfo) { + return doCheckWithFullInfo(data, &KColData::checkSphereCollision, pInfo, maskOut); + } + + return doCheckMaskOnly(data, &KColData::checkSphereCollision, maskOut); } /// @addr{0x807C4B40} -bool CourseColMgr::checkSphereCachedFullPush(KColData *data, const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 scale, f32 radius) { +bool CourseColMgr::checkSphereCachedFullPush(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfo *colInfo, KCLTypeMask *maskOut) { if (!data) { data = m_data; } @@ -126,14 +333,13 @@ bool CourseColMgr::checkSphereCachedFullPush(KColData *data, const EGG::Vector3f m_kclScale = scale; - data->lookupSphereCached(pos / scale, prevPos / scale, typeMask, radius / scale); + data->lookupSphereCached(pos / scale, prevPos / scale, mask, radius / scale); if (colInfo) { - return doCheckWithFullInfoPush(data, &KColData::checkSphereCollision, colInfo, typeMaskOut); - } else { - // Not needed currently - return false; + return doCheckWithFullInfoPush(data, &KColData::checkSphereCollision, colInfo, maskOut); } + + return doCheckMaskOnlyPush(data, &KColData::checkSphereCollision, maskOut); } /// @brief Loads a particular section of a .szs file @@ -174,7 +380,7 @@ CourseColMgr::~CourseColMgr() { /// @addr{0x807C2BD8} bool CourseColMgr::doCheckWithPartialInfo(KColData *data, CollisionCheckFunc collisionCheckFunc, - CollisionInfo *colInfo, KCLTypeMask *typeMask) { + CollisionInfoPartial *info, KCLTypeMask *typeMask) { f32 dist; EGG::Vector3f fnrm; u16 attribute; @@ -202,8 +408,8 @@ bool CourseColMgr::doCheckWithPartialInfo(KColData *data, CollisionCheckFunc col } if (flags & KCL_TYPE_SOLID_SURFACE) { EGG::Vector3f offset = fnrm * dist; - colInfo->bbox.min = colInfo->bbox.min.minimize(offset); - colInfo->bbox.max = colInfo->bbox.max.maximize(offset); + info->bbox.min = info->bbox.min.minimize(offset); + info->bbox.max = info->bbox.max.maximize(offset); } } } @@ -215,7 +421,7 @@ bool CourseColMgr::doCheckWithPartialInfo(KColData *data, CollisionCheckFunc col /// @addr{0x807C2F18} bool CourseColMgr::doCheckWithPartialInfoPush(KColData *data, CollisionCheckFunc collisionCheckFunc, - CollisionInfo *colInfo, KCLTypeMask *typeMask) { + CollisionInfoPartial *info, KCLTypeMask *typeMask) { f32 dist; EGG::Vector3f fnrm; u16 attribute; @@ -232,8 +438,8 @@ bool CourseColMgr::doCheckWithPartialInfoPush(KColData *data, CollisionCheckFunc } if (flags & KCL_TYPE_SOLID_SURFACE) { EGG::Vector3f offset = fnrm * dist; - colInfo->bbox.min = colInfo->bbox.min.minimize(offset); - colInfo->bbox.max = colInfo->bbox.max.maximize(offset); + info->bbox.min = info->bbox.min.minimize(offset); + info->bbox.max = info->bbox.max.maximize(offset); } } else { if (m_localMtx) { @@ -335,17 +541,32 @@ bool CourseColMgr::doCheckWithFullInfoPush(KColData *data, CollisionCheckFunc co return hasCol; } -bool CourseColMgr::doCheckMaskOnlyPush(KColData *data, CollisionCheckFunc collisionCheckFunc, - KCLTypeMask *typeMaskOut) { +bool CourseColMgr::doCheckMaskOnly(KColData *data, CollisionCheckFunc collisionCheckFunc, + KCLTypeMask *maskOut) { bool hasCol = false; f32 dist; u16 attribute; while ((data->*collisionCheckFunc)(&dist, nullptr, &attribute)) { - KCLTypeMask mask = KCL_ATTRIBUTE_TYPE_BIT(attribute); + if ((!m_noBounceWallInfo || !(attribute & KCL_SOFT_WALL_MASK)) && maskOut) { + *maskOut |= KCL_ATTRIBUTE_TYPE_BIT(attribute); + } + hasCol = true; + } - if ((!m_noBounceWallInfo || !(attribute & KCL_SOFT_WALL_MASK)) && typeMaskOut) { - CollisionDirector::Instance()->pushCollisionEntry(dist, typeMaskOut, mask, attribute); + return hasCol; +} + +bool CourseColMgr::doCheckMaskOnlyPush(KColData *data, CollisionCheckFunc collisionCheckFunc, + KCLTypeMask *maskOut) { + bool hasCol = false; + f32 dist; + u16 attribute; + + while ((data->*collisionCheckFunc)(&dist, nullptr, &attribute)) { + if ((!m_noBounceWallInfo || !(attribute & KCL_SOFT_WALL_MASK)) && maskOut) { + CollisionDirector::Instance()->pushCollisionEntry(dist, maskOut, + KCL_ATTRIBUTE_TYPE_BIT(attribute), attribute); } hasCol = true; } diff --git a/source/game/field/CourseColMgr.hh b/source/game/field/CourseColMgr.hh index 320fab2c..358e4970 100644 --- a/source/game/field/CourseColMgr.hh +++ b/source/game/field/CourseColMgr.hh @@ -17,6 +17,11 @@ typedef bool ( /// @nosubgrouping class CourseColMgr : EGG::Disposer { public: + struct CollisionInfoPartial { + EGG::BoundBox3f bbox; + EGG::Vector3f tangentOff; + }; + struct CollisionInfo { EGG::BoundBox3f bbox; EGG::Vector3f tangentOff; @@ -59,22 +64,57 @@ public: void scaledNarrowScopeLocal(f32 scale, f32 radius, KColData *data, const EGG::Vector3f &pos, KCLTypeMask mask); + [[nodiscard]] bool checkPointPartial(f32 scale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut); + [[nodiscard]] bool checkPointPartialPush(f32 scale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut); + [[nodiscard]] bool checkPointFull(f32 kclScale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, + KCLTypeMask *maskOut); + [[nodiscard]] bool checkPointFullPush(f32 kclScale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, + KCLTypeMask *maskOut); + + [[nodiscard]] bool checkSpherePartial(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut); + [[nodiscard]] bool checkSpherePartialPush(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut); [[nodiscard]] bool checkSphereFull(f32 scalar, f32 radius, KColData *data, - const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, - CollisionInfo *info, KCLTypeMask *kcl_flags_out); + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfo *info, KCLTypeMask *maskOut); [[nodiscard]] bool checkSphereFullPush(f32 scalar, f32 radius, KColData *data, - const EGG::Vector3f &v0, const EGG::Vector3f &v1, KCLTypeMask flags, - CollisionInfo *info, KCLTypeMask *kcl_flags_out); - - [[nodiscard]] bool checkSphereCachedPartial(KColData *data, const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 scale, f32 radius); - [[nodiscard]] bool checkSphereCachedPartialPush(KColData *data, const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 scale, f32 radius); - [[nodiscard]] bool checkSphereCachedFullPush(KColData *data, const EGG::Vector3f &pos, - const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo, - KCLTypeMask *typeMaskOut, f32 scale, f32 radius); + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfo *info, KCLTypeMask *maskOut); + + [[nodiscard]] bool checkPointCachedPartial(f32 scale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info, + KCLTypeMask *maskOut); + [[nodiscard]] bool checkPointCachedPartialPush(f32 scale, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask mask, + CollisionInfoPartial *info, KCLTypeMask *maskOut); + [[nodiscard]] bool checkPointCachedFull(f32 scale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, + KCLTypeMask *maskOut); + [[nodiscard]] bool checkPointCachedFullPush(f32 scale, KColData *data, const EGG::Vector3f &pos, + const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, + KCLTypeMask *maskOut); + + [[nodiscard]] bool checkSphereCachedPartial(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, + CollisionInfoPartial *info, KCLTypeMask *maskOut); + [[nodiscard]] bool checkSphereCachedPartialPush(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, + CollisionInfoPartial *info, KCLTypeMask *maskOut); + [[nodiscard]] bool checkSphereCachedFull(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, + CollisionInfo *colInfo, KCLTypeMask *maskOut); + [[nodiscard]] bool checkSphereCachedFullPush(f32 scale, f32 radius, KColData *data, + const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask, + CollisionInfo *colInfo, KCLTypeMask *maskOut); /// @beginSetters void setNoBounceWallInfo(NoBounceWallColInfo *info) { @@ -106,15 +146,18 @@ private: ~CourseColMgr() override; [[nodiscard]] bool doCheckWithPartialInfo(KColData *data, CollisionCheckFunc collisionCheckFunc, - CollisionInfo *colInfo, KCLTypeMask *typeMask); + CollisionInfoPartial *info, KCLTypeMask *typeMask); [[nodiscard]] bool doCheckWithPartialInfoPush(KColData *data, - CollisionCheckFunc collisionCheckFunc, CollisionInfo *colInfo, KCLTypeMask *typeMask); + CollisionCheckFunc collisionCheckFunc, CollisionInfoPartial *info, + KCLTypeMask *typeMask); [[nodiscard]] bool doCheckWithFullInfo(KColData *data, CollisionCheckFunc collisionCheckFunc, CollisionInfo *colInfo, KCLTypeMask *flagsOut); [[nodiscard]] bool doCheckWithFullInfoPush(KColData *data, CollisionCheckFunc collisionCheckFunc, CollisionInfo *colInfo, KCLTypeMask *flagsOut); + [[nodiscard]] bool doCheckMaskOnly(KColData *data, CollisionCheckFunc collisionCheckFunc, + KCLTypeMask *maskOut); [[nodiscard]] bool doCheckMaskOnlyPush(KColData *data, CollisionCheckFunc collisionCheckFunc, - KCLTypeMask *typeMaskOut); + KCLTypeMask *maskOut); KColData *m_data; f32 m_kclScale; diff --git a/source/game/field/KColData.cc b/source/game/field/KColData.cc index 344d6302..13055694 100644 --- a/source/game/field/KColData.cc +++ b/source/game/field/KColData.cc @@ -117,6 +117,12 @@ void KColData::computeBBox() { } } +/// @addr{0x807C1F80} +bool KColData::checkPointCollision(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut) { + return std::isfinite(m_prevPos.y) ? checkPointMovement(distOut, fnrmOut, flagsOut) : + checkPoint(distOut, fnrmOut, flagsOut); +} + /// @addr{0x807C2410} bool KColData::checkSphereCollision(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut) { return std::isfinite(m_prevPos.y) ? checkSphereMovement(distOut, fnrmOut, flagsOut) : @@ -178,7 +184,18 @@ bool KColData::checkSphereSingle(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flag return false; } -/// @brief Sets members in preparation of a subsequent collision check call +/// @brief Sets members in preparation of a subsequent point collision check call +/// @addr{0x807C1B0C} +void KColData::lookupPoint(const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, + KCLTypeMask typeMask) { + m_prismIter = searchBlock(pos); + m_pos = pos; + m_prevPos = prevPos; + m_movement = pos - prevPos; + m_typeMask = typeMask; +} + +/// @brief Sets members in preparation of a subsequent sphere collision check call /// @addr{0x807C1BB4} void KColData::lookupSphere(f32 radius, const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask) { @@ -534,6 +551,65 @@ bool KColData::checkCollision(const KCollisionPrism &prism, f32 *distOut, EGG::V return out(dist); } +/// @brief This is a combination of two point collision check functions. They only vary based on +/// whether we are checking movement. +bool KColData::checkPointCollision(const KCollisionPrism &prism, f32 *distOut, + EGG::Vector3f *fnrmOut, u16 *flagsOut, bool movement) { + KCLTypeMask attrMask = KCL_ATTRIBUTE_TYPE_BIT(prism.attribute); + if (!(attrMask & m_typeMask)) { + return false; + } + + const EGG::Vector3f relativePos = m_pos - m_vertices[prism.pos_i]; + + const EGG::Vector3f &enrm1 = m_nrms[prism.enrm1_i]; + f32 dist_ca = relativePos.ps_dot(enrm1); + if (dist_ca >= 0.01f) { + return false; + } + + const EGG::Vector3f &enrm2 = m_nrms[prism.enrm2_i]; + f32 dist_ab = relativePos.ps_dot(enrm2); + if (dist_ab >= 0.01f) { + return false; + } + + const EGG::Vector3f &enrm3 = m_nrms[prism.enrm3_i]; + f32 dist_bc = relativePos.ps_dot(enrm3) - prism.height; + if (dist_bc >= 0.01f) { + return false; + } + + const EGG::Vector3f &fnrm = m_nrms[prism.fnrm_i]; + f32 plane_dist = relativePos.ps_dot(fnrm); + f32 dist_in_plane = 0.01f - plane_dist; + if (dist_in_plane <= 0.0f) { + return false; + } + + if (m_prismThickness <= dist_in_plane && 0.02f + m_prismThickness <= dist_in_plane) { + return false; + } + + if (movement && (attrMask & KCL_TYPE_DIRECTIONAL) && m_movement.dot(fnrm) < 0.0f) { + return false; + } + + if (distOut) { + *distOut = dist_in_plane; + } + + if (fnrmOut) { + *fnrmOut = fnrm; + } + + if (flagsOut) { + *flagsOut = prism.attribute; + } + + return true; +} + /// @brief Iterates the local data block to check for directional collision /// @addr{0x807C0884} /// @param distOut If colliding, returns the distance between the player and the tri @@ -559,6 +635,46 @@ bool KColData::checkSphereMovement(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *at return false; } +/// @addr{0x807C21F4} +bool KColData::checkPoint(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *attributeOut) { + // If there's no list of triangles to check, there's no collision + if (!m_prismIter) { + return false; + } + + // Check collision for all triangles, and continuously call the function until we're out + while (*++m_prismIter != 0) { + const KCollisionPrism &prism = m_prisms[parse(*m_prismIter)]; + if (checkPointCollision(prism, distOut, fnrmOut, attributeOut, false)) { + return true; + } + } + + // We're out of triangles to check - another list must be prepared for subsequent calls + m_prismIter = nullptr; + return false; +} + +/// @addr{0x807C1F80} +bool KColData::checkPointMovement(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *attributeOut) { + // If there's no list of triangles to check, there's no collision + if (!m_prismIter) { + return false; + } + + // Check collision for all triangles, and continuously call the function until we're out + while (*++m_prismIter != 0) { + const KCollisionPrism &prism = m_prisms[parse(*m_prismIter)]; + if (checkPointCollision(prism, distOut, fnrmOut, attributeOut, true)) { + return true; + } + } + + // We're out of triangles to check - another list must be prepared for subsequent calls + m_prismIter = nullptr; + return false; +} + KColData::KCollisionPrism::KCollisionPrism() = default; KColData::KCollisionPrism::KCollisionPrism(f32 height, u16 posIndex, u16 faceNormIndex, diff --git a/source/game/field/KColData.hh b/source/game/field/KColData.hh index bf71ed0c..daeb4537 100644 --- a/source/game/field/KColData.hh +++ b/source/game/field/KColData.hh @@ -41,10 +41,12 @@ public: void narrowPolygon_EachBlock(const u16 *prismArray); void computeBBox(); + [[nodiscard]] bool checkPointCollision(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut); [[nodiscard]] bool checkSphereCollision(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut); [[nodiscard]] bool checkSphere(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut); [[nodiscard]] bool checkSphereSingle(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut); + void lookupPoint(const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask); void lookupSphere(f32 radius, const EGG::Vector3f &pos, const EGG::Vector3f &prevPos, KCLTypeMask typeMask); void lookupSphereCached(const EGG::Vector3f &p1, const EGG::Vector3f &p2, u32 typeMask, @@ -66,7 +68,11 @@ private: [[nodiscard]] bool checkCollision(const KCollisionPrism &prism, f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut, CollisionCheckType type); + [[nodiscard]] bool checkPointCollision(const KCollisionPrism &prism, f32 *distOut, + EGG::Vector3f *fnrmOut, u16 *flagsOut, bool movement); [[nodiscard]] bool checkSphereMovement(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *attributeOut); + [[nodiscard]] bool checkPointMovement(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *attributeOut); + [[nodiscard]] bool checkPoint(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *attributeOut); const void *m_posData; const void *m_nrmData; diff --git a/source/game/kart/KartCollide.cc b/source/game/kart/KartCollide.cc index 1b22211e..51a4a14f 100644 --- a/source/game/kart/KartCollide.cc +++ b/source/game/kart/KartCollide.cc @@ -232,8 +232,8 @@ void KartCollide::calcBodyCollision(f32 totalScale, f32 sinkDepth, const EGG::Qu hitbox.calc(totalScale, sinkDepth, scale, rot, pos()); - if (Field::CollisionDirector::Instance()->checkSphereCachedFullPush(hitbox.worldPos(), - hitbox.lastPos(), flags, &colInfo, &maskOut, hitbox.radius(), 0)) { + if (Field::CollisionDirector::Instance()->checkSphereCachedFullPush(hitbox.radius(), + hitbox.worldPos(), hitbox.lastPos(), flags, &colInfo, &maskOut, 0)) { if (!!(maskOut & KCL_TYPE_VEHICLE_COLLIDEABLE)) { Field::CollisionDirector::Instance()->findClosestCollisionEntry(&maskOut, KCL_TYPE_VEHICLE_COLLIDEABLE); @@ -292,7 +292,7 @@ void KartCollide::calcFloorEffect() { void KartCollide::calcTriggers(Field::KCLTypeMask *mask, const EGG::Vector3f &pos, bool twoPoint) { EGG::Vector3f v1 = twoPoint ? physics()->pos() : EGG::Vector3f::inf; Field::KCLTypeMask typeMask = twoPoint ? KCL_TYPE_DIRECTIONAL : KCL_TYPE_NON_DIRECTIONAL; - f32 fVar1 = twoPoint ? 80.0f : 100.0f * move()->totalScale(); + f32 radius = twoPoint ? 80.0f : 100.0f * move()->totalScale(); f32 scalar = -bsp().initialYPos * move()->totalScale() * 0.3f; EGG::Vector3f scaledPos = pos + scalar * componentYAxis(); EGG::Vector3f back = dynamics()->mainRot().rotateVector(EGG::Vector3f::ez); @@ -302,8 +302,8 @@ void KartCollide::calcTriggers(Field::KCLTypeMask *mask, const EGG::Vector3f &po scalar = m_smoothedBack * -physics()->fc() * 1.8f * move()->totalScale(); scaledPos += scalar * back; - bool collide = Field::CollisionDirector::Instance()->checkSphereCachedPartialPush(scaledPos, v1, - typeMask, nullptr, mask, fVar1, 0); + bool collide = Field::CollisionDirector::Instance()->checkSphereCachedPartialPush(radius, + scaledPos, v1, typeMask, nullptr, mask, 0); if (!collide) { return; @@ -402,8 +402,8 @@ void KartCollide::calcWheelCollision(u16 /*wheelIdx*/, CollisionGroup *hitboxGro Field::CourseColMgr::Instance()->setNoBounceWallInfo(&noBounceWallInfo); bool collided = Field::CollisionDirector::Instance()->checkSphereCachedFullPush( - firstHitbox.worldPos(), firstHitbox.lastPos(), KCL_TYPE_VEHICLE_COLLIDEABLE, &colInfo, - &kclOut, firstHitbox.radius(), 0); + firstHitbox.radius(), firstHitbox.worldPos(), firstHitbox.lastPos(), + KCL_TYPE_VEHICLE_COLLIDEABLE, &colInfo, &kclOut, 0); CollisionData &collisionData = hitboxGroup->collisionData(); @@ -474,11 +474,11 @@ void KartCollide::calcSideCollision(CollisionData &collisionData, Hitbox &hitbox f32 sign = i == 1 ? -1.0f : 1.0f; f32 effectiveRadius = sign * hitbox.radius(); EGG::Vector3f effectivePos = hitbox.worldPos() + effectiveRadius * right; - Field::CourseColMgr::CollisionInfo tempColInfo; + Field::CourseColMgr::CollisionInfoPartial tempColInfo; - if (Field::CollisionDirector::Instance()->checkSphereCachedPartial(effectivePos, - hitbox.lastPos(), KCL_TYPE_DRIVER_WALL, &tempColInfo, nullptr, - hitbox.radius())) { + if (Field::CollisionDirector::Instance()->checkSphereCachedPartial(hitbox.radius(), + effectivePos, hitbox.lastPos(), KCL_TYPE_DRIVER_WALL, &tempColInfo, nullptr, + 0)) { tangents[i] = colInfo->tangentOff.squaredLength(); } }