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 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->reset();
20 }
21
22 if (pFlagsOut) {
23 *pFlagsOut = 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->checkSphereFull(1.0f, radius, nullptr, v0, v1, flags, pInfo, pFlagsOut);
35
36 colliding |= ObjectDrivableDirector::Instance()->checkSphereFull(radius, v0, v1, flags, pInfo,
37 pFlagsOut, timeOffset);
38
39 if (colliding) {
40 if (pInfo) {
41 pInfo->tangentOff = pInfo->bbox.min + pInfo->bbox.max;
42 }
43
44 if (noBounceInfo) {
45 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
46 }
47 }
48
49 courseColMgr->clearNoBounceWallInfo();
50
51 return colliding;
52}
53
55bool CollisionDirector::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0,
56 const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut,
57 u32 timeOffset) {
58 if (pInfo) {
59 pInfo->reset();
60 }
61
62 if (pFlagsOut) {
63 resetCollisionEntries(pFlagsOut);
64 }
65
66 auto *courseColMgr = CourseColMgr::Instance();
67 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
68 if (noBounceInfo) {
69 noBounceInfo->bbox.setZero();
70 noBounceInfo->dist = std::numeric_limits<f32>::min();
71 }
72
73 bool colliding = flags &&
74 courseColMgr->checkSphereFullPush(1.0f, radius, nullptr, v0, v1, flags, pInfo,
75 pFlagsOut);
76
77 colliding |= ObjectDrivableDirector::Instance()->checkSphereFullPush(radius, v0, v1, flags,
78 pInfo, 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::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &pos,
97 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfoPartial *info,
98 KCLTypeMask *typeMaskOut, u32 timeOffset) {
99 if (info) {
100 info->bbox.setZero();
101 }
102
103 if (typeMaskOut) {
104 *typeMaskOut = KCL_NONE;
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 = courseColMgr->checkSphereCachedPartial(1.0f, radius, nullptr, pos, prevPos,
115 typeMask, info, typeMaskOut);
116
117 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedPartial(radius, pos, prevPos,
118 typeMask, info, typeMaskOut, timeOffset);
119
120 if (colliding) {
121 if (info) {
122 info->tangentOff = info->bbox.min + info->bbox.max;
123 }
124
125 if (noBounceInfo) {
126 noBounceInfo->tangentOff = noBounceInfo->bbox.min + noBounceInfo->bbox.max;
127 }
128 }
129
130 courseColMgr->clearNoBounceWallInfo();
131
132 return colliding;
133}
134
136bool CollisionDirector::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &pos,
137 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfoPartial *info,
138 KCLTypeMask *typeMaskOut, u32 timeOffset) {
139 if (info) {
140 info->bbox.setZero();
141 }
142
143 if (typeMaskOut) {
144 resetCollisionEntries(typeMaskOut);
145 }
146
147 auto *courseColMgr = CourseColMgr::Instance();
148 auto *noBounceInfo = courseColMgr->noBounceWallInfo();
149 if (noBounceInfo) {
150 noBounceInfo->bbox.setZero();
151 noBounceInfo->dist = std::numeric_limits<f32>::min();
152 }
153
154 bool colliding = courseColMgr->checkSphereCachedPartialPush(1.0f, radius, nullptr, pos, prevPos,
155 typeMask, info, typeMaskOut);
156
157 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedPartialPush(radius, pos,
158 prevPos, typeMask, info, typeMaskOut, timeOffset);
159
160 courseColMgr->clearNoBounceWallInfo();
161
162 return colliding;
163}
164
166bool CollisionDirector::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &pos,
167 const EGG::Vector3f &prevPos, KCLTypeMask typeMask, CollisionInfo *colInfo,
168 KCLTypeMask *typeMaskOut, u32 timeOffset) {
169 if (colInfo) {
170 colInfo->reset();
171 }
172
173 if (typeMaskOut) {
174 resetCollisionEntries(typeMaskOut);
175 }
176
177 auto *courseColMgr = CourseColMgr::Instance();
178 auto *info = courseColMgr->noBounceWallInfo();
179 if (info) {
180 info->bbox.setZero();
181 info->dist = std::numeric_limits<f32>::min();
182 }
183
184 bool colliding = courseColMgr->checkSphereCachedFullPush(1.0f, radius, nullptr, pos, prevPos,
185 typeMask, colInfo, typeMaskOut);
186
187 colliding |= ObjectDrivableDirector::Instance()->checkSphereCachedFullPush(radius, pos, prevPos,
188 typeMask, colInfo, typeMaskOut, timeOffset);
189
190 if (colliding) {
191 if (colInfo) {
192 colInfo->tangentOff = colInfo->bbox.min + colInfo->bbox.max;
193 }
194
195 if (info) {
196 info->tangentOff = info->bbox.min + info->bbox.max;
197 }
198 }
199
200 courseColMgr->clearNoBounceWallInfo();
201
202 return colliding;
203}
204
206void CollisionDirector::resetCollisionEntries(KCLTypeMask *ptr) {
207 *ptr = 0;
208 m_collisionEntryCount = 0;
209 m_closestCollisionEntry = nullptr;
210}
211
219 u16 attribute) {
220 *typeMask = *typeMask | kclTypeBit;
221 if (m_collisionEntryCount >= m_entries.size()) {
222 m_collisionEntryCount = m_entries.size() - 1;
223 }
224
225 m_entries[m_collisionEntryCount++] = CollisionEntry(kclTypeBit, attribute, dist);
226}
227
233 m_closestCollisionEntry = nullptr;
234 f32 minDist = -std::numeric_limits<f32>::min();
235
236 for (size_t i = 0; i < m_collisionEntryCount; ++i) {
237 const auto &entry = m_entries[i];
238 u32 typeMask = entry.typeMask & type;
239 if (typeMask != 0 && entry.dist > minDist) {
240 minDist = entry.dist;
241 m_closestCollisionEntry = &entry;
242 }
243 }
244
245 return !!m_closestCollisionEntry;
246}
247
249CollisionDirector *CollisionDirector::CreateInstance() {
250 ASSERT(!s_instance);
251 s_instance = new CollisionDirector;
252 return s_instance;
253}
254
256void CollisionDirector::DestroyInstance() {
257 ASSERT(s_instance);
258 auto *instance = s_instance;
259 s_instance = nullptr;
260 delete instance;
261}
262
264CollisionDirector::CollisionDirector() {
265 m_collisionEntryCount = 0;
266 m_closestCollisionEntry = nullptr;
267 CourseColMgr::CreateInstance()->init();
268}
269
271CollisionDirector::~CollisionDirector() {
272 if (s_instance) {
273 s_instance = nullptr;
274 WARN("CollisionDirector instance not explicitly handled!");
275 }
276
277 CourseColMgr::DestroyInstance();
278}
279
280CollisionDirector *CollisionDirector::s_instance = nullptr;
281
282} // 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