mirror of
https://github.com/korenkonder/ReDIVA.git
synced 2026-10-05 13:18:01 +03:00
674 lines
24 KiB
C++
674 lines
24 KiB
C++
/*
|
|
by korenkonder
|
|
GitHub/GitLab: korenkonder
|
|
*/
|
|
|
|
#include "mot.hpp"
|
|
#include "f2/struct.hpp"
|
|
#include "io/path.h"
|
|
#include "io/stream.h"
|
|
#include "half_t.h"
|
|
#include "hash.hpp"
|
|
#include "str_utils.h"
|
|
|
|
struct mot_header_classic {
|
|
uint32_t key_set_count_offset;
|
|
uint32_t key_set_types_offset;
|
|
uint32_t key_set_offset;
|
|
uint32_t bone_info_offset;
|
|
};
|
|
|
|
struct mot_header_modern {
|
|
uint32_t hash;
|
|
int64_t name_offset;
|
|
int64_t key_set_count_offset;
|
|
int64_t key_set_types_offset;
|
|
int64_t key_set_offset;
|
|
int64_t bone_info_offset;
|
|
int64_t bone_hash_offset;
|
|
int32_t bone_info_count;
|
|
};
|
|
|
|
static void mot_classic_read_inner(mot_set* ms, stream* s);
|
|
static void mot_classic_write_inner(mot_set* ms, stream* s);
|
|
static void mot_modern_read_inner(mot_set* ms, stream* s);
|
|
static void mot_modern_write_inner(mot_set* ms, stream* s);
|
|
|
|
mot_bone_info::mot_bone_info() : index() {
|
|
|
|
}
|
|
|
|
mot_bone_info::~mot_bone_info() {
|
|
|
|
}
|
|
|
|
mot_key_set_data::mot_key_set_data() : type(), frames(), values(), keys_count(), data_type() {
|
|
|
|
}
|
|
|
|
mot_key_set_data::~mot_key_set_data() {
|
|
|
|
}
|
|
|
|
mot_data::mot_data() : info(), frame_count(), bone_info_count(),
|
|
murmurhash(), div_frames(), div_count(), bone_info(), key_set() {
|
|
|
|
}
|
|
|
|
mot_data::~mot_data() {
|
|
|
|
}
|
|
|
|
mot_set::mot_set() : ready(), modern(), is_x() {
|
|
|
|
}
|
|
|
|
mot_set::~mot_set() {
|
|
|
|
}
|
|
|
|
void mot_set::pack_file(void** data, size_t* size) {
|
|
if (!data || !size || !ready)
|
|
return;
|
|
|
|
stream s;
|
|
io_open(&s);
|
|
if (!modern)
|
|
mot_classic_write_inner(this, &s);
|
|
else
|
|
mot_modern_write_inner(this, &s);
|
|
io_copy(&s, data, size);
|
|
io_free(&s);
|
|
}
|
|
|
|
void mot_set::unpack_file(const void* data, size_t size, bool modern) {
|
|
if (!data || !size)
|
|
return;
|
|
|
|
stream s;
|
|
io_open(&s, data, size);
|
|
if (!modern)
|
|
mot_classic_read_inner(this, &s);
|
|
else
|
|
mot_modern_read_inner(this, &s);
|
|
io_free(&s);
|
|
}
|
|
|
|
static void mot_classic_read_inner(mot_set* ms, stream* s) {
|
|
size_t count = 0;
|
|
while (io_read_uint64_t(s) != 0) {
|
|
io_read_uint64_t(s);
|
|
count++;
|
|
}
|
|
|
|
if (count == 0) {
|
|
ms->ready = false;
|
|
ms->modern = false;
|
|
ms->is_x = false;
|
|
}
|
|
|
|
io_set_position(s, 0x00, SEEK_SET);
|
|
ms->vec.resize(count);
|
|
mot_header_classic* mh = force_malloc_s(mot_header_classic, count);
|
|
for (size_t i = 0; i < count; i++) {
|
|
mh[i].key_set_count_offset = io_read_uint32_t(s);
|
|
mh[i].key_set_types_offset = io_read_uint32_t(s);
|
|
mh[i].key_set_offset = io_read_uint32_t(s);
|
|
mh[i].bone_info_offset = io_read_uint32_t(s);
|
|
}
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
mot_data* m = &ms->vec[i];
|
|
|
|
io_set_position(s, mh[i].bone_info_offset, SEEK_SET);
|
|
m->bone_info_count = 0;
|
|
io_read_uint16_t(s);
|
|
do
|
|
m->bone_info_count++;
|
|
while (io_read_uint16_t(s) != 0 && io_get_position(s) < s->length);
|
|
|
|
io_set_position(s, mh[i].bone_info_offset, SEEK_SET);
|
|
m->bone_info.resize(m->bone_info_count);
|
|
for (size_t j = 0; j < m->bone_info_count; j++)
|
|
m->bone_info[j].index = io_read_uint16_t(s);
|
|
|
|
io_set_position(s, mh[i].key_set_count_offset, SEEK_SET);
|
|
m->info = io_read_uint16_t(s);
|
|
m->frame_count = io_read_uint16_t(s);
|
|
|
|
m->key_set.resize(m->key_set_count);
|
|
io_set_position(s, mh[i].key_set_types_offset, SEEK_SET);
|
|
for (int32_t j = 0, b = 0; j < m->key_set_count; j++) {
|
|
if (j % 8 == 0)
|
|
b = io_read_uint16_t(s);
|
|
|
|
m->key_set[j].type = (mot_key_set_type)((b >> (j % 8 * 2)) & 0x03);
|
|
}
|
|
|
|
io_set_position(s, mh[i].key_set_offset, SEEK_SET);
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
mot_key_set_data* mks = &m->key_set[j];
|
|
if (mks->type == MOT_KEY_SET_NONE) {
|
|
mks->keys_count = 0;
|
|
mks->frames.resize(0);
|
|
mks->values.resize(0);
|
|
}
|
|
else if (mks->type == MOT_KEY_SET_STATIC) {
|
|
mks->keys_count = 1;
|
|
mks->frames.resize(0);
|
|
mks->values.resize(1);
|
|
mks->values[0] = io_read_float_t(s);
|
|
}
|
|
else {
|
|
bool has_tangents = mks->type != MOT_KEY_SET_HERMITE;
|
|
uint16_t keys_count = io_read_uint16_t(s);
|
|
mks->keys_count = keys_count;
|
|
|
|
mks->frames.resize(keys_count);
|
|
mks->values.resize(has_tangents ? keys_count * 2ULL : keys_count);
|
|
|
|
uint16_t* frames = mks->frames.data();
|
|
for (int32_t k = 0; k < keys_count; k++)
|
|
*frames++ = io_read_uint16_t(s);
|
|
io_align_read(s, 0x04);
|
|
|
|
float_t* values = mks->values.data();
|
|
if (!has_tangents)
|
|
for (int32_t k = 0; k < keys_count; k++)
|
|
*values++ = io_read_float_t(s);
|
|
else
|
|
for (int32_t k = 0; k < keys_count; k++) {
|
|
*values++ = io_read_float_t(s);
|
|
*values++ = io_read_float_t(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free(mh);
|
|
|
|
ms->ready = true;
|
|
ms->modern = false;
|
|
ms->is_x = false;
|
|
}
|
|
|
|
static void mot_classic_write_inner(mot_set* ms, stream* s) {
|
|
size_t count = ms->vec.size();
|
|
io_set_position(s, count * 0x10 + 0x10, SEEK_SET);
|
|
mot_header_classic* mh = force_malloc_s(mot_header_classic, count);
|
|
for (size_t i = 0; i < count; i++) {
|
|
mot_data* m = &ms->vec[i];
|
|
|
|
mh[i].key_set_count_offset = (uint32_t)io_get_position(s);
|
|
io_write_uint16_t(s, m->info);
|
|
io_write_uint16_t(s, m->frame_count);
|
|
|
|
mh[i].key_set_types_offset = (uint32_t)io_get_position(s);
|
|
uint16_t key_set_type_buf = 0;
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
key_set_type_buf |= ((uint16_t)m->key_set[j].type & 0x03) << (j % 8 * 2);
|
|
|
|
if (j % 8 == 7) {
|
|
io_write_uint16_t(s, key_set_type_buf);
|
|
key_set_type_buf = 0;
|
|
}
|
|
}
|
|
|
|
if (m->key_set_count % 8 != 0)
|
|
io_write_uint16_t(s, key_set_type_buf);
|
|
io_align_write(s, 0x04);
|
|
|
|
mh[i].key_set_offset = (uint32_t)io_get_position(s);
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
mot_key_set_data* mks = &m->key_set[j];
|
|
if (mks->type == MOT_KEY_SET_STATIC)
|
|
io_write_float_t(s, mks->values[0]);
|
|
else {
|
|
bool has_tangents = mks->type != MOT_KEY_SET_HERMITE;
|
|
uint16_t keys_count = mks->keys_count;
|
|
io_write_uint16_t(s, keys_count);
|
|
|
|
uint16_t* frames = mks->frames.data();
|
|
for (int32_t k = 0; k < keys_count; k++)
|
|
io_write_uint16_t(s, *frames++);
|
|
io_align_write(s, 0x04);
|
|
|
|
float_t* values = mks->values.data();
|
|
if (!has_tangents)
|
|
for (int32_t k = 0; k < keys_count; k++)
|
|
io_write_float_t(s, *values++);
|
|
else
|
|
for (int32_t k = 0; k < keys_count; k++) {
|
|
io_write_float_t(s, *values++);
|
|
io_write_float_t(s, *values++);
|
|
}
|
|
}
|
|
}
|
|
io_align_write(s, 0x04);
|
|
|
|
mh[i].bone_info_offset = (uint32_t)io_get_position(s);
|
|
if (m->bone_info_count)
|
|
for (int32_t j = 0; j < m->bone_info_count; j++)
|
|
io_write_uint16_t(s, m->bone_info[j].index);
|
|
else
|
|
io_write_uint16_t(s, 0x00);
|
|
io_write_uint16_t(s, 0x00);
|
|
}
|
|
io_align_write(s, 0x10);
|
|
|
|
io_set_position(s, 0x00, SEEK_SET);
|
|
for (size_t i = 0; i < count; i++) {
|
|
io_write_uint32_t(s, mh[i].key_set_count_offset);
|
|
io_write_uint32_t(s, mh[i].key_set_types_offset);
|
|
io_write_uint32_t(s, mh[i].key_set_offset);
|
|
io_write_uint32_t(s, mh[i].bone_info_offset);
|
|
}
|
|
free(mh);
|
|
}
|
|
|
|
static void mot_modern_read_inner(mot_set* ms, stream* s) {
|
|
bool ret = false;
|
|
f2_struct st;
|
|
st.read(s);
|
|
if (st.header.signature != reverse_endianness_uint32_t('MOTC') || !st.data.size()) {
|
|
ms->ready = false;
|
|
ms->modern = false;
|
|
ms->is_x = false;
|
|
}
|
|
|
|
stream s_motc;
|
|
io_open(&s_motc, &st.data);
|
|
s_motc.is_big_endian = st.header.use_big_endian;
|
|
|
|
io_set_position(&s_motc, 0x0C, SEEK_SET);
|
|
bool is_x = io_read_uint32_t_stream_reverse_endianness(&s_motc) == 0;
|
|
|
|
io_set_position(&s_motc, 0x00, SEEK_SET);
|
|
ms->vec.resize(1);
|
|
mot_header_modern mh;
|
|
memset(&mh, 0, sizeof(mot_header_modern));
|
|
if (!is_x) {
|
|
mh.hash = (uint32_t)io_read_uint64_t_stream_reverse_endianness(&s_motc);
|
|
mh.name_offset = io_read_offset_f2(&s_motc, st.header.length);
|
|
mh.key_set_count_offset = io_read_offset_f2(&s_motc, st.header.length);
|
|
mh.key_set_types_offset = io_read_offset_f2(&s_motc, st.header.length);
|
|
mh.key_set_offset = io_read_offset_f2(&s_motc, st.header.length);
|
|
mh.bone_info_offset = io_read_offset_f2(&s_motc, st.header.length);
|
|
mh.bone_hash_offset = io_read_offset_f2(&s_motc, st.header.length);
|
|
mh.bone_info_count = io_read_int32_t_stream_reverse_endianness(&s_motc);
|
|
}
|
|
else {
|
|
mh.hash = (uint32_t)io_read_uint64_t_stream_reverse_endianness(&s_motc);
|
|
mh.name_offset = io_read_offset_x(&s_motc);
|
|
mh.key_set_count_offset = io_read_offset_x(&s_motc);
|
|
mh.key_set_types_offset = io_read_offset_x(&s_motc);
|
|
mh.key_set_offset = io_read_offset_x(&s_motc);
|
|
mh.bone_info_offset = io_read_offset_x(&s_motc);
|
|
mh.bone_hash_offset = io_read_offset_x(&s_motc);
|
|
mh.bone_info_count = io_read_int32_t_stream_reverse_endianness(&s_motc);
|
|
}
|
|
|
|
mot_data* m = &ms->vec[0];
|
|
m->div_frames = io_read_uint16_t_stream_reverse_endianness(&s_motc);
|
|
m->div_count = io_read_uint8_t(&s_motc);
|
|
|
|
io_read_string_null_terminated_offset(&s_motc, mh.name_offset, &m->name);
|
|
|
|
io_set_position(&s_motc, mh.bone_info_offset, SEEK_SET);
|
|
m->bone_info_count = mh.bone_info_count;
|
|
m->bone_info.resize(m->bone_info_count);
|
|
if (!is_x)
|
|
for (size_t j = 0; j < mh.bone_info_count; j++)
|
|
io_read_string_null_terminated_offset(&s_motc,
|
|
io_read_offset_f2(&s_motc, st.header.length), &m->bone_info[j].name);
|
|
else
|
|
for (size_t j = 0; j < mh.bone_info_count; j++)
|
|
io_read_string_null_terminated_offset(&s_motc,
|
|
io_read_offset_x(&s_motc), &m->bone_info[j].name);
|
|
|
|
io_set_position(&s_motc, mh.bone_hash_offset, SEEK_SET);
|
|
for (size_t j = 0; j < mh.bone_info_count; j++)
|
|
io_read_uint64_t_stream_reverse_endianness(&s_motc);
|
|
|
|
io_set_position(&s_motc, mh.key_set_count_offset, SEEK_SET);
|
|
m->info = io_read_uint16_t_stream_reverse_endianness(&s_motc);
|
|
m->frame_count = io_read_uint16_t_stream_reverse_endianness(&s_motc);
|
|
|
|
m->key_set.resize(m->key_set_count);
|
|
io_set_position(&s_motc, mh.key_set_types_offset, SEEK_SET);
|
|
for (int32_t j = 0, b = 0; j < m->key_set_count; j++) {
|
|
if (j % 8 == 0)
|
|
b = io_read_uint16_t_stream_reverse_endianness(&s_motc);
|
|
|
|
m->key_set[j].type = (mot_key_set_type)((b >> (j % 8 * 2)) & 0x03);
|
|
}
|
|
|
|
io_set_position(&s_motc, mh.key_set_offset, SEEK_SET);
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
mot_key_set_data* mks = &m->key_set[j];
|
|
if (mks->type == MOT_KEY_SET_NONE) {
|
|
mks->keys_count = 0;
|
|
mks->frames.resize(0);
|
|
mks->values.resize(0);
|
|
}
|
|
else if (mks->type == MOT_KEY_SET_STATIC) {
|
|
mks->keys_count = 1;
|
|
mks->frames.resize(0);
|
|
mks->values.resize(1);
|
|
mks->values[0] = io_read_float_t_stream_reverse_endianness(&s_motc);
|
|
}
|
|
else {
|
|
bool has_tangents = mks->type != MOT_KEY_SET_HERMITE;
|
|
uint16_t keys_count = io_read_uint16_t_stream_reverse_endianness(s);
|
|
mot_key_set_data_type data_type
|
|
= (mot_key_set_data_type)io_read_uint16_t_stream_reverse_endianness(&s_motc);
|
|
mks->keys_count = keys_count;
|
|
mks->data_type = data_type;
|
|
|
|
mks->frames.resize(keys_count);
|
|
mks->values.resize(has_tangents ? keys_count * 2ULL : keys_count);
|
|
|
|
uint8_t step = has_tangents ? 2 : 1;
|
|
if (has_tangents) {
|
|
float_t* values = &mks->values[1];
|
|
for (int32_t k = 0; k < keys_count; k++, values += step)
|
|
*values = io_read_float_t_stream_reverse_endianness(&s_motc);
|
|
}
|
|
|
|
float_t* values = mks->values.data();
|
|
if (data_type == MOT_KEY_SET_DATA_F16)
|
|
for (int32_t k = 0; k < keys_count; k++, values += step)
|
|
*values = half_to_float(io_read_half_t_stream_reverse_endianness(&s_motc));
|
|
else
|
|
for (int32_t k = 0; k < keys_count; k++, values += step)
|
|
*values = io_read_float_t_stream_reverse_endianness(&s_motc);
|
|
io_align_read(&s_motc, 0x04);
|
|
|
|
int16_t* frames = (int16_t*)mks->frames.data();
|
|
for (int32_t k = 0; k < keys_count; k++)
|
|
*frames++ = io_read_int16_t_stream_reverse_endianness(&s_motc);
|
|
io_align_read(&s_motc, 0x04);
|
|
}
|
|
}
|
|
|
|
m->murmurhash = st.header.murmurhash;
|
|
|
|
io_free(&s_motc);
|
|
|
|
ms->ready = true;
|
|
ms->modern = true;
|
|
ms->is_x = is_x;
|
|
}
|
|
|
|
static void mot_modern_write_inner(mot_set* ms, stream* s) {
|
|
stream s_motc;
|
|
io_open(&s_motc);
|
|
uint32_t o;
|
|
enrs e;
|
|
enrs_entry ee;
|
|
pof pof;
|
|
uint32_t murmurhash = 0;
|
|
if (ms->vec.size() > 0) {
|
|
mot_header_modern mh;
|
|
memset(&mh, 0, sizeof(mot_header_modern));
|
|
mot_data* m = &ms->vec[0];
|
|
|
|
if (!ms->is_x) {
|
|
ee = { 0, 3, 48, 1 };
|
|
ee.append(0, 1, ENRS_QWORD);
|
|
ee.append(0, 7, ENRS_DWORD);
|
|
ee.append(0, 1, ENRS_WORD);
|
|
e.vec.push_back(ee);
|
|
o = 48;
|
|
}
|
|
else {
|
|
ee = { 0, 3, 64, 1 };
|
|
ee.append(0, 7, ENRS_QWORD);
|
|
ee.append(0, 1, ENRS_DWORD);
|
|
ee.append(0, 1, ENRS_WORD);
|
|
e.vec.push_back(ee);
|
|
o = 64;
|
|
};
|
|
|
|
ee = { o, 1, 4, 1 };
|
|
ee.append(0, 2, ENRS_WORD);
|
|
e.vec.push_back(ee);
|
|
o = 4;
|
|
|
|
ee = { o, 1, (uint32_t)((m->key_set_count + 3ULL) / 4), 1 };
|
|
ee.append(0, (uint32_t)((m->key_set_count + 7ULL) / 8), ENRS_WORD);
|
|
e.vec.push_back(ee);
|
|
o = (m->key_set_count + 3) / 4;
|
|
o = align_val(o, 4);
|
|
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
mot_key_set_data* mks = &m->key_set[j];
|
|
if (mks->type == MOT_KEY_SET_STATIC) {
|
|
ee = { o, 1, 4, 1 };
|
|
ee.append(0, 1, ENRS_DWORD);
|
|
e.vec.push_back(ee);
|
|
o = 4;
|
|
}
|
|
else if (mks->type != MOT_KEY_SET_NONE) {
|
|
bool has_tangents = mks->type != MOT_KEY_SET_HERMITE;
|
|
if (has_tangents)
|
|
ee = { o, 1, 4, 1 };
|
|
else
|
|
ee = { o, 1, 3, 1 };
|
|
|
|
uint16_t keys_count = mks->keys_count;
|
|
mot_key_set_data_type data_type = mks->data_type;
|
|
o = 4;
|
|
if (has_tangents)
|
|
o += keys_count * 4;
|
|
|
|
if (data_type == MOT_KEY_SET_DATA_F16)
|
|
o += align_val(keys_count * 2, 4);
|
|
else
|
|
o += keys_count * 4;
|
|
o += align_val(keys_count * 2, 4);
|
|
o = align_val(o, 4);
|
|
ee.size = o;
|
|
|
|
ee.append(0, 2, ENRS_WORD);
|
|
if (has_tangents)
|
|
ee.append(0, keys_count, ENRS_DWORD);
|
|
if (data_type == MOT_KEY_SET_DATA_F16) {
|
|
ee.append(0, keys_count, ENRS_WORD);
|
|
ee.append(keys_count % 2 == 1 ? 2u : 0u, keys_count, ENRS_WORD);
|
|
}
|
|
else {
|
|
ee.append(0, keys_count, ENRS_DWORD);
|
|
ee.append(0, keys_count, ENRS_WORD);
|
|
}
|
|
e.vec.push_back(ee);
|
|
}
|
|
}
|
|
o = align_val(o, 16);
|
|
|
|
if (!ms->is_x) {
|
|
ee = { o, 1, (uint32_t)(m->bone_info_count * 4ULL), 1 };
|
|
ee.append(0, (uint32_t)m->bone_info_count, ENRS_DWORD);
|
|
e.vec.push_back(ee);
|
|
o = m->bone_info_count * 4;
|
|
}
|
|
else {
|
|
ee = { o, 1, (uint32_t)(m->bone_info_count * 8ULL), 1 };
|
|
ee.append(0, (uint32_t)m->bone_info_count, ENRS_QWORD);
|
|
e.vec.push_back(ee);
|
|
o = m->bone_info_count * 8;
|
|
}
|
|
o = align_val(o, 16);
|
|
|
|
ee = { o, 1,(uint32_t)(m->bone_info_count * 8ULL), 1 };
|
|
ee.append(0, (uint32_t)m->bone_info_count, ENRS_QWORD);
|
|
e.vec.push_back(ee);
|
|
o = m->bone_info_count * 8;
|
|
|
|
if (!ms->is_x) {
|
|
io_write_uint64_t(&s_motc, 0);
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
io_write_int32_t(&s_motc, 0);
|
|
io_write_int32_t(&s_motc, 0);
|
|
}
|
|
else {
|
|
io_write_uint64_t(&s_motc, 0);
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_write_int32_t(&s_motc, 0);
|
|
}
|
|
io_write_uint16_t(&s_motc, 0);
|
|
io_write_uint8_t(&s_motc, 0);
|
|
io_align_write(&s_motc, 0x10);
|
|
|
|
mh.hash = hash_string_murmurhash(&m->name);
|
|
|
|
mh.key_set_count_offset = io_get_position(&s_motc);
|
|
io_write_uint16_t(&s_motc, m->info);
|
|
io_write_uint16_t(&s_motc, m->frame_count);
|
|
|
|
mh.key_set_types_offset = io_get_position(&s_motc);
|
|
uint16_t key_set_type_buf = 0;
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
key_set_type_buf |= ((uint16_t)m->key_set[j].type & 0x03) << (j % 8 * 2);
|
|
|
|
if (j % 8 == 7) {
|
|
io_write_uint16_t(&s_motc, key_set_type_buf);
|
|
key_set_type_buf = 0;
|
|
}
|
|
}
|
|
|
|
if (m->key_set_count % 8 != 0)
|
|
io_write_uint16_t(&s_motc, key_set_type_buf);
|
|
io_align_write(&s_motc, 0x04);
|
|
|
|
mh.key_set_offset = io_get_position(&s_motc);
|
|
for (int32_t j = 0; j < m->key_set_count; j++) {
|
|
mot_key_set_data* mks = &m->key_set[j];
|
|
if (mks->type == MOT_KEY_SET_STATIC)
|
|
io_write_float_t(&s_motc, mks->values[0]);
|
|
else if (mks->type != MOT_KEY_SET_NONE) {
|
|
bool has_tangents = mks->type != MOT_KEY_SET_HERMITE;
|
|
uint16_t keys_count = mks->keys_count;
|
|
mot_key_set_data_type data_type = mks->data_type;
|
|
io_write_uint16_t(&s_motc, keys_count);
|
|
io_write_uint16_t(&s_motc, (uint16_t)data_type);
|
|
|
|
uint8_t step = has_tangents ? 2 : 1;
|
|
if (has_tangents) {
|
|
float_t* values = &mks->values[1];
|
|
for (int32_t k = 0; k < keys_count; k++, values += step)
|
|
io_write_float_t(&s_motc, *values);
|
|
}
|
|
|
|
float_t* values = mks->values.data();
|
|
if (data_type == MOT_KEY_SET_DATA_F16)
|
|
for (int32_t k = 0; k < keys_count; k++, values += step)
|
|
io_write_half_t(&s_motc, float_to_half(*values));
|
|
else
|
|
for (int32_t k = 0; k < keys_count; k++, values += step)
|
|
io_write_float_t(&s_motc, *values);
|
|
io_align_write(&s_motc, 0x04);
|
|
|
|
int16_t* frames = (int16_t*)mks->frames.data();
|
|
for (int32_t k = 0; k < keys_count; k++)
|
|
io_write_int16_t(&s_motc, *frames++);
|
|
io_align_write(&s_motc, 0x04);
|
|
}
|
|
}
|
|
io_align_write(&s_motc, 0x10);
|
|
|
|
size_t* bone_info_offsets = force_malloc_s(size_t, m->bone_info_count);
|
|
mh.bone_info_offset = io_get_position(&s_motc);
|
|
if (!ms->is_x)
|
|
for (int32_t j = 0; j < m->bone_info_count; j++)
|
|
io_write_offset_f2_pof_add(&s_motc, 0, 0x40, &pof);
|
|
else
|
|
for (int32_t j = 0; j < m->bone_info_count; j++)
|
|
io_write_offset_x_pof_add(&s_motc, 0, &pof);
|
|
io_align_write(&s_motc, 0x10);
|
|
|
|
mh.bone_hash_offset = io_get_position(&s_motc);
|
|
for (int32_t j = 0; j < m->bone_info_count; j++)
|
|
io_write_uint64_t(&s_motc, hash_string_murmurhash(&m->bone_info[j].name));
|
|
io_align_write(&s_motc, 0x10);
|
|
|
|
mh.name_offset = io_get_position(&s_motc);
|
|
io_write_string_null_terminated(&s_motc, &m->name);
|
|
|
|
for (int32_t j = 0; j < m->bone_info_count; j++) {
|
|
bone_info_offsets[j] = io_get_position(&s_motc);
|
|
io_write_string_null_terminated(&s_motc, &m->bone_info[j].name);
|
|
}
|
|
io_align_write(&s_motc, 0x10);
|
|
|
|
io_set_position(&s_motc, mh.bone_info_offset, SEEK_SET);
|
|
mh.bone_info_count = m->bone_info_count;
|
|
if (!ms->is_x)
|
|
for (int32_t j = 0; j < m->bone_info_count; j++)
|
|
io_write_offset_f2(&s_motc, bone_info_offsets[j], 0x40);
|
|
else
|
|
for (int32_t j = 0; j < m->bone_info_count; j++)
|
|
io_write_offset_x(&s_motc, bone_info_offsets[j]);
|
|
free(bone_info_offsets);
|
|
|
|
io_set_position(&s_motc, 0x00, SEEK_SET);
|
|
if (!ms->is_x) {
|
|
io_write_uint64_t(&s_motc, (uint64_t)mh.hash);
|
|
io_write_offset_f2(&s_motc, mh.name_offset, 0x40);
|
|
io_write_offset_f2(&s_motc, mh.key_set_count_offset, 0x40);
|
|
io_write_offset_f2(&s_motc, mh.key_set_types_offset, 0x40);
|
|
io_write_offset_f2(&s_motc, mh.key_set_offset, 0x40);
|
|
io_write_offset_f2(&s_motc, mh.bone_info_offset, 0x40);
|
|
io_write_offset_f2(&s_motc, mh.bone_hash_offset, 0x40);
|
|
io_write_int32_t(&s_motc, mh.bone_info_count);
|
|
}
|
|
else {
|
|
io_write_uint64_t(&s_motc, (uint64_t)mh.hash);
|
|
io_write_offset_x(&s_motc, mh.name_offset);
|
|
io_write_offset_x(&s_motc, mh.key_set_count_offset);
|
|
io_write_offset_x(&s_motc, mh.key_set_types_offset);
|
|
io_write_offset_x(&s_motc, mh.key_set_offset);
|
|
io_write_offset_x(&s_motc, mh.bone_info_offset);
|
|
io_write_offset_x(&s_motc, mh.bone_hash_offset);
|
|
io_write_int32_t(&s_motc, mh.bone_info_count);
|
|
}
|
|
|
|
if (m->div_frames > 0) {
|
|
io_write_uint16_t(&s_motc, m->div_frames);
|
|
io_write_uint8_t(&s_motc, m->div_count);
|
|
}
|
|
else {
|
|
io_write_uint16_t(&s_motc, 0);
|
|
io_write_uint8_t(&s_motc, 0);
|
|
}
|
|
|
|
murmurhash = m->murmurhash;
|
|
}
|
|
|
|
f2_struct st;
|
|
io_align_write(&s_motc, 0x10);
|
|
io_copy(&s_motc, &st.data);
|
|
io_free(&s_motc);
|
|
|
|
st.enrs = e;
|
|
st.pof = pof;
|
|
|
|
st.header.signature = reverse_endianness_uint32_t('MOTC');
|
|
st.header.length = 0x40;
|
|
st.header.use_big_endian = false;
|
|
st.header.use_section_size = true;
|
|
st.header.murmurhash = murmurhash;
|
|
st.header.inner_signature = 0xFF010008;
|
|
|
|
st.write(s, true, ms->is_x);
|
|
}
|