A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
MapdataArea.cc
1#include "MapdataArea.hh"
2
3#include "game/system/CourseMap.hh"
4
5namespace System {
6
8MapdataAreaBase::MapdataAreaBase(const SData *data, s16 index) : m_rawData(data), m_index(index) {
9 EGG::RamStream stream = EGG::RamStream(data,
10 CourseMap::Instance()->version() > 2200 ? sizeof(SData) : sizeof(SData) - 4);
11 read(stream);
12
13 m_sqBoundingSphereRadius = 0.0f;
14 m_ellipseAspectRatio = 0.0f;
15 m_ellipseRadiusSq = 0.0f;
16 m_dimensions = EGG::Vector3f::zero;
17 m_right = EGG::Vector3f::zero;
18 m_up = EGG::Vector3f::zero;
19 m_forward = EGG::Vector3f::zero;
20}
21
22void MapdataAreaBase::read(EGG::Stream &stream) {
23 stream.skip(1);
24 m_type = static_cast<Type>(stream.read_s8());
25 stream.skip(1);
26 m_priority = stream.read_u8();
27 m_position.read(stream);
28 m_rotation.read(stream);
29 m_scale.read(stream);
30
31 for (auto &param : m_params) {
32 param = stream.read_s16();
33 }
34
35 if (CourseMap::Instance()->version() > 2200) {
36 m_railId = stream.read_s8();
37 }
38}
39
41MapdataPointInfo *MapdataAreaBase::getPointInfo() const {
42 // The rail ID doesn't exist in prior versions, so there's no point info
43 auto *courseMap = CourseMap::Instance();
44 if (courseMap->version() < 2200) {
45 return nullptr;
46 }
47
48 return courseMap->getPointInfo(m_railId);
49}
50
52MapdataAreaBox::MapdataAreaBox(const SData *data, s16 index) : MapdataAreaBase(data, index) {
53 m_dimensions.x = 0.5f * (10000.0f * m_scale.x);
54 m_dimensions.y = 10000.0f * m_scale.y;
55 m_dimensions.z = 0.5f * (10000.0f * m_scale.z);
56
57 m_ellipseAspectRatio = 0.0f;
58 m_ellipseRadiusSq = 0.0f;
59 m_sqBoundingSphereRadius = m_dimensions.squaredLength();
60
61 EGG::Quatf rotation = EGG::Quatf::FromRPY(DEG2RAD * m_rotation.x, DEG2RAD * m_rotation.y,
62 DEG2RAD * m_rotation.z);
63
64 m_right = rotation.rotateVector(EGG::Vector3f::ex);
65 m_up = rotation.rotateVector(EGG::Vector3f::ey);
66 m_forward = rotation.rotateVector(EGG::Vector3f::ez);
67}
68
70bool MapdataAreaBox::testImpl(const EGG::Vector3f &pos) const {
71 EGG::Vector3f relPos = pos - m_position;
72
73 f32 u = relPos.dot(m_up);
74 if (u > m_dimensions.y || u < 0.0f) {
75 return false;
76 }
77
78 f32 r = relPos.dot(m_right);
79 if (r > m_dimensions.x || r < -m_dimensions.x) {
80 return false;
81 }
82
83 f32 f = relPos.dot(m_forward);
84 if (f > m_dimensions.z || f < -m_dimensions.z) {
85 return false;
86 }
87
88 return true;
89}
90
92MapdataAreaCylinder::MapdataAreaCylinder(const SData *data, s16 index)
93 : MapdataAreaBase(data, index) {
94 m_dimensions = m_scale * 5000.0f;
95 m_ellipseRadiusSq = m_dimensions.x * m_dimensions.x;
96 m_sqBoundingSphereRadius = m_dimensions.x * m_dimensions.x + m_dimensions.z * m_dimensions.z;
97 m_ellipseAspectRatio = m_scale.x / m_scale.z;
98
99 EGG::Quatf rotation = EGG::Quatf::FromRPY(DEG2RAD * m_rotation.x, DEG2RAD * m_rotation.y,
100 DEG2RAD * m_rotation.z);
101
102 m_right = rotation.rotateVector(EGG::Vector3f::ex);
103 m_up = rotation.rotateVector(EGG::Vector3f::ey);
104 m_forward = rotation.rotateVector(EGG::Vector3f::ez);
105}
106
108bool MapdataAreaCylinder::testImpl(const EGG::Vector3f &pos) const {
109 EGG::Vector3f relPos = pos - m_position;
110
111 if (relPos.dot(m_up) > m_dimensions.y) {
112 return false;
113 }
114
115 f32 f = m_ellipseAspectRatio * relPos.dot(m_forward);
116 f32 r = relPos.dot(m_right);
117 if (r * r + f * f < m_ellipseRadiusSq) {
118 return false;
119 }
120
121 return true;
122}
123
125MapdataAreaAccessor::MapdataAreaAccessor(const MapSectionHeader *header)
126 : MapdataAccessorBase<MapdataAreaBase, MapdataAreaBase::SData>(header) {
127 init(reinterpret_cast<const MapdataAreaBase::SData *>(m_sectionHeader + 1),
128 parse<u16>(m_sectionHeader->count));
129
130 m_sortedEntries =
131 std::span<MapdataAreaBase *>(new MapdataAreaBase *[m_entryCount], m_entryCount);
132}
133
135MapdataAreaAccessor::~MapdataAreaAccessor() {
136 delete m_sortedEntries.data();
137}
138
139void MapdataAreaAccessor::init(const MapdataAreaBase::SData *start, u16 count) {
140 if (count != 0) {
141 m_entryCount = count;
142 m_entries = new MapdataAreaBase *[count];
143 }
144
145 for (u16 i = 0; i < count; ++i) {
146 // Iterators will be wrong for versions < 2200, so we need to factor out the new members
147 const MapdataAreaBase::SData *data = CourseMap::Instance()->version() > 2200 ?
148 &start[i] :
149 reinterpret_cast<const MapdataAreaBase::SData *>(
150 reinterpret_cast<uintptr_t>(start) +
151 i * (sizeof(MapdataAreaBase::SData) - 4));
152
153 // Reading this is safe because 8-bit integers are immune to endianness issues
154 MapdataAreaBase::Shape shape = static_cast<MapdataAreaBase::Shape>(data->shape);
155
156 switch (shape) {
157 case MapdataAreaBase::Shape::Box:
158 m_entries[i] = new MapdataAreaBox(data, i);
159 break;
160 case MapdataAreaBase::Shape::Cylinder:
161 m_entries[i] = new MapdataAreaCylinder(data, i);
162 break;
163 default:
164 PANIC("Invalid area shape!");
165 break;
166 }
167 }
168}
169
171void MapdataAreaAccessor::sort() {
172 for (size_t i = 0; i < m_entryCount; ++i) {
173 m_sortedEntries[i] = get(i);
174 }
175
176 for (size_t i = 1; i < m_entryCount; ++i) {
177 size_t j = i;
178 for (; j > 0 && m_sortedEntries[j - 1]->priority() < m_sortedEntries[i]->priority(); --j) {
179 m_sortedEntries[j] = m_sortedEntries[j - 1];
180 }
181 }
182}
183
184} // namespace System
A stream of data stored in memory.
Definition Stream.hh:83
A stream of data, abstracted to allow for continuous seeking.
Definition Stream.hh:10
High-level handling for generic system operations, such as input reading, race configuration,...
Definition CourseMap.cc:5
A quaternion, used to represent 3D rotation.
Definition Quat.hh:12
Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
Definition Quat.cc:55
A 3D float vector.
Definition Vector.hh:88
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:187