summaryrefslogtreecommitdiff
path: root/src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp
diff options
context:
space:
mode:
authorMonsterDruide1 <5958456@gmail.com>2021-07-07 20:29:45 +0200
committerMonsterDruide1 <5958456@gmail.com>2021-08-02 01:11:23 +0200
commit90c34d80feabe1849a7e668edfd705eee8b33444 (patch)
tree30f092b0fd415a4f00c7dc437cb9af77bc6e73da /src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp
parent3c0648e51f1440fd28836499485102ba8e2703db (diff)
ksys/phys: Add SupportBoneResource
[committer's note: rebased]
Diffstat (limited to 'src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp')
-rw-r--r--src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp b/src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp
new file mode 100644
index 00000000..3b885129
--- /dev/null
+++ b/src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp
@@ -0,0 +1,254 @@
+#include "KingSystem/Physics/SupportBone/physSupportBoneResource.h"
+
+#include <cmath>
+
+namespace ksys::phys {
+
+SupportBoneResource::Bone::~Bone() = default;
+
+SupportBoneResource::BaseBone::BaseBone()
+ : bone(-1, "bone", "bone", this), aim(sead::Vector3f::ez, "aim", "aim", this),
+ up(sead::Vector3f::ey, "up", "up", this), space(-1, "space", "space", this),
+ base_rotate(sead::Quatf::unit, "base_rotate", "base_rotate", this),
+ base_translate(sead::Vector3f::zero, "base_translate", "base_translate", this) {}
+
+SupportBoneResource::SupportBone::SupportBone()
+ : bendH(-1, "bendH", "bendH", this), bendV(-1, "bendV", "bendV", this),
+ roll(-1, "roll", "roll", this), translateX(-1, "translateX", "translateX", this),
+ translateY(-1, "translateY", "translateY", this),
+ translateZ(-1, "translateZ", "translateZ", this) {}
+
+SupportBoneResource::SupportBoneResource()
+ : IParameterIO("physsb", 0), mBoneNum(0, "bone_num", "bone_num", &mSupportBoneHeader),
+ mConnectionLinearNum(0, "connection_linear_num", "connection_linear_num",
+ &mSupportBoneHeader),
+ mConnectionCurveNum(0, "connection_curve_num", "connection_curve_num", &mSupportBoneHeader),
+ mOutputSingleNum(0, "output_single_num", "output_single_num", &mSupportBoneHeader),
+ mOutputDoubleNum(0, "output_double_num", "output_double_num", &mSupportBoneHeader),
+ // labels have two underscores instead of a single one
+ mMainBoneNum(0, "main_bone_num", "main_bone__num" /* sic */, &mSupportBoneHeader),
+ mSupportBoneNum(0, "support_bone_num", "support_bone__num" /* sic */, &mSupportBoneHeader) {
+ addObj(&mSupportBoneHeader, "support_bone_header");
+ addList(&mSupportBoneData, "support_bone_data");
+}
+
+SupportBoneResource::~SupportBoneResource() {
+ freeBuffers();
+}
+
+void SupportBoneResource::freeBuffers() {
+ boneBuffer.freeBuffer();
+ mConnectionLinearBuffer.freeBuffer();
+ mConnectionCurveBuffer.freeBuffer();
+ mOutputSingleBuffer.freeBuffer();
+ mOutputDoubleBuffer.freeBuffer();
+ mMainBoneBuffer.freeBuffer();
+ mSupportBoneBuffer.freeBuffer();
+}
+
+bool uninlineAllocDoubleBuffer(sead::Buffer<ksys::phys::SupportBoneResource::OutputDouble>* buffer,
+ int size, sead::Heap* heap, s32 alignment = sizeof(void*)) {
+ return buffer->allocBufferAssert(size, heap, alignment);
+}
+
+void SupportBoneResource::doCreate_(u8* data, u32 actualFileSize, sead::Heap* heap) {
+ init(agl::utl::ResParameterArchive(data), heap);
+}
+
+float SupportBoneResource::somethingGetLinearConnection(u32 a2, float a3) {
+ sead::Vector2f slope_intercept = mConnectionLinearBuffer[a2].slope_intercept.ref();
+ float result = slope_intercept.x * a3 + slope_intercept.y;
+ return std::isnan(result) ? 0.0f : result;
+}
+
+int SupportBoneResource::getSupportBoneIndexByName(const sead::SafeString& name) {
+ s32 support_bone_num = mSupportBoneNum.ref();
+ for (s32 i = 0; i < support_bone_num; i++) {
+ int bone_index = mSupportBoneBuffer[i].bone.ref();
+ sead::SafeString bone_name = boneBuffer[bone_index].name.ref().cstr();
+ if (name == bone_name)
+ return i;
+ }
+ return -1;
+}
+
+bool SupportBoneResource::init(agl::utl::ResParameterArchive archive, sead::Heap* heap) {
+ agl::utl::ResParameterList param_list = archive.getRootList();
+ const auto support_bone_list = param_list.getResParameterList(0);
+ mSupportBoneHeader.applyResParameterObj(param_list.getResParameterObj(0));
+
+ int bone_num = mBoneNum.ref();
+ if (bone_num < 1)
+ return false;
+ mSupportBoneData.addList(&mBoneList, "bone_list");
+ boneBuffer.allocBufferAssert(bone_num, heap);
+ for (int i = 0; i < bone_num; i++) {
+ auto bone_name = sead::FormatFixedSafeString<32>("bone_%d", i);
+ mBoneList.addObj(&boneBuffer[i], bone_name);
+ boneBuffer[i].name.init(sead::FixedSafeString<64>::cEmptyString, "name", "name",
+ &boneBuffer[i]);
+ }
+
+ int connection_linear_num = mConnectionLinearNum.ref();
+ if (connection_linear_num > 0) {
+ mSupportBoneData.addList(&mConnectionLinearList, "connection_linear_list");
+ mConnectionLinearBuffer.allocBufferAssert(connection_linear_num, heap);
+
+ for (int i = 0; i < connection_linear_num; i++) {
+ auto connection_name = sead::FormatFixedSafeString<32>("connection_linear_%d", i);
+ mConnectionLinearList.addObj(&mConnectionLinearBuffer[i], connection_name);
+ mConnectionLinearBuffer[i].bone_attribute.init(
+ 0, "bone_attribute", "bone_attribute",
+ &mConnectionLinearBuffer[i]); // initialised with 0 instead of -1
+ mConnectionLinearBuffer[i].slope_intercept.init(
+ {1, -1}, "slope_intercept", "slope_intercept", &mConnectionLinearBuffer[i]);
+ }
+ }
+
+ int connection_curve_num = mConnectionCurveNum.ref();
+ if (connection_curve_num > 0) {
+ mSupportBoneData.addList(&mConnectionCurveList, "connection_curve_list");
+ mConnectionCurveBuffer.allocBufferAssert(connection_curve_num, heap);
+
+ for (int i = 0; i < connection_curve_num; i++) {
+ auto connection_name = sead::FormatFixedSafeString<32>("connection_curve_%d", i);
+ mConnectionCurveList.addObj(&mConnectionCurveBuffer[i], connection_name);
+ mConnectionCurveBuffer[i].bone_attribute.init(-1, "bone_attribute", "bone_attribute",
+ &mConnectionCurveBuffer[i]);
+ mConnectionCurveBuffer[i].constant_in.init(true, "constant_in", "constant_in",
+ &mConnectionCurveBuffer[i]);
+ mConnectionCurveBuffer[i].constant_out.init(true, "constant_out", "constant_out",
+ &mConnectionCurveBuffer[i]);
+ mConnectionCurveBuffer[i].key0.init({0, 0, 1, 1}, "key_0", "key_0",
+ &mConnectionCurveBuffer[i]);
+ mConnectionCurveBuffer[i].key1.init({0.5, 0.5, 1, 1}, "key_1", "key_1",
+ &mConnectionCurveBuffer[i]);
+ mConnectionCurveBuffer[i].key2.init({1, 1, 1, 1}, "key_2", "key_2",
+ &mConnectionCurveBuffer[i]);
+ }
+ }
+
+ int output_single_num = mOutputSingleNum.ref();
+ if (output_single_num > 0) {
+ mSupportBoneData.addList(&mOutputSingleList, "output_single_list");
+ mOutputSingleBuffer.allocBufferAssert(output_single_num, heap);
+
+ for (int i = 0; i < output_single_num; i++) {
+ auto output_name = sead::FormatFixedSafeString<32>("output_single_%d", i);
+ mOutputSingleList.addObj(&mOutputSingleBuffer[i], output_name);
+ mOutputSingleBuffer[i].connection.init(0, "connection", "connection",
+ &mOutputSingleBuffer[i]);
+ mOutputSingleBuffer[i].weight.init(0, "weight", "weight", &mOutputSingleBuffer[i]);
+ }
+ }
+
+ int output_double_num = mOutputDoubleNum.ref();
+ if (output_double_num > 0) {
+ mSupportBoneData.addList(&mOutputDoubleList, "output_double_list");
+ uninlineAllocDoubleBuffer(&mOutputDoubleBuffer, output_double_num, heap);
+
+ for (int i = 0; i < output_double_num; i++) {
+ auto output_name = sead::FormatFixedSafeString<32>("output_double_%d", i);
+ mOutputDoubleList.addObj(&mOutputDoubleBuffer[i], output_name);
+ mOutputDoubleBuffer[i].connection_0.init(0, "connection_0", "connection_0",
+ &mOutputDoubleBuffer[i]);
+ mOutputDoubleBuffer[i].weight_0.init(0, "weight_0", "weight_0",
+ &mOutputDoubleBuffer[i]);
+ mOutputDoubleBuffer[i].connection_1.init(0, "connection_1", "connection_1",
+ &mOutputDoubleBuffer[i]);
+ mOutputDoubleBuffer[i].weight_1.init(0, "weight_1", "weight_1",
+ &mOutputDoubleBuffer[i]);
+ }
+ }
+
+ int main_bone_num = mMainBoneNum.ref();
+ if (main_bone_num < 1)
+ return false;
+ mSupportBoneData.addList(&mMainBoneList, "main_bone_list");
+ mMainBoneBuffer.allocBufferAssert(main_bone_num, heap);
+ for (int i = 0; i < main_bone_num; i++) {
+ auto name = sead::FormatFixedSafeString<32>("main_bone_%d", i);
+ mMainBoneList.addObj(&mMainBoneBuffer[i], name);
+ }
+
+ int support_bone_num = mSupportBoneNum.ref();
+ if (support_bone_num < 1)
+ return false;
+ mSupportBoneData.addList(&mSupportBoneList, "support_bone_list");
+ mSupportBoneBuffer.allocBufferAssert(support_bone_num, heap);
+ for (int i = 0; i < support_bone_num; i++) {
+ auto name = sead::FormatFixedSafeString<32>("support_bone_%d", i);
+ mSupportBoneList.addObj(&mSupportBoneBuffer[i], name);
+ }
+
+ mSupportBoneData.applyResParameterList(support_bone_list);
+ return true;
+}
+
+inline float cubicHermiteInterpolate(const sead::Vector4f& key1, const sead::Vector4f& key2,
+ float lookup) {
+ if (key1.x == key2.x) {
+ return key2.y;
+ }
+ float diff = key2.x - key1.x;
+ float t = (lookup - key1.x) / diff;
+ float h00 = (2 * t * t * t) - (3 * t * t) + 1;
+ float h01 = (-2 * t * t * t) + (3 * t * t);
+ float h10 = (t * t * t) - (2 * t * t) + t;
+ float h10_scaled = h10 * diff;
+ float h11 = (t * t * t) - (t * t);
+ float h11_scaled = h11 * diff;
+ return (h00 * key1.y) + (h01 * key2.y) + (h10_scaled * key1.w) + (h11_scaled * key2.z);
+}
+
+float SupportBoneResource::getInterpolatedConnectionCurve(u32 index, float lookup) {
+ auto& connection_curve = mConnectionCurveBuffer[index];
+ float result;
+ float x0 = connection_curve.key0->x; // lowest (always minus pi?)
+ float x1 = connection_curve.key1->x; // middle (0 in most cases)
+ float x2 = connection_curve.key2->x; // highest
+ if (x0 == lookup) {
+ result = connection_curve.key0->y;
+ } else if (x1 == lookup) {
+ result = connection_curve.key1->y;
+ } else if (x2 == lookup) {
+ result = connection_curve.key2->y;
+ } else if (x0 > lookup) {
+ result = connection_curve.key0->y;
+ if (!connection_curve.constant_in.ref())
+ result -= (x0 - lookup) * connection_curve.key0->z;
+ } else if (x1 > lookup) {
+ result = cubicHermiteInterpolate(connection_curve.key0.ref(), connection_curve.key1.ref(),
+ lookup);
+ } else if (x2 > lookup) {
+ result = cubicHermiteInterpolate(connection_curve.key1.ref(), connection_curve.key2.ref(),
+ lookup);
+ } else {
+ if (!connection_curve.constant_out.ref())
+ result = connection_curve.key2->y + ((lookup - x2) * connection_curve.key2->z);
+ else
+ result = connection_curve.key2->y;
+ }
+
+ return std::isnan(result) ? 0.0f : result;
+}
+
+// NON_MATCHING: Due to seadQuat::normalize() mismatch, this function does not match.
+void SupportBoneResource::BaseBone::postRead_() {
+ sead::Vector3f aim_local = aim.ref();
+ sead::Vector3f up_local = up.ref();
+ aim_local.normalize();
+
+ side = sead::cross(aim_local, up_local);
+ side.normalize();
+
+ up_local = sead::cross(side, aim_local);
+ up_local.normalize();
+ aim = aim_local;
+ up = up_local;
+
+ base_rotate->normalize();
+ reverse_rotate = base_rotate->inverse();
+}
+
+} // namespace ksys::phys \ No newline at end of file