A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
CollisionDirector.cc
1#include "CollisionDirector.hh"
2
3#include "game/field/ObjectDrivableDirector.hh"
4
5namespace Kinoko::Field {
6
8void CollisionDirector::checkCourseColNarrScLocal(f32 radius, const EGG::Vector3f &pos,
9 KCLTypeMask mask, u32 timeOffset) {
10 CourseColMgr::Instance()->scaledNarrowScopeLocal(1.0f, radius, nullptr, pos, mask);
11 ObjectDrivableDirector::Instance()->colNarScLocal(radius, pos, mask, timeOffset);
12}
13
15bool CollisionDirector::checkSpherePartialPush(f32 radius, const EGG::Vector3f &pos,
16 const EGG::Vector3f &prevPos, KCLTypeMask flags, CollisionInfoPartial *info,
17 KCLTypeMask *typeMaskOut, u32 timeOffset) {
18 if (info) {
19 info->bbox.setZero();
20 }
21
22 if (typeMaskOut) {
23 *typeMaskOut = KCL_NONE;
24 }
25
26 auto *courseColMgr = CourseColMgr::Instance();
27 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
28 if (noBounceInfo) {
29 noBounceInfo->bbox.setZero();
30 noBounceInfo->dist = std::numeric_limits<f32>::min();
31 }
32
33 bool colliding = flags &&
34 courseColMgr->checkSpherePartialPush(1.0f, radius, nullptr, pos, prevPos, flags, info,
35 typeMaskOut);
36
37 colliding |= ObjectDrivableDirector::Instance()->checkSpherePartialPush(radius, pos, prevPos,
38 flags, info, typeMaskOut, timeOffset);
39
40 if (colliding) {
41 if (info) {
42 info->tangentOff = info->bbox.min + info->bbox.max;
43 }
44
45 if (noBounceInfo) {
46 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
47 }
48 }
49
50 courseColMgr->clearNoBounceWallInfo();
51
52 return colliding;
53}
54
56bool CollisionDirector::checkSphereFull(f32 radius, const EGG::Vector3f &v0,
57 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
58 u32 timeOffset) {
59 if (pInfo) {
60 pInfo->reset();
61 }
62
63 if (pFlagsOut) {
64 *pFlagsOut = KCL_NONE;
65 }
66
67 auto *courseColMgr = CourseColMgr::Instance();
68 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
69 if (noBounceInfo) {
70 noBounceInfo->bbox.setZero();
71 noBounceInfo->dist = std::numeric_limits<f32>::min();
72 }
73
74 bool colliding = flags &&
75 courseColMgr->checkSphereFull(1.0f, radius, nullptr, v0, v1, flags, pInfo, pFlagsOut);
76
77 colliding |= ObjectDrivableDirector::Instance()->checkSphereFull(radius, v0, v1, flags, pInfo,
78 pFlagsOut, timeOffset);
79
80 if (colliding) {
81 if (pInfo) {
82 pInfo->tangentOff = pInfo->bbox.min + pInfo->bbox.max;
83 }
84
85 if (noBounceInfo) {
86 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
87 }
88 }
89
90 courseColMgr->clearNoBounceWallInfo();
91
92 return colliding;
93}
94
96bool CollisionDirector::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0,
97 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
98 u32 timeOffset) {
99 if (pInfo) {
100 pInfo->reset();
101 }
102
103 if (pFlagsOut) {
104 resetCollisionEntries(pFlagsOut);
105 }
106
107 auto *courseColMgr = CourseColMgr::Instance();
108 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
109 if (noBounceInfo) {
110 noBounceInfo->bbox.setZero();
111 noBounceInfo->dist = std::numeric_limits<f32>::min();
112 }
113
114 bool colliding = flags &&
115 courseColMgr->checkSphereFullPush(1.0f, radius, nullptr, v0, v1, flags, pInfo,
116 pFlagsOut);
117
118 colliding |= ObjectDrivableDirector::Instance()->checkSphereFullPush(radius, v0, v1, flags,
119 pInfo, pFlagsOut, timeOffset);
120
121 if (colliding) {
122 if (pInfo) {
123 pInfo->tangentOff = pInfo->bbox.min + pInfo->bbox.max;
124 }
125
126 if (noBounceInfo) {
127 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
128 }
129 }
130
131 courseColMgr->clearNoBounceWallInfo();
132
133 return colliding;
134}
135
137bool CollisionDirector::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &pos,
138 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfoPartial *info,
139 KCLTypeMask *typeMaskOut, u32 timeOffset) {
140 if (info) {
141 info->bbox.setZero();
142 }
143
144 if (typeMaskOut) {
145 *typeMaskOut = KCL_NONE;
146 }
147
148 auto *courseColMgr = CourseColMgr::Instance();
149 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
150 if (noBounceInfo) {
151 noBounceInfo->bbox.setZero();
152 noBounceInfo->dist = std::numeric_limits<f32>::min();
153 }
154
155 bool colliding = courseColMgr->checkSphereCachedPartial(1.0f, radius, nullptr, pos, prevPos,
156 typeMask, info, typeMaskOut);
157
158 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedPartial(radius, pos, prevPos,
159 typeMask, info, typeMaskOut, timeOffset);
160
161 if (colliding) {
162 if (info) {
163 info->tangentOff = info->bbox.min + info->bbox.max;
164 }
165
166 if (noBounceInfo) {
167 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
168 }
169 }
170
171 courseColMgr->clearNoBounceWallInfo();
172
173 return colliding;
174}
175
177bool CollisionDirector::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &pos,
178 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfoPartial *info,
179 KCLTypeMask *typeMaskOut, u32 timeOffset) {
180 if (info) {
181 info->bbox.setZero();
182 }
183
184 if (typeMaskOut) {
185 resetCollisionEntries(typeMaskOut);
186 }
187
188 auto *courseColMgr = CourseColMgr::Instance();
189 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
190 if (noBounceInfo) {
191 noBounceInfo->bbox.setZero();
192 noBounceInfo->dist = std::numeric_limits<f32>::min();
193 }
194
195 bool colliding = courseColMgr->checkSphereCachedPartialPush(1.0f, radius, nullptr, pos, prevPos,
196 typeMask, info, typeMaskOut);
197
198 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedPartialPush(radius, pos,
199 prevPos, typeMask, info, typeMaskOut, timeOffset);
200
201 courseColMgr->clearNoBounceWallInfo();
202
203 return colliding;
204}
205
207bool CollisionDirector::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &pos,
208 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo,
209 KCLTypeMask *typeMaskOut, u32 timeOffset) {
210 if (colInfo) {
211 colInfo->reset();
212 }
213
214 if (typeMaskOut) {
215 resetCollisionEntries(typeMaskOut);
216 }
217
218 auto *courseColMgr = CourseColMgr::Instance();
219 auto *info = courseColMgr->noBounceWallInfo();
220 if (info) {
221 info->bbox.setZero();
222 info->dist = std::numeric_limits<f32>::min();
223 }
224
225 bool colliding = courseColMgr->checkSphereCachedFullPush(1.0f, radius, nullptr, pos, prevPos,
226 typeMask, colInfo, typeMaskOut);
227
228 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedFullPush(radius, pos, prevPos,
229 typeMask, colInfo, typeMaskOut, timeOffset);
230
231 if (colliding) {
232 if (colInfo) {
233 colInfo->tangentOff = colInfo->bbox.min + colInfo->bbox.max;
234 }
235
236 if (info) {
237 info->tangentOff = info->bbox.min + info->bbox.max;
238 }
239 }
240
241 courseColMgr->clearNoBounceWallInfo();
242
243 return colliding;
244}
245
247void CollisionDirector::resetCollisionEntries(KCLTypeMask *ptr) {
248 *ptr = 0;
249 m_collisionEntryCount = 0;
250 m_closestCollisionEntry = nullptr;
251}
252
259void CollisionDirector::pushCollisionEntry(f32 dist, KCLTypeMask *typeMask, KCLTypeMask kclTypeBit,
260 CollisionAttribute attribute) {
261 *typeMask = *typeMask | kclTypeBit;
262 if (m_collisionEntryCount >= m_entries.size()) {
263 m_collisionEntryCount = m_entries.size() - 1;
264 }
265
266 m_entries[m_collisionEntryCount++] = CollisionEntry(kclTypeBit, attribute, dist);
267}
268
273bool CollisionDirector::findClosestCollisionEntry(KCLTypeMask * /*typeMask*/, KCLTypeMask type) {
274 m_closestCollisionEntry = nullptr;
275 f32 minDist = -std::numeric_limits<f32>::min();
276
277 for (size_t i = 0; i < m_collisionEntryCount; ++i) {
278 const auto &entry = m_entries[i];
279 u32 typeMask = entry.typeMask & type;
280 if (typeMask != 0 && entry.dist > minDist) {
281 minDist = entry.dist;
282 m_closestCollisionEntry = &entry;
283 }
284 }
285
286 return !!m_closestCollisionEntry;
287}
288
290CollisionDirector *CollisionDirector::CreateInstance() {
291 ASSERT(!s_instance);
292 s_instance = new CollisionDirector;
293 return s_instance;
294}
295
297void CollisionDirector::DestroyInstance() {
298 ASSERT(s_instance);
299 auto *instance = s_instance;
300 s_instance = nullptr;
301 delete instance;
302}
303
305CollisionDirector::CollisionDirector() {
306 m_collisionEntryCount = 0;
307 m_closestCollisionEntry = nullptr;
308 CourseColMgr::CreateInstance()->init();
309}
310
312CollisionDirector::~CollisionDirector() {
313 if (s_instance) {
314 s_instance = nullptr;
315 WARN("CollisionDirector instance not explicitly handled!");
316 }
317
318 CourseColMgr::DestroyInstance();
319}
320
321CollisionDirector *CollisionDirector::s_instance = nullptr;
322
323} // namespace Kinoko::Field
Manages the caching of colliding KCL triangles and exposes queries for collision checks.
bool findClosestCollisionEntry(KCLTypeMask *typeMask, KCLTypeMask type)
Finds the closest KCL triangle out of the list of tris we are colliding with.
void pushCollisionEntry(f32 dist, KCLTypeMask *typeMask, KCLTypeMask kclTypeBit, CollisionAttribute attribute)
Called when we find a piece of collision we are touching and want to save it temporarily.
Pertains to collision.