#include "Library/Rail/RailUtil.h" #include #include #include "Library/LiveActor/ActorClippingFunction.h" #include "Library/LiveActor/ActorInitUtil.h" #include "Library/LiveActor/ActorMovementFunction.h" #include "Library/LiveActor/ActorPoseUtil.h" #include "Library/LiveActor/LiveActor.h" #include "Library/LiveActor/LiveActorGroup.h" #include "Library/Math/MathUtil.h" #include "Library/Placement/PlacementFunction.h" #include "Library/Rail/IUseRail.h" #include "Library/Rail/Rail.h" #include "Library/Rail/RailRider.h" namespace al { static RailRider* getRailRider(const IUseRail* railHolder) { return railHolder->getRailRider(); } static const Rail* getRail(const IUseRail* railHolder) { return getRailRider(railHolder)->getRail(); } void setRailPosToStart(IUseRail* railHolder) { getRailRider(railHolder)->moveToRailStart(); } void setRailPosToEnd(IUseRail* railHolder) { getRailRider(railHolder)->moveToRailEnd(); } void setRailPosToNearestPos(IUseRail* railHolder, const sead::Vector3f& pos) { getRailRider(railHolder)->moveToNearestRail(pos); } void setRailPosToCoord(IUseRail* railHolder, f32 coord) { getRailRider(railHolder)->setCoord(coord); } void setRailPosToRailPoint(IUseRail* railHolder, s32 index) { setRailPosToCoord(railHolder, calcRailCoordByPoint(railHolder, index)); } void setSyncRailToStart(LiveActor* actor) { setRailPosToStart(actor); syncRailTrans(actor); } void syncRailTrans(LiveActor* actor) { setTrans(actor, getRailPos(actor)); } void setSyncRailToEnd(LiveActor* actor) { setRailPosToEnd(actor); syncRailTrans(actor); } void setSyncRailToNearestPos(LiveActor* actor, const sead::Vector3f& pos) { setRailPosToNearestPos(actor, pos); syncRailTrans(actor); } void setSyncRailToNearestRailControlPoint(LiveActor* actor) { RailRider* railRider = getRailRider(actor); const Rail* rail = railRider->getRail(); sead::Vector3f railPos; u32 index; rail->calcNearestRailPointPosFast(&railPos, &index, getTrans(actor)); setTrans(actor, railPos); if (index == 0) { railRider->moveToRailStart(); return; } railRider->moveToRailPoint(index); } void setSyncRailToNearestPos(LiveActor* actor) { setSyncRailToNearestPos(actor, getTrans(actor)); } void setSyncRailToCoord(LiveActor* actor, f32 coord) { setRailPosToCoord(actor, coord); syncRailTrans(actor); } void setSyncRailToRailPoint(LiveActor* actor, s32 index) { setRailPosToRailPoint(actor, index); syncRailTrans(actor); } bool moveRail(IUseRail* railHolder, f32 speed) { RailRider* railRider = getRailRider(railHolder); railRider->setSpeed(speed); railRider->move(); return isRailReachedGoal(railHolder); } bool isRailReachedGoal(const IUseRail* railHolder) { return getRailRider(railHolder)->isReachedGoal(); } bool moveRailLoop(IUseRail* railHolder, f32 speed) { f32 coord = getRailCoord(railHolder); moveRail(railHolder, speed); if (isRailReachedGoal(railHolder)) { if (isRailGoingToEnd(railHolder)) setRailPosToCoord(railHolder, (coord + speed) - getRailTotalLength(railHolder)); else setRailPosToCoord(railHolder, getRailTotalLength(railHolder) - (speed - coord)); return true; } return false; } f32 getRailCoord(const IUseRail* railHolder) { return getRailRider(railHolder)->getCoord(); } bool isRailGoingToEnd(const IUseRail* railHolder) { return getRailRider(railHolder)->isMoveForwards(); } f32 getRailTotalLength(const IUseRail* railHolder) { return getRail(railHolder)->getTotalLength(); } bool moveRailTurn(IUseRail* railHolder, f32 speed, f32 goalCoord) { if (speed < 0.0f) reverseRail(railHolder); moveRail(railHolder, sead::Mathf::abs(speed)); bool isReversed = goalCoord <= 0.0f ? isRailReachedGoal(railHolder) : isRailReachedNearGoal(railHolder, goalCoord); if (isReversed) reverseRail(railHolder); if (speed < 0.0f) reverseRail(railHolder); return isReversed; } void reverseRail(IUseRail* railHolder) { getRailRider(railHolder)->reverse(); } bool isRailReachedNearGoal(const IUseRail* railHolder, f32 goalCoord) { return isRailReachedNearGoal(railHolder, goalCoord, goalCoord); } bool turnToRailDir(LiveActor* actor, f32 deg) { sead::Vector3f moveDir = {0.0f, 0.0f, 0.0f}; calcRailMoveDir(&moveDir, actor); sead::Quatf* quat = tryGetQuatPtr(actor); if (quat) return turnQuatFrontToDirDegreeH(actor, moveDir, deg); return turnDirectionDegree(actor, getFrontPtr(actor), moveDir, deg); } void calcRailMoveDir(sead::Vector3f* moveDir, const IUseRail* railHolder) { moveDir->set(isRailGoingToEnd(railHolder) ? getRailDir(railHolder) : -getRailDir(railHolder)); } bool turnToRailDirImmediately(LiveActor* actor) { return turnToRailDir(actor, 180.0f); } const sead::Vector3f& getRailPos(const IUseRail* railHolder) { return getRailRider(railHolder)->getPosition(); } bool moveSyncRail(LiveActor* actor, f32 speed) { bool isReachedGoal = moveRail(actor, speed); syncRailTrans(actor); return isReachedGoal; } bool moveSyncRailLoop(LiveActor* actor, f32 speed) { bool isReachedGoal = moveRailLoop(actor, speed); syncRailTrans(actor); if (isReachedGoal) resetPosition(actor); return isReachedGoal; } bool moveSyncRailTurn(LiveActor* actor, f32 speed) { bool isReversed = moveRailTurn(actor, speed, 0.0f); syncRailTrans(actor); return isReversed; } f32 calcNearestRailCoord(const IUseRail* railHolder, const sead::Vector3f& pos) { return getRail(railHolder)->calcNearestRailPosCoord(pos, 20.0f); } f32 calcNearestRailPos(sead::Vector3f* railPos, const IUseRail* railHolder, const sead::Vector3f& pos) { return getRail(railHolder)->calcNearestRailPos(railPos, pos, 20.0f); } void calcNearestRailDir(sead::Vector3f* dir, const IUseRail* railHolder, const sead::Vector3f& pos) { f32 coord = calcNearestRailCoord(railHolder, pos); calcRailDirAtCoord(dir, railHolder, coord); } void calcNearestRailPosAndDir(sead::Vector3f* railPos, sead::Vector3f* dir, const IUseRail* railHolder, const sead::Vector3f& pos) { f32 coord = calcNearestRailCoord(railHolder, pos); calcRailPosDir(railPos, dir, railHolder, coord); } void calcRailPosDir(sead::Vector3f* railPos, sead::Vector3f* dir, const IUseRail* railHolder, f32 coord) { getRail(railHolder)->calcPosDir(railPos, dir, coord); } void calcRailPointPos(sead::Vector3f* pos, const IUseRail* railHolder, s32 index) { getRail(railHolder)->calcRailPointPos(pos, index); } s32 calcNearestRailPointNo(const IUseRail* railHolder, const sead::Vector3f& pos) { s32 index = 0; getRail(railHolder)->calcNearestRailPointNo(&index, pos); return index; } s32 calcNearestRailPointNo(const IUseRail* railHolder) { return calcNearestRailPointNo(railHolder, getRailPos(railHolder)); } s32 calcCoordNearestRailPointNo(const IUseRail* railHolder) { s32 index = getRailPartIndex(railHolder); f32 rate = calcRailPartRate(railHolder); if (isRailGoingToEnd(railHolder)) index += rate > 0.5f; else index += rate < 0.5f; s32 pointNo = index; if (isLoopRail(railHolder) && index == getRailPointNum(railHolder)) pointNo = 0; return pointNo; } s32 getRailPartIndex(const IUseRail* railHolder) { return getRail(railHolder)->getIncludedSectionIndex(getRailCoord(railHolder)); } f32 calcRailPartRate(const IUseRail* railHolder) { const Rail* rail = getRail(railHolder); f32 partDistance = 0.0f; f32 length = 0.0f; f32 sectionLength = rail->getIncludedSectionLength(&partDistance, &length, getRailCoord(railHolder)); if (isRailGoingToEnd(railHolder)) return partDistance / sectionLength; return length / sectionLength; } bool isLoopRail(const IUseRail* railHolder) { return getRail(railHolder)->isClosed(); } s32 getRailPointNum(const IUseRail* railHolder) { return getRail(railHolder)->getRailPointsCount(); } f32 calcNearestRailPointPosCoord(const IUseRail* railHolder, const sead::Vector3f& pos) { return calcRailCoordByPoint(railHolder, calcNearestRailPointNo(railHolder, pos)); } f32 calcRailCoordByPoint(const IUseRail* railHolder, s32 index) { return getRail(railHolder)->getLengthToPoint(index); } void calcRailUp(sead::Vector3f* up, const IUseRail* railHolder) { sead::Vector3f currentAngle = {0.0f, 0.0f, 0.0f}; sead::Vector3f nextAngle = {0.0f, 0.0f, 0.0f}; tryGetRotate(¤tAngle, *getRailPointInfo(railHolder, getRailPointNo(railHolder))); tryGetRotate(&nextAngle, *getRailPointInfo(railHolder, getNextRailPointNo(railHolder))); sead::Matrix34f rotationMatrix; rotationMatrix.makeR({sead::Mathf::deg2rad(currentAngle.x), sead::Mathf::deg2rad(currentAngle.y), sead::Mathf::deg2rad(currentAngle.z)}); sead::Vector3f currentUp = rotationMatrix.getBase(1); rotationMatrix.makeR({sead::Mathf::deg2rad(nextAngle.x), sead::Mathf::deg2rad(nextAngle.y), sead::Mathf::deg2rad(nextAngle.z)}); sead::Vector3f nextUp = rotationMatrix.getBase(1); f32 rate = calcRailPartRate(railHolder); up->set(currentUp * (1.0f - rate) + nextUp * rate); normalize(up); } PlacementInfo* getRailPointInfo(const IUseRail* railHolder, s32 index) { return getRail(railHolder)->getRailPoint(index); } s32 getRailPointNo(const IUseRail* railHolder) { if (isLoopRail(railHolder)) return getRailPartIndex(railHolder); if (isRailReachedEnd(railHolder)) return getRailPointNum(railHolder) - 1; return getRailPartIndex(railHolder); } s32 getNextRailPointNo(const IUseRail* railHolder) { s32 modifier = isRailGoingToEnd(railHolder) ? 1 : -1; bool isLoop = isLoopRail(railHolder); s32 newIndex = getRailPointNo(railHolder) + modifier; s32 railPointNum = getRailPointNum(railHolder); if (isLoop) return wrapValue(railPointNum + newIndex, getRailPointNum(railHolder)); return sead::Mathi::clamp2(0, newIndex, railPointNum - 1); } f32 calcRailToGoalLength(const IUseRail* railHolder) { const Rail* rail = getRail(railHolder); f32 length = rail->getTotalLength(); if (rail->isClosed()) return length; f32 coord = getRailCoord(railHolder); if (isRailGoingToEnd(railHolder)) return length - coord; return coord; } f32 calcRailTotalRate(const IUseRail* railHolder) { f32 coord = getRailCoord(railHolder); f32 length = getRailTotalLength(railHolder); return normalize(coord, 0.0f, length); } f32 calcRailToNextRailPointLength(const IUseRail* railHolder) { const Rail* rail = getRail(railHolder); f32 length = 0.0f; f32 partDistance = 0.0f; rail->getIncludedSectionLength(&partDistance, &length, getRailCoord(railHolder)); if (isRailGoingToEnd(railHolder)) return length; return partDistance; } f32 calcRailToPreviousRailPointLength(const IUseRail* railHolder) { const Rail* rail = getRail(railHolder); f32 length = 0.0f; f32 partDistance = 0.0f; rail->getIncludedSectionLength(&partDistance, &length, getRailCoord(railHolder)); if (isRailGoingToEnd(railHolder)) return partDistance; return length; } s32 getRailNum(const IUseRail* railHolder) { return getRail(railHolder)->getRailPartCount(); } const sead::Vector3f& getRailDir(const IUseRail* railHolder) { return getRailRider(railHolder)->getDirection(); } bool isRailReachedEnd(const IUseRail* railHolder) { return getRailRider(railHolder)->isReachedRailEnd(); } f32 getRailPartLength(const IUseRail* railHolder, s32 index) { return getRail(railHolder)->getPartLength(index); } bool tryGetCurrentRailPointArg(f32* arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getRailPointNo(railHolder); return tryGetArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetNextRailPointArg(f32* arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getNextRailPointNo(railHolder); return tryGetArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetCurrentRailPointArg(s32* arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getRailPointNo(railHolder); return tryGetArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetNextRailPointArg(s32* arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getNextRailPointNo(railHolder); return tryGetArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetCurrentRailPointArg(bool* arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getRailPointNo(railHolder); return tryGetArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetNextRailPointArg(bool* arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getNextRailPointNo(railHolder); return tryGetArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetCurrentRailPointArg(const char** arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getRailPointNo(railHolder); return tryGetStringArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool tryGetNextRailPointArg(const char** arg, const IUseRail* railHolder, const char* argName) { s32 pointNo = getNextRailPointNo(railHolder); return tryGetStringArg(arg, *getRailPointInfo(railHolder, pointNo), argName); } bool isExistRail(const IUseRail* railHolder) { return getRailRider(railHolder) != nullptr; } bool isRailReachedStart(const IUseRail* railHolder) { return getRailRider(railHolder)->isReachedRailStart(); } bool isRailReachedNearGoal(const IUseRail* railHolder, f32 goalCoordStart, f32 goalCoordEnd) { if (isLoopRail(railHolder)) return false; if (isRailGoingToEnd(railHolder)) { if (getRailTotalLength(railHolder) - goalCoordEnd <= getRailCoord(railHolder)) return true; } else { if (goalCoordStart >= getRailCoord(railHolder)) return true; } return false; } bool isRailReachedEdge(const IUseRail* railHolder) { return getRailRider(railHolder)->isReachedEdge(); } bool isRailReachedNearRailPoint(const IUseRail* railHolder, f32 epsilon) { return getRail(railHolder)->isNearRailPoint(getRailCoord(railHolder), epsilon); } bool isRailIncludeBezierPart(const IUseRail* railHolder) { return getRail(railHolder)->isIncludeBezierRailPart(); } bool isRailBezierPart(const IUseRail* railHolder, s32 index) { return getRail(railHolder)->isBezierRailPart(index); } bool isRailPlusDir(const IUseRail* railHolder, const sead::Vector3f& dir) { return dir.dot(getRailDir(railHolder)) >= 0.0f; } bool isRailPlusPoseSide(const LiveActor* actor) { sead::Vector3f sideDir; calcSideDir(&sideDir, actor); return isRailPlusDir(actor, sideDir); } bool isRailPlusPoseUp(const LiveActor* actor) { sead::Vector3f upDir; calcUpDir(&upDir, actor); return isRailPlusDir(actor, upDir); } bool isRailPlusPoseFront(const LiveActor* actor) { sead::Vector3f frontDir; calcFrontDir(&frontDir, actor); return isRailPlusDir(actor, frontDir); } void calcRailPosAtCoord(sead::Vector3f* pos, const IUseRail* railHolder, f32 coord) { getRail(railHolder)->calcPos(pos, coord); } void calcRailDirAtCoord(sead::Vector3f* dir, const IUseRail* railHolder, f32 coord) { getRail(railHolder)->calcDirection(dir, coord); } // Mismatch: https://decomp.me/scratch/0vmMR void calcRailPosFront(sead::Vector3f* pos, const IUseRail* railHolder, f32 offset) { if (!isRailGoingToEnd(railHolder)) offset = -offset; f32 coordOffset = offset + getRailCoord(railHolder); const Rail* rail = getRail(railHolder); if (rail->isClosed()) { f32 totalLength = rail->getTotalLength(); f32 distance = wrapValue(coordOffset, totalLength); rail->calcPos(pos, distance); return; } f32 length = rail->getTotalLength(); f32 beep = (coordOffset <= length) ? coordOffset : 0.0f; rail->calcPos(pos, (coordOffset < 0.0f) ? beep : length); } // Mismatch: https://decomp.me/scratch/0vmMR void calcRailDirFront(sead::Vector3f* pos, const IUseRail* railHolder, f32 offset) { if (!isRailGoingToEnd(railHolder)) offset = -offset; f32 coordOffset = offset + getRailCoord(railHolder); const Rail* rail = getRail(railHolder); if (rail->isClosed()) { f32 totalLength = rail->getTotalLength(); f32 distance = wrapValue(coordOffset, totalLength); rail->calcDirection(pos, distance); return; } f32 length = rail->getTotalLength(); f32 beep = (coordOffset <= length) ? coordOffset : 0.0f; rail->calcDirection(pos, (coordOffset < 0.0f) ? beep : length); } void calcRailPointPose(sead::Quatf* pose, const IUseRail* railHolder, s32 index) { getQuat(pose, *getRailPointInfo(railHolder, index)); } s32 calcRailPointNum(const IUseRail* railHolder, f32 distance1, f32 distance2) { return getRail(railHolder)->calcRailPointNum(distance1, distance2); } s32 calcForwardRailPointNo(const IUseRail* railHolder, s32 index) { s32 pointNum = getRailPointNum(railHolder); if (isRailGoingToEnd(railHolder)) { if (pointNum - 1 == index) return isLoopRail(railHolder) ? 0 : -1; return index + 1; } else { if (index == 0) return isLoopRail(railHolder) ? pointNum - 1 : -1; return index - 1; } } s32 calcPreviousRailPointNo(const IUseRail* railHolder, s32 index) { s32 pointNum = getRailPointNum(railHolder); if (isRailGoingToEnd(railHolder)) { if (index == 0) return isLoopRail(railHolder) ? pointNum - 1 : -1; return index - 1; } else { if (pointNum - 1 == index) return isLoopRail(railHolder) ? 0 : -1; return index + 1; } } void calcRailClippingInfo(sead::Vector3f* pos, f32* distance, const IUseRail* railHolder, f32 step, f32 offset) { f32 totalLength = getRailTotalLength(railHolder); s32 stepNum = totalLength / step; sead::Vector3f railPos = {0.0f, 0.0f, 0.0f}; sead::Vector3f lastRailPos = {0.0f, 0.0f, 0.0f}; calcRailPosAtCoord(&railPos, railHolder, 0.0f); calcRailPosAtCoord(&lastRailPos, railHolder, totalLength); sead::BoundBox3f boundBox{ {sead::Mathf::min(railPos.x, lastRailPos.x), sead::Mathf::min(railPos.y, lastRailPos.y), sead::Mathf::min(railPos.z, lastRailPos.z)}, {sead::Mathf::max(railPos.x, lastRailPos.x), sead::Mathf::max(railPos.y, lastRailPos.y), sead::Mathf::max(railPos.z, lastRailPos.z)}, }; for (s32 index = 1; index < stepNum; index++) { sead::Vector3f helper = {0.0f, 0.0f, 0.0f}; getRail(railHolder)->calcPos(&helper, index * step); boundBox.addPoint(helper); } pos->set(boundBox.getCenter()); *distance = 0.0f; for (s32 index = 0; index < stepNum; index++) { sead::Vector3f helper = {0.0f, 0.0f, 0.0f}; getRail(railHolder)->calcPos(&helper, index * step); *distance = sead::Mathf::max((helper - *pos).length(), *distance); } *distance = sead::Mathf::max((lastRailPos - *pos).length(), *distance); *distance += offset; } void setRailClippingInfo(sead::Vector3f* pos, LiveActor* actor, f32 step, f32 offset) { f32 distance = 0.0f; calcRailClippingInfo(pos, &distance, actor, step, offset); setClippingInfo(actor, distance, pos); } void calcAndSyncMoveFitRailDir(IUseRail* railHolder, sead::Vector3f* outDir, f32 step, const sead::Vector3f& pos, const sead::Vector3f& gravity, bool reverse) { setRailPosToNearestPos(railHolder, pos); RailRider* railRider = getRailRider(railHolder); sead::Vector3f railDir = getRailDir(railHolder); if (reverse) railDir.negate(); sead::Vector3f railDirH; verticalizeVec(&railDirH, gravity, railDir); tryNormalizeOrZero(&railDirH); sead::Vector3f posOff = railRider->getPosition() - pos; sead::Vector3f posDirH; verticalizeVec(&posDirH, gravity, posOff); f32 posOffDistance; separateScalarAndDirection(&posOffDistance, &posDirH, posDirH); lerpVec(outDir, railDirH, posDirH, sead::Mathf::clamp(posOffDistance / step, 0.0f, 1.0f)); tryNormalizeOrZero(outDir); } void calcAndSyncMoveFitRailDir(LiveActor* actor, sead::Vector3f* outDir, f32 step, bool reverse) { calcAndSyncMoveFitRailDir(actor, outDir, step, getTrans(actor), getGravity(actor), reverse); } LiveActorGroup* createRailModelGroup(const IUseRail* railHolder, const ActorInitInfo& initInfo, const char* actorName, const char* archiveName) { s32 railPointNum = getRailPointNum(railHolder); getRailRider(railHolder); LiveActorGroup* group = new LiveActorGroup("レールモデルグループ", railPointNum); for (s32 i = 0; i < railPointNum; i++) { sead::Vector3f pointPos = {0.0f, 0.0f, 0.0f}; calcRailPointPos(&pointPos, railHolder, i); if (i == 0) { if (!isLoopRail(railHolder)) continue; sead::Vector3f prevPointPos = {0.0f, 0.0f, 0.0f}; calcRailPointPos(&prevPointPos, railHolder, railPointNum - 1); LiveActor* actor = createRailModelActor(initInfo, pointPos, prevPointPos, actorName, archiveName); group->registerActor(actor); } if (i > 0) { sead::Vector3f prevPointPos = {0.0f, 0.0f, 0.0f}; calcRailPointPos(&prevPointPos, railHolder, i - 1); LiveActor* actor = createRailModelActor(initInfo, prevPointPos, pointPos, actorName, archiveName); group->registerActor(actor); } } return group; } LiveActor* createRailModelActor(const ActorInitInfo& info, const sead::Vector3f& prevPointPos, const sead::Vector3f& pointPos, const char* actorName, const char* archiveName) { LiveActor* actor = new LiveActor(actorName); initActorWithArchiveName(actor, info, archiveName, nullptr); actor->makeActorAlive(); sead::Vector3f front = pointPos; front -= prevPointPos; f32 frontLength = front.length(); front.normalize(); sead::Quatf quat; makeQuatFrontUp(&quat, front, isParallelDirection(front, sead::Vector3f::ey) ? sead::Vector3f::ex : sead::Vector3f::ey); updatePoseQuat(actor, quat); resetPosition(actor, pointPos - frontLength * front * 0.5f); setScale(actor, 1.0f, 1.0f, frontLength * 0.01f); return actor; } s32 calcRailDivideNum(const IUseRail* railHolder, f32 segmentLength, bool isForce) { if (isForce) return calcRailDivideForcePointNum(railHolder, segmentLength); else return calcRailDivideEquallyNum(railHolder, segmentLength); } s32 calcRailDivideForcePointNum(const IUseRail* railHolder, f32 segmentLength) { s32 railNum = getRailNum(railHolder); s32 i; s32 total = 0; for (i = 0; i < railNum; i++) total += (s32)(getRailPartLength(railHolder, i) / segmentLength) + 1; // For looping rails, Rail::init already counts up by one if (!isLoopRail(railHolder)) total += 1; return total; } s32 calcRailDivideEquallyNum(const IUseRail* railHolder, f32 segmentLength) { return (s32)(getRailTotalLength(railHolder) / segmentLength) + 1; } void placementRailDivide(const IUseRail* railHolder, f32 segmentLength, bool isForce, const RailPlacementCallBack& callback) { if (isForce) placementRailDivideForcePoint(railHolder, segmentLength, callback); else placementRailDivideEqually(railHolder, segmentLength, callback); } void placementRailDivideForcePoint(const IUseRail* railHolder, f32 segmentLength, const RailPlacementCallBack& callback) { s32 railNum = getRailNum(railHolder); f32 coord = 0.0f; s32 index = 0; for (s32 i = 0; i < railNum; i++) { f32 length = getRailPartLength(railHolder, i); s32 railSegments = (s32)(length / segmentLength) + 1; for (s32 e = 0; e < railSegments; e++) { sead::Vector3f vec = sead::Vector3f::zero; calcRailPosAtCoord(&vec, railHolder, coord); callback(vec, index, coord); index++; coord += length / railSegments; } } // Additional rail also listed in calcRailDivideForcePointNum if (!isLoopRail(railHolder)) { sead::Vector3f vec = sead::Vector3f::zero; f32 totalLength = getRailTotalLength(railHolder); calcRailPosAtCoord(&vec, railHolder, totalLength); callback(vec, index, totalLength); } } void placementRailDivideEqually(const IUseRail* railHolder, f32 segmentLength, const RailPlacementCallBack& callback) { f32 length = getRailTotalLength(railHolder); s32 railNum = (s32)(length / segmentLength) + 1; f32 coord = 0.0f; for (s32 i = 0; i < railNum; i++) { sead::Vector3f vec = sead::Vector3f::zero; calcRailPosAtCoord(&vec, railHolder, coord); callback(vec, i, coord); coord += length / railNum; } } } // namespace al