OdysseyDecomp/lib/al/Library/Math/ParabolicPath.cpp

124 lines
4.1 KiB
C++

#include "Library/Math/ParabolicPath.h"
#include "Library/Math/MathUtil.h"
namespace al {
ParabolicPath::ParabolicPath() {}
void ParabolicPath::initFromUpVector(const sead::Vector3f& start, const sead::Vector3f& end,
const sead::Vector3f& up) {
f32 scalar;
sead::Vector3f upDir;
separateScalarAndDirection(&scalar, &upDir, up);
initFromUpVector(start, end, upDir, scalar);
}
void ParabolicPath::initFromUpVector(const sead::Vector3f& start, const sead::Vector3f& end,
const sead::Vector3f& up, f32 maxHeight) {
mUp.set(up);
sead::Vector3f diff = end - start;
f32 verticalDistance = diff.dot(mUp);
mHorizontalDirection = diff - (mUp * verticalDistance);
separateScalarAndDirection(&mHorizontalDistance, &mHorizontalDirection, mHorizontalDirection);
calcParabolicFunctionParam(&mGravity, &mInitialVelY, maxHeight, verticalDistance);
mStart.set(start);
}
void ParabolicPath::initFromMaxHeight(const sead::Vector3f& start, const sead::Vector3f& end,
const sead::Vector3f& projectedEnd) {
sead::Vector3f up;
f32 scalar;
separateScalarAndDirection(&scalar, &up, projectedEnd - end);
initFromUpVector(start, end, up, (projectedEnd - start).dot(up));
}
void ParabolicPath::initFromUpVectorAddHeight(const sead::Vector3f& start,
const sead::Vector3f& end, const sead::Vector3f& up,
f32 height) {
f32 verticalDistance = sead::Mathf::clampMin((end - start).dot(up), 0.0f);
initFromUpVector(start, end, up, verticalDistance + height);
}
f32 ParabolicPath::getLength(f32 start, f32 end, s32 iterations) const {
s32 steps = sead::Mathi::clampMin(iterations, 1);
f32 stepSize = (end - start) / steps;
f32 squaredHStepSize = sead::Mathf::square(stepSize * mHorizontalDistance);
f32 vDist = (mGravity * start + mInitialVelY) * start;
f32 length = 0;
for (s32 i = 0; i < steps;) {
i++;
f32 prevVDist = vDist;
f32 curStep = start + i * stepSize;
vDist = (mGravity * curStep + mInitialVelY) * curStep;
length += sead::Mathf::sqrt(squaredHStepSize + sead::Mathf::square(vDist - prevVDist));
}
return length;
}
f32 ParabolicPath::getTotalLength(s32 iterations) const {
return getLength(0.0f, 1.0f, iterations);
}
void ParabolicPath::calcPositionHV(sead::Vector3f* pos, f32 h, f32 v) const {
f32 hDist = mHorizontalDistance * h;
f32 vDist = (mGravity * v + mInitialVelY) * v;
*pos = mStart + (vDist * mUp) + (hDist * mHorizontalDirection);
}
void ParabolicPath::calcPosition(sead::Vector3f* pos, f32 prog) const {
calcPositionHV(pos, prog, prog);
}
void ParabolicPath::calcPositionEaseOutH(sead::Vector3f* pos, f32 prog) const {
calcPositionHV(pos, easeOut(prog), prog);
}
void ParabolicPath::calcDirection(sead::Vector3f* dir, f32 prog, f32 stepSize) const {
f32 prog1, prog2;
if (prog < stepSize) {
prog1 = 0.0f;
prog2 = stepSize;
} else if ((1.0f - stepSize) < prog) {
prog2 = 1.0f;
prog1 = 1.0f - stepSize;
} else {
prog2 = prog + stepSize;
prog1 = prog;
}
sead::Vector3f pos1, pos2;
calcPosition(&pos1, prog1);
calcPosition(&pos2, prog2);
*dir = pos2 - pos1;
tryNormalizeOrZero(dir);
}
f32 ParabolicPath::calcPathSpeedFromGravityAccel(f32 frames) const {
return sead::Mathf::abs(frames / mGravity);
}
f32 ParabolicPath::calcPathSpeedFromAverageSpeed(f32 frames) const {
return frames / getTotalLength(10);
}
f32 ParabolicPath::calcPathSpeedFromHorizontalSpeed(f32 frames) const {
return frames / mHorizontalDistance;
}
s32 ParabolicPath::calcPathTimeFromGravityAccel(f32 frames) const {
return 1.0f / calcPathSpeedFromGravityAccel(frames);
}
s32 ParabolicPath::calcPathTimeFromAverageSpeed(f32 frames) const {
return 1.0f / calcPathSpeedFromAverageSpeed(frames);
}
s32 ParabolicPath::calcPathTimeFromHorizontalSpeed(f32 frames) const {
return 1.0f / calcPathSpeedFromHorizontalSpeed(frames);
}
} // namespace al