/* by korenkonder GitHub/GitLab: korenkonder */ #include "glitter.hpp" #include "../../KKdLib/io/path.hpp" #include "../../KKdLib/farc.hpp" #include "../data.hpp" #include "../object.hpp" namespace Glitter { FileReader::FileReader(GLT) : file_handler(), farc(), effect_group(), load_count(), state(), init_scene(), obj_db(), tex_db() { emission = -1.0f; type = GLT_VAL; hash = GLT_VAL != Glitter::FT ? hash_murmurhash_empty : hash_fnv1a64m_empty; } FileReader::FileReader(GLT, const char* path, const char* file, float_t emission) : file_handler(), farc(), effect_group(), load_count(), state(), init_scene(), obj_db(), tex_db() { this->path = path ? path : (GLT_VAL != Glitter::FT ? "root+/particle/" : "rom/particle/"); this->file = file; this->emission = emission; this->type = GLT_VAL; this->hash = GLT_VAL != Glitter::FT ? hash_utf8_murmurhash(file) : hash_utf8_fnv1a64m(file); } FileReader::FileReader(GLT, const wchar_t* path, const wchar_t* file, float_t emission) : file_handler(), farc(), effect_group(), load_count(), state(), init_scene(), obj_db(), tex_db() { char* path_temp = utf16_to_utf8(path); char* file_temp = utf16_to_utf8(file); this->path = path_temp ? path_temp : (GLT_VAL != Glitter::FT ? "root+/particle/" : "rom/particle/"); this->file = file_temp; this->emission = emission; this->type = GLT_VAL; this->hash = GLT_VAL != Glitter::FT ? hash_utf8_murmurhash(file_temp) : hash_utf8_fnv1a64m(file_temp); free_def(path_temp); free_def(file_temp); } FileReader::~FileReader() { delete farc; delete file_handler; } bool FileReader::CheckInit(GPM) { if (!effect_group) return true; bool ret = false; if (!effect_group->scene_init) { float_t v20 = Glitter::glt_particle_manager->field_D4; if (Glitter::glt_particle_manager->field_D4 > 0.0f) { if (effect_group->scene) { if (effect_group->scene->ResetCheckInit(GPM_VAL, &v20)) ret = true; else effect_group->scene_init = true; glt_particle_manager->sub_1403A53E0(v20); } else effect_group->scene_init = true; } else ret = true; } #if defined(CRE_DEV) if (type == Glitter::X) for (Mesh& i : effect_group->meshes) if (!i.ready && i.object_set_hash != hash_murmurhash_empty && i.object_set_hash != -1) if (object_storage_load_obj_set_check_not_read(i.object_set_hash, obj_db, tex_db)) ret = true; else i.ready = true; #endif if (!ret) { effect_group = 0; return true; } return false; } bool FileReader::LoadFarc(void* data, const char* path, const char* file, uint64_t hash, object_database* obj_db, texture_database* tex_db) { this->obj_db = obj_db; this->tex_db = tex_db; if (type == Glitter::FT && this->hash != hash_fnv1a64m_empty || type != Glitter::FT && this->hash != hash_murmurhash_empty) return false; this->path = path; this->file = file; std::string file_temp = this->file + ".farc"; file_handler = new p_file_handler; farc = new ::farc; if (file_handler->read_file(data, path, file_temp.c_str())) { this->hash = hash; load_count = 1; return true; } return false; } void FileReader::ParseAnimation(f2_struct* st, Animation* anim) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('ANIM')) return; for (f2_struct& i : st->sub_structs) ParseCurve(&i, anim); } void FileReader::ParseCurve(f2_struct* st, Animation* anim) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('CURV')) return; Curve* c = new Curve(type); if (!c) return; c->version = st->header.version; size_t d = (size_t)st->data.data(); uint32_t keys_count; if (type == Glitter::X) { if (st->header.version == 1) { if (st->header.use_big_endian) { c->type = (CurveType)load_reverse_endianness_uint32_t((void*)d); c->repeat = load_reverse_endianness_uint32_t((void*)(d + 4)) != 0; c->flags = (CurveFlag)load_reverse_endianness_uint32_t((void*)(d + 8)); c->random_range = load_reverse_endianness_float_t((void*)(d + 12)); keys_count = (uint32_t)load_reverse_endianness_int16_t((void*)(d + 16)); c->start_time = load_reverse_endianness_int16_t((void*)(d + 18)); c->end_time = load_reverse_endianness_int16_t((void*)(d + 20)); } else { c->type = (CurveType) * (uint32_t*)d; c->repeat = *(uint32_t*)(d + 4) != 0; c->flags = (CurveFlag) * (uint32_t*)(d + 8); c->random_range = *(float_t*)(d + 12); keys_count = *(uint16_t*)(d + 16); c->start_time = *(uint16_t*)(d + 18); c->end_time = *(uint16_t*)(d + 20); } } else { if (st->header.use_big_endian) { c->type = (CurveType)load_reverse_endianness_uint32_t((void*)d); c->repeat = load_reverse_endianness_uint32_t((void*)(d + 4)) != 0; c->flags = (CurveFlag)load_reverse_endianness_uint32_t((void*)(d + 8)); c->random_range = load_reverse_endianness_float_t((void*)(d + 12)); keys_count = (uint32_t)load_reverse_endianness_uint16_t((void*)(d + 28)); c->start_time = load_reverse_endianness_uint16_t((void*)(d + 30)); c->end_time = load_reverse_endianness_uint16_t((void*)(d + 32)); } else { c->type = (CurveType) * (uint32_t*)d; c->repeat = *(uint32_t*)(d + 4) != 0; c->flags = (CurveFlag) * (uint32_t*)(d + 8); c->random_range = *(float_t*)(d + 12); keys_count = *(uint16_t*)(d + 28); c->start_time = *(uint16_t*)(d + 30); c->end_time = *(uint16_t*)(d + 32); } } } else { if (st->header.use_big_endian) { c->type = (CurveType)load_reverse_endianness_uint32_t((void*)d); c->repeat = load_reverse_endianness_uint32_t((void*)(d + 4)) != 0; c->flags = (CurveFlag)load_reverse_endianness_uint32_t((void*)(d + 8)); c->random_range = load_reverse_endianness_float_t((void*)(d + 12)); keys_count = load_reverse_endianness_uint16_t((void*)(d + 16)); c->start_time = load_reverse_endianness_uint16_t((void*)(d + 18)); c->end_time = load_reverse_endianness_uint16_t((void*)(d + 20)); } else { c->type = (CurveType) * (uint32_t*)d; c->repeat = *(uint32_t*)(d + 4) != 0; c->flags = (CurveFlag) * (uint32_t*)(d + 8); c->random_range = *(float_t*)(d + 12); keys_count = *(uint16_t*)(d + 16); c->start_time = *(uint16_t*)(d + 18); c->end_time = *(uint16_t*)(d + 20); } 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; } } for (f2_struct& i : st->sub_structs) if (i.header.data_size && i.header.signature == reverse_endianness_uint32_t('KEYS')) { UnpackCurve(i.data.data(), anim, c, keys_count, i.header.version, i.header.use_big_endian); break; } anim->curves.push_back(c); } bool FileReader::ParseDivaEffect(GPM, f2_struct* st) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('DVEF')) return false; uint32_t dvef_version = st->header.version; EffectGroup* eff_group = new EffectGroup(type); if (!eff_group) return false; eff_group->scene = 0; if (!ParseEffectGroup(st, &eff_group->effects, eff_group)) { eff_group->not_loaded = true; if (GPM_VAL->AppendEffectGroup(hash, eff_group, this)) return true; } else if (GPM_VAL->AppendEffectGroup(hash, eff_group, this)) { #if defined(CRE_DEV) if (type == Glitter::X) for (Mesh& i : eff_group->meshes) if (i.object_set_hash != hash_murmurhash_empty) { object_storage_load_set_hash(file_handler->ptr->ds, i.object_set_hash); i.load = true; } #endif if (!init_scene) return true; effect_group = eff_group; int32_t id = 1; for (Effect*& i : eff_group->effects) { if (i->data.start_time <= 0.0f) { id++; continue; } if (!effect_group->scene) effect_group->scene = new Scene(0, type == Glitter::FT ? hash_fnv1a64m_empty : hash_murmurhash_empty, eff_group, true); if (effect_group->scene) effect_group->scene->InitEffect(GPM_VAL, i, id, true); id++; } return true; } delete eff_group; return false; } bool FileReader::ParseDivaList(f2_struct* st, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('LIST')) return false; for (f2_struct& i : st->sub_structs) if (UnpackDivaList(&i, eff_group)) break; return true; } bool FileReader::ParseDivaResource(GPM, f2_struct* st, EffectGroup* eff_group) { if (!st || !st->header.data_size) return false; for (f2_struct& i : st->sub_structs) if (UnpackDivaResource(GPM_VAL, &i, eff_group)) break; return true; } bool FileReader::ParseEffect(f2_struct* st, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('EFCT')) return false; Effect* eff = new Effect(type); if (!UnpackEffect(st->data.data(), eff, st->header.version, st->header.use_big_endian)) { delete eff; return false; } ParseAnimation(st->sub_structs.size() ? st->sub_structs.data() : 0, &eff->animation); for (f2_struct& i : st->sub_structs) ParseEmitter(&i, eff, eff_group); eff_group->effects.push_back(eff); return true; } bool FileReader::ParseEffectGroup(f2_struct* st, std::vector* vec, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('DVEF')) return false; for (f2_struct& i : st->sub_structs) { if (!i.header.data_size) continue; if (i.header.signature == reverse_endianness_uint32_t('EFCT')) { if (!ParseEffect(&i, eff_group)) return false; } else if (i.header.signature == reverse_endianness_uint32_t('DVRS') && !UnpackDivaResourceHashes(&i, eff_group)) return false; } return true; } bool FileReader::ParseEmitter(f2_struct* st, Effect* eff, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('EMIT')) return false; Emitter* emit = new Emitter(type); if (!UnpackEmitter(st->data.data(), emit, st->header.version, st->header.use_big_endian)) { delete emit; return false; } ParseAnimation(st->sub_structs.size() ? st->sub_structs.data() : 0, &emit->animation); for (f2_struct& i : st->sub_structs) ParseParticle(&i, emit, eff, eff_group); eff->emitters.push_back(emit); return true; } bool FileReader::ParseParticle(f2_struct* st, Emitter* emit, Effect* eff, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('PTCL')) return false; Particle* ptcl = new Particle(type); if (!UnpackParticle(st->data.data(), ptcl, st->header.version, eff, st->header.use_big_endian, eff_group)) { delete ptcl; return false; } ParseAnimation(st->sub_structs.size() ? st->sub_structs.data() : 0, &ptcl->animation); emit->particles.push_back(ptcl); return true; } bool FileReader::Read(GPM) { std::string dve_file = file + ".dve"; farc_file* dve_ff = farc->read_file(dve_file.c_str()); if (!dve_ff) return false; f2_struct st; st.read(dve_ff->data, dve_ff->size); if (st.header.signature != reverse_endianness_uint32_t('DVEF')) return false; if (!ParseDivaEffect(GPM_VAL, &st)) { EffectGroup* eff_group = new EffectGroup(type); if (eff_group) { eff_group->not_loaded = true; if (!GPM_VAL->AppendEffectGroup(hash, eff_group, this)) delete eff_group; } return false; } EffectGroup* eff_group = GPM_VAL->GetEffectGroup(hash); if (!eff_group) return false; std::string drs_file = file + ".drs"; farc_file* drs_ff = farc->read_file(drs_file.c_str()); if (drs_ff) { f2_struct st; st.read(drs_ff->data, drs_ff->size); if (st.header.signature == reverse_endianness_uint32_t('DVRS')) ParseDivaResource(GPM_VAL, &st, eff_group); } std::string lst_file = file + ".lst"; farc_file* lst_ff = farc->read_file(lst_file.c_str()); if (lst_ff) { f2_struct st; st.read(lst_ff->data, lst_ff->size); if (st.header.signature == reverse_endianness_uint32_t('LIST')) ParseDivaList(&st, eff_group); } return true; } bool FileReader::ReadFarc(GPM) { if (state) { if (state == 1) if (CheckInit(GPM_VAL)) state = 2; else return false; return true; } if (file_handler && !file_handler->check_not_ready()) { farc->read(file_handler->get_data(), file_handler->get_size(), true); if (Read(GPM_VAL) && init_scene) state = 1; else return true; } return false; } void FileReader::UnpackCurve(void* data, Animation* anim, Curve* c, uint32_t count, uint32_t keys_version, bool big_endian) { if (!data || !c || count < 1) return; c->keys_version = keys_version; size_t d = (size_t)data; Curve::Key key; key.type = KEY_CONSTANT; key.frame = 0; key.value = 0.0f; key.tangent1 = 0.0f; key.tangent2 = 0.0f; key.random_range = 0.0f; std::vector& keys = c->keys; keys.reserve(count); if (type == Glitter::X) { if (c->keys_version == 2) { if (big_endian) if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)); key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)); key.random_range = load_reverse_endianness_float_t((void*)(d + 12)); key.value = load_reverse_endianness_float_t((void*)(d + 16)); keys.push_back(key); d += 20; } else { key.random_range = load_reverse_endianness_float_t((void*)(d + 4)); key.value = load_reverse_endianness_float_t((void*)(d + 8)); keys.push_back(key); d += 12; } } else for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)); key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)); key.value = load_reverse_endianness_float_t((void*)(d + 12)); keys.push_back(key); d += 16; } else { key.value = load_reverse_endianness_float_t((void*)(d + 4)); keys.push_back(key); d += 8; } } else if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4); key.tangent2 = *(float_t*)(d + 8); key.random_range = *(float_t*)(d + 12); key.value = *(float_t*)(d + 16); keys.push_back(key); d += 20; } else { key.random_range = *(float_t*)(d + 4); key.value = *(float_t*)(d + 8); keys.push_back(key); d += 12; } } else for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4); key.tangent2 = *(float_t*)(d + 8); key.value = *(float_t*)(d + 12); keys.push_back(key); d += 16; } else { key.value = *(float_t*)(d + 4); keys.push_back(key); d += 8; } } } else { if (big_endian) if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 16)); key.tangent2 = load_reverse_endianness_float_t((void*)(d + 20)); key.random_range = load_reverse_endianness_float_t((void*)(d + 24)); key.value = load_reverse_endianness_float_t((void*)(d + 28)); keys.push_back(key); d += 32; } else { key.random_range = load_reverse_endianness_float_t((void*)(d + 8)); key.value = load_reverse_endianness_float_t((void*)(d + 12)); keys.push_back(key); d += 16; } } else for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)); key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)); key.value = load_reverse_endianness_float_t((void*)(d + 12)); keys.push_back(key); d += 16; } else { key.value = load_reverse_endianness_float_t((void*)(d + 12)); keys.push_back(key); d += 16; } } else if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 16); key.tangent2 = *(float_t*)(d + 20); key.random_range = *(float_t*)(d + 24); key.value = *(float_t*)(d + 28); keys.push_back(key); d += 32; } else { key.random_range = *(float_t*)(d + 8); key.value = *(float_t*)(d + 12); keys.push_back(key); d += 16; } } else for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4); key.tangent2 = *(float_t*)(d + 8); key.value = *(float_t*)(d + 12); keys.push_back(key); d += 16; } else { key.value = *(float_t*)(d + 12); keys.push_back(key); 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 = DEG_TO_RAD_FLOAT; break; case CURVE_COLOR_R: case CURVE_COLOR_G: case CURVE_COLOR_B: case CURVE_COLOR_A: scale = (float_t)(1.0 / 255.0); break; } if (big_endian) if (scale == 1.0f) if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)); key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)); key.random_range = load_reverse_endianness_float_t((void*)(d + 12)); key.value = load_reverse_endianness_float_t((void*)(d + 16)); keys.push_back(key); d += 20; } else { key.random_range = load_reverse_endianness_float_t((void*)(d + 4)); key.value = load_reverse_endianness_float_t((void*)(d + 8)); keys.push_back(key); d += 12; } } else for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)); key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)); key.value = load_reverse_endianness_float_t((void*)(d + 12)); keys.push_back(key); d += 16; } else { key.value = load_reverse_endianness_float_t((void*)(d + 4)); keys.push_back(key); d += 8; } } else if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)) * scale; key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)) * scale; key.random_range = load_reverse_endianness_float_t((void*)(d + 12)) * scale; key.value = load_reverse_endianness_float_t((void*)(d + 16)) * scale; keys.push_back(key); d += 20; } else { key.random_range = load_reverse_endianness_float_t((void*)(d + 4)) * scale; key.value = load_reverse_endianness_float_t((void*)(d + 8)) * scale; keys.push_back(key); d += 12; } } else for (size_t i = count; i; i--) { key.type = (KeyType)load_reverse_endianness_int16_t((void*)d); key.frame = load_reverse_endianness_int16_t((void*)(d + 2)); if (key.type == KEY_HERMITE) { key.tangent1 = load_reverse_endianness_float_t((void*)(d + 4)) * scale; key.tangent2 = load_reverse_endianness_float_t((void*)(d + 8)) * scale; key.value = load_reverse_endianness_float_t((void*)(d + 12)) * scale; keys.push_back(key); d += 16; } else { key.value = load_reverse_endianness_float_t((void*)(d + 4)) * scale; keys.push_back(key); d += 8; } } else if (scale == 1.0f) if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4); key.tangent2 = *(float_t*)(d + 8); key.random_range = *(float_t*)(d + 12); key.value = *(float_t*)(d + 16); keys.push_back(key); d += 20; } else { key.random_range = *(float_t*)(d + 4); key.value = *(float_t*)(d + 8); keys.push_back(key); d += 12; } } else for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4); key.tangent2 = *(float_t*)(d + 8); key.value = *(float_t*)(d + 12); keys.push_back(key); d += 16; } else { key.value = *(float_t*)(d + 4); keys.push_back(key); d += 8; } } else if (c->flags & CURVE_KEY_RANDOM_RANGE) for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4) * scale; key.tangent2 = *(float_t*)(d + 8) * scale; key.random_range = *(float_t*)(d + 12) * scale; key.value = *(float_t*)(d + 16) * scale; keys.push_back(key); d += 20; } else { key.random_range = *(float_t*)(d + 4) * scale; key.value = *(float_t*)(d + 8) * scale; keys.push_back(key); d += 12; } } else for (size_t i = count; i; i--) { key.type = (KeyType) * (int16_t*)d; key.frame = *(int16_t*)(d + 2); if (key.type == KEY_HERMITE) { key.tangent1 = *(float_t*)(d + 4) * scale; key.tangent2 = *(float_t*)(d + 8) * scale; key.value = *(float_t*)(d + 12) * scale; keys.push_back(key); d += 16; } else { key.value = *(float_t*)(d + 4) * scale; keys.push_back(key); d += 8; } } } #if defined(CRE_DEV) extern bool glitter_editor_enable; if (glitter_editor_enable) c->FitKeysIntoCurve(type); #endif } bool FileReader::UnpackDivaList(f2_struct* st, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('GEFF')) return false; size_t d = (size_t)st->data.data(); uint32_t length; if (st->header.use_big_endian) length = load_reverse_endianness_uint32_t((void*)d); else length = *(uint32_t*)d; if (length != eff_group->effects.size()) { for (Effect*& i : eff_group->effects) if (i) i->name.clear(); return false; } if (length) { d += 0x04; for (Effect*& i : eff_group->effects) { if (i) { char buf[0x80]; memcpy(buf, (void*)d, 0x80); buf[0x7F] = 0; i->name.assign(buf); } d += 0x80; } } return true; } bool FileReader::UnpackDivaResource(GPM, f2_struct* st, EffectGroup* eff_group) { if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('TXPC')) return false; eff_group->resources_tex.unpack_file(st->data.data(), st->header.use_big_endian); if (!eff_group->resources_count) return false; size_t count = eff_group->resources_tex.textures.size(); if (count < 1 || eff_group->resources_count < 1 || eff_group->resources_count != count) return false; texture_id* ids = force_malloc(count); for (size_t i = 0; i < count; i++) { ids[i] = texture_id(0x2A, GPM_VAL->texture_counter); GPM_VAL->texture_counter++; } if (!texture_txp_set_load(&eff_group->resources_tex, &eff_group->resources, ids)) { free_def(ids); return false; } free_def(ids); for (Effect*& i : eff_group->effects) { if (!i) continue; for (Emitter*& j : i->emitters) { if (!j) continue; for (Particle*& k : j->particles) { if (!k) continue; k->data.texture = 0; k->data.mask_texture = 0; if (k->data.type == PARTICLE_LINE || k->data.type == PARTICLE_MESH) continue; for (size_t l = 0; l < eff_group->resources_count; l++) { if (k->data.tex_hash == eff_group->resource_hashes[l]) k->data.texture = eff_group->resources[l]->tex; if (k->data.mask_tex_hash == eff_group->resource_hashes[l]) k->data.mask_texture = eff_group->resources[l]->tex; } } } } return true; } bool FileReader::UnpackDivaResourceHashes(f2_struct* st, EffectGroup* eff_group) { if (eff_group->resources_count && eff_group->resource_hashes.size() > 0) return true; else if (!st || !st->header.data_size || st->header.signature != reverse_endianness_uint32_t('DVRS')) return false; size_t d = (size_t)st->data.data(); if (!d) return false; uint32_t count; if (st->header.use_big_endian) count = load_reverse_endianness_uint32_t((void*)d); else count = *(int32_t*)d; d += 8; eff_group->resources_count = count; if (count) { eff_group->resource_hashes = std::vector(count); uint64_t* resource_hashes = eff_group->resource_hashes.data(); if (!resource_hashes) return false; if (st->header.use_big_endian) for (size_t i = count; i; i--, resource_hashes++, d += sizeof(uint64_t)) *resource_hashes = load_reverse_endianness_uint64_t((void*)d); else memcpy(resource_hashes, (void*)d, sizeof(uint64_t) * count); } return true; } bool FileReader::UnpackEffect(void* data, Effect* eff, int32_t efct_version, bool big_endian) { eff->version = efct_version; if (type == Glitter::X) { eff->scale = 1.0f; eff->data.start_time = 0; eff->data.ext_anim_x = 0; eff->data.flags = (EffectFlag)0; eff->data.name_hash = hash_murmurhash_empty; eff->data.seed = 0; if (eff->version < 8 || eff->version > 12) return false; size_t d = (size_t)data; EffectFileFlag flags; if (big_endian) { eff->data.name_hash = load_reverse_endianness_uint64_t((void*)d); eff->data.appear_time = load_reverse_endianness_int32_t((void*)(d + 8)); eff->data.life_time = load_reverse_endianness_int32_t((void*)(d + 12)); eff->data.start_time = load_reverse_endianness_int32_t((void*)(d + 16)); eff->data.color.b = *(uint8_t*)(d + 20); eff->data.color.g = *(uint8_t*)(d + 21); eff->data.color.r = *(uint8_t*)(d + 22); eff->data.color.a = *(uint8_t*)(d + 23); if (load_reverse_endianness_int32_t((void*)(d + 24))) enum_or(eff->data.flags, EFFECT_LOOP); eff->translation.x = load_reverse_endianness_float_t((void*)(d + 28)); eff->translation.y = load_reverse_endianness_float_t((void*)(d + 32)); eff->translation.z = load_reverse_endianness_float_t((void*)(d + 36)); eff->rotation.x = load_reverse_endianness_float_t((void*)(d + 40)); eff->rotation.y = load_reverse_endianness_float_t((void*)(d + 44)); eff->rotation.z = load_reverse_endianness_float_t((void*)(d + 48)); flags = (EffectFileFlag)load_reverse_endianness_int32_t((void*)(d + 52)); } else { eff->data.name_hash = *(uint64_t*)data; eff->data.appear_time = *(int32_t*)(d + 8); eff->data.life_time = *(int32_t*)(d + 12); eff->data.start_time = *(int32_t*)(d + 16); eff->data.color.b = *(uint8_t*)(d + 20); eff->data.color.g = *(uint8_t*)(d + 21); eff->data.color.r = *(uint8_t*)(d + 22); eff->data.color.a = *(uint8_t*)(d + 23); if (*(int32_t*)(d + 24)) enum_or(eff->data.flags, EFFECT_LOOP); eff->translation = *(vec3*)(d + 28); eff->rotation = *(vec3*)(d + 40); flags = (EffectFileFlag) * (int32_t*)(d + 52); } d += 56; if (flags & EFFECT_FILE_ALPHA) enum_or(eff->data.flags, EFFECT_ALPHA); if (flags & EFFECT_FILE_FOG) enum_or(eff->data.flags, EFFECT_FOG); else if (flags & EFFECT_FILE_FOG_HEIGHT) enum_or(eff->data.flags, EFFECT_FOG_HEIGHT); if (flags & EFFECT_FILE_EMISSION) enum_or(eff->data.flags, EFFECT_EMISSION); if (flags & EFFECT_FILE_USE_SEED) enum_or(eff->data.flags, EFFECT_USE_SEED); if (eff->version != 8 && flags & 0x20) enum_or(eff->data.flags, 0x80); if (big_endian) { eff->data.emission = load_reverse_endianness_float_t((void*)d); eff->data.seed = load_reverse_endianness_int32_t((void*)(d + 4)); eff->data.unk = load_reverse_endianness_float_t((void*)(d + 8)); } else { eff->data.emission = *(float_t*)d; eff->data.seed = *(int32_t*)(d + 4); eff->data.unk = *(float_t*)(d + 8); } d += 12; if (eff->version != 8) d += 8; else d += 12; int32_t type; if (big_endian) type = load_reverse_endianness_int32_t((void*)d); else type = *(int32_t*)d; if (eff->version != 8) d += 4; else d += 8; if (type == 1) enum_or(eff->data.flags, EFFECT_LOCAL); else if (type == 2) { Effect::ExtAnimX* ext_anim_x = force_malloc(); eff->data.ext_anim_x = ext_anim_x; if (ext_anim_x) { if (big_endian) { ext_anim_x->chara_index = load_reverse_endianness_int32_t((void*)d); ext_anim_x->flags = (EffectExtAnimFlag) load_reverse_endianness_int32_t((void*)(d + 4)); ext_anim_x->node_index = (EffectExtAnimCharaNode) load_reverse_endianness_int32_t((void*)(d + 8)); } else { ext_anim_x->chara_index = *(int32_t*)d; ext_anim_x->flags = (EffectExtAnimFlag) * (int32_t*)(d + 4); ext_anim_x->node_index = (EffectExtAnimCharaNode) * (int32_t*)(d + 8); } enum_or(ext_anim_x->flags, EFFECT_EXT_ANIM_CHARA_ANIM); } } else if (type == 3) { if (eff->version == 8) { Effect::ExtAnimX* ext_anim_x = force_malloc(); eff->data.ext_anim_x = ext_anim_x; if (ext_anim_x) { if (big_endian) { ext_anim_x->object_hash = (uint32_t) load_reverse_endianness_uint64_t((void*)d); ext_anim_x->flags = (EffectExtAnimFlag) load_reverse_endianness_int32_t((void*)(d + 8)); } else { ext_anim_x->object_hash = (uint32_t) * (uint64_t*)d; ext_anim_x->flags = (EffectExtAnimFlag) * (int32_t*)(d + 8); } ext_anim_x->instance_id = 0; ext_anim_x->file_name_hash = hash_murmurhash_empty; if (*(char*)(d + 12)) { strncpy_s(ext_anim_x->mesh_name, 0x80, (char*)(d + 12), 0x7F); ext_anim_x->mesh_name[0x7F] = 0; } else ext_anim_x->mesh_name[0] = 0; } } else if (eff->version == 10) { Effect::ExtAnimX* ext_anim_x = force_malloc(); eff->data.ext_anim_x = ext_anim_x; if (ext_anim_x) { if (big_endian) { ext_anim_x->object_hash = (uint32_t) load_reverse_endianness_uint64_t((void*)d); ext_anim_x->flags = (EffectExtAnimFlag) load_reverse_endianness_int32_t((void*)(d + 8)); } else { ext_anim_x->object_hash = (uint32_t) * (uint64_t*)d; ext_anim_x->flags = (EffectExtAnimFlag) * (int32_t*)(d + 8); } ext_anim_x->instance_id = 0; ext_anim_x->file_name_hash = hash_murmurhash_empty; if (*(char*)(d + 16)) { strncpy_s(ext_anim_x->mesh_name, 0x80, (char*)(d + 16), 0x7F); ext_anim_x->mesh_name[0x7F] = 0; } else ext_anim_x->mesh_name[0] = 0; } } else { Effect::ExtAnimX* ext_anim_x = force_malloc(); eff->data.ext_anim_x = ext_anim_x; if (ext_anim_x) { if (big_endian) { ext_anim_x->object_hash = (uint32_t) load_reverse_endianness_uint64_t((void*)d); ext_anim_x->flags = (EffectExtAnimFlag) load_reverse_endianness_int32_t((void*)(d + 8)); ext_anim_x->instance_id = load_reverse_endianness_int32_t((void*)(d + 12)); ext_anim_x->file_name_hash = (uint32_t) load_reverse_endianness_uint64_t((void*)(d + 16)); } else { ext_anim_x->object_hash = (uint32_t) * (uint64_t*)d; ext_anim_x->flags = (EffectExtAnimFlag) * (int32_t*)(d + 8); ext_anim_x->instance_id = *(int32_t*)(d + 12); ext_anim_x->file_name_hash = (uint32_t) * (uint64_t*)(d + 16); } if (*(char*)(d + 32)) { strncpy_s(ext_anim_x->mesh_name, 0x80, (char*)(d + 32), 0x7F); ext_anim_x->mesh_name[0x7F] = 0; } else ext_anim_x->mesh_name[0] = 0; } } } } else { eff->scale = 1.0f; eff->data.start_time = 0; eff->data.ext_anim = 0; eff->data.flags = (EffectFlag)0; eff->data.name_hash = type != Glitter::FT ? hash_murmurhash_empty : hash_fnv1a64m_empty; eff->data.seed = 0; if (eff->version < 6 || eff->version > 7) return false; size_t d = (size_t)data; EffectFileFlag flags; if (big_endian) { eff->data.name_hash = load_reverse_endianness_uint64_t((void*)d); eff->data.appear_time = load_reverse_endianness_int32_t((void*)(d + 8)); eff->data.life_time = load_reverse_endianness_int32_t((void*)(d + 12)); eff->data.start_time = load_reverse_endianness_int32_t((void*)(d + 16)); eff->data.color.b = *(uint8_t*)(d + 20); eff->data.color.g = *(uint8_t*)(d + 21); eff->data.color.r = *(uint8_t*)(d + 22); eff->data.color.a = *(uint8_t*)(d + 23); if (load_reverse_endianness_int32_t((void*)(d + 24))) enum_or(eff->data.flags, EFFECT_LOOP); eff->translation.x = load_reverse_endianness_float_t((void*)(d + 28)); eff->translation.y = load_reverse_endianness_float_t((void*)(d + 32)); eff->translation.z = load_reverse_endianness_float_t((void*)(d + 36)); eff->rotation.x = load_reverse_endianness_float_t((void*)(d + 40)); eff->rotation.y = load_reverse_endianness_float_t((void*)(d + 44)); eff->rotation.z = load_reverse_endianness_float_t((void*)(d + 48)); flags = (EffectFileFlag)load_reverse_endianness_int32_t((void*)(d + 52)); } else { eff->data.name_hash = *(uint64_t*)data; eff->data.appear_time = *(int32_t*)(d + 8); eff->data.life_time = *(int32_t*)(d + 12); eff->data.start_time = *(int32_t*)(d + 16); eff->data.color.b = *(uint8_t*)(d + 20); eff->data.color.g = *(uint8_t*)(d + 21); eff->data.color.r = *(uint8_t*)(d + 22); eff->data.color.a = *(uint8_t*)(d + 23); if (*(int32_t*)(d + 24)) enum_or(eff->data.flags, EFFECT_LOOP); eff->translation = *(vec3*)(d + 28); eff->rotation = *(vec3*)(d + 40); flags = (EffectFileFlag) * (int32_t*)(d + 52); } d += 56; if (flags & EFFECT_FILE_ALPHA) enum_or(eff->data.flags, EFFECT_ALPHA); if (flags & EFFECT_FILE_FOG) enum_or(eff->data.flags, EFFECT_FOG); else if (flags & EFFECT_FILE_FOG_HEIGHT) enum_or(eff->data.flags, EFFECT_FOG_HEIGHT); if (flags & EFFECT_FILE_EMISSION) enum_or(eff->data.flags, EFFECT_EMISSION); if (eff->version == 7) { if (big_endian) eff->data.emission = load_reverse_endianness_float_t((void*)d); else eff->data.emission = *(float_t*)d; d += 4; } int32_t type; if (big_endian) type = load_reverse_endianness_int32_t((void*)d); else type = *(int32_t*)d; d += 4; if (type == 1) enum_or(eff->data.flags, EFFECT_LOCAL); else if (type == 2) { Effect::ExtAnim* ext_anim = force_malloc(); eff->data.ext_anim = ext_anim; if (ext_anim) { if (big_endian) { ext_anim->chara_index = load_reverse_endianness_int32_t((void*)d); ext_anim->flags = (EffectExtAnimFlag) load_reverse_endianness_int32_t((void*)(d + 4)); ext_anim->node_index = (EffectExtAnimCharaNode) load_reverse_endianness_int32_t((void*)(d + 8)); } else { ext_anim->chara_index = *(int32_t*)d; ext_anim->flags = (EffectExtAnimFlag) * (int32_t*)(d + 4); ext_anim->node_index = (EffectExtAnimCharaNode) * (int32_t*)(d + 8); } enum_or(ext_anim->flags, EFFECT_EXT_ANIM_CHARA_ANIM); } } else if (type == 3) { Effect::ExtAnim* ext_anim = force_malloc(); eff->data.ext_anim = ext_anim; if (ext_anim) { if (big_endian) { ext_anim->object_hash = load_reverse_endianness_uint64_t((void*)d); ext_anim->flags = (EffectExtAnimFlag) load_reverse_endianness_int32_t((void*)(d + 8)); } else { ext_anim->object_hash = *(uint64_t*)d; ext_anim->flags = (EffectExtAnimFlag) * (int32_t*)(d + 8); } ext_anim->object = obj_db->get_object_info_by_fnv1a64m_hash_upper(ext_anim->object_hash); ext_anim->node_index = EFFECT_EXT_ANIM_CHARA_MAX; if (*(char*)(d + 12)) { strncpy_s(ext_anim->mesh_name, 0x80, (char*)(d + 12), 0x7F); ext_anim->mesh_name[0x7F] = 0; } else ext_anim->mesh_name[0x00] = 0; } } } return true; } bool FileReader::UnpackEmitter(void* data, Emitter* emit, uint32_t emit_version, bool big_endian) { emit->version = emit_version; if (type == Glitter::X) { size_t d = (size_t)data; if (big_endian) { emit->data.start_time = load_reverse_endianness_int32_t((void*)d); emit->data.life_time = load_reverse_endianness_int32_t((void*)(d + 4)); emit->data.loop_start_time = load_reverse_endianness_int32_t((void*)(d + 8)); emit->data.loop_end_time = load_reverse_endianness_int32_t((void*)(d + 12)); emit->data.flags = (EmitterFlag) load_reverse_endianness_int32_t((void*)(d + 16)); } else { emit->data.start_time = *(int32_t*)d; emit->data.life_time = *(int32_t*)(d + 4); emit->data.loop_start_time = *(int32_t*)(d + 8); emit->data.loop_end_time = *(int32_t*)(d + 12); emit->data.flags = (EmitterFlag) * (int32_t*)(d + 16); } d += 20; if (emit->version < 3 || emit->version > 4) return false; if (big_endian) { emit->data.type = (EmitterType) load_reverse_endianness_int16_t((void*)d); emit->data.direction = (Direction) load_reverse_endianness_int16_t((void*)(d + 2)); emit->data.emission_interval = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.particles_per_emission = load_reverse_endianness_float_t((void*)(d + 8)); emit->data.timer = (EmitterTimerType) load_reverse_endianness_int16_t((void*)(d + 12)); emit->data.seed = load_reverse_endianness_int32_t((void*)(d + 16)); } else { emit->data.type = (EmitterType) * (int16_t*)d; emit->data.direction = (Direction) * (int16_t*)(d + 2); emit->data.emission_interval = *(float_t*)(d + 4); emit->data.particles_per_emission = *(float_t*)(d + 8); emit->data.timer = (EmitterTimerType) * (int16_t*)(d + 12); emit->data.seed = *(int32_t*)(d + 16); } d += emit->version == 3 ? 36 : 32; if (big_endian) { emit->translation.x = load_reverse_endianness_float_t((void*)d); emit->translation.y = load_reverse_endianness_float_t((void*)(d + 4)); emit->translation.z = load_reverse_endianness_float_t((void*)(d + 8)); emit->rotation.x = load_reverse_endianness_float_t((void*)(d + 12)); emit->rotation.y = load_reverse_endianness_float_t((void*)(d + 16)); emit->rotation.z = load_reverse_endianness_float_t((void*)(d + 20)); emit->scale.x = load_reverse_endianness_float_t((void*)(d + 24)); emit->scale.y = load_reverse_endianness_float_t((void*)(d + 28)); emit->scale.z = load_reverse_endianness_float_t((void*)(d + 32)); emit->data.rotation_add.x = load_reverse_endianness_float_t((void*)(d + 36)); emit->data.rotation_add.y = load_reverse_endianness_float_t((void*)(d + 40)); emit->data.rotation_add.z = load_reverse_endianness_float_t((void*)(d + 44)); emit->data.rotation_add_random.x = load_reverse_endianness_float_t((void*)(d + 48)); emit->data.rotation_add_random.y = load_reverse_endianness_float_t((void*)(d + 52)); emit->data.rotation_add_random.z = load_reverse_endianness_float_t((void*)(d + 56)); } else { emit->translation = *(vec3*)d; emit->rotation = *(vec3*)(d + 12); emit->scale = *(vec3*)(d + 24); emit->data.rotation_add = *(vec3*)(d + 36); emit->data.rotation_add_random = *(vec3*)(d + 48); } d += 60; if (big_endian) switch (emit->data.type) { case EMITTER_BOX: emit->data.box.size.x = load_reverse_endianness_float_t((void*)d); emit->data.box.size.y = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.box.size.z = load_reverse_endianness_float_t((void*)(d + 8)); return true; case EMITTER_CYLINDER: emit->data.cylinder.radius = load_reverse_endianness_float_t((void*)d); emit->data.cylinder.height = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.cylinder.start_angle = load_reverse_endianness_float_t((void*)(d + 8)); emit->data.cylinder.end_angle = load_reverse_endianness_float_t((void*)(d + 12)); emit->data.cylinder.on_edge = load_reverse_endianness_int32_t((void*)(d + 16)) & 1 ? true : false; emit->data.cylinder.direction = (EmitterEmissionDirection) (load_reverse_endianness_int32_t((void*)(d + 16)) >> 1); return true; case EMITTER_SPHERE: emit->data.sphere.radius = load_reverse_endianness_float_t((void*)d); emit->data.sphere.latitude = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.sphere.longitude = load_reverse_endianness_float_t((void*)(d + 8)); emit->data.sphere.on_edge = load_reverse_endianness_int32_t((void*)(d + 12)) & 1 ? true : false; emit->data.sphere.direction = (EmitterEmissionDirection) (load_reverse_endianness_int32_t((void*)(d + 12)) >> 1); return true; case EMITTER_POLYGON: emit->data.polygon.size = load_reverse_endianness_float_t((void*)d); emit->data.polygon.count = load_reverse_endianness_int32_t((void*)(d + 4)); emit->data.polygon.direction = (EmitterEmissionDirection) (load_reverse_endianness_int32_t((void*)(d + 8)) >> 1); return true; } else switch (emit->data.type) { case EMITTER_BOX: emit->data.box.size = *(vec3*)d; return true; case EMITTER_CYLINDER: emit->data.cylinder.radius = *(float_t*)d; emit->data.cylinder.height = *(float_t*)(d + 4); emit->data.cylinder.start_angle = *(float_t*)(d + 8); emit->data.cylinder.end_angle = *(float_t*)(d + 12); emit->data.cylinder.on_edge = *(int32_t*)(d + 16) & 1 ? true : false; emit->data.cylinder.direction = (EmitterEmissionDirection) (*(int32_t*)(d + 16) >> 1); return true; case EMITTER_SPHERE: emit->data.sphere.radius = *(float_t*)d; emit->data.sphere.latitude = *(float_t*)(d + 4); emit->data.sphere.longitude = *(float_t*)(d + 8); emit->data.sphere.on_edge = *(int32_t*)(d + 12) & 1 ? true : false; emit->data.sphere.direction = (EmitterEmissionDirection) (*(int32_t*)(d + 12) >> 1); return true; case EMITTER_POLYGON: emit->data.polygon.size = *(float_t*)d; emit->data.polygon.count = *(int32_t*)(d + 4); emit->data.polygon.direction = (EmitterEmissionDirection) (*(int32_t*)(d + 8) >> 1); return true; } return false; } else { size_t d = (size_t)data; if (big_endian) { emit->data.start_time = load_reverse_endianness_int32_t((void*)d); emit->data.life_time = load_reverse_endianness_int32_t((void*)(d + 4)); emit->data.loop_start_time = load_reverse_endianness_int32_t((void*)(d + 8)); emit->data.loop_end_time = load_reverse_endianness_int32_t((void*)(d + 12)); emit->data.flags = (EmitterFlag) load_reverse_endianness_int32_t((void*)(d + 16)); } else { emit->data.start_time = *(int32_t*)d; emit->data.life_time = *(int32_t*)(d + 4); emit->data.loop_start_time = *(int32_t*)(d + 8); emit->data.loop_end_time = *(int32_t*)(d + 12); emit->data.flags = (EmitterFlag) * (int32_t*)(d + 16); } d += 20; emit->data.timer = EMITTER_TIMER_BY_TIME; emit->data.seed = 0; if (emit->version < 1 || emit->version > 2) return false; if (big_endian) { emit->data.type = (EmitterType) load_reverse_endianness_int16_t((void*)d); emit->data.direction = (Direction) load_reverse_endianness_int16_t((void*)(d + 2)); emit->data.emission_interval = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.particles_per_emission = load_reverse_endianness_float_t((void*)(d + 8)); emit->translation.x = load_reverse_endianness_float_t((void*)(d + 16)); emit->translation.y = load_reverse_endianness_float_t((void*)(d + 20)); emit->translation.z = load_reverse_endianness_float_t((void*)(d + 24)); emit->rotation.x = load_reverse_endianness_float_t((void*)(d + 28)); emit->rotation.y = load_reverse_endianness_float_t((void*)(d + 32)); emit->rotation.z = load_reverse_endianness_float_t((void*)(d + 36)); emit->scale.x = load_reverse_endianness_float_t((void*)(d + 40)); emit->scale.y = load_reverse_endianness_float_t((void*)(d + 44)); emit->scale.z = load_reverse_endianness_float_t((void*)(d + 48)); emit->data.rotation_add.x = load_reverse_endianness_float_t((void*)(d + 52)); emit->data.rotation_add.y = load_reverse_endianness_float_t((void*)(d + 56)); emit->data.rotation_add.z = load_reverse_endianness_float_t((void*)(d + 60)); emit->data.rotation_add_random.x = load_reverse_endianness_float_t((void*)(d + 64)); emit->data.rotation_add_random.y = load_reverse_endianness_float_t((void*)(d + 68)); emit->data.rotation_add_random.z = load_reverse_endianness_float_t((void*)(d + 72)); } else { emit->data.type = (EmitterType) * (int16_t*)d; emit->data.direction = (Direction) * (int16_t*)(d + 2); emit->data.emission_interval = *(float_t*)(d + 4); emit->data.particles_per_emission = *(float_t*)(d + 8); emit->translation = *(vec3*)(d + 16); emit->rotation = *(vec3*)(d + 28); emit->scale = *(vec3*)(d + 40); emit->data.rotation_add = *(vec3*)(d + 52); emit->data.rotation_add_random = *(vec3*)(d + 64); } d += 76; if (big_endian) switch (emit->data.type) { case EMITTER_BOX: emit->data.box.size.x = load_reverse_endianness_float_t((void*)d); emit->data.box.size.y = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.box.size.z = load_reverse_endianness_float_t((void*)(d + 8)); return true; case EMITTER_CYLINDER: emit->data.cylinder.radius = load_reverse_endianness_float_t((void*)d); emit->data.cylinder.height = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.cylinder.start_angle = load_reverse_endianness_float_t((void*)(d + 8)); emit->data.cylinder.end_angle = load_reverse_endianness_float_t((void*)(d + 12)); emit->data.cylinder.on_edge = load_reverse_endianness_int32_t((void*)(d + 16)) & 1 ? true : false; emit->data.cylinder.direction = (EmitterEmissionDirection) (load_reverse_endianness_int32_t((void*)(d + 16)) >> 1); return true; case EMITTER_SPHERE: emit->data.sphere.radius = load_reverse_endianness_float_t((void*)d); emit->data.sphere.latitude = load_reverse_endianness_float_t((void*)(d + 4)); emit->data.sphere.longitude = load_reverse_endianness_float_t((void*)(d + 8)); emit->data.sphere.on_edge = load_reverse_endianness_int32_t((void*)(d + 12)) & 1 ? true : false; emit->data.sphere.direction = (EmitterEmissionDirection) (load_reverse_endianness_int32_t((void*)(d + 12)) >> 1); return true; case EMITTER_POLYGON: emit->data.polygon.size = load_reverse_endianness_float_t((void*)d); emit->data.polygon.count = load_reverse_endianness_int32_t((void*)(d + 4)); return true; } else switch (emit->data.type) { case EMITTER_BOX: emit->data.box.size = *(vec3*)d; return true; case EMITTER_CYLINDER: emit->data.cylinder.radius = *(float_t*)d; emit->data.cylinder.height = *(float_t*)(d + 4); emit->data.cylinder.start_angle = *(float_t*)(d + 8); emit->data.cylinder.end_angle = *(float_t*)(d + 12); emit->data.cylinder.on_edge = *(int32_t*)(d + 16) & 1 ? true : false; emit->data.cylinder.direction = (EmitterEmissionDirection)(*(int32_t*)(d + 16) >> 1); return true; case EMITTER_SPHERE: emit->data.sphere.radius = *(float_t*)d; emit->data.sphere.latitude = *(float_t*)(d + 4); emit->data.sphere.longitude = *(float_t*)(d + 8); emit->data.sphere.on_edge = *(int32_t*)(d + 12) & 1 ? true : false; emit->data.sphere.direction = (EmitterEmissionDirection)(*(int32_t*)(d + 12) >> 1); return true; case EMITTER_POLYGON: emit->data.polygon.size = *(float_t*)d; emit->data.polygon.count = *(int32_t*)(d + 4); return true; } return false; } } bool FileReader::UnpackParticle(void* data, Particle* ptcl, uint32_t ptcl_version, Effect* eff, bool big_endian, EffectGroup* eff_group) { ptcl->version = ptcl_version; uint8_t r; uint8_t b; uint8_t g; uint8_t a; ParticleBlend blend_mode; ParticleBlend mask_blend_mode; uint64_t tex_hash; uint64_t mask_tex_hash; int32_t frame_step_uv; int32_t uv_index_start; int32_t uv_index; int32_t uv_index_end; UVIndexType uv_index_type; uint8_t split_u; uint8_t split_v; int32_t unk2; int32_t unk3; int32_t unk4; if (type == Glitter::X) { ptcl->data.mesh.object_set_name_hash = hash_murmurhash_empty; ptcl->data.mesh.object_name_hash = hash_murmurhash_empty; //ptcl->data.mesh.mesh_name[0] = 0; //ptcl->data.mesh.sub_mesh_hash = hash_murmurhash_empty; size_t d = (size_t)data; if (big_endian) { ptcl->data.life_time = load_reverse_endianness_int32_t((void*)d); ptcl->data.life_time_random = load_reverse_endianness_int32_t((void*)(d + 4)); ptcl->data.fade_in = load_reverse_endianness_int32_t((void*)(d + 8)); ptcl->data.fade_in_random = load_reverse_endianness_int32_t((void*)(d + 12)); ptcl->data.fade_out = load_reverse_endianness_int32_t((void*)(d + 16)); ptcl->data.fade_out_random = load_reverse_endianness_int32_t((void*)(d + 20)); ptcl->data.type = (ParticleType)load_reverse_endianness_int32_t((void*)(d + 24)); ptcl->data.draw_type = (Direction)load_reverse_endianness_int32_t((void*)(d + 28)); } else { ptcl->data.life_time = *(int32_t*)d; ptcl->data.life_time_random = *(int32_t*)(d + 4); ptcl->data.fade_in = *(int32_t*)(d + 8); ptcl->data.fade_in_random = *(int32_t*)(d + 12); ptcl->data.fade_out = *(int32_t*)(d + 16); ptcl->data.fade_out_random = *(int32_t*)(d + 20); ptcl->data.type = (ParticleType) * (int32_t*)(d + 24); ptcl->data.draw_type = (Direction) * (int32_t*)(d + 28); } ptcl->data.unk0 = 0; ptcl->data.unk1 = -1.0f; if (ptcl->version < 4 || ptcl->version > 5) return false; if (big_endian) { ptcl->data.rotation.x = load_reverse_endianness_float_t((void*)(d + 32)); ptcl->data.rotation.y = load_reverse_endianness_float_t((void*)(d + 36)); ptcl->data.rotation.z = load_reverse_endianness_float_t((void*)(d + 40)); ptcl->data.rotation_random.x = load_reverse_endianness_float_t((void*)(d + 44)); ptcl->data.rotation_random.y = load_reverse_endianness_float_t((void*)(d + 48)); ptcl->data.rotation_random.z = load_reverse_endianness_float_t((void*)(d + 52)); ptcl->data.rotation_add.x = load_reverse_endianness_float_t((void*)(d + 56)); ptcl->data.rotation_add.y = load_reverse_endianness_float_t((void*)(d + 60)); ptcl->data.rotation_add.z = load_reverse_endianness_float_t((void*)(d + 64)); ptcl->data.rotation_add_random.x = load_reverse_endianness_float_t((void*)(d + 68)); ptcl->data.rotation_add_random.y = load_reverse_endianness_float_t((void*)(d + 72)); ptcl->data.rotation_add_random.z = load_reverse_endianness_float_t((void*)(d + 76)); ptcl->data.scale.x = load_reverse_endianness_float_t((void*)(d + 80)); ptcl->data.scale.y = load_reverse_endianness_float_t((void*)(d + 84)); ptcl->data.scale.z = load_reverse_endianness_float_t((void*)(d + 88)); ptcl->data.scale_random.x = load_reverse_endianness_float_t((void*)(d + 92)); ptcl->data.scale_random.y = load_reverse_endianness_float_t((void*)(d + 96)); ptcl->data.scale_random.z = load_reverse_endianness_float_t((void*)(d + 100)); ptcl->data.z_offset = load_reverse_endianness_float_t((void*)(d + 104)); ptcl->data.pivot = (Pivot)load_reverse_endianness_int32_t((void*)(d + 108)); ptcl->data.flags = (ParticleFlag)load_reverse_endianness_int32_t((void*)(d + 112)); ptcl->data.unk0 = load_reverse_endianness_int32_t((void*)(d + 116)); } else { ptcl->data.rotation = *(vec3*)(d + 32); ptcl->data.rotation_random = *(vec3*)(d + 44); ptcl->data.rotation_add = *(vec3*)(d + 56); ptcl->data.rotation_add_random = *(vec3*)(d + 68); ptcl->data.scale = *(vec3*)(d + 80); ptcl->data.scale_random = *(vec3*)(d + 92); ptcl->data.z_offset = *(float_t*)(d + 104); ptcl->data.pivot = (Pivot) * (int32_t*)(d + 108); ptcl->data.flags = (ParticleFlag) * (int32_t*)(d + 112); ptcl->data.unk0 = *(int32_t*)(d + 116); } if (eff->data.flags & EFFECT_LOCAL) enum_or(ptcl->data.flags, PARTICLE_LOCAL); if (eff->data.flags & EFFECT_EMISSION) enum_or(ptcl->data.flags, PARTICLE_EMISSION); if (big_endian) { ptcl->data.uv_scroll_2nd_add.x = load_reverse_endianness_float_t((void*)(d + 120)); ptcl->data.uv_scroll_2nd_add.y = load_reverse_endianness_float_t((void*)(d + 124)); ptcl->data.uv_scroll_2nd_add_scale = load_reverse_endianness_float_t((void*)(d + 128)); ptcl->data.speed = load_reverse_endianness_float_t((void*)(d + 136)); ptcl->data.speed_random = load_reverse_endianness_float_t((void*)(d + 140)); ptcl->data.deceleration = load_reverse_endianness_float_t((void*)(d + 144)); ptcl->data.deceleration_random = load_reverse_endianness_float_t((void*)(d + 148)); ptcl->data.direction.x = load_reverse_endianness_float_t((void*)(d + 152)); ptcl->data.direction.y = load_reverse_endianness_float_t((void*)(d + 156)); ptcl->data.direction.z = load_reverse_endianness_float_t((void*)(d + 160)); ptcl->data.direction_random.x = load_reverse_endianness_float_t((void*)(d + 164)); ptcl->data.direction_random.y = load_reverse_endianness_float_t((void*)(d + 168)); ptcl->data.direction_random.z = load_reverse_endianness_float_t((void*)(d + 172)); ptcl->data.gravity.x = load_reverse_endianness_float_t((void*)(d + 176)); ptcl->data.gravity.y = load_reverse_endianness_float_t((void*)(d + 180)); ptcl->data.gravity.z = load_reverse_endianness_float_t((void*)(d + 184)); ptcl->data.acceleration.x = load_reverse_endianness_float_t((void*)(d + 188)); ptcl->data.acceleration.y = load_reverse_endianness_float_t((void*)(d + 192)); ptcl->data.acceleration.z = load_reverse_endianness_float_t((void*)(d + 196)); ptcl->data.acceleration_random.x = load_reverse_endianness_float_t((void*)(d + 200)); ptcl->data.acceleration_random.y = load_reverse_endianness_float_t((void*)(d + 204)); ptcl->data.acceleration_random.z = load_reverse_endianness_float_t((void*)(d + 208)); ptcl->data.reflection_coeff = load_reverse_endianness_float_t((void*)(d + 212)); ptcl->data.reflection_coeff_random = load_reverse_endianness_float_t((void*)(d + 216)); ptcl->data.rebound_plane_y = load_reverse_endianness_float_t((void*)(d + 220)); ptcl->data.uv_scroll_add.x = load_reverse_endianness_float_t((void*)(d + 224)); ptcl->data.uv_scroll_add.y = load_reverse_endianness_float_t((void*)(d + 228)); ptcl->data.uv_scroll_add_scale = load_reverse_endianness_float_t((void*)(d + 232)); ptcl->data.sub_flags = (ParticleSubFlag) load_reverse_endianness_int32_t((void*)(d + 236)); ptcl->data.count = load_reverse_endianness_int32_t((void*)(d + 240)); ptcl->data.draw_flags = (ParticleDrawFlag) load_reverse_endianness_int32_t((void*)(d + 244)); ptcl->data.unk1 = load_reverse_endianness_float_t((void*)(d + 248)); ptcl->data.emission = load_reverse_endianness_float_t((void*)(d + 252)); } else { ptcl->data.uv_scroll_2nd_add = *(vec2*)(d + 120); ptcl->data.uv_scroll_2nd_add_scale = *(float_t*)(d + 128); ptcl->data.speed = *(float_t*)(d + 136); ptcl->data.speed_random = *(float_t*)(d + 140); ptcl->data.deceleration = *(float_t*)(d + 144); ptcl->data.deceleration_random = *(float_t*)(d + 148); ptcl->data.direction = *(vec3*)(d + 152); ptcl->data.direction_random = *(vec3*)(d + 164); ptcl->data.gravity = *(vec3*)(d + 176); ptcl->data.acceleration = *(vec3*)(d + 188); ptcl->data.acceleration_random = *(vec3*)(d + 200); ptcl->data.reflection_coeff = *(float_t*)(d + 212); ptcl->data.reflection_coeff_random = *(float_t*)(d + 216); ptcl->data.rebound_plane_y = *(float_t*)(d + 220); ptcl->data.uv_scroll_add = *(vec2*)(d + 224); ptcl->data.uv_scroll_add_scale = *(float_t*)(d + 232); ptcl->data.sub_flags = (ParticleSubFlag) * (int32_t*)(d + 236); ptcl->data.count = *(int32_t*)(d + 240); ptcl->data.draw_flags = (ParticleDrawFlag) * (int32_t*)(d + 244); ptcl->data.unk1 = *(float_t*)(d + 248); ptcl->data.emission = *(float_t*)(d + 252); } d += 256; if (ptcl->version == 4) { ptcl->data.direction *= 10.0f; ptcl->data.direction_random *= 10.0f; } if (ptcl->data.emission >= min_emission) enum_or(ptcl->data.flags, PARTICLE_EMISSION); ptcl->data.locus_history_size = 0; ptcl->data.locus_history_size_random = 0; switch (ptcl->data.type) { case 3: ptcl->data.type = PARTICLE_LINE; break; case 1: ptcl->data.type = PARTICLE_MESH; break; } bool has_tex; if (ptcl->data.type == PARTICLE_QUAD) has_tex = true; else if (ptcl->data.type == PARTICLE_LINE) has_tex = false; else if (ptcl->data.type == PARTICLE_LOCUS) { if (big_endian) { ptcl->data.locus_history_size = load_reverse_endianness_uint16_t((void*)(d + 0)); ptcl->data.locus_history_size_random = load_reverse_endianness_uint16_t((void*)(d + 2)); } else { ptcl->data.locus_history_size = *(uint16_t*)(d + 0); ptcl->data.locus_history_size_random = *(uint16_t*)(d + 2); } d += 4; has_tex = true; } else if (ptcl->data.type == PARTICLE_MESH) { if (big_endian) { ptcl->data.mesh.object_name_hash = load_reverse_endianness_uint64_t((void*)d); ptcl->data.mesh.object_set_name_hash = load_reverse_endianness_uint64_t((void*)(d + 8)); } else { ptcl->data.mesh.object_name_hash = *(uint64_t*)d; ptcl->data.mesh.object_set_name_hash = *(uint64_t*)(d + 8); } //if (*(char*)(d + 10)) { // strncpy_s(ptcl->data.mesh.mesh_name, 0x40, (char*)(d + 16), 0x3F); // ptcl->data.mesh.mesh_name[0x3F] = 0; //} //else // ptcl->data.mesh.mesh_name[0] = 0; //if (big_endian) // ptcl->data.mesh.sub_mesh_hash = load_reverse_endianness_uint64_t((void*)(d + 80)); //else // ptcl->data.mesh.sub_mesh_hash = *(uint64_t*)(d + 80); d += 88; has_tex = false; eff_group->meshes.push_back((uint32_t)ptcl->data.mesh.object_set_name_hash); } else return false; ptcl->data.texture = 0; ptcl->data.mask_texture = 0; tex_hash = hash_murmurhash_empty; mask_tex_hash = hash_murmurhash_empty; unk2 = 0; unk3 = 0; if (big_endian) { if (has_tex) tex_hash = load_reverse_endianness_uint64_t((void*)d); r = *(uint8_t*)(d + 8); g = *(uint8_t*)(d + 9); b = *(uint8_t*)(d + 10); a = *(uint8_t*)(d + 11); blend_mode = (ParticleBlend)load_reverse_endianness_int32_t((void*)(d + 12)); unk2 = load_reverse_endianness_int32_t((void*)(d + 16)); split_u = (uint8_t)load_reverse_endianness_int32_t((void*)(d + 20)); split_v = (uint8_t)load_reverse_endianness_int32_t((void*)(d + 24)); uv_index_type = (UVIndexType)load_reverse_endianness_int32_t((void*)(d + 28)); uv_index = load_reverse_endianness_int16_t((void*)(d + 32)); frame_step_uv = load_reverse_endianness_int16_t((void*)(d + 34)); uv_index_start = load_reverse_endianness_int32_t((void*)(d + 36)); uv_index_end = load_reverse_endianness_int32_t((void*)(d + 40)); unk3 = load_reverse_endianness_int32_t((void*)(d + 44)); } else { if (has_tex) tex_hash = *(uint64_t*)d; r = *(uint8_t*)(d + 8); g = *(uint8_t*)(d + 9); b = *(uint8_t*)(d + 10); a = *(uint8_t*)(d + 11); blend_mode = (ParticleBlend) * (int32_t*)(d + 12); unk2 = *(int32_t*)(d + 16); split_u = (uint8_t) * (int32_t*)(d + 20); split_v = (uint8_t) * (int32_t*)(d + 24); uv_index_type = (UVIndexType) * (int32_t*)(d + 28); uv_index = *(int16_t*)(d + 32); frame_step_uv = *(int16_t*)(d + 34); uv_index_start = *(int32_t*)(d + 36); uv_index_end = *(int32_t*)(d + 40); unk3 = *(int32_t*)(d + 44); } d += 48; if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) if (big_endian) { if (has_tex) mask_tex_hash = load_reverse_endianness_uint64_t((void*)d); mask_blend_mode = (ParticleBlend) load_reverse_endianness_int32_t((void*)(d + 8)); unk4 = load_reverse_endianness_int32_t((void*)(d + 12)); } else { if (has_tex) mask_tex_hash = *(uint64_t*)d; mask_blend_mode = (ParticleBlend) * (int32_t*)(d + 8); unk4 = *(int32_t*)(d + 12); } else { mask_blend_mode = PARTICLE_BLEND_TYPICAL; unk4 = 0xFF; } } else { size_t d = (size_t)data; if (big_endian) { ptcl->data.life_time = load_reverse_endianness_int32_t((void*)d); ptcl->data.type = (ParticleType)load_reverse_endianness_int32_t((void*)(d + 4)); ptcl->data.draw_type = (Direction)load_reverse_endianness_int32_t((void*)(d + 8)); } else { ptcl->data.life_time = *(int32_t*)d; ptcl->data.type = (ParticleType) * (int32_t*)(d + 4); ptcl->data.draw_type = (Direction) * (int32_t*)(d + 8); } ptcl->data.unk0 = 0; ptcl->data.unk1 = -1.0f; if (ptcl->version < 2 || ptcl->version > 3) return false; if (big_endian) { ptcl->data.rotation.x = load_reverse_endianness_float_t((void*)(d + 12)); ptcl->data.rotation.y = load_reverse_endianness_float_t((void*)(d + 16)); ptcl->data.rotation.z = load_reverse_endianness_float_t((void*)(d + 20)); ptcl->data.rotation_random.x = load_reverse_endianness_float_t((void*)(d + 24)); ptcl->data.rotation_random.y = load_reverse_endianness_float_t((void*)(d + 28)); ptcl->data.rotation_random.z = load_reverse_endianness_float_t((void*)(d + 32)); ptcl->data.rotation_add.x = load_reverse_endianness_float_t((void*)(d + 36)); ptcl->data.rotation_add.y = load_reverse_endianness_float_t((void*)(d + 40)); ptcl->data.rotation_add.z = load_reverse_endianness_float_t((void*)(d + 44)); ptcl->data.rotation_add_random.x = load_reverse_endianness_float_t((void*)(d + 48)); ptcl->data.rotation_add_random.y = load_reverse_endianness_float_t((void*)(d + 52)); ptcl->data.rotation_add_random.z = load_reverse_endianness_float_t((void*)(d + 56)); ptcl->data.scale.x = load_reverse_endianness_float_t((void*)(d + 60)); ptcl->data.scale.y = load_reverse_endianness_float_t((void*)(d + 64)); ptcl->data.scale.z = load_reverse_endianness_float_t((void*)(d + 68)); ptcl->data.scale_random.x = load_reverse_endianness_float_t((void*)(d + 72)); ptcl->data.scale_random.y = load_reverse_endianness_float_t((void*)(d + 76)); ptcl->data.scale_random.z = load_reverse_endianness_float_t((void*)(d + 80)); ptcl->data.z_offset = load_reverse_endianness_float_t((void*)(d + 84)); ptcl->data.pivot = (Pivot)load_reverse_endianness_int32_t((void*)(d + 88)); ptcl->data.flags = (ParticleFlag)load_reverse_endianness_int32_t((void*)(d + 92)); } else { ptcl->data.rotation = *(vec3*)(d + 12); ptcl->data.rotation_random = *(vec3*)(d + 24); ptcl->data.rotation_add = *(vec3*)(d + 36); ptcl->data.rotation_add_random = *(vec3*)(d + 48); ptcl->data.scale = *(vec3*)(d + 60); ptcl->data.scale_random = *(vec3*)(d + 72); ptcl->data.z_offset = *(float_t*)(d + 84); ptcl->data.pivot = (Pivot) * (int32_t*)(d + 88); ptcl->data.flags = (ParticleFlag) * (int32_t*)(d + 92); } if (eff->data.flags & EFFECT_LOCAL) enum_or(ptcl->data.flags, PARTICLE_LOCAL); if (eff->data.flags & EFFECT_EMISSION) enum_or(ptcl->data.flags, PARTICLE_EMISSION); if (big_endian) { ptcl->data.speed = load_reverse_endianness_float_t((void*)(d + 96)); ptcl->data.speed_random = load_reverse_endianness_float_t((void*)(d + 100)); ptcl->data.deceleration = load_reverse_endianness_float_t((void*)(d + 104)); ptcl->data.deceleration_random = load_reverse_endianness_float_t((void*)(d + 108)); ptcl->data.direction.x = load_reverse_endianness_float_t((void*)(d + 112)); ptcl->data.direction.y = load_reverse_endianness_float_t((void*)(d + 116)); ptcl->data.direction.z = load_reverse_endianness_float_t((void*)(d + 120)); ptcl->data.direction_random.x = load_reverse_endianness_float_t((void*)(d + 124)); ptcl->data.direction_random.y = load_reverse_endianness_float_t((void*)(d + 128)); ptcl->data.direction_random.z = load_reverse_endianness_float_t((void*)(d + 132)); ptcl->data.gravity.x = load_reverse_endianness_float_t((void*)(d + 136)); ptcl->data.gravity.y = load_reverse_endianness_float_t((void*)(d + 140)); ptcl->data.gravity.z = load_reverse_endianness_float_t((void*)(d + 144)); ptcl->data.acceleration.x = load_reverse_endianness_float_t((void*)(d + 148)); ptcl->data.acceleration.y = load_reverse_endianness_float_t((void*)(d + 152)); ptcl->data.acceleration.z = load_reverse_endianness_float_t((void*)(d + 156)); ptcl->data.acceleration_random.x = load_reverse_endianness_float_t((void*)(d + 160)); ptcl->data.acceleration_random.y = load_reverse_endianness_float_t((void*)(d + 164)); ptcl->data.acceleration_random.z = load_reverse_endianness_float_t((void*)(d + 168)); ptcl->data.reflection_coeff = load_reverse_endianness_float_t((void*)(d + 172)); ptcl->data.reflection_coeff_random = load_reverse_endianness_float_t((void*)(d + 176)); ptcl->data.rebound_plane_y = load_reverse_endianness_float_t((void*)(d + 180)); ptcl->data.uv_scroll_add.x = load_reverse_endianness_float_t((void*)(d + 184)); ptcl->data.uv_scroll_add.y = load_reverse_endianness_float_t((void*)(d + 188)); ptcl->data.uv_scroll_add_scale = load_reverse_endianness_float_t((void*)(d + 192)); ptcl->data.sub_flags = (ParticleSubFlag) load_reverse_endianness_int32_t((void*)(d + 196)); ptcl->data.count = load_reverse_endianness_int32_t((void*)(d + 200)); } else { ptcl->data.speed = *(float_t*)(d + 96); ptcl->data.speed_random = *(float_t*)(d + 100); ptcl->data.deceleration = *(float_t*)(d + 104); ptcl->data.deceleration_random = *(float_t*)(d + 108); ptcl->data.direction = *(vec3*)(d + 112); ptcl->data.direction_random = *(vec3*)(d + 124); ptcl->data.gravity = *(vec3*)(d + 136); ptcl->data.acceleration = *(vec3*)(d + 148); ptcl->data.acceleration_random = *(vec3*)(d + 160); ptcl->data.reflection_coeff = *(float_t*)(d + 172); ptcl->data.reflection_coeff_random = *(float_t*)(d + 176); ptcl->data.rebound_plane_y = *(float_t*)(d + 180); ptcl->data.uv_scroll_add = *(vec2*)(d + 184); ptcl->data.uv_scroll_add_scale = *(float_t*)(d + 192); ptcl->data.sub_flags = (ParticleSubFlag) * (int32_t*)(d + 196); ptcl->data.count = *(int32_t*)(d + 200); } d += 204; ptcl->data.locus_history_size = 0; ptcl->data.locus_history_size_random = 0; ptcl->data.draw_flags = (ParticleDrawFlag)0; ptcl->data.emission = 0.0f; if (ptcl->version == 3) { if (big_endian) { ptcl->data.unk1 = load_reverse_endianness_float_t((void*)d); ptcl->data.emission = load_reverse_endianness_float_t((void*)(d + 4)); } else { ptcl->data.unk1 = *(float_t*)d; ptcl->data.emission = *(float_t*)(d + 4); } if (ptcl->data.emission >= min_emission) enum_or(ptcl->data.flags, PARTICLE_EMISSION); d += 8; } if (ptcl->data.type == PARTICLE_LOCUS || ptcl->data.type == PARTICLE_MESH) { if (big_endian) { ptcl->data.locus_history_size = load_reverse_endianness_uint16_t((void*)d); ptcl->data.locus_history_size_random = load_reverse_endianness_uint16_t((void*)(d + 2)); } else { ptcl->data.locus_history_size = *(uint16_t*)d; ptcl->data.locus_history_size_random = *(uint16_t*)(d + 2); } d += 4; } ptcl->data.texture = 0; ptcl->data.mask_texture = 0; unk2 = 0; unk3 = 0; if (big_endian) { tex_hash = load_reverse_endianness_uint64_t((void*)d); r = *(uint8_t*)(d + 8); g = *(uint8_t*)(d + 9); b = *(uint8_t*)(d + 10); a = *(uint8_t*)(d + 11); blend_mode = (ParticleBlend)load_reverse_endianness_int32_t((void*)(d + 12)); unk2 = load_reverse_endianness_int32_t((void*)(d + 16)); split_u = (uint8_t)load_reverse_endianness_int32_t((void*)(d + 20)); split_v = (uint8_t)load_reverse_endianness_int32_t((void*)(d + 24)); uv_index_type = (UVIndexType)load_reverse_endianness_int32_t((void*)(d + 28)); uv_index = load_reverse_endianness_int16_t((void*)(d + 32)); frame_step_uv = load_reverse_endianness_int16_t((void*)(d + 34)); uv_index_start = load_reverse_endianness_int32_t((void*)(d + 36)); uv_index_end = load_reverse_endianness_int32_t((void*)(d + 40)); } else { tex_hash = *(uint64_t*)d; r = *(uint8_t*)(d + 8); g = *(uint8_t*)(d + 9); b = *(uint8_t*)(d + 10); a = *(uint8_t*)(d + 11); blend_mode = (ParticleBlend) * (int32_t*)(d + 12); unk2 = *(int32_t*)(d + 16); split_u = (uint8_t) * (int32_t*)(d + 20); split_v = (uint8_t) * (int32_t*)(d + 24); uv_index_type = (UVIndexType) * (int32_t*)(d + 28); uv_index = *(int16_t*)(d + 32); frame_step_uv = *(int16_t*)(d + 34); uv_index_start = *(int32_t*)(d + 36); uv_index_end = *(int32_t*)(d + 40); } d += 44; if (eff_group->version >= 7) { if (big_endian) unk3 = load_reverse_endianness_int32_t((void*)d); else unk3 = *(int32_t*)d; d += 4; } if (ptcl->data.flags & PARTICLE_TEXTURE_MASK) if (big_endian) { mask_tex_hash = load_reverse_endianness_uint64_t((void*)d); mask_blend_mode = (ParticleBlend) load_reverse_endianness_int32_t((void*)(d + 8)); unk4 = load_reverse_endianness_int32_t((void*)(d + 12)); } else { mask_tex_hash = *(uint64_t*)d; mask_blend_mode = (ParticleBlend) * (int32_t*)(d + 8); unk4 = *(int32_t*)(d + 12); } else { mask_tex_hash = type != Glitter::FT ? hash_murmurhash_empty : hash_fnv1a64m_empty; mask_blend_mode = PARTICLE_BLEND_TYPICAL; unk4 = 0xFF; } } ptcl->data.tex_hash = tex_hash; ptcl->data.mask_tex_hash = mask_tex_hash; ptcl->data.color.x = (float_t)r; ptcl->data.color.y = (float_t)g; ptcl->data.color.z = (float_t)b; ptcl->data.color.w = (float_t)a; ptcl->data.blend_mode = blend_mode; ptcl->data.mask_blend_mode = mask_blend_mode; ptcl->data.split_u = split_u; ptcl->data.split_v = split_v; ptcl->data.uv_index_type = uv_index_type; ptcl->data.uv_index = max_def(uv_index, 0); ptcl->data.frame_step_uv = frame_step_uv; ptcl->data.uv_index_start = max_def(uv_index_start, 0); ptcl->data.uv_index_end = uv_index_end; ptcl->data.split_uv.x = (float_t)split_u; ptcl->data.split_uv.y = (float_t)split_v; ptcl->data.unk2 = unk2; ptcl->data.unk3 = unk3; ptcl->data.unk4 = unk4; ptcl->data.split_uv = vec2::rcp(ptcl->data.split_uv); ptcl->data.color *= (float_t)(1.0 / 255.0); int32_t uv_max_count = (int32_t)(split_u * split_v); if (uv_max_count) uv_max_count--; switch (uv_index_type) { case UV_INDEX_FIXED: case UV_INDEX_RANDOM: case UV_INDEX_FORWARD: case UV_INDEX_REVERSE: case UV_INDEX_USER: ptcl->data.uv_index &= uv_max_count; break; case UV_INDEX_INITIAL_RANDOM_FIXED: case UV_INDEX_INITIAL_RANDOM_FORWARD: case UV_INDEX_INITIAL_RANDOM_REVERSE: if (uv_index < uv_index_start) ptcl->data.uv_index = uv_index_start; else if (uv_index_end >= 0 && uv_index > uv_index_end) ptcl->data.uv_index = uv_index_end; ptcl->data.uv_index = min_def(ptcl->data.uv_index, uv_max_count); break; } if (uv_index_end >= 0) ptcl->data.uv_index_count = uv_index_end - uv_index_start + 1; else ptcl->data.uv_index_count = uv_max_count - uv_index_start; if (ptcl->data.uv_index_count < 0) ptcl->data.uv_index_count = 0; return true; } }