3#include "game/field/CollisionDirector.hh"
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;
21 delete m_floorNrms.data();
26 m_points.back().pos = point;
32void Rail::checkSphereFull() {
33 if (m_hasCheckedCol) {
37 m_floorNrms = std::span<EGG::Vector3f>(
new EGG::Vector3f[m_pointCount], m_pointCount);
39 for (
size_t i = 0; i < m_pointCount; ++i) {
43 bool hasCourseCol = CollisionDirector::Instance()->checkSphereFull(100.0f, m_points[i].pos,
47 if (info.floorDist > std::numeric_limits<f32>::min()) {
48 m_floorNrms[i] = info.floorNrm;
51 m_floorNrms[i] = EGG::Vector3f::ey;
55 m_hasCheckedCol =
true;
60 m_dirCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
61 m_transitions = std::span<RailLineTransition>(
new RailLineTransition[m_dirCount], m_dirCount);
64 for (
u16 i = 0; i < m_pointCount - 1; ++i) {
65 auto &transition = m_transitions[i];
66 transition.m_dir = m_points[i + 1].pos - m_points[i].pos;
67 transition.m_length = transition.m_dir.normalise();
68 transition.m_lengthInv = 1.0f / transition.m_length;
69 m_pathLength += transition.m_length;
72 if (!m_isOscillating) {
73 auto &transition = m_transitions.back();
74 transition.m_dir = m_points.front().pos - m_points.back().pos;
75 transition.m_length = transition.m_dir.normalise();
76 transition.m_lengthInv = 1.0f / transition.m_length;
77 m_pathLength += transition.m_length;
82RailLine::~RailLine() {
83 delete m_transitions.data();
88 m_transitionCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
89 m_transitions = std::span<RailSplineTransition>(
new RailSplineTransition[m_transitionCount],
91 m_estimatorSampleCount = 10;
92 m_estimatorStep = 1.0f /
static_cast<f32
>(m_estimatorSampleCount);
97 m_doNotAllocatePathPercentages =
false;
99 invalidateTransitions(
false);
103 for (
size_t i = 0; i < m_transitionCount; ++i) {
104 m_pathLength += m_transitions[i].m_length;
109RailSpline::~RailSpline() {
110 delete m_transitions.data();
111 delete m_pathPercentages.data();
115void RailSpline::onPointsChanged() {
116 m_doNotAllocatePathPercentages =
true;
117 m_transitionCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
119 invalidateTransitions(
false);
123 for (
auto &transition : m_transitions) {
124 m_pathLength += transition.m_length;
129void RailSpline::onPointAdded() {
130 m_doNotAllocatePathPercentages =
true;
131 m_transitionCount = m_isOscillating ? m_pointCount - 1 : m_pointCount;
133 invalidateTransitions(
true);
137 for (
auto &transition : m_transitions) {
138 m_pathLength += transition.m_length;
143void RailSpline::invalidateTransitions(
bool lastOnly) {
144 if (!m_doNotAllocatePathPercentages) {
145 size_t count = m_estimatorSampleCount * m_transitionCount + 1;
146 m_pathPercentages = std::span<f32>(
new f32[count], count);
151 if (m_isOscillating) {
153 auto &firstTransition = m_transitions[0];
154 firstTransition.m_p0 = m_points[0].pos;
155 firstTransition.m_p1 =
156 (m_points[1].pos - m_points[0].pos).multInv(4.0f) + m_points[0].pos;
157 firstTransition.m_p2 =
158 calcCubicBezierP2(m_points[0].pos, m_points[1].pos, m_points[2].pos);
159 firstTransition.m_p3 = m_points[1].pos;
160 firstTransition.m_length = estimateLength(firstTransition, m_estimatorSampleCount);
161 firstTransition.m_lengthInv = 1.0f / firstTransition.m_length;
163 for (
u16 i = 1; i < m_transitionCount - 1; ++i) {
164 calcCubicBezierControlPoints(m_points[i - 1].pos, m_points[i].pos,
165 m_points[i + 1].pos, m_points[i + 2].pos, m_estimatorSampleCount,
170 auto &lastTransition = m_transitions.back();
171 lastTransition.m_p0 = m_points[m_transitionCount - 1].pos;
172 lastTransition.m_p1 = calcCubicBezierP1(m_points[m_transitionCount - 2].pos,
173 m_points[m_transitionCount - 1].pos, m_points[m_transitionCount].pos);
174 lastTransition.m_p2 =
175 (m_points[m_transitionCount - 1].pos - m_points[m_transitionCount].pos)
177 m_points[m_transitionCount].pos;
178 lastTransition.m_p3 = m_points[m_transitionCount].pos;
179 lastTransition.m_length = estimateLength(lastTransition, m_estimatorSampleCount);
180 lastTransition.m_lengthInv = 1.0f / lastTransition.m_length;
183 auto &firstTransition = m_transitions[0];
184 firstTransition.m_p0 = m_points[0].pos;
185 firstTransition.m_p1 = calcCubicBezierP1(m_points[m_transitionCount - 1].pos,
186 m_points[0].pos, m_points[1].pos);
187 firstTransition.m_p2 =
188 calcCubicBezierP2(m_points[0].pos, m_points[1].pos, m_points[2].pos);
189 firstTransition.m_p3 = m_points[1].pos;
190 firstTransition.m_length = estimateLength(firstTransition, m_estimatorSampleCount);
191 firstTransition.m_lengthInv = 1.0f / firstTransition.m_length;
193 for (
u16 i = 1; i < m_transitionCount - 1; ++i) {
194 if (i + 2 != m_transitionCount) {
195 calcCubicBezierControlPoints(m_points[i - 1].pos, m_points[i].pos,
196 m_points[i + 1].pos, m_points[i + 2].pos, m_estimatorSampleCount,
199 calcCubicBezierControlPoints(m_points[i - 1].pos, m_points[i].pos,
200 m_points[i + 1].pos, m_points[0].pos, m_estimatorSampleCount,
206 auto &lastTransition = m_transitions.back();
207 lastTransition.m_p0 = m_points[m_transitionCount - 1].pos;
208 lastTransition.m_p1 = calcCubicBezierP1(m_points[m_transitionCount - 2].pos,
209 m_points[m_transitionCount - 1].pos, m_points[0].pos);
210 lastTransition.m_p2 = calcCubicBezierP2(m_points[m_transitionCount - 1].pos,
211 m_points[0].pos, m_points[1].pos);
212 lastTransition.m_p3 = m_points[0].pos;
213 lastTransition.m_length = estimateLength(lastTransition, m_estimatorSampleCount);
214 lastTransition.m_lengthInv = 1.0f / lastTransition.m_length;
221 RailSplineTransition &transition) {
222 transition.m_p0 = p1;
223 transition.m_p1 = calcCubicBezierP1(p0, p1, p2);
224 transition.m_p2 = calcCubicBezierP2(p1, p2, p3);
225 transition.m_p3 = p2;
226 transition.m_length = estimateLength(transition, count);
227 transition.m_lengthInv = 1.0f / transition.m_length;
231f32 RailSpline::estimateLength(
const RailSplineTransition &transition, s32 count) {
232 std::array<EGG::Vector3f, 11> waypoints;
234 for (s32 i = 0; i < count + 1; ++i) {
235 waypoints[i] = cubicBezier(m_estimatorStep *
static_cast<f32
>(i), transition);
240 for (s32 i = 0; i < count; ++i) {
241 m_pathPercentages[m_segmentCount++] = length;
242 length += (waypoints[i] - waypoints[i + 1]).length();
246 for (s32 i = m_segmentCount - 1; i > m_segmentCount - count - 1; --i) {
247 m_pathPercentages[i] /= length;
259 return p1 + res * (len * m_someScale);
268 return p1 + res * (len * m_someScale);
272EGG::Vector3f RailSpline::cubicBezier(f32 t,
const RailSplineTransition &transition)
const {
276 res += transition.m_p1 * (3.0f * t * (dt * dt));
277 res += transition.m_p2 * (3.0f * (t * t) * dt);
278 res += transition.m_p3 * (t * t * t);
#define KCL_TYPE_FLOOR
0x20E80FFF - Any KCL that the player or items can drive/land on.
f32 length() const
The square root of the vector's dot product.