Files
botw/src/KingSystem/Physics/SupportBone/physSupportBoneResource.cpp
T
2021-10-10 05:21:18 -05:00

255 lines
11 KiB
C++

#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;
}
void SupportBoneResource::BaseBone::postRead_() {
sead::Vector3f aim_local = aim.ref();
sead::Vector3f up_local = up.ref();
aim_local.normalize();
side.setCross(aim_local, up_local);
// XXX: this looks like a hack. Why does this not match without an inline function?
[&] { side.normalize(); }();
up_local.setCross(side, aim_local);
up_local.normalize();
up = up_local;
aim = aim_local;
base_rotate->normalize();
base_rotate->inverse(&reverse_rotate);
}
} // namespace ksys::phys