mirror of
https://github.com/MonsterDruide1/OdysseyDecomp
synced 2026-05-10 09:18:01 +00:00
192 lines
6.1 KiB
C++
192 lines
6.1 KiB
C++
#include "Project/Rail/BezierCurve.h"
|
|
|
|
namespace al {
|
|
|
|
BezierCurve::BezierCurve() = default;
|
|
|
|
void BezierCurve::set(const sead::Vector3f& start, const sead::Vector3f& startHandle,
|
|
const sead::Vector3f& endHandle, const sead::Vector3f& end) {
|
|
sead::Vector3f diff1 = startHandle - start;
|
|
sead::Vector3f diff2 = endHandle - startHandle;
|
|
sead::Vector3f diff3 = end - endHandle;
|
|
|
|
sead::Vector3f diffDiff1 = diff2 - diff1;
|
|
sead::Vector3f diffDiff2 = diff3 - diff2;
|
|
|
|
sead::Vector3f diffDiffDiff = diffDiff2 - diffDiff1;
|
|
|
|
mStart = start;
|
|
mControlPoint1 = diff1 * 3;
|
|
mControlPoint2 = diffDiff1 * 3;
|
|
mControlPoint3 = diffDiffDiff;
|
|
|
|
mDistance = calcLength(0.0, 1.0, 10);
|
|
}
|
|
|
|
f32 BezierCurve::calcLength(f32 startParam, f32 endParam, s32 stepCount) const {
|
|
f32 avgVelocity = (calcDeltaLength(startParam) + calcDeltaLength(endParam)) / 2;
|
|
f32 halfStepSize = (endParam - startParam) * (1.0f / (stepCount * 2.0f));
|
|
|
|
f32 sumVelHalfStep = 0.0f;
|
|
f32 sumVelFullStep = 0.0f;
|
|
for (s32 i = 1; i <= stepCount; i++) {
|
|
f32 doubleI = i * 2.0f;
|
|
|
|
sumVelHalfStep += calcDeltaLength((halfStepSize * (doubleI - 1)) + startParam);
|
|
|
|
if (i != stepCount)
|
|
sumVelFullStep += calcDeltaLength((halfStepSize * (doubleI)) + startParam);
|
|
}
|
|
|
|
return std::floor((halfStepSize * 0.33333f) *
|
|
(avgVelocity + (sumVelFullStep * 2) + (sumVelHalfStep * 4)) * 1024.0f) /
|
|
1024.0f;
|
|
}
|
|
|
|
void BezierCurve::calcPos(sead::Vector3f* pos, f32 param) const {
|
|
f32 square = param * param;
|
|
f32 cube = square * param;
|
|
|
|
pos->x = (mControlPoint1.x * param) + mStart.x;
|
|
pos->y = (mControlPoint1.y * param) + mStart.y;
|
|
pos->z = (mControlPoint1.z * param) + mStart.z;
|
|
|
|
pos->x = (mControlPoint2.x * square) + pos->x;
|
|
pos->y = (mControlPoint2.y * square) + pos->y;
|
|
pos->z = (mControlPoint2.z * square) + pos->z;
|
|
|
|
pos->x = (mControlPoint3.x * cube) + pos->x;
|
|
pos->y = (mControlPoint3.y * cube) + pos->y;
|
|
pos->z = (mControlPoint3.z * cube) + pos->z;
|
|
}
|
|
|
|
void BezierCurve::calcVelocity(sead::Vector3f* vel, f32 param) const {
|
|
f32 fac1 = param + param;
|
|
f32 fac2 = 3 * param * param;
|
|
|
|
vel->x = (mControlPoint2.x * fac1) + mControlPoint1.x;
|
|
vel->y = (mControlPoint2.y * fac1) + mControlPoint1.y;
|
|
vel->z = (mControlPoint2.z * fac1) + mControlPoint1.z;
|
|
|
|
vel->x = (mControlPoint3.x * fac2) + vel->x;
|
|
vel->y = (mControlPoint3.y * fac2) + vel->y;
|
|
vel->z = (mControlPoint3.z * fac2) + vel->z;
|
|
}
|
|
|
|
f32 BezierCurve::calcDeltaLength(f32 param) const {
|
|
sead::Vector3f tmp;
|
|
calcVelocity(&tmp, param);
|
|
return tmp.length();
|
|
}
|
|
|
|
// NON_MATCHING: flipped parts of if in last statement and unoptimized 1.0f - load
|
|
// (https://decomp.me/scratch/hGwGZ)
|
|
f32 BezierCurve::calcCurveParam(f32 distance) const {
|
|
f32 percent = distance / mDistance;
|
|
f32 partLength = calcLength(0, percent, 10);
|
|
if (sead::Mathf::abs(distance - partLength) <= 0.01f)
|
|
return percent;
|
|
|
|
for (s32 i = 0; i <= 4; i++) {
|
|
f32 len = std::max(calcDeltaLength(percent), 0.001f);
|
|
f32 newPercent = percent + ((distance - partLength) / len);
|
|
|
|
percent = sead::Mathf::clamp(newPercent, 0.0f, 1.0f);
|
|
partLength = calcLength(0.0f, percent, 10);
|
|
if (sead::Mathf::abs(distance - partLength) <= 0.01f)
|
|
return percent;
|
|
}
|
|
|
|
if (partLength < 0.0f || percent > 1.0f)
|
|
return sead::Mathf::clamp(percent, 0.0f, 1.0f);
|
|
return percent;
|
|
}
|
|
|
|
f32 BezierCurve::calcNearestParam(const sead::Vector3f& pos, f32 interval) const {
|
|
f32 currentParam = 0.0;
|
|
f32 bestParam = -1.0;
|
|
f32 bestDist = 3.4028e38;
|
|
do {
|
|
sead::Vector3f nearest;
|
|
calcPos(&nearest, currentParam);
|
|
f32 currentDist = (nearest - pos).squaredLength();
|
|
|
|
if (currentDist < bestDist) {
|
|
bestParam = currentParam;
|
|
bestDist = currentDist;
|
|
}
|
|
currentParam = currentParam + interval;
|
|
} while (currentParam <= 1.0);
|
|
return bestParam;
|
|
}
|
|
|
|
f32 BezierCurve::calcNearestLength(f32* param, const sead::Vector3f& pos, f32 max,
|
|
f32 interval) const {
|
|
f32 bestParam = -1.0;
|
|
f32 currentParam = 0.0;
|
|
f32 bestDist = 3.4028e38;
|
|
while (currentParam < max) {
|
|
sead::Vector3f nearest;
|
|
calcPos(&nearest, calcCurveParam(currentParam));
|
|
f32 currentDist = (nearest - pos).squaredLength();
|
|
|
|
if (currentDist < bestDist) {
|
|
bestParam = currentParam;
|
|
bestDist = currentDist;
|
|
}
|
|
currentParam = currentParam + interval;
|
|
}
|
|
*param = bestParam;
|
|
return bestDist;
|
|
}
|
|
|
|
// NON_MATCHING: Difference in loading for calcNearestParam (https://decomp.me/scratch/mFZVT)
|
|
void BezierCurve::calcNearestPos(sead::Vector3f* nearest, const sead::Vector3f& pos,
|
|
f32 interval) const {
|
|
calcPos(nearest, calcNearestParam(pos, interval));
|
|
}
|
|
|
|
void BezierCurve::calcStartPos(sead::Vector3f* pos) const {
|
|
*pos = mStart;
|
|
}
|
|
|
|
void BezierCurve::calcCtrlPos1(sead::Vector3f* pos) const {
|
|
pos->x = mControlPoint1.x * 0.333333f;
|
|
pos->y = mControlPoint1.y * 0.333333f;
|
|
pos->z = mControlPoint1.z * 0.333333f;
|
|
|
|
pos->x = pos->x + mStart.x;
|
|
pos->y = pos->y + mStart.y;
|
|
pos->z = pos->z + mStart.z;
|
|
}
|
|
|
|
void BezierCurve::calcCtrlPos2(sead::Vector3f* pos) const {
|
|
pos->x = mControlPoint2.x * 0.333333f;
|
|
pos->y = mControlPoint2.y * 0.333333f;
|
|
pos->z = mControlPoint2.z * 0.333333f;
|
|
|
|
pos->x = (mControlPoint1.x * 0.6666667f) + pos->x;
|
|
pos->y = (mControlPoint1.y * 0.6666667f) + pos->y;
|
|
pos->z = (mControlPoint1.z * 0.6666667f) + pos->z;
|
|
|
|
pos->x = pos->x + mStart.x;
|
|
pos->y = pos->y + mStart.y;
|
|
pos->z = pos->z + mStart.z;
|
|
}
|
|
|
|
void BezierCurve::calcEndPos(sead::Vector3f* pos) const {
|
|
pos->x = mStart.x + mControlPoint1.x;
|
|
pos->y = mStart.y + mControlPoint1.y;
|
|
pos->z = mStart.z + mControlPoint1.z;
|
|
|
|
pos->x = pos->x + mControlPoint2.x;
|
|
pos->y = pos->y + mControlPoint2.y;
|
|
pos->z = pos->z + mControlPoint2.z;
|
|
|
|
pos->x = pos->x + mControlPoint3.x;
|
|
pos->y = pos->y + mControlPoint3.y;
|
|
pos->z = pos->z + mControlPoint3.z;
|
|
}
|
|
|
|
} // namespace al
|