3#include "game/field/CollisionDirector.hh"
8Rail::Rail(u16 idx, System::MapdataPointInfo *info) {
10 m_pointCapacity = info->pointCount();
11 m_pointCount = info->pointCount();
12 m_isOscillating = info->setting(1) == 1;
13 m_points = info->points();
14 m_hasCheckedCol =
false;
23void Rail::addPoint(f32 scale,
const EGG::Vector3f &point) {
24 m_points.back().pos = point;
30void Rail::checkSphereFull() {
31 if (m_hasCheckedCol) {
35 m_floorNrms = owning_span<EGG::Vector3f>(m_pointCount);
37 for (
size_t i = 0; i < m_pointCount; ++i) {
41 bool hasCourseCol = CollisionDirector::Instance()->checkSphereFull(100.0f, m_points[i].pos,
45 if (info.floorDist > std::numeric_limits<f32>::min()) {
46 m_floorNrms[i] = info.floorNrm;
49 m_floorNrms[i] = EGG::Vector3f::ey;
53 m_hasCheckedCol =
true;
57RailLine::RailLine(u16 idx, System::MapdataPointInfo *info) :
Rail(idx, info) {
58 m_dirCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
59 m_transitions = owning_span<RailLineTransition>(m_dirCount);
62 for (u16 i = 0; i < m_pointCount - 1; ++i) {
63 auto &transition = m_transitions[i];
64 transition.m_dir = m_points[i + 1].pos - m_points[i].pos;
65 transition.m_length = transition.m_dir.normalise();
66 transition.m_lengthInv = 1.0f / transition.m_length;
67 m_pathLength += transition.m_length;
70 if (!m_isOscillating) {
71 auto &transition = m_transitions.back();
72 transition.m_dir = m_points.front().pos - m_points.back().pos;
73 transition.m_length = transition.m_dir.normalise();
74 transition.m_lengthInv = 1.0f / transition.m_length;
75 m_pathLength += transition.m_length;
80RailLine::~RailLine() =
default;
83RailSpline::RailSpline(u16 idx, System::MapdataPointInfo *info) : Rail(idx, info) {
84 m_transitionCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
85 m_transitions = owning_span<RailSplineTransition>(m_transitionCount);
90 m_doNotAllocatePathPercentages =
false;
92 invalidateTransitions(
false);
96 for (
size_t i = 0; i < m_transitionCount; ++i) {
97 m_pathLength += m_transitions[i].m_length;
102RailSpline::~RailSpline() =
default;
105void RailSpline::onPointsChanged() {
106 m_doNotAllocatePathPercentages =
true;
107 m_transitionCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
109 invalidateTransitions(
false);
113 for (
const auto &transition : m_transitions) {
114 m_pathLength += transition.m_length;
119void RailSpline::onPointAdded() {
120 m_doNotAllocatePathPercentages =
true;
121 m_transitionCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
123 invalidateTransitions(
true);
127 for (
const auto &transition : m_transitions) {
128 m_pathLength += transition.m_length;
133void RailSpline::invalidateTransitions(
bool lastOnly) {
134 if (!m_doNotAllocatePathPercentages) {
135 size_t count = ESTIMATOR_SAMPLE_COUNT * m_transitionCount + 1;
136 m_pathPercentages = owning_span<f32>(count);
141 if (m_isOscillating) {
143 auto &firstTransition = m_transitions[0];
144 firstTransition.m_p0 = m_points[0].pos;
145 firstTransition.m_p1 =
146 (m_points[1].pos - m_points[0].pos).multInv(4.0f) + m_points[0].pos;
147 firstTransition.m_p2 =
148 calcCubicBezierP2(m_points[0].pos, m_points[1].pos, m_points[2].pos);
149 firstTransition.m_p3 = m_points[1].pos;
150 firstTransition.m_length = estimateLength(firstTransition, ESTIMATOR_SAMPLE_COUNT);
151 firstTransition.m_lengthInv = 1.0f / firstTransition.m_length;
153 for (u16 i = 1; i < m_transitionCount - 1; ++i) {
154 calcCubicBezierControlPoints(m_points[i - 1].pos, m_points[i].pos,
155 m_points[i + 1].pos, m_points[i + 2].pos, ESTIMATOR_SAMPLE_COUNT,
160 auto &lastTransition = m_transitions.back();
161 lastTransition.m_p0 = m_points[m_transitionCount - 1].pos;
162 lastTransition.m_p1 = calcCubicBezierP1(m_points[m_transitionCount - 2].pos,
163 m_points[m_transitionCount - 1].pos, m_points[m_transitionCount].pos);
164 lastTransition.m_p2 =
165 (m_points[m_transitionCount - 1].pos - m_points[m_transitionCount].pos)
167 m_points[m_transitionCount].pos;
168 lastTransition.m_p3 = m_points[m_transitionCount].pos;
169 lastTransition.m_length = estimateLength(lastTransition, ESTIMATOR_SAMPLE_COUNT);
170 lastTransition.m_lengthInv = 1.0f / lastTransition.m_length;
173 auto &firstTransition = m_transitions[0];
174 firstTransition.m_p0 = m_points[0].pos;
175 firstTransition.m_p1 = calcCubicBezierP1(m_points[m_transitionCount - 1].pos,
176 m_points[0].pos, m_points[1].pos);
177 firstTransition.m_p2 =
178 calcCubicBezierP2(m_points[0].pos, m_points[1].pos, m_points[2].pos);
179 firstTransition.m_p3 = m_points[1].pos;
180 firstTransition.m_length = estimateLength(firstTransition, ESTIMATOR_SAMPLE_COUNT);
181 firstTransition.m_lengthInv = 1.0f / firstTransition.m_length;
183 for (u16 i = 1; i < m_transitionCount - 1; ++i) {
184 if (i + 2 != m_transitionCount) {
185 calcCubicBezierControlPoints(m_points[i - 1].pos, m_points[i].pos,
186 m_points[i + 1].pos, m_points[i + 2].pos, ESTIMATOR_SAMPLE_COUNT,
189 calcCubicBezierControlPoints(m_points[i - 1].pos, m_points[i].pos,
190 m_points[i + 1].pos, m_points[0].pos, ESTIMATOR_SAMPLE_COUNT,
196 auto &lastTransition = m_transitions.back();
197 lastTransition.m_p0 = m_points[m_transitionCount - 1].pos;
198 lastTransition.m_p1 = calcCubicBezierP1(m_points[m_transitionCount - 2].pos,
199 m_points[m_transitionCount - 1].pos, m_points[0].pos);
200 lastTransition.m_p2 = calcCubicBezierP2(m_points[m_transitionCount - 1].pos,
201 m_points[0].pos, m_points[1].pos);
202 lastTransition.m_p3 = m_points[0].pos;
203 lastTransition.m_length = estimateLength(lastTransition, ESTIMATOR_SAMPLE_COUNT);
204 lastTransition.m_lengthInv = 1.0f / lastTransition.m_length;
209void RailSpline::calcCubicBezierControlPoints(
const EGG::Vector3f &p0,
const EGG::Vector3f &p1,
210 const EGG::Vector3f &p2,
const EGG::Vector3f &p3, s32 count,
211 RailSplineTransition &transition) {
212 transition.m_p0 = p1;
213 transition.m_p1 = calcCubicBezierP1(p0, p1, p2);
214 transition.m_p2 = calcCubicBezierP2(p1, p2, p3);
215 transition.m_p3 = p2;
216 transition.m_length = estimateLength(transition, count);
217 transition.m_lengthInv = 1.0f / transition.m_length;
221f32 RailSpline::estimateLength(
const RailSplineTransition &transition, s32 count) {
222 std::array<EGG::Vector3f, 11> waypoints;
224 for (s32 i = 0; i < count + 1; ++i) {
225 waypoints[i] = cubicBezier(ESTIMATOR_STEP *
static_cast<f32
>(i), transition);
230 for (s32 i = 0; i < count; ++i) {
231 m_pathPercentages[m_segmentCount++] = length;
232 length += (waypoints[i] - waypoints[i + 1]).length();
236 for (s32 i = m_segmentCount - 1; i > m_segmentCount - count - 1; --i) {
237 m_pathPercentages[i] /= length;
244EGG::Vector3f RailSpline::calcCubicBezierP1(
const EGG::Vector3f &p0,
const EGG::Vector3f &p1,
245 const EGG::Vector3f &p2)
const {
246 EGG::Vector3f res = p2 - p0;
247 f32 len = res.length();
249 return p1 + res * (len * m_someScale);
253EGG::Vector3f RailSpline::calcCubicBezierP2(
const EGG::Vector3f &p0,
const EGG::Vector3f &p1,
254 const EGG::Vector3f &p2)
const {
255 EGG::Vector3f res = p0 - p2;
256 f32 len = res.length();
258 return p1 + res * (len * m_someScale);
262EGG::Vector3f RailSpline::cubicBezier(f32 t,
const RailSplineTransition &transition)
const {
265 EGG::Vector3f res = transition.m_p0 * (dt * dt * dt);
266 res += transition.m_p1 * (3.0f * t * (dt * dt));
267 res += transition.m_p2 * (3.0f * (t * t) * dt);
268 res += transition.m_p3 * (t * t * t);
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.