Loading [MathJax]/extensions/tex2jax.js
A reimplementation of Mario Kart Wii's physics engine in C++
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages Concepts
CollisionDirector.cc
1#include "CollisionDirector.hh"
2
3#include "game/field/ObjectDrivableDirector.hh"
4
5namespace 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::checkSphereFull(f32 radius, const EGG::Vector3f &v0,
16 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
17 u32 timeOffset) {
18 if (pInfo) {
19 pInfo->bbox.min = EGG::Vector3f::zero;
20 pInfo->bbox.max = EGG::Vector3f::zero;
21 pInfo->_50 = -std::numeric_limits<f32>::min();
22 pInfo->wallDist = -std::numeric_limits<f32>::min();
23 pInfo->floorDist = -std::numeric_limits<f32>::min();
24 pInfo->perpendicularity = 0.0f;
25 }
26
27 if (pFlagsOut) {
28 *pFlagsOut = KCL_NONE;
29 }
30
31 auto *courseColMgr = CourseColMgr::Instance();
32 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
33 if (noBounceInfo) {
34 noBounceInfo->bbox.setZero();
35 noBounceInfo->dist = std::numeric_limits<f32>::min();
36 }
37
38 bool colliding = flags &&
39 courseColMgr->checkSphereFull(1.0f, radius, nullptr, v0, v1, flags, pInfo, pFlagsOut);
40
41 colliding |= ObjectDrivableDirector::Instance()->checkSphereFull(radius, v0, v1, flags, pInfo,
42 pFlagsOut, timeOffset);
43
44 if (colliding) {
45 if (pInfo) {
46 pInfo->tangentOff = pInfo->bbox.min + pInfo->bbox.max;
47 }
48
49 if (noBounceInfo) {
50 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
51 }
52 }
53
54 courseColMgr->clearNoBounceWallInfo();
55
56 return colliding;
57}
58
60bool CollisionDirector::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0,
61 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
62 u32 timeOffset) {
63 if (pInfo) {
64 pInfo->bbox.setZero();
65 pInfo->_50 = -std::numeric_limits<f32>::min();
66 pInfo->wallDist = -std::numeric_limits<f32>::min();
67 pInfo->floorDist = -std::numeric_limits<f32>::min();
68 pInfo->perpendicularity = 0.0f;
69 }
70
71 if (pFlagsOut) {
72 resetCollisionEntries(pFlagsOut);
73 }
74
75 auto *courseColMgr = CourseColMgr::Instance();
76 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
77 if (noBounceInfo) {
78 noBounceInfo->bbox.setZero();
79 noBounceInfo->dist = std::numeric_limits<f32>::min();
80 }
81
82 bool colliding = flags &&
83 courseColMgr->checkSphereFullPush(1.0f, radius, nullptr, v0, v1, flags, pInfo,
84 pFlagsOut);
85
86 colliding |= ObjectDrivableDirector::Instance()->checkSphereFullPush(radius, v0, v1, flags,
87 pInfo, pFlagsOut, timeOffset);
88
89 if (colliding) {
90 if (pInfo) {
91 pInfo->tangentOff = pInfo->bbox.min + pInfo->bbox.max;
92 }
93
94 if (noBounceInfo) {
95 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
96 }
97 }
98
99 courseColMgr->clearNoBounceWallInfo();
100
101 return colliding;
102}
103
105bool CollisionDirector::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &pos,
106 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfoPartial *info,
107 KCLTypeMask *typeMaskOut, u32 timeOffset) {
108 if (info) {
109 info->bbox.setZero();
110 }
111
112 if (typeMaskOut) {
113 *typeMaskOut = KCL_NONE;
114 }
115
116 auto *courseColMgr = CourseColMgr::Instance();
117 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
118 if (noBounceInfo) {
119 noBounceInfo->bbox.setZero();
120 noBounceInfo->dist = std::numeric_limits<f32>::min();
121 }
122
123 bool colliding = courseColMgr->checkSphereCachedPartial(1.0f, radius, nullptr, pos, prevPos,
124 typeMask, info, typeMaskOut);
125
126 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedPartial(radius, pos, prevPos,
127 typeMask, info, typeMaskOut, timeOffset);
128
129 if (colliding) {
130 if (info) {
131 info->tangentOff = info->bbox.min + info->bbox.max;
132 }
133
134 if (noBounceInfo) {
135 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
136 }
137 }
138
139 courseColMgr->clearNoBounceWallInfo();
140
141 return colliding;
142}
143
145bool CollisionDirector::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &pos,
146 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfoPartial *info,
147 KCLTypeMask *typeMaskOut, u32 timeOffset) {
148 if (info) {
149 info->bbox.setZero();
150 }
151
152 if (typeMaskOut) {
153 resetCollisionEntries(typeMaskOut);
154 }
155
156 auto *courseColMgr = CourseColMgr::Instance();
157 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
158 if (noBounceInfo) {
159 noBounceInfo->bbox.setZero();
160 noBounceInfo->dist = std::numeric_limits<f32>::min();
161 }
162
163 bool colliding = courseColMgr->checkSphereCachedPartialPush(1.0f, radius, nullptr, pos, prevPos,
164 typeMask, info, typeMaskOut);
165
166 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedPartialPush(radius, pos,
167 prevPos, typeMask, info, typeMaskOut, timeOffset);
168
169 courseColMgr->clearNoBounceWallInfo();
170
171 return colliding;
172}
173
175bool CollisionDirector::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &pos,
176 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo,
177 KCLTypeMask *typeMaskOut, u32 timeOffset) {
178 if (colInfo) {
179 colInfo->bbox.min.setZero();
180 colInfo->bbox.max.setZero();
181 colInfo->_50 = -std::numeric_limits<f32>::min();
182 colInfo->wallDist = -std::numeric_limits<f32>::min();
183 colInfo->floorDist = -std::numeric_limits<f32>::min();
184 colInfo->perpendicularity = 0.0f;
185 }
186
187 if (typeMaskOut) {
188 resetCollisionEntries(typeMaskOut);
189 }
190
191 auto *courseColMgr = CourseColMgr::Instance();
192 auto *info = courseColMgr->noBounceWallInfo();
193 if (info) {
194 info->bbox.setZero();
195 info->dist = std::numeric_limits<f32>::min();
196 }
197
198 bool colliding = courseColMgr->checkSphereCachedFullPush(1.0f, radius, nullptr, pos, prevPos,
199 typeMask, colInfo, typeMaskOut);
200
201 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedFullPush(radius, pos, prevPos,
202 typeMask, colInfo, typeMaskOut, timeOffset);
203
204 if (colliding) {
205 if (colInfo) {
206 colInfo->tangentOff = colInfo->bbox.min + colInfo->bbox.max;
207 }
208
209 if (info) {
210 info->tangentOff = info->bbox.min + info->bbox.max;
211 }
212 }
213
214 courseColMgr->clearNoBounceWallInfo();
215
216 return colliding;
217}
218
220void CollisionDirector::resetCollisionEntries(KCLTypeMask *ptr) {
221 *ptr = 0;
222 m_collisionEntryCount = 0;
223 m_closestCollisionEntry = nullptr;
224}
225
232void CollisionDirector::pushCollisionEntry(f32 dist, KCLTypeMask *typeMask, KCLTypeMask kclTypeBit,
233 u16 attribute) {
234 *typeMask = *typeMask | kclTypeBit;
235 if (m_collisionEntryCount >= m_entries.size()) {
236 m_collisionEntryCount = m_entries.size() - 1;
237 }
238
239 m_entries[m_collisionEntryCount++] = CollisionEntry(kclTypeBit, attribute, dist);
240}
241
246bool CollisionDirector::findClosestCollisionEntry(KCLTypeMask * /*typeMask*/, KCLTypeMask type) {
247 m_closestCollisionEntry = nullptr;
248 f32 minDist = -std::numeric_limits<f32>::min();
249
250 for (size_t i = 0; i < m_collisionEntryCount; ++i) {
251 const auto &entry = m_entries[i];
252 u32 typeMask = entry.typeMask & type;
253 if (typeMask != 0 && entry.dist > minDist) {
254 minDist = entry.dist;
255 m_closestCollisionEntry = &entry;
256 }
257 }
258
259 return !!m_closestCollisionEntry;
260}
261
263CollisionDirector *CollisionDirector::CreateInstance() {
264 ASSERT(!s_instance);
265 s_instance = new CollisionDirector;
266 return s_instance;
267}
268
270void CollisionDirector::DestroyInstance() {
271 ASSERT(s_instance);
272 auto *instance = s_instance;
273 s_instance = nullptr;
274 delete instance;
275}
276
278CollisionDirector::CollisionDirector() {
279 m_collisionEntryCount = 0;
280 m_closestCollisionEntry = nullptr;
281 CourseColMgr::CreateInstance()->init();
282}
283
285CollisionDirector::~CollisionDirector() {
286 if (s_instance) {
287 s_instance = nullptr;
288 WARN("CollisionDirector instance not explicitly handled!");
289 }
290
291 CourseColMgr::DestroyInstance();
292}
293
294CollisionDirector *CollisionDirector::s_instance = nullptr;
295
296} // namespace Field
Manages the caching of colliding KCL triangles and exposes queries for collision checks.
void pushCollisionEntry(f32 dist, KCLTypeMask *typeMask, KCLTypeMask kclTypeBit, u16 attribute)
Called when we find a piece of collision we are touching and want to save it temporarily.
bool findClosestCollisionEntry(KCLTypeMask *typeMask, KCLTypeMask type)
Finds the closest KCL triangle out of the list of tris we are colliding with.
Pertains to collision.
A 3D float vector.
Definition Vector.hh:83