Files
korenkonder_ReDIVA/src/CRE/Glitter/file_writer.cpp
T
2023-12-30 22:19:06 +03:00

2232 lines
99 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#include "glitter.hpp"
#include "../../KKdLib/io/file_stream.hpp"
#include "../../KKdLib/io/path.hpp"
#include "../../KKdLib/interpolation.hpp"
#include "../../KKdLib/farc.hpp"
#include "../../KKdLib/str_utils.hpp"
#include "../data.hpp"
namespace Glitter {
FileWriter::FileWriter() : type() {
}
void add_f2_key_random_range(KeyType key_type, enrs_entry& ee, uint32_t o) {
if (key_type == KEY_HERMITE) {
ee = { o, 2, 20, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 4, ENRS_DWORD);
}
else {
ee = { o, 2, 12, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 2, ENRS_DWORD);
}
};
void add_f2_key_no_random_range(KeyType key_type, enrs_entry& ee, uint32_t o) {
if (key_type == KEY_HERMITE) {
ee = { o, 2, 16, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 3, ENRS_DWORD);
}
else {
ee = { o, 2, 8, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 1, ENRS_DWORD);
}
};
int32_t get_f2_size_random_range(KeyType key_type) {
return key_type == KEY_HERMITE ? 20 : 12;
};
int32_t get_f2_size_no_random_range(KeyType key_type) {
return key_type == KEY_HERMITE ? 16 : 8;
};
void add_x_key_random_range(KeyType key_type, enrs_entry& ee, uint32_t o) {
if (key_type == KEY_HERMITE) {
ee = { o, 2, 32, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 7, ENRS_DWORD);
}
else {
ee = { o, 2, 16, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 3, ENRS_DWORD);
}
};
void add_x_key_no_random_range(KeyType key_type, enrs_entry& ee, uint32_t o) {
if (key_type == KEY_HERMITE) {
ee = { o, 2, 16, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 3, ENRS_DWORD);
}
else {
ee = { o, 2, 16, 1 };
ee.append(0, 2, ENRS_WORD);
ee.append(0, 3, ENRS_DWORD);
}
};
int32_t get_x_size_random_range(KeyType key_type) {
return key_type == KEY_HERMITE ? 32 : 16;
};
int32_t get_x_size_no_random_range(KeyType key_type) {
return key_type == KEY_HERMITE ? 16 : 16;
};
void FileWriter::PackCurve(f2_struct* st, Curve* c, bool big_endian) {
if (!c->keys.size()) {
st->header.signature = reverse_endianness_uint32_t('KEYS');
st->header.length = 0x20;
st->header.use_big_endian = false;
st->header.use_section_size = true;
st->header.version = c->keys_version;
return;
}
size_t l = 0;
enrs e;
enrs_entry ee;
size_t count;
void (*add_key)(KeyType key_type, enrs_entry & ee, uint32_t o);
int32_t(*get_size)(KeyType key_type);
const bool key_random_range = !!(c->flags & CURVE_KEY_RANDOM_RANGE);
if (type == Glitter::X && c->keys_version != 2)
if (key_random_range) {
add_key = add_x_key_random_range;
get_size = get_x_size_random_range;
}
else {
add_key = add_x_key_no_random_range;
get_size = get_x_size_no_random_range;
}
else
if (key_random_range) {
add_key = add_f2_key_random_range;
get_size = get_f2_size_random_range;
}
else {
add_key = add_f2_key_no_random_range;
get_size = get_f2_size_no_random_range;
}
KeyType key_type = c->keys.front().type;
add_key(key_type, ee, 0);
count = 1;
auto i_begin = c->keys.begin() + 1;
auto i_end = c->keys.end();
for (auto i = i_begin; i != i_end; i++, count++) {
if (i->type == key_type)
continue;
ee.repeat_count = (uint32_t)count;
e.vec.push_back(ee);
l += get_size(key_type) * count;
add_key(key_type, ee, (uint32_t)(get_size(key_type) * count));
count = 1;
key_type = i->type;
}
ee.repeat_count = (uint32_t)count;
e.vec.push_back(ee);
l += get_size(key_type) * count;
l = align_val(l, 0x10);
st->data.resize(l);
size_t d = (size_t)st->data.data();
if (type == Glitter::X) {
if (c->keys_version == 2) {
if (big_endian)
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (const Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2);
store_reverse_endianness_float_t((void*)(d + 12), i.random_range);
store_reverse_endianness_float_t((void*)(d + 16), i.value);
d += 20;
}
else {
store_reverse_endianness_float_t((void*)(d + 4), i.random_range);
store_reverse_endianness_float_t((void*)(d + 8), i.value);
d += 12;
}
}
else
for (const Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2);
store_reverse_endianness_float_t((void*)(d + 12), i.value);
d += 16;
}
else {
store_reverse_endianness_float_t((void*)(d + 4), i.value);
d += 8;
}
}
else
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (const Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1;
*(float_t*)(d + 8) = i.tangent2;
*(float_t*)(d + 12) = i.random_range;
*(float_t*)(d + 16) = i.value;
d += 20;
}
else {
*(float_t*)(d + 4) = i.random_range;
*(float_t*)(d + 8) = i.value;
d += 12;
}
}
else
for (const Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1;
*(float_t*)(d + 8) = i.tangent2;
*(float_t*)(d + 12) = i.value;
d += 16;
}
else {
*(float_t*)(d + 4) = i.value;
d += 8;
}
}
}
else {
if (big_endian)
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (const Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 16), i.tangent1);
store_reverse_endianness_float_t((void*)(d + 20), i.tangent2);
store_reverse_endianness_float_t((void*)(d + 24), i.random_range);
store_reverse_endianness_float_t((void*)(d + 28), i.value);
d += 32;
}
else {
store_reverse_endianness_float_t((void*)(d + 8), i.random_range);
store_reverse_endianness_float_t((void*)(d + 12), i.value);
d += 16;
}
}
else
for (const Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2);
store_reverse_endianness_float_t((void*)(d + 12), i.value);
d += 16;
}
else {
store_reverse_endianness_float_t((void*)(d + 12), i.value);
d += 16;
}
}
else
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (const Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 16) = i.tangent1;
*(float_t*)(d + 20) = i.tangent2;
*(float_t*)(d + 24) = i.random_range;
*(float_t*)(d + 28) = i.value;
d += 32;
}
else {
*(float_t*)(d + 8) = i.random_range;
*(float_t*)(d + 12) = i.value;
d += 16;
}
}
else
for (const Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1;
*(float_t*)(d + 8) = i.tangent2;
*(float_t*)(d + 12) = i.value;
d += 16;
}
else {
*(float_t*)(d + 12) = i.value;
d += 16;
}
}
}
}
else {
float_t scale = 1.0f;
if (c->keys_version == 0)
switch (c->type) {
case CURVE_ROTATION_X:
case CURVE_ROTATION_Y:
case CURVE_ROTATION_Z:
scale = RAD_TO_DEG_FLOAT;
break;
case CURVE_COLOR_R:
case CURVE_COLOR_G:
case CURVE_COLOR_B:
case CURVE_COLOR_A:
scale = 255.0f;
break;
}
if (scale == 1.0f) {
if (big_endian)
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2);
store_reverse_endianness_float_t((void*)(d + 12), i.random_range);
store_reverse_endianness_float_t((void*)(d + 16), i.value);
d += 20;
}
else {
store_reverse_endianness_float_t((void*)(d + 4), i.random_range);
store_reverse_endianness_float_t((void*)(d + 8), i.value);
d += 12;
}
}
else
for (Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2);
store_reverse_endianness_float_t((void*)(d + 12), i.value);
d += 16;
}
else {
store_reverse_endianness_float_t((void*)(d + 4), i.value);
d += 8;
}
}
else
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1;
*(float_t*)(d + 8) = i.tangent2;
*(float_t*)(d + 12) = i.random_range;
*(float_t*)(d + 16) = i.value;
d += 20;
}
else {
*(float_t*)(d + 4) = i.random_range;
*(float_t*)(d + 8) = i.value;
d += 12;
}
}
else
for (Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1;
*(float_t*)(d + 8) = i.tangent2;
*(float_t*)(d + 12) = i.value;
d += 16;
}
else {
*(float_t*)(d + 4) = i.value;
d += 8;
}
}
}
else {
if (big_endian)
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1 * scale);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2 * scale);
store_reverse_endianness_float_t((void*)(d + 12), i.random_range * scale);
store_reverse_endianness_float_t((void*)(d + 16), i.value * scale);
d += 20;
}
else {
store_reverse_endianness_float_t((void*)(d + 4), i.random_range * scale);
store_reverse_endianness_float_t((void*)(d + 8), i.value * scale);
d += 12;
}
}
else
for (Curve::Key& i : c->keys) {
store_reverse_endianness_int16_t((void*)d, (int16_t)i.type);
store_reverse_endianness_int16_t((void*)(d + 2), (int16_t)i.frame);
if (i.type == KEY_HERMITE) {
store_reverse_endianness_float_t((void*)(d + 4), i.tangent1 * scale);
store_reverse_endianness_float_t((void*)(d + 8), i.tangent2 * scale);
store_reverse_endianness_float_t((void*)(d + 12), i.value * scale);
d += 16;
}
else {
store_reverse_endianness_float_t((void*)(d + 4), i.value * scale);
d += 8;
}
}
else
if (c->flags & CURVE_KEY_RANDOM_RANGE)
for (Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1 * scale;
*(float_t*)(d + 8) = i.tangent2 * scale;
*(float_t*)(d + 12) = i.random_range * scale;
*(float_t*)(d + 16) = i.value * scale;
d += 20;
}
else {
*(float_t*)(d + 4) = i.random_range * scale;
*(float_t*)(d + 8) = i.value * scale;
d += 12;
}
}
else
for (Curve::Key& i : c->keys) {
*(int16_t*)d = (int16_t)i.type;
*(int16_t*)(d + 2) = (int16_t)i.frame;
if (i.type == KEY_HERMITE) {
*(float_t*)(d + 4) = i.tangent1 * scale;
*(float_t*)(d + 8) = i.tangent2 * scale;
*(float_t*)(d + 12) = i.value * scale;
d += 16;
}
else {
*(float_t*)(d + 4) = i.value * scale;
d += 8;
}
}
}
}
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('KEYS');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
st->header.version = c->keys_version;
}
bool FileWriter::PackDivaList(EffectGroup* eff_group, f2_struct* st, bool big_endian) {
if (!eff_group->effects.size())
return false;
enrs e;
enrs_entry ee;
ee = { 0, 1, 4, 1 };
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
size_t length = 0;
for (Effect*& i : eff_group->effects)
if (i)
length++;
st->data.resize(0x10 + 0x80 * length);
size_t d = (size_t)st->data.data();
if (big_endian)
store_reverse_endianness_uint32_t((void*)d, (uint32_t)length);
else
*(uint32_t*)d = (uint32_t)length;
d += 4;
for (Effect*& i : eff_group->effects)
if (i) {
size_t size = min_def(i->name.size(), 0x7F);
memcpy((void*)d, i->name.c_str(), size);
memset((void*)(d + size), 0, 0x80 - size);
d += 0x80;
}
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('GEFF');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
return true;
}
bool FileWriter::PackDivaResource(EffectGroup* eff_group, f2_struct* st) {
if (eff_group->resources_tex.textures.size() < 1)
return false;
if (!eff_group->resources_tex.produce_enrs(&st->enrs))
return false;
eff_group->resources_tex.pack_file(st->data, false);
st->header.signature = reverse_endianness_uint32_t('TXPC');
st->header.length = 0x20;
st->header.use_big_endian = false;
st->header.use_section_size = true;
return true;
}
bool FileWriter::PackDivaResourceHashes(EffectGroup* eff_group, f2_struct* st, bool big_endian) {
if (eff_group->effects.size() < 1 || !eff_group->resources_count
|| eff_group->resource_hashes.size() < 1)
return false;
size_t count = eff_group->resources_count;
size_t l = 0;
enrs e;
enrs_entry ee;
ee = { 0, 2, (uint32_t)(8 + count * 8), 1 };
ee.append(0, 1, ENRS_DWORD);
ee.append(4, (uint32_t)count, ENRS_QWORD);
e.vec.push_back(ee);
l += 8 + count * 8;
l = align_val(l, 0x10);
st->data.resize(l);
size_t d = (size_t)st->data.data();
if (big_endian)
store_reverse_endianness_int32_t((void*)d, (int32_t)count);
else
*(int32_t*)d = (int32_t)count;
*(int32_t*)(d + 4) = 0;
d += 8;
if (big_endian) {
uint64_t* hashes_src = eff_group->resource_hashes.data();
uint64_t* hashes_dst = (uint64_t*)(void*)d;
for (size_t i = 0; i < count; i++)
store_reverse_endianness_uint64_t(hashes_dst++, *hashes_src++);
}
else
memcpy((void*)d, eff_group->resource_hashes.data(), sizeof(uint64_t) * count);
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('DVRS');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
return true;
}
bool FileWriter::PackEffect(f2_struct* st, Effect* eff, bool big_endian) {
if (type != Glitter::X && (eff->version < 6 || eff->version > 7)
|| type == Glitter::X && (eff->version < 8 || eff->version > 12))
return false;
Effect::ExtAnim* ext_anim = eff->data.ext_anim;
int32_t type;
if (eff->data.flags & EFFECT_LOCAL)
type = 1;
else if (!ext_anim)
type = 0;
else if (ext_anim->flags & EFFECT_EXT_ANIM_CHARA_ANIM)
type = 2;
else
type = 3;
size_t l = 0;
uint32_t o;
enrs e;
enrs_entry ee;
if (this->type == Glitter::X) {
if (eff->version != 8) {
ee = { 0, 16, 80, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 3, ENRS_DWORD);
ee.append(4, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 80;
}
else {
ee = { 0, 18, 88, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 3, ENRS_DWORD);
ee.append(4, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 88;
}
if (type == 2) {
ee = { o, 1, 12, 1 };
ee.append(0, 3, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 12;
}
else if (type == 3) {
if (eff->version == 8) {
ee = { o, 2, 140, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 140;
}
else if (eff->version == 10) {
ee = { o, 2, 144, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 2, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 144;
}
else {
ee = { o, 4, 160, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 2, ENRS_DWORD);
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 2, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 160;
}
}
}
else {
if (eff->version == 7) {
ee = { 0, 3, 64, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 3, ENRS_DWORD);
ee.append(4, 10, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 64;
}
else {
ee = { 0, 3, 64, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 3, ENRS_DWORD);
ee.append(4, 9, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 60;
}
if (type == 2) {
ee = { 0, 1, 12, 1 };
ee.append(0, 3, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 12;
}
else if (type == 3) {
ee = { 0, 2, 140, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 140;
}
}
l = align_val(l, 0x10);
st->data.resize(l);
size_t d = (size_t)st->data.data();
EffectFileFlag flags = (EffectFileFlag)0;
if (eff->data.flags & EFFECT_ALPHA)
enum_or(flags, EFFECT_FILE_ALPHA);
if (eff->data.flags & EFFECT_FOG)
enum_or(flags, EFFECT_FILE_FOG);
else if (eff->data.flags & EFFECT_FOG_HEIGHT)
enum_or(flags, EFFECT_FILE_FOG_HEIGHT);
if (eff->data.flags & EFFECT_EMISSION)
enum_or(flags, EFFECT_FILE_EMISSION);
if (this->type == Glitter::X) {
if (eff->data.flags & EFFECT_USE_SEED)
enum_or(flags, EFFECT_FILE_USE_SEED);
if (eff->version != 8 && eff->data.flags & 0x80)
enum_or(flags, 0x20);
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, (uint64_t)hash_string_murmurhash(eff->name));
store_reverse_endianness_int32_t((void*)(d + 8), eff->data.appear_time);
store_reverse_endianness_int32_t((void*)(d + 12), eff->data.life_time);
store_reverse_endianness_int32_t((void*)(d + 16), eff->data.start_time);
store_reverse_endianness_int32_t((void*)(d + 20), 0xFFFFFFFF);
store_reverse_endianness_int32_t((void*)(d + 24), eff->data.flags & EFFECT_LOOP ? 1 : 0);
store_reverse_endianness_float_t((void*)(d + 28), eff->translation.x);
store_reverse_endianness_float_t((void*)(d + 32), eff->translation.y);
store_reverse_endianness_float_t((void*)(d + 36), eff->translation.z);
store_reverse_endianness_float_t((void*)(d + 40), eff->rotation.x);
store_reverse_endianness_float_t((void*)(d + 40), eff->rotation.y);
store_reverse_endianness_float_t((void*)(d + 40), eff->rotation.z);
store_reverse_endianness_int32_t((void*)(d + 52), flags);
}
else {
*(uint64_t*)d = hash_string_murmurhash(eff->name);
*(int32_t*)(d + 8) = eff->data.appear_time;
*(int32_t*)(d + 12) = eff->data.life_time;
*(int32_t*)(d + 16) = eff->data.start_time;
*(int32_t*)(d + 20) = 0xFFFFFFFF;
*(int32_t*)(d + 24) = eff->data.flags & EFFECT_LOOP ? 1 : 0;
*(vec3*)(d + 28) = eff->translation;
*(vec3*)(d + 40) = eff->rotation;
*(int32_t*)(d + 52) = flags;
}
d += 56;
if (big_endian) {
store_reverse_endianness_float_t((void*)d, eff->data.emission);
store_reverse_endianness_int32_t((void*)(d + 4), eff->data.seed);
store_reverse_endianness_float_t((void*)(d + 8), eff->data.unk);
}
else {
*(float_t*)d = eff->data.emission;
*(int32_t*)(d + 4) = eff->data.seed;
*(float_t*)(d + 8) = eff->data.unk;
}
d += 12;
if (eff->version != 8)
d += 8;
else
d += 12;
if (big_endian)
store_reverse_endianness_int32_t((void*)d, type);
else
*(int32_t*)d = type;
if (eff->version != 8)
d += 4;
else
d += 8;
Effect::ExtAnimX* ext_anim_x = eff->data.ext_anim_x;
if (type == 2) {
EffectExtAnimFlag ext_anim_flag = ext_anim_x->flags;
enum_and(ext_anim_flag, ~EFFECT_EXT_ANIM_CHARA_ANIM);
if (big_endian) {
store_reverse_endianness_int32_t((void*)d, ext_anim_x->chara_index);
store_reverse_endianness_int32_t((void*)(d + 4), ext_anim_flag);
store_reverse_endianness_int32_t((void*)(d + 8), ext_anim_x->node_index);
}
else {
*(int32_t*)d = ext_anim_x->chara_index;
*(int32_t*)(d + 4) = ext_anim_flag;
*(int32_t*)(d + 8) = ext_anim_x->node_index;
}
}
else if (type == 3) {
if (eff->version == 8) {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, (uint64_t)ext_anim_x->object_hash);
store_reverse_endianness_int32_t((void*)(d + 8), ext_anim_x->flags);
}
else {
*(uint64_t*)d = ext_anim_x->object_hash;
*(int32_t*)(d + 8) = ext_anim_x->flags;
}
if (ext_anim_x->mesh_name[0]) {
strncpy_s((char*)(d + 12), 0x80, ext_anim_x->mesh_name, 0x80);
((char*)(d + 12))[0x7F] = 0;
}
else
*(char*)(d + 12) = 0;
}
else if (eff->version == 10) {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, (uint64_t)ext_anim_x->object_hash);
store_reverse_endianness_int32_t((void*)(d + 8), ext_anim_x->flags);
}
else {
*(uint64_t*)d = ext_anim_x->object_hash;
*(int32_t*)(d + 8) = ext_anim_x->flags;
}
if (ext_anim_x->mesh_name[0]) {
strncpy_s((char*)(d + 16), 0x80, ext_anim_x->mesh_name, 0x80);
((char*)(d + 16))[0x7F] = 0;
}
else
*(char*)(d + 16) = 0;
}
else {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, (uint64_t)ext_anim_x->object_hash);
store_reverse_endianness_int32_t((void*)(d + 8), ext_anim_x->flags);
store_reverse_endianness_int32_t((void*)(d + 12), ext_anim_x->instance_id);
store_reverse_endianness_uint64_t((void*)(d + 16), (uint64_t)ext_anim_x->file_name_hash);
}
else {
*(uint64_t*)d = ext_anim_x->object_hash;
*(int32_t*)(d + 8) = ext_anim_x->flags;
*(int32_t*)(d + 12) = ext_anim_x->instance_id;
*(uint64_t*)(d + 16) = ext_anim_x->file_name_hash;
}
if (ext_anim_x->mesh_name[0]) {
strncpy_s((char*)(d + 32), 0x80, ext_anim_x->mesh_name, 0x80);
((char*)(d + 32))[0x7F] = 0;
}
else
*(char*)(d + 32) = 0;
}
}
}
else {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, type != Glitter::FT
? hash_string_murmurhash(eff->name) : hash_string_fnv1a64m(eff->name));
store_reverse_endianness_int32_t((void*)(d + 8), eff->data.appear_time);
store_reverse_endianness_int32_t((void*)(d + 12), eff->data.life_time);
store_reverse_endianness_int32_t((void*)(d + 16), eff->data.start_time);
store_reverse_endianness_int32_t((void*)(d + 20), 0xFFFFFFFF);
store_reverse_endianness_int32_t((void*)(d + 24), eff->data.flags & EFFECT_LOOP ? 1 : 0);
store_reverse_endianness_float_t((void*)(d + 28), eff->translation.x);
store_reverse_endianness_float_t((void*)(d + 32), eff->translation.y);
store_reverse_endianness_float_t((void*)(d + 36), eff->translation.z);
store_reverse_endianness_float_t((void*)(d + 40), eff->rotation.x);
store_reverse_endianness_float_t((void*)(d + 40), eff->rotation.y);
store_reverse_endianness_float_t((void*)(d + 40), eff->rotation.z);
store_reverse_endianness_int32_t((void*)(d + 52), flags);
}
else {
*(uint64_t*)d = type != Glitter::FT
? hash_string_murmurhash(eff->name) : hash_string_fnv1a64m(eff->name);
*(int32_t*)(d + 8) = eff->data.appear_time;
*(int32_t*)(d + 12) = eff->data.life_time;
*(int32_t*)(d + 16) = eff->data.start_time;
*(int32_t*)(d + 20) = 0xFFFFFFFF;
*(int32_t*)(d + 24) = eff->data.flags & EFFECT_LOOP ? 1 : 0;
*(vec3*)(d + 28) = eff->translation;
*(vec3*)(d + 40) = eff->rotation;
*(int32_t*)(d + 52) = flags;
}
d += 56;
if (eff->version == 7) {
if (big_endian)
store_reverse_endianness_float_t((void*)d, eff->data.emission);
else
*(float_t*)d = eff->data.emission;
d += 4;
}
if (big_endian)
store_reverse_endianness_int32_t((void*)d, type);
else
*(int32_t*)d = type;
d += 4;
if (type == 2) {
EffectExtAnimFlag ext_anim_flag = ext_anim->flags;
enum_and(ext_anim_flag, ~EFFECT_EXT_ANIM_CHARA_ANIM);
if (big_endian) {
store_reverse_endianness_int32_t((void*)d, ext_anim->chara_index);
store_reverse_endianness_int32_t((void*)(d + 4), ext_anim_flag);
store_reverse_endianness_int32_t((void*)(d + 8), ext_anim->node_index);
}
else {
*(int32_t*)d = ext_anim->chara_index;
*(int32_t*)(d + 4) = ext_anim_flag;
*(int32_t*)(d + 8) = ext_anim->node_index;
}
}
else if (type == 3) {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, ext_anim->object_hash);
store_reverse_endianness_int32_t((void*)(d + 8), ext_anim->flags);
}
else {
*(uint64_t*)d = ext_anim->object_hash;
*(int32_t*)(d + 8) = ext_anim->flags;
}
if (ext_anim->mesh_name[0]) {
strncpy_s((char*)(d + 12), 0x80, ext_anim->mesh_name, 0x80);
((char*)(d + 12))[0x7F] = 0;
}
else
*(char*)(d + 12) = 0;
}
}
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('EFCT');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
st->header.version = eff->version;
return true;
}
bool FileWriter::PackEmitter(f2_struct* st, Emitter* emit, bool big_endian) {
if (type != Glitter::X && (emit->version < 1 || emit->version > 2)
|| type == Glitter::X && (emit->version < 3 || emit->version > 4))
return false;
switch (emit->data.type) {
case EMITTER_BOX:
case EMITTER_CYLINDER:
case EMITTER_SPHERE:
case EMITTER_POLYGON:
break;
default:
return false;
}
size_t l = 0;
uint32_t o;
enrs e;
enrs_entry ee;
if (type == Glitter::X) {
if (emit->version == 3) {
ee = { 0, 5, 116, 1 };
ee.append(0, 5, ENRS_DWORD);
ee.append(0, 2, ENRS_WORD);
ee.append(0, 2, ENRS_DWORD);
ee.append(0, 2, ENRS_WORD);
ee.append(0, 20, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 116;
}
else {
ee = { 0, 5, 112, 1 };
ee.append(0, 5, ENRS_DWORD);
ee.append(0, 2, ENRS_WORD);
ee.append(0, 2, ENRS_DWORD);
ee.append(0, 2, ENRS_WORD);
ee.append(0, 19, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 112;
}
switch (emit->data.type) {
case EMITTER_BOX:
ee = { o, 1, 12, 1 };
ee.append(0, 3, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 12;
break;
case EMITTER_CYLINDER:
ee = { o, 1, 20, 1 };
ee.append(0, 5, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 20;
break;
case EMITTER_SPHERE:
ee = { o, 1, 16, 1 };
ee.append(0, 4, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 16;
break;
case EMITTER_POLYGON:
ee = { o, 1, 12, 1 };
ee.append(0, 3, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 12;
break;
}
l = align_val(l, 0x10);
st->data.resize(l);
size_t d = (size_t)st->data.data();
if (big_endian) {
store_reverse_endianness_int32_t((void*)d, emit->data.start_time);
store_reverse_endianness_int32_t((void*)(d + 4), emit->data.life_time);
store_reverse_endianness_int32_t((void*)(d + 8), emit->data.loop_start_time);
store_reverse_endianness_int32_t((void*)(d + 12), emit->data.loop_end_time);
store_reverse_endianness_int32_t((void*)(d + 16), emit->data.flags);
store_reverse_endianness_int32_t((void*)(d + 20), (int16_t)emit->data.type);
store_reverse_endianness_int32_t((void*)(d + 22), (int16_t)emit->data.direction);
store_reverse_endianness_float_t((void*)(d + 24), emit->data.emission_interval);
store_reverse_endianness_float_t((void*)(d + 28), emit->data.particles_per_emission);
store_reverse_endianness_int16_t((void*)(d + 32), (int16_t)emit->data.timer);
store_reverse_endianness_int16_t((void*)(d + 34), (int16_t)0);
store_reverse_endianness_int32_t((void*)(d + 36), emit->data.seed);
}
else {
*(int32_t*)d = emit->data.start_time;
*(int32_t*)(d + 4) = emit->data.life_time;
*(int32_t*)(d + 8) = emit->data.loop_start_time;
*(int32_t*)(d + 12) = emit->data.loop_end_time;
*(int32_t*)(d + 16) = emit->data.flags;
*(int16_t*)(d + 20) = (int16_t)emit->data.type;
*(int16_t*)(d + 22) = (int16_t)emit->data.direction;
*(float_t*)(d + 24) = emit->data.emission_interval;
*(float_t*)(d + 28) = emit->data.particles_per_emission;
*(int16_t*)(d + 32) = (int16_t)emit->data.timer;
*(int16_t*)(d + 34) = 0;
*(int32_t*)(d + 36) = emit->data.seed;
}
d += emit->version == 3 ? 56 : 52;
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->translation.x);
store_reverse_endianness_float_t((void*)(d + 4), emit->translation.y);
store_reverse_endianness_float_t((void*)(d + 8), emit->translation.z);
store_reverse_endianness_float_t((void*)(d + 12), emit->rotation.x);
store_reverse_endianness_float_t((void*)(d + 16), emit->rotation.y);
store_reverse_endianness_float_t((void*)(d + 20), emit->rotation.z);
store_reverse_endianness_float_t((void*)(d + 24), emit->scale.x);
store_reverse_endianness_float_t((void*)(d + 28), emit->scale.y);
store_reverse_endianness_float_t((void*)(d + 32), emit->scale.z);
store_reverse_endianness_float_t((void*)(d + 36), emit->data.rotation_add.x);
store_reverse_endianness_float_t((void*)(d + 40), emit->data.rotation_add.y);
store_reverse_endianness_float_t((void*)(d + 44), emit->data.rotation_add.z);
store_reverse_endianness_float_t((void*)(d + 48), emit->data.rotation_add_random.x);
store_reverse_endianness_float_t((void*)(d + 52), emit->data.rotation_add_random.y);
store_reverse_endianness_float_t((void*)(d + 56), emit->data.rotation_add_random.z);
}
else {
*(vec3*)d = emit->translation;
*(vec3*)(d + 12) = emit->rotation;
*(vec3*)(d + 24) = emit->scale;
*(vec3*)(d + 36) = emit->data.rotation_add;
*(vec3*)(d + 48) = emit->data.rotation_add_random;
}
d += 60;
switch (emit->data.type) {
case EMITTER_BOX:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.box.size.x);
store_reverse_endianness_float_t((void*)(d + 4), emit->data.box.size.y);
store_reverse_endianness_float_t((void*)(d + 8), emit->data.box.size.z);
}
else
*(vec3*)d = emit->data.box.size;
break;
case EMITTER_CYLINDER:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.cylinder.radius);
store_reverse_endianness_float_t((void*)(d + 4), emit->data.cylinder.height);
store_reverse_endianness_float_t((void*)(d + 8), emit->data.cylinder.start_angle);
store_reverse_endianness_float_t((void*)(d + 12), emit->data.cylinder.end_angle);
store_reverse_endianness_int32_t((void*)(d + 16), ((int32_t)emit->data.cylinder.direction << 1)
| (emit->data.cylinder.on_edge ? 1 : 0));
}
else {
*(float_t*)d = emit->data.cylinder.radius;
*(float_t*)(d + 4) = emit->data.cylinder.height;
*(float_t*)(d + 8) = emit->data.cylinder.start_angle;
*(float_t*)(d + 12) = emit->data.cylinder.end_angle;
*(int32_t*)(d + 16) = ((int32_t)emit->data.cylinder.direction << 1)
| (emit->data.cylinder.on_edge ? 1 : 0);
}
break;
case EMITTER_SPHERE:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.sphere.radius);
store_reverse_endianness_float_t((void*)(d + 4), emit->data.sphere.latitude);
store_reverse_endianness_float_t((void*)(d + 8), emit->data.sphere.longitude);
store_reverse_endianness_int32_t((void*)(d + 12), ((int32_t)emit->data.sphere.direction << 1)
| (emit->data.sphere.on_edge ? 1 : 0));
}
else {
*(float_t*)d = emit->data.sphere.radius;
*(float_t*)(d + 4) = emit->data.sphere.latitude;
*(float_t*)(d + 8) = emit->data.sphere.longitude;
*(int32_t*)(d + 12) = ((int32_t)emit->data.sphere.direction << 1)
| (emit->data.sphere.on_edge ? 1 : 0);
}
break;
case EMITTER_POLYGON:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.polygon.size);
store_reverse_endianness_int32_t((void*)(d + 4), emit->data.polygon.count);
store_reverse_endianness_int32_t((void*)(d + 8), (int32_t)emit->data.polygon.direction << 1);
}
else {
*(float_t*)d = emit->data.polygon.size;
*(int32_t*)(d + 4) = emit->data.polygon.count;
*(int32_t*)(d + 8) = (int32_t)emit->data.polygon.direction << 1;
}
break;
}
}
else {
ee = { 0, 5, 96, 1 };
ee.append(0, 5, ENRS_DWORD);
ee.append(0, 2, ENRS_WORD);
ee.append(0, 2, ENRS_DWORD);
ee.append(0, 2, ENRS_WORD);
ee.append(0, 15, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 96;
switch (emit->data.type) {
case EMITTER_BOX:
ee = { o, 1, 12, 1 };
ee.append(0, 3, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 12;
break;
case EMITTER_CYLINDER:
ee = { o, 1, 20, 1 };
ee.append(0, 5, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 20;
break;
case EMITTER_SPHERE:
ee = { o, 1, 16, 1 };
ee.append(0, 4, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 16;
break;
case EMITTER_POLYGON:
ee = { o, 1, 8, 1 };
ee.append(0, 2, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 8;
break;
}
l = align_val(l, 0x10);
st->data.resize(l);
size_t d = (size_t)st->data.data();
if (big_endian) {
store_reverse_endianness_int32_t((void*)d, emit->data.start_time);
store_reverse_endianness_int32_t((void*)(d + 4), emit->data.life_time);
store_reverse_endianness_int32_t((void*)(d + 8), emit->data.loop_start_time);
store_reverse_endianness_int32_t((void*)(d + 12), emit->data.loop_end_time);
store_reverse_endianness_int32_t((void*)(d + 16), emit->data.flags);
store_reverse_endianness_int32_t((void*)(d + 20), (int16_t)emit->data.type);
store_reverse_endianness_int32_t((void*)(d + 22), (int16_t)emit->data.direction);
store_reverse_endianness_float_t((void*)(d + 24), emit->data.emission_interval);
store_reverse_endianness_float_t((void*)(d + 28), emit->data.particles_per_emission);
store_reverse_endianness_int16_t((void*)(d + 32), (int16_t)0);
store_reverse_endianness_int16_t((void*)(d + 34), (int16_t)0);
store_reverse_endianness_float_t((void*)(d + 36), emit->translation.x);
store_reverse_endianness_float_t((void*)(d + 40), emit->translation.y);
store_reverse_endianness_float_t((void*)(d + 44), emit->translation.z);
store_reverse_endianness_float_t((void*)(d + 48), emit->rotation.x);
store_reverse_endianness_float_t((void*)(d + 52), emit->rotation.y);
store_reverse_endianness_float_t((void*)(d + 56), emit->rotation.z);
store_reverse_endianness_float_t((void*)(d + 60), emit->scale.x);
store_reverse_endianness_float_t((void*)(d + 64), emit->scale.y);
store_reverse_endianness_float_t((void*)(d + 68), emit->scale.z);
store_reverse_endianness_float_t((void*)(d + 72), emit->data.rotation_add.x);
store_reverse_endianness_float_t((void*)(d + 76), emit->data.rotation_add.y);
store_reverse_endianness_float_t((void*)(d + 80), emit->data.rotation_add.z);
store_reverse_endianness_float_t((void*)(d + 84), emit->data.rotation_add_random.x);
store_reverse_endianness_float_t((void*)(d + 88), emit->data.rotation_add_random.y);
store_reverse_endianness_float_t((void*)(d + 92), emit->data.rotation_add_random.z);
}
else {
*(int32_t*)d = emit->data.start_time;
*(int32_t*)(d + 4) = emit->data.life_time;
*(int32_t*)(d + 8) = emit->data.loop_start_time;
*(int32_t*)(d + 12) = emit->data.loop_end_time;
*(int32_t*)(d + 16) = emit->data.flags;
*(int16_t*)(d + 20) = (int16_t)emit->data.type;
*(int16_t*)(d + 22) = (int16_t)emit->data.direction;
*(float_t*)(d + 24) = emit->data.emission_interval;
*(float_t*)(d + 28) = emit->data.particles_per_emission;
*(int16_t*)(d + 32) = 0;
*(int16_t*)(d + 34) = 0;
*(vec3*)(d + 36) = emit->translation;
*(vec3*)(d + 48) = emit->rotation;
*(vec3*)(d + 60) = emit->scale;
*(vec3*)(d + 72) = emit->data.rotation_add;
*(vec3*)(d + 84) = emit->data.rotation_add_random;
}
d += 96;
switch (emit->data.type) {
case EMITTER_BOX:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.box.size.x);
store_reverse_endianness_float_t((void*)(d + 4), emit->data.box.size.y);
store_reverse_endianness_float_t((void*)(d + 8), emit->data.box.size.z);
}
else
*(vec3*)d = emit->data.box.size;
break;
case EMITTER_CYLINDER:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.cylinder.radius);
store_reverse_endianness_float_t((void*)(d + 4), emit->data.cylinder.height);
store_reverse_endianness_float_t((void*)(d + 8), emit->data.cylinder.start_angle);
store_reverse_endianness_float_t((void*)(d + 12), emit->data.cylinder.end_angle);
store_reverse_endianness_int32_t((void*)(d + 16), ((int32_t)emit->data.cylinder.direction << 1)
| (emit->data.cylinder.on_edge ? 1 : 0));
}
else {
*(float_t*)d = emit->data.cylinder.radius;
*(float_t*)(d + 4) = emit->data.cylinder.height;
*(float_t*)(d + 8) = emit->data.cylinder.start_angle;
*(float_t*)(d + 12) = emit->data.cylinder.end_angle;
*(int32_t*)(d + 16) = ((int32_t)emit->data.cylinder.direction << 1)
| (emit->data.cylinder.on_edge ? 1 : 0);
}
break;
case EMITTER_SPHERE:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.sphere.radius);
store_reverse_endianness_float_t((void*)(d + 4), emit->data.sphere.latitude);
store_reverse_endianness_float_t((void*)(d + 8), emit->data.sphere.longitude);
store_reverse_endianness_int32_t((void*)(d + 12), ((int32_t)emit->data.sphere.direction << 1)
| (emit->data.sphere.on_edge ? 1 : 0));
}
else {
*(float_t*)d = emit->data.sphere.radius;
*(float_t*)(d + 4) = emit->data.sphere.latitude;
*(float_t*)(d + 8) = emit->data.sphere.longitude;
*(int32_t*)(d + 12) = ((int32_t)emit->data.sphere.direction << 1)
| (emit->data.sphere.on_edge ? 1 : 0);
}
break;
case EMITTER_POLYGON:
if (big_endian) {
store_reverse_endianness_float_t((void*)d, emit->data.polygon.size);
store_reverse_endianness_int32_t((void*)(d + 4), emit->data.polygon.count);
}
else {
*(float_t*)d = emit->data.polygon.size;
*(int32_t*)(d + 4) = emit->data.polygon.count;
}
break;
}
}
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('EMIT');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
st->header.version = emit->version;
return true;
}
bool FileWriter::PackParticle(EffectGroup* eff_group,
f2_struct* st, Particle* ptcl, Effect* eff, bool big_endian) {
if (type != Glitter::X && ptcl->version < 2
|| type == Glitter::X && (ptcl->version < 4 || ptcl->version > 5))
return false;
size_t l = 0;
uint32_t o;
enrs e;
enrs_entry ee;
if (type == Glitter::X) {
ee = { 0, 1, 256, 1 };
ee.append(0, 64, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 256;
if (ptcl->data.type == PARTICLE_LOCUS) {
ee = { o, 1, 4, 1 };
ee.append(0, 2, ENRS_WORD);
e.vec.push_back(ee);
l += o = 4;
}
else if (ptcl->data.type == PARTICLE_MESH) {
ee = { o, 2, 88, 1 };
ee.append(0, 2, ENRS_QWORD);
ee.append(64, 1, ENRS_QWORD);
e.vec.push_back(ee);
l += o = 88;
}
ee = { o, 11, 48, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(4, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_WORD);
ee.append(0, 1, ENRS_WORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 48;
if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) {
ee = { o, 2, 16, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 2, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 16;
}
}
else {
ee = { 0, 1, 204, 1 };
ee.append(0, 51, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 204;
if (ptcl->version == 3) {
ee = { o, 1, 8, 1 };
ee.append(0, 2, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 8;
}
if (ptcl->data.type == PARTICLE_LOCUS || ptcl->data.type == PARTICLE_MESH) {
ee = { o, 1, 4, 1 };
ee.append(0, 2, ENRS_WORD);
e.vec.push_back(ee);
l += o = 4;
}
if (eff_group->version >= 7) {
ee = { o, 11, 48, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(4, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_WORD);
ee.append(0, 1, ENRS_WORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 48;
}
else {
ee = { o, 10, 44, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(4, 5, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_WORD);
ee.append(0, 1, ENRS_WORD);
ee.append(0, 1, ENRS_DWORD);
ee.append(0, 1, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 44;
}
if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) {
ee = { o, 2, 16, 1 };
ee.append(0, 1, ENRS_QWORD);
ee.append(0, 2, ENRS_DWORD);
e.vec.push_back(ee);
l += o = 16;
}
}
l = align_val(l, 0x10);
st->data.resize(l);
size_t d = (size_t)st->data.data();
ParticleFlag flags = ptcl->data.flags;
if (eff->data.flags & EFFECT_LOCAL)
enum_and(flags, ~PARTICLE_LOCAL);
if (eff->data.flags & EFFECT_EMISSION)
enum_and(flags, ~PARTICLE_EMISSION);
if (type == Glitter::X) {
int32_t type = ptcl->data.type;
switch (type) {
case PARTICLE_LINE:
type = 3;
break;
case PARTICLE_MESH:
type = 1;
break;
}
vec3 direction = ptcl->data.direction;
vec3 direction_random = ptcl->data.direction_random;
if (ptcl->version == 4) {
direction /= 10.0f;
direction_random /= 10.0f;
}
if (big_endian) {
store_reverse_endianness_int32_t((void*)d, ptcl->data.life_time);
store_reverse_endianness_int32_t((void*)(d + 4), ptcl->data.life_time_random);
store_reverse_endianness_int32_t((void*)(d + 8), ptcl->data.fade_in);
store_reverse_endianness_int32_t((void*)(d + 12), ptcl->data.fade_in_random);
store_reverse_endianness_int32_t((void*)(d + 16), ptcl->data.fade_out);
store_reverse_endianness_int32_t((void*)(d + 20), ptcl->data.fade_out_random);
store_reverse_endianness_int32_t((void*)(d + 24), type);
store_reverse_endianness_int32_t((void*)(d + 28), ptcl->data.draw_type);
store_reverse_endianness_float_t((void*)(d + 32), ptcl->data.rotation.x);
store_reverse_endianness_float_t((void*)(d + 36), ptcl->data.rotation.y);
store_reverse_endianness_float_t((void*)(d + 40), ptcl->data.rotation.z);
store_reverse_endianness_float_t((void*)(d + 44), ptcl->data.rotation_random.x);
store_reverse_endianness_float_t((void*)(d + 48), ptcl->data.rotation_random.y);
store_reverse_endianness_float_t((void*)(d + 52), ptcl->data.rotation_random.z);
store_reverse_endianness_float_t((void*)(d + 56), ptcl->data.rotation_add.x);
store_reverse_endianness_float_t((void*)(d + 60), ptcl->data.rotation_add.y);
store_reverse_endianness_float_t((void*)(d + 64), ptcl->data.rotation_add.z);
store_reverse_endianness_float_t((void*)(d + 68), ptcl->data.rotation_add_random.x);
store_reverse_endianness_float_t((void*)(d + 72), ptcl->data.rotation_add_random.y);
store_reverse_endianness_float_t((void*)(d + 76), ptcl->data.rotation_add_random.z);
store_reverse_endianness_float_t((void*)(d + 80), ptcl->data.scale.x);
store_reverse_endianness_float_t((void*)(d + 84), ptcl->data.scale.y);
store_reverse_endianness_float_t((void*)(d + 88), ptcl->data.scale.z);
store_reverse_endianness_float_t((void*)(d + 92), ptcl->data.scale_random.x);
store_reverse_endianness_float_t((void*)(d + 96), ptcl->data.scale_random.y);
store_reverse_endianness_float_t((void*)(d + 100), ptcl->data.scale_random.z);
store_reverse_endianness_float_t((void*)(d + 104), ptcl->data.z_offset);
store_reverse_endianness_int32_t((void*)(d + 108), ptcl->data.pivot);
store_reverse_endianness_int32_t((void*)(d + 112), flags);
store_reverse_endianness_int32_t((void*)(d + 116), ptcl->data.unk0);
store_reverse_endianness_float_t((void*)(d + 120), ptcl->data.uv_scroll_2nd_add.x);
store_reverse_endianness_float_t((void*)(d + 124), ptcl->data.uv_scroll_2nd_add.y);
store_reverse_endianness_float_t((void*)(d + 128), ptcl->data.uv_scroll_2nd_add_scale);
store_reverse_endianness_float_t((void*)(d + 136), ptcl->data.speed);
store_reverse_endianness_float_t((void*)(d + 140), ptcl->data.speed_random);
store_reverse_endianness_float_t((void*)(d + 144), ptcl->data.deceleration);
store_reverse_endianness_float_t((void*)(d + 148), ptcl->data.deceleration_random);
store_reverse_endianness_float_t((void*)(d + 152), direction.x);
store_reverse_endianness_float_t((void*)(d + 156), direction.y);
store_reverse_endianness_float_t((void*)(d + 160), direction.z);
store_reverse_endianness_float_t((void*)(d + 164), direction_random.x);
store_reverse_endianness_float_t((void*)(d + 168), direction_random.y);
store_reverse_endianness_float_t((void*)(d + 172), direction_random.z);
store_reverse_endianness_float_t((void*)(d + 176), ptcl->data.gravity.x);
store_reverse_endianness_float_t((void*)(d + 180), ptcl->data.gravity.y);
store_reverse_endianness_float_t((void*)(d + 184), ptcl->data.gravity.z);
store_reverse_endianness_float_t((void*)(d + 188), ptcl->data.acceleration.x);
store_reverse_endianness_float_t((void*)(d + 192), ptcl->data.acceleration.y);
store_reverse_endianness_float_t((void*)(d + 196), ptcl->data.acceleration.z);
store_reverse_endianness_float_t((void*)(d + 200), ptcl->data.acceleration_random.x);
store_reverse_endianness_float_t((void*)(d + 204), ptcl->data.acceleration_random.y);
store_reverse_endianness_float_t((void*)(d + 208), ptcl->data.acceleration_random.z);
store_reverse_endianness_float_t((void*)(d + 212), ptcl->data.reflection_coeff);
store_reverse_endianness_float_t((void*)(d + 216), ptcl->data.reflection_coeff_random);
store_reverse_endianness_float_t((void*)(d + 220), ptcl->data.rebound_plane_y);
store_reverse_endianness_float_t((void*)(d + 224), ptcl->data.uv_scroll_add.x);
store_reverse_endianness_float_t((void*)(d + 228), ptcl->data.uv_scroll_add.y);
store_reverse_endianness_float_t((void*)(d + 232), ptcl->data.uv_scroll_add_scale);
store_reverse_endianness_int32_t((void*)(d + 236), ptcl->data.sub_flags);
store_reverse_endianness_int32_t((void*)(d + 240), ptcl->data.count);
store_reverse_endianness_int32_t((void*)(d + 244), ptcl->data.draw_flags);
store_reverse_endianness_float_t((void*)(d + 248), ptcl->data.unk1);
store_reverse_endianness_float_t((void*)(d + 252), ptcl->data.emission);
}
else {
*(int32_t*)d = ptcl->data.life_time;
*(int32_t*)(d + 4) = ptcl->data.life_time_random;
*(int32_t*)(d + 8) = ptcl->data.fade_in;
*(int32_t*)(d + 12) = ptcl->data.fade_in_random;
*(int32_t*)(d + 16) = ptcl->data.fade_out;
*(int32_t*)(d + 20) = ptcl->data.fade_out_random;
*(int32_t*)(d + 24) = type;
*(int32_t*)(d + 28) = ptcl->data.draw_type;
*(vec3*)(d + 32) = ptcl->data.rotation;
*(vec3*)(d + 44) = ptcl->data.rotation_random;
*(vec3*)(d + 56) = ptcl->data.rotation_add;
*(vec3*)(d + 68) = ptcl->data.rotation_add_random;
*(vec3*)(d + 80) = ptcl->data.scale;
*(vec3*)(d + 92) = ptcl->data.scale_random;
*(float_t*)(d + 104) = ptcl->data.z_offset;
*(int32_t*)(d + 108) = ptcl->data.pivot;
*(int32_t*)(d + 112) = flags;
*(int32_t*)(d + 116) = ptcl->data.unk0;
*(vec2*)(d + 120) = ptcl->data.uv_scroll_2nd_add;
*(float_t*)(d + 128) = ptcl->data.uv_scroll_2nd_add_scale;
*(float_t*)(d + 136) = ptcl->data.speed;
*(float_t*)(d + 140) = ptcl->data.speed_random;
*(float_t*)(d + 144) = ptcl->data.deceleration;
*(float_t*)(d + 148) = ptcl->data.deceleration_random;
*(vec3*)(d + 152) = direction;
*(vec3*)(d + 164) = direction_random;
*(vec3*)(d + 176) = ptcl->data.gravity;
*(vec3*)(d + 188) = ptcl->data.acceleration;
*(vec3*)(d + 200) = ptcl->data.acceleration_random;
*(float_t*)(d + 212) = ptcl->data.reflection_coeff;
*(float_t*)(d + 216) = ptcl->data.reflection_coeff_random;
*(float_t*)(d + 220) = ptcl->data.rebound_plane_y;
*(vec2*)(d + 224) = ptcl->data.uv_scroll_add;
*(float_t*)(d + 232) = ptcl->data.uv_scroll_add_scale;
*(int32_t*)(d + 236) = ptcl->data.sub_flags;
*(int32_t*)(d + 240) = ptcl->data.count;
*(int32_t*)(d + 244) = ptcl->data.draw_flags;
*(float_t*)(d + 248) = ptcl->data.unk1;
*(float_t*)(d + 252) = ptcl->data.emission;
}
d += 256;
if (ptcl->data.type == PARTICLE_LOCUS) {
if (big_endian) {
store_reverse_endianness_uint16_t((void*)d, (uint16_t)ptcl->data.locus_history_size);
store_reverse_endianness_uint16_t((void*)(d + 2), (uint16_t)ptcl->data.locus_history_size_random);
}
else {
*(uint16_t*)d = (uint16_t)ptcl->data.locus_history_size;
*(uint16_t*)(d + 2) = (uint16_t)ptcl->data.locus_history_size_random;
}
d += 4;
}
else if (ptcl->data.type == PARTICLE_MESH) {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, ptcl->data.mesh.object_name_hash);
store_reverse_endianness_uint64_t((void*)(d + 8), ptcl->data.mesh.object_set_name_hash);
}
else {
*(uint64_t*)d = ptcl->data.mesh.object_name_hash;
*(uint64_t*)(d + 8) = ptcl->data.mesh.object_set_name_hash;
}
//strncpy_s((char*)(d + 16), ptcl->data.mesh.mesh_name, 0x40);
//if (big_endian)
// store_reverse_endianness_uint64_t((void*)(d + 80), ptcl->data.mesh.sub_mesh_hash);
//else
// *(uint64_t*)(d + 80) = ptcl->data.mesh.sub_mesh_hash;
if (big_endian)
store_reverse_endianness_uint64_t((void*)(d + 80), (uint64_t)hash_murmurhash_empty);
else
*(uint64_t*)(d + 80) = hash_murmurhash_empty;
d += 88;
}
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, ptcl->data.tex_hash);
*(uint8_t*)(d + 8) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 9) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 10) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 11) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f);
store_reverse_endianness_int32_t((void*)(d + 12), ptcl->data.blend_mode);
store_reverse_endianness_int32_t((void*)(d + 16), ptcl->data.unk2);
store_reverse_endianness_int32_t((void*)(d + 20), ptcl->data.split_u);
store_reverse_endianness_int32_t((void*)(d + 24), ptcl->data.split_v);
store_reverse_endianness_int32_t((void*)(d + 28), ptcl->data.uv_index_type);
store_reverse_endianness_int16_t((void*)(d + 32), (int16_t)ptcl->data.uv_index);
store_reverse_endianness_int16_t((void*)(d + 34), (int16_t)ptcl->data.frame_step_uv);
store_reverse_endianness_int32_t((void*)(d + 36), ptcl->data.uv_index_start);
store_reverse_endianness_int32_t((void*)(d + 40), ptcl->data.uv_index_end);
store_reverse_endianness_int32_t((void*)(d + 44), ptcl->data.unk3);
}
else {
*(uint64_t*)d = ptcl->data.tex_hash;
*(uint8_t*)(d + 8) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 9) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 10) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 11) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f);
*(int32_t*)(d + 12) = ptcl->data.blend_mode;
*(int32_t*)(d + 16) = ptcl->data.unk2;
*(int32_t*)(d + 20) = ptcl->data.split_u;
*(int32_t*)(d + 24) = ptcl->data.split_v;
*(int32_t*)(d + 28) = ptcl->data.uv_index_type;
*(int16_t*)(d + 32) = (int16_t)ptcl->data.uv_index;
*(int16_t*)(d + 34) = (int16_t)ptcl->data.frame_step_uv;
*(int32_t*)(d + 36) = ptcl->data.uv_index_start;
*(int32_t*)(d + 40) = ptcl->data.uv_index_end;
*(int32_t*)(d + 44) = ptcl->data.unk3;
}
d += 48;
if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, ptcl->data.mask_tex_hash);
store_reverse_endianness_int32_t((void*)(d + 8), ptcl->data.mask_blend_mode);
store_reverse_endianness_int32_t((void*)(d + 12), ptcl->data.unk4);
}
else {
*(uint64_t*)d = ptcl->data.mask_tex_hash;
*(int32_t*)(d + 8) = ptcl->data.mask_blend_mode;
*(int32_t*)(d + 12) = ptcl->data.unk4;
}
d += 16;
}
}
else {
if (big_endian) {
store_reverse_endianness_int32_t((void*)d, ptcl->data.life_time);
store_reverse_endianness_int32_t((void*)(d + 4), ptcl->data.type);
store_reverse_endianness_int32_t((void*)(d + 8), ptcl->data.draw_type);
store_reverse_endianness_float_t((void*)(d + 12), ptcl->data.rotation.x);
store_reverse_endianness_float_t((void*)(d + 16), ptcl->data.rotation.y);
store_reverse_endianness_float_t((void*)(d + 20), ptcl->data.rotation.z);
store_reverse_endianness_float_t((void*)(d + 24), ptcl->data.rotation_random.x);
store_reverse_endianness_float_t((void*)(d + 28), ptcl->data.rotation_random.y);
store_reverse_endianness_float_t((void*)(d + 32), ptcl->data.rotation_random.z);
store_reverse_endianness_float_t((void*)(d + 36), ptcl->data.rotation_add.x);
store_reverse_endianness_float_t((void*)(d + 40), ptcl->data.rotation_add.y);
store_reverse_endianness_float_t((void*)(d + 44), ptcl->data.rotation_add.z);
store_reverse_endianness_float_t((void*)(d + 48), ptcl->data.rotation_add_random.x);
store_reverse_endianness_float_t((void*)(d + 52), ptcl->data.rotation_add_random.y);
store_reverse_endianness_float_t((void*)(d + 56), ptcl->data.rotation_add_random.z);
store_reverse_endianness_float_t((void*)(d + 60), ptcl->data.scale.x);
store_reverse_endianness_float_t((void*)(d + 64), ptcl->data.scale.y);
store_reverse_endianness_float_t((void*)(d + 68), ptcl->data.scale.z);
store_reverse_endianness_float_t((void*)(d + 72), ptcl->data.scale_random.x);
store_reverse_endianness_float_t((void*)(d + 76), ptcl->data.scale_random.y);
store_reverse_endianness_float_t((void*)(d + 80), ptcl->data.scale_random.z);
store_reverse_endianness_float_t((void*)(d + 84), ptcl->data.z_offset);
store_reverse_endianness_int32_t((void*)(d + 88), ptcl->data.pivot);
store_reverse_endianness_int32_t((void*)(d + 92), flags);
store_reverse_endianness_float_t((void*)(d + 96), ptcl->data.speed);
store_reverse_endianness_float_t((void*)(d + 100), ptcl->data.speed_random);
store_reverse_endianness_float_t((void*)(d + 104), ptcl->data.deceleration);
store_reverse_endianness_float_t((void*)(d + 108), ptcl->data.deceleration_random);
store_reverse_endianness_float_t((void*)(d + 112), ptcl->data.direction.x);
store_reverse_endianness_float_t((void*)(d + 116), ptcl->data.direction.y);
store_reverse_endianness_float_t((void*)(d + 120), ptcl->data.direction.z);
store_reverse_endianness_float_t((void*)(d + 124), ptcl->data.direction_random.x);
store_reverse_endianness_float_t((void*)(d + 128), ptcl->data.direction_random.y);
store_reverse_endianness_float_t((void*)(d + 132), ptcl->data.direction_random.z);
store_reverse_endianness_float_t((void*)(d + 136), ptcl->data.gravity.x);
store_reverse_endianness_float_t((void*)(d + 140), ptcl->data.gravity.y);
store_reverse_endianness_float_t((void*)(d + 144), ptcl->data.gravity.z);
store_reverse_endianness_float_t((void*)(d + 148), ptcl->data.acceleration.x);
store_reverse_endianness_float_t((void*)(d + 152), ptcl->data.acceleration.y);
store_reverse_endianness_float_t((void*)(d + 156), ptcl->data.acceleration.z);
store_reverse_endianness_float_t((void*)(d + 160), ptcl->data.acceleration_random.x);
store_reverse_endianness_float_t((void*)(d + 164), ptcl->data.acceleration_random.y);
store_reverse_endianness_float_t((void*)(d + 168), ptcl->data.acceleration_random.z);
store_reverse_endianness_float_t((void*)(d + 172), ptcl->data.reflection_coeff);
store_reverse_endianness_float_t((void*)(d + 176), ptcl->data.reflection_coeff_random);
store_reverse_endianness_float_t((void*)(d + 180), ptcl->data.rebound_plane_y);
store_reverse_endianness_float_t((void*)(d + 184), ptcl->data.uv_scroll_add.x);
store_reverse_endianness_float_t((void*)(d + 188), ptcl->data.uv_scroll_add.y);
store_reverse_endianness_float_t((void*)(d + 192), ptcl->data.uv_scroll_add_scale);
store_reverse_endianness_int32_t((void*)(d + 196), ptcl->data.sub_flags);
store_reverse_endianness_int32_t((void*)(d + 200), ptcl->data.count);
}
else {
*(int32_t*)d = ptcl->data.life_time;
*(int32_t*)(d + 4) = ptcl->data.type;
*(int32_t*)(d + 8) = ptcl->data.draw_type;
*(vec3*)(d + 12) = ptcl->data.rotation;
*(vec3*)(d + 24) = ptcl->data.rotation_random;
*(vec3*)(d + 36) = ptcl->data.rotation_add;
*(vec3*)(d + 48) = ptcl->data.rotation_add_random;
*(vec3*)(d + 60) = ptcl->data.scale;
*(vec3*)(d + 72) = ptcl->data.scale_random;
*(float_t*)(d + 84) = ptcl->data.z_offset;
*(int32_t*)(d + 88) = ptcl->data.pivot;
*(int32_t*)(d + 92) = flags;
*(float_t*)(d + 96) = ptcl->data.speed;
*(float_t*)(d + 100) = ptcl->data.speed_random;
*(float_t*)(d + 104) = ptcl->data.deceleration;
*(float_t*)(d + 108) = ptcl->data.deceleration_random;
*(vec3*)(d + 112) = ptcl->data.direction;
*(vec3*)(d + 124) = ptcl->data.direction_random;
*(vec3*)(d + 136) = ptcl->data.gravity;
*(vec3*)(d + 148) = ptcl->data.acceleration;
*(vec3*)(d + 160) = ptcl->data.acceleration_random;
*(float_t*)(d + 172) = ptcl->data.reflection_coeff;
*(float_t*)(d + 176) = ptcl->data.reflection_coeff_random;
*(float_t*)(d + 180) = ptcl->data.rebound_plane_y;
*(vec2*)(d + 184) = ptcl->data.uv_scroll_add;
*(float_t*)(d + 192) = ptcl->data.uv_scroll_add_scale;
*(int32_t*)(d + 196) = ptcl->data.sub_flags;
*(int32_t*)(d + 200) = ptcl->data.count;
}
d += 204;
if (ptcl->version == 3) {
*(int32_t*)d = 0;
if (big_endian) {
store_reverse_endianness_float_t((void*)d, ptcl->data.unk1);
store_reverse_endianness_float_t((void*)(d + 4), ptcl->data.emission);
}
else {
*(float_t*)d = ptcl->data.unk1;
*(float_t*)(d + 4) = ptcl->data.emission;
}
d += 8;
}
if (ptcl->data.type == PARTICLE_LOCUS || ptcl->data.type == PARTICLE_MESH) {
if (big_endian) {
store_reverse_endianness_uint16_t((void*)d, (uint16_t)ptcl->data.locus_history_size);
store_reverse_endianness_uint16_t((void*)(d + 2), (uint16_t)ptcl->data.locus_history_size_random);
}
else {
*(uint16_t*)d = (uint16_t)ptcl->data.locus_history_size;
*(uint16_t*)(d + 2) = (uint16_t)ptcl->data.locus_history_size_random;
}
d += 4;
}
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, ptcl->data.tex_hash);
*(uint8_t*)(d + 8) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 9) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 10) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 11) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f);
store_reverse_endianness_int32_t((void*)(d + 12), ptcl->data.blend_mode);
store_reverse_endianness_int32_t((void*)(d + 16), ptcl->data.unk2);
store_reverse_endianness_int32_t((void*)(d + 20), ptcl->data.split_u);
store_reverse_endianness_int32_t((void*)(d + 24), ptcl->data.split_v);
store_reverse_endianness_int32_t((void*)(d + 28), ptcl->data.uv_index_type);
store_reverse_endianness_int16_t((void*)(d + 32), (int16_t)ptcl->data.uv_index);
store_reverse_endianness_int16_t((void*)(d + 34), (int16_t)ptcl->data.frame_step_uv);
store_reverse_endianness_int32_t((void*)(d + 36), ptcl->data.uv_index_start);
store_reverse_endianness_int32_t((void*)(d + 40), ptcl->data.uv_index_end);
}
else {
*(uint64_t*)d = ptcl->data.tex_hash;
*(uint8_t*)(d + 8) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.x, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 9) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.y, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 10) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.z, 0.0f, 1.0f) * 255.0f);
*(uint8_t*)(d + 11) = (uint8_t)prj::roundf(clamp_def(ptcl->data.color.w, 0.0f, 1.0f) * 255.0f);
*(int32_t*)(d + 12) = ptcl->data.blend_mode;
*(int32_t*)(d + 16) = ptcl->data.unk2;
*(int32_t*)(d + 20) = ptcl->data.split_u;
*(int32_t*)(d + 24) = ptcl->data.split_v;
*(int32_t*)(d + 28) = ptcl->data.uv_index_type;
*(int16_t*)(d + 32) = (int16_t)ptcl->data.uv_index;
*(int16_t*)(d + 34) = (int16_t)ptcl->data.frame_step_uv;
*(int32_t*)(d + 36) = ptcl->data.uv_index_start;
*(int32_t*)(d + 40) = ptcl->data.uv_index_end;
}
d += 44;
if (eff_group->version >= 7) {
if (big_endian)
store_reverse_endianness_int32_t((void*)d, ptcl->data.unk3);
else
*(int32_t*)d = ptcl->data.unk3;
d += 4;
}
if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) {
if (big_endian) {
store_reverse_endianness_uint64_t((void*)d, ptcl->data.mask_tex_hash);
store_reverse_endianness_int32_t((void*)(d + 8), ptcl->data.mask_blend_mode);
store_reverse_endianness_int32_t((void*)(d + 12), ptcl->data.unk4);
}
else {
*(uint64_t*)d = ptcl->data.mask_tex_hash;
*(int32_t*)(d + 8) = ptcl->data.mask_blend_mode;
*(int32_t*)(d + 12) = ptcl->data.unk4;
}
d += 16;
}
}
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('PTCL');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
st->header.version = ptcl->version;
return true;
}
bool FileWriter::UnparseAnimation(f2_struct* st, Animation* anim, CurveTypeFlags flags, bool big_endian) {
if (anim->curves.size() < 1)
return false;
static const CurveType order[] = {
CURVE_COLOR_A,
CURVE_COLOR_R,
CURVE_COLOR_G,
CURVE_COLOR_B,
CURVE_COLOR_RGB_SCALE,
CURVE_COLOR_A_2ND,
CURVE_COLOR_R_2ND,
CURVE_COLOR_G_2ND,
CURVE_COLOR_B_2ND,
CURVE_COLOR_RGB_SCALE_2ND,
CURVE_TRANSLATION_X,
CURVE_TRANSLATION_Y,
CURVE_TRANSLATION_Z,
CURVE_ROTATION_X,
CURVE_ROTATION_Y,
CURVE_ROTATION_Z,
CURVE_SCALE_X,
CURVE_SCALE_Y,
CURVE_SCALE_Z,
CURVE_SCALE_ALL,
CURVE_EMISSION_INTERVAL,
CURVE_PARTICLES_PER_EMISSION,
CURVE_U_SCROLL,
CURVE_V_SCROLL,
CURVE_U_SCROLL_ALPHA,
CURVE_V_SCROLL_ALPHA,
CURVE_U_SCROLL_2ND,
CURVE_V_SCROLL_2ND,
CURVE_U_SCROLL_ALPHA_2ND,
CURVE_V_SCROLL_ALPHA_2ND,
};
for (int32_t i = CURVE_TRANSLATION_X; i <= CURVE_V_SCROLL_ALPHA_2ND; i++) {
if (!(flags & (1 << (size_t)order[i])))
continue;
for (Curve*& j : anim->curves) {
Curve* c = j;
if (!c || c->type != order[i])
continue;
f2_struct s;
if (UnparseCurve(&s, c, big_endian)) {
st->sub_structs.push_back(s);
break;
}
}
}
if (st->sub_structs.size() < 1)
return false;
st->header.signature = reverse_endianness_uint32_t('ANIM');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
return true;
}
bool FileWriter::UnparseCurve(f2_struct* st, Curve* c, bool big_endian) {
#if !defined(CRE_DEV)
if (c->keys.size() < 1)
return false;
#else
std::vector<Curve::Key> keys = c->keys;
if (c->keys_rev.size() < 1)
return false;
c->Recalculate(type);
if (!c->keys.size()) {
c->keys = keys;
return false;
}
#endif
size_t l;
size_t d;
l = 0;
uint32_t o;
enrs e;
enrs_entry ee;
if (type == Glitter::X) {
if (st->header.version == 1) {
ee = { 0, 2, 24, 1 };
ee.append(0, 4, ENRS_DWORD);
ee.append(0, 4, ENRS_WORD);
e.vec.push_back(ee);
l += o = 24;
l = align_val(l, 0x10);
st->data.resize(l);
d = (size_t)st->data.data();
if (st->header.use_big_endian) {
store_reverse_endianness_uint32_t((void*)d, c->type);
store_reverse_endianness_uint32_t((void*)(d + 4), c->repeat ? 1 : 0);
store_reverse_endianness_uint32_t((void*)(d + 8), c->flags);
store_reverse_endianness_float_t((void*)(d + 12), c->random_range);
store_reverse_endianness_uint16_t((void*)(d + 16), (uint16_t)c->keys.size());
store_reverse_endianness_uint16_t((void*)(d + 18), (uint16_t)c->start_time);
store_reverse_endianness_uint16_t((void*)(d + 20), (uint16_t)c->end_time);
}
else {
*(uint32_t*)d = c->type;
*(uint32_t*)(d + 4) = c->repeat ? 1 : 0;
*(uint32_t*)(d + 8) = c->flags;
*(float_t*)(d + 12) = c->random_range;
*(uint16_t*)(d + 16) = (uint16_t)c->keys.size();;;
*(uint16_t*)(d + 18) = c->start_time;
*(uint16_t*)(d + 20) = c->end_time;
}
}
else {
ee = { 0, 2, 36, 1 };
ee.append(0, 7, ENRS_DWORD);
ee.append(0, 4, ENRS_WORD);
e.vec.push_back(ee);
l += o = 36;
l = align_val(l, 0x10);
st->data.resize(l);
d = (size_t)st->data.data();
if (st->header.use_big_endian) {
store_reverse_endianness_uint32_t((void*)d, c->type);
store_reverse_endianness_uint32_t((void*)(d + 4), c->repeat ? 1 : 0);
store_reverse_endianness_uint32_t((void*)(d + 8), c->flags);
store_reverse_endianness_float_t((void*)(d + 12), c->random_range);
store_reverse_endianness_uint16_t((void*)(d + 28), (uint16_t)c->keys.size());
store_reverse_endianness_uint16_t((void*)(d + 30), (uint16_t)c->start_time);
store_reverse_endianness_uint16_t((void*)(d + 32), (uint16_t)c->end_time);
}
else {
*(uint32_t*)d = c->type;
*(uint32_t*)(d + 4) = c->repeat ? 1 : 0;
*(uint32_t*)(d + 8) = c->flags;
*(float_t*)(d + 12) = c->random_range;
*(uint16_t*)(d + 28) = (uint16_t)c->keys.size();;
*(uint16_t*)(d + 30) = c->start_time;
*(uint16_t*)(d + 32) = c->end_time;
}
}
}
else {
ee = { 0, 2, 24, 1 };
ee.append(0, 4, ENRS_DWORD);
ee.append(0, 4, ENRS_WORD);
e.vec.push_back(ee);
l += o = 24;
l = align_val(l, 0x10);
st->data.resize(l);
d = (size_t)st->data.data();
float_t random_range = c->random_range;
if (c->version == 0)
switch (c->type) {
case CURVE_ROTATION_X:
case CURVE_ROTATION_Y:
case CURVE_ROTATION_Z:
random_range = 0.0f;
break;
}
if (big_endian) {
store_reverse_endianness_uint32_t((void*)d, c->type);
store_reverse_endianness_uint32_t((void*)(d + 4), c->repeat ? 1 : 0);
store_reverse_endianness_uint32_t((void*)(d + 8), c->flags);
store_reverse_endianness_float_t((void*)(d + 12), random_range);
store_reverse_endianness_uint16_t((void*)(d + 16), (uint16_t)c->keys.size());
store_reverse_endianness_uint16_t((void*)(d + 18), (uint16_t)c->start_time);
store_reverse_endianness_uint16_t((void*)(d + 20), (uint16_t)c->end_time);
}
else {
*(uint32_t*)d = c->type;
*(uint32_t*)(d + 4) = c->repeat ? 1 : 0;
*(uint32_t*)(d + 8) = c->flags;
*(float_t*)(d + 12) = random_range;
*(uint16_t*)(d + 16) = (uint16_t)c->keys.size();
*(uint16_t*)(d + 18) = (uint16_t)c->start_time;
*(uint16_t*)(d + 20) = (uint16_t)c->end_time;
}
if (c->version == 0)
switch (c->type) {
case CURVE_ROTATION_X:
case CURVE_ROTATION_Y:
case CURVE_ROTATION_Z:
c->random_range = 0.0f;
break;
}
}
st->enrs = e;
st->header.signature = reverse_endianness_uint32_t('CURV');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
st->header.version = c->version;
f2_struct s;
PackCurve(&s, c, big_endian);
st->sub_structs.push_back(s);
#if defined(CRE_DEV)
c->keys = keys;
#endif
return true;
}
bool FileWriter::UnparseDivaEffect(EffectGroup* eff_group, f2_struct* st, bool big_endian) {
UnparseEffectGroup(eff_group, st, big_endian);
st->header.signature = reverse_endianness_uint32_t('DVEF');
st->header.length = 0x20;
st->header.use_big_endian = false;
st->header.use_section_size = true;
st->header.version = eff_group->version;
return true;
}
bool FileWriter::UnparseDivaList(EffectGroup* eff_group, f2_struct* st, bool big_endian) {
f2_struct s;
if (!PackDivaList(eff_group, &s, big_endian))
return false;
st->sub_structs.push_back(s);
st->header.signature = reverse_endianness_uint32_t('LIST');
st->header.length = 0x20;
st->header.use_big_endian = big_endian;
st->header.use_section_size = true;
return true;
}
bool FileWriter::UnparseDivaResource(EffectGroup* eff_group, f2_struct* st) {
f2_struct s;
if (!PackDivaResource(eff_group, &s))
return false;
st->sub_structs.push_back(s);
st->header.signature = reverse_endianness_uint32_t('DVRS');
st->header.length = 0x20;
st->header.use_big_endian = false;
st->header.use_section_size = true;
st->header.version = 1;
return true;
}
bool FileWriter::UnparseEffect(EffectGroup* eff_group, f2_struct* st, Effect* eff, bool big_endian) {
if (!PackEffect(st, eff, big_endian))
return false;
f2_struct s;
if (UnparseAnimation(&s, &eff->animation, effect_curve_flags, big_endian))
st->sub_structs.push_back(s);
for (Emitter*& i : eff->emitters) {
if (!i)
continue;
f2_struct s;
if (UnparseEmitter(eff_group, &s, i, eff, big_endian))
st->sub_structs.push_back(s);
}
return true;
}
void FileWriter::UnparseEffectGroup(EffectGroup* eff_group, f2_struct* st, bool big_endian) {
for (Effect*& i : eff_group->effects) {
if (!i)
continue;
f2_struct s;
if (UnparseEffect(eff_group, &s, i, big_endian))
st->sub_structs.push_back(s);
}
f2_struct s;
if (PackDivaResourceHashes(eff_group, &s, big_endian))
st->sub_structs.push_back(s);
}
bool FileWriter::UnparseEmitter(EffectGroup* eff_group,
f2_struct* st, Emitter* emit, Effect* eff, bool big_endian) {
if (!PackEmitter(st, emit, big_endian))
return false;
f2_struct s;
if (UnparseAnimation(&s, &emit->animation, emitter_curve_flags, big_endian))
st->sub_structs.push_back(s);
for (Particle*& i : emit->particles) {
if (!i)
continue;
f2_struct s;
if (UnparseParticle(eff_group, &s, i, eff, big_endian))
st->sub_structs.push_back(s);
}
return true;
}
bool FileWriter::UnparseParticle(EffectGroup* eff_group,
f2_struct* st, Particle* ptcl, Effect* eff, bool big_endian) {
if (!PackParticle(eff_group, st, ptcl, eff, big_endian))
return false;
CurveTypeFlags flags;
if (type == Glitter::X)
flags = particle_x_curve_flags;
else
flags = particle_curve_flags;
if (ptcl->data.type != PARTICLE_MESH) {
enum_and(flags, ~CURVE_TYPE_UV_SCROLL_2ND);
if (ptcl->data.draw_type != DIRECTION_PARTICLE_ROTATION)
enum_and(flags, ~(CURVE_TYPE_ROTATION_X | CURVE_TYPE_ROTATION_Y));
}
f2_struct s;
if (UnparseAnimation(&s, &ptcl->animation, flags, big_endian))
st->sub_structs.push_back(s);
return true;
}
void FileWriter::Write(GLT, EffectGroup* eff_group, const char* path,
const char* file, bool compress, bool encrypt, bool big_endian) {
FileWriter fr;
fr.type = GLT_VAL;
farc f;
{
size_t file_len = utf8_length(file);
char* temp = force_malloc<char>(file_len + 5);
if (!temp)
return;
memcpy(temp, file, file_len);
temp[file_len] = 0;
{
f2_struct dve_st;
if (fr.UnparseDivaEffect(eff_group, &dve_st, big_endian)) {
memcpy(&temp[file_len], ".dve", 4);
temp[file_len + 4] = 0;
farc_file* ff_dve = f.add_file(temp);
dve_st.write(&ff_dve->data, &ff_dve->size);
ff_dve->compressed = compress;
ff_dve->encrypted = encrypt;
}
else {
free(temp);
return;
}
}
{
f2_struct drs_st;
if (fr.UnparseDivaResource(eff_group, &drs_st)) {
memcpy(&temp[file_len], ".drs", 4);
temp[file_len + 4] = 0;
farc_file* ff_drs = f.add_file(temp);
drs_st.write(&ff_drs->data, &ff_drs->size);
ff_drs->compressed = compress;
ff_drs->encrypted = encrypt;
}
}
if (fr.type == Glitter::FT) {
f2_struct lst_st;
if (fr.UnparseDivaList(eff_group, &lst_st, big_endian)) {
memcpy(&temp[file_len], ".lst", 4);
temp[file_len + 4] = 0;
farc_file* ff_lst = f.add_file(temp);
lst_st.write(&ff_lst->data, &ff_lst->size);
ff_lst->compressed = compress;
ff_lst->encrypted = encrypt;
}
else {
free(temp);
return;
}
}
free(temp);
}
farc_signature signature;
farc_flags flags;
if (encrypt) {
signature = FARC_FARC;
flags = FARC_AES;
if (compress)
enum_or(flags, FARC_GZIP);
}
else if (compress) {
signature = FARC_FArC;
flags = FARC_NONE;
}
else {
signature = FARC_FArc;
flags = FARC_NONE;
}
char* temp = str_utils_add(path, file);
if (glt_type != Glitter::FT) {
char* list_temp = str_utils_add(temp, ".glitter.txt");
file_stream s;
s.open(list_temp, "wb");
if (s.check_not_null()) {
for (Glitter::Effect*& i : eff_group->effects)
if (i) {
s.write_string(i->name);
s.write_char('\n');
}
}
free_def(list_temp);
}
f.write(temp, signature, flags, false);
free_def(temp);
}
}