Files
korenkonder_ReDIVA/src/ReDIVA/x_pv_game.cpp
T

10897 lines
363 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#if defined(ReDIVA_DEV)
#include "x_pv_game.hpp"
#include "../CRE/light_param/light.hpp"
#include "../CRE/light_param.hpp"
#include "../CRE/rob/rob.hpp"
#include "../CRE/rob/motion.hpp"
#include "../CRE/rob/skin_param.hpp"
#include "../CRE/data.hpp"
#include "../CRE/item_table.hpp"
#include "../CRE/object.hpp"
#include "../CRE/pv_expression.hpp"
#include "../CRE/pv_param.hpp"
#include "../CRE/random.hpp"
#include "../CRE/shader_ft.hpp"
#include "../CRE/sound.hpp"
#include "../CRE/sprite.hpp"
#include "../CRE/task_effect.hpp"
#include "../KKdLib/io/file_stream.hpp"
#include "../KKdLib/prj/algorithm.hpp"
#include "../KKdLib/farc.hpp"
#include "../KKdLib/interpolation.hpp"
#include "../KKdLib/sort.hpp"
#include "../KKdLib/str_utils.hpp"
#if BAKE_PNG
#include <lodepng/lodepng.h>
#endif
#if BAKE_VIDEO
#include <glad/glad_wgl.h>
#include <d3d11.h>
#include "../CRE/shader_dev.hpp"
#include "nvenc/nvenc_encoder.hpp"
#endif
#if BAKE_PV826
#include "../KKdLib/waitable_timer.hpp"
#endif
#include "imgui_helper.hpp"
#include "input.hpp"
enum dsc_x_func {
DSC_X_END = 0,
DSC_X_TIME,
DSC_X_MIKU_MOVE,
DSC_X_MIKU_ROT,
DSC_X_MIKU_DISP,
DSC_X_MIKU_SHADOW,
DSC_X_TARGET,
DSC_X_SET_MOTION,
DSC_X_SET_PLAYDATA,
DSC_X_EFFECT,
DSC_X_FADEIN_FIELD,
DSC_X_EFFECT_OFF,
DSC_X_SET_CAMERA,
DSC_X_DATA_CAMERA,
DSC_X_CHANGE_FIELD,
DSC_X_HIDE_FIELD,
DSC_X_MOVE_FIELD,
DSC_X_FADEOUT_FIELD,
DSC_X_EYE_ANIM,
DSC_X_MOUTH_ANIM,
DSC_X_HAND_ANIM,
DSC_X_LOOK_ANIM,
DSC_X_EXPRESSION,
DSC_X_LOOK_CAMERA,
DSC_X_LYRIC,
DSC_X_MUSIC_PLAY,
DSC_X_MODE_SELECT,
DSC_X_EDIT_MOTION,
DSC_X_BAR_TIME_SET,
DSC_X_SHADOWHEIGHT,
DSC_X_EDIT_FACE,
DSC_X_DUMMY,
DSC_X_PV_END,
DSC_X_SHADOWPOS,
DSC_X_EDIT_LYRIC,
DSC_X_EDIT_TARGET,
DSC_X_EDIT_MOUTH,
DSC_X_SET_CHARA,
DSC_X_EDIT_MOVE,
DSC_X_EDIT_SHADOW,
DSC_X_EDIT_EYELID,
DSC_X_EDIT_EYE,
DSC_X_EDIT_ITEM,
DSC_X_EDIT_EFFECT,
DSC_X_EDIT_DISP,
DSC_X_EDIT_HAND_ANIM,
DSC_X_AIM,
DSC_X_HAND_ITEM,
DSC_X_EDIT_BLUSH,
DSC_X_NEAR_CLIP,
DSC_X_CLOTH_WET,
DSC_X_LIGHT_ROT,
DSC_X_SCENE_FADE,
DSC_X_TONE_TRANS,
DSC_X_SATURATE,
DSC_X_FADE_MODE,
DSC_X_AUTO_BLINK,
DSC_X_PARTS_DISP,
DSC_X_TARGET_FLYING_TIME,
DSC_X_CHARA_SIZE,
DSC_X_CHARA_HEIGHT_ADJUST,
DSC_X_ITEM_ANIM,
DSC_X_CHARA_POS_ADJUST,
DSC_X_SCENE_ROT,
DSC_X_EDIT_MOT_SMOOTH_LEN,
DSC_X_PV_BRANCH_MODE,
DSC_X_DATA_CAMERA_START,
DSC_X_MOVIE_PLAY,
DSC_X_MOVIE_DISP,
DSC_X_WIND,
DSC_X_OSAGE_STEP,
DSC_X_OSAGE_MV_CCL,
DSC_X_CHARA_COLOR,
DSC_X_SE_EFFECT,
DSC_X_CHARA_SHADOW_QUALITY,
DSC_X_STAGE_SHADOW_QUALITY,
DSC_X_COMMON_LIGHT,
DSC_X_TONE_MAP,
DSC_X_IBL_COLOR,
DSC_X_REFLECTION,
DSC_X_CHROMATIC_ABERRATION,
DSC_X_STAGE_SHADOW,
DSC_X_REFLECTION_QUALITY,
DSC_X_PV_END_FADEOUT,
DSC_X_CREDIT_TITLE,
DSC_X_BAR_POINT,
DSC_X_BEAT_POINT,
DSC_X_RESERVE1,
DSC_X_PV_AUTH_LIGHT_PRIORITY,
DSC_X_PV_CHARA_LIGHT,
DSC_X_PV_STAGE_LIGHT,
DSC_X_TARGET_EFFECT,
DSC_X_FOG,
DSC_X_BLOOM,
DSC_X_COLOR_CORRECTION,
DSC_X_DOF,
DSC_X_CHARA_ALPHA,
DSC_X_AUTO_CAPTURE_BEGIN,
DSC_X_MANUAL_CAPTURE,
DSC_X_TOON_EDGE,
DSC_X_SHIMMER,
DSC_X_ITEM_ALPHA,
DSC_X_MOVIE_CUT,
DSC_X_EDIT_CAMERA_BOX,
DSC_X_EDIT_STAGE_PARAM,
DSC_X_EDIT_CHANGE_FIELD,
DSC_X_MIKUDAYO_ADJUST,
DSC_X_LYRIC_2,
DSC_X_LYRIC_READ,
DSC_X_LYRIC_READ_2,
DSC_X_ANNOTATION,
DSC_X_STAGE_EFFECT,
DSC_X_SONG_EFFECT,
DSC_X_SONG_EFFECT_ATTACH,
DSC_X_LIGHT_AUTH,
DSC_X_FADE,
DSC_X_SET_STAGE_EFFECT_ENV,
DSC_X_RESERVE2,
DSC_X_COMMON_EFFECT_AET_FRONT,
DSC_X_COMMON_EFFECT_AET_FRONT_LOW,
DSC_X_COMMON_EFFECT_PARTICLE,
DSC_X_SONG_EFFECT_ALPHA_SORT,
DSC_X_LOOK_CAMERA_FACE_LIMIT,
DSC_X_ITEM_LIGHT,
DSC_X_CHARA_EFFECT,
DSC_X_MARKER,
DSC_X_CHARA_EFFECT_CHARA_LIGHT,
DSC_X_ENABLE_COMMON_LIGHT_TO_CHARA,
DSC_X_ENABLE_FXAA,
DSC_X_ENABLE_TEMPORAL_AA,
DSC_X_ENABLE_REFLECTION,
DSC_X_BANK_BRANCH,
DSC_X_BANK_END,
DSC_X_NULL1,
DSC_X_NULL2,
DSC_X_NULL3,
DSC_X_NULL4,
DSC_X_NULL5,
DSC_X_NULL6,
DSC_X_NULL7,
DSC_X_NULL8,
DSC_X_VR_LIVE_MOVIE,
DSC_X_VR_CHEER,
DSC_X_VR_CHARA_PSMOVE,
DSC_X_VR_MOVE_PATH,
DSC_X_VR_SET_BASE,
DSC_X_VR_TECH_DEMO_EFFECT,
DSC_X_VR_TRANSFORM,
DSC_X_GAZE,
DSC_X_TECH_DEMO_GESUTRE,
DSC_X_VR_CHEMICAL_LIGHT_COLOR,
DSC_X_VR_LIVE_MOB,
DSC_X_VR_LIVE_HAIR_OSAGE,
DSC_X_VR_LIVE_LOOK_CAMERA,
DSC_X_VR_LIVE_CHEER,
DSC_X_VR_LIVE_GESTURE,
DSC_X_VR_LIVE_CLONE,
DSC_X_VR_LOOP_EFFECT,
DSC_X_VR_LIVE_ONESHOT_EFFECT,
DSC_X_VR_LIVE_PRESENT,
DSC_X_VR_LIVE_TRANSFORM,
DSC_X_VR_LIVE_FLY,
DSC_X_VR_LIVE_CHARA_VOICE,
DSC_X_MAX,
};
#define DOF_BAKE 0
#if DOF_BAKE
struct dof_cam {
std::vector<float_t> position_x;
std::vector<float_t> position_y;
std::vector<float_t> position_z;
std::vector<float_t> focus;
std::vector<float_t> focus_range;
std::vector<float_t> fuzzing_range;
std::vector<float_t> ratio;
prj::vector_pair<int32_t, bool> enable_frame;
int32_t frame;
bool enable;
dof_cam();
~dof_cam();
void reset();
};
#endif
static int32_t aet_index_table[] = { 0, 1, 2, 6, 5 };
#if DOF_BAKE
dof_cam dof_cam_data;
#endif
x_pv_game* x_pv_game_ptr;
x_pv_game_music* x_pv_game_music_ptr;
XPVGameSelector* x_pv_game_selector_ptr;
extern render_context* rctx_ptr;
static vec4 bright_scale_get(int32_t index, float_t value);
static float_t dsc_time_to_frame(int64_t time);
static void x_pv_game_chara_item_alpha_callback(void* data, int32_t chara_id, int32_t type, float_t alpha);
static void x_pv_game_change_field(x_pv_game* xpvgm, int32_t field, int64_t dsc_time, int64_t curr_time);
static bool x_pv_game_dsc_process(x_pv_game* xpvgm, int64_t curr_time);
#if BAKE_PV826
static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys);
#endif
static void x_pv_game_reset_field(x_pv_game* xpvgm);
static void x_pv_game_split_auth_3d_hrc_material_list(x_pv_game* xpvgm,
std::vector<object_info>& object_hrc, std::vector<std::string>& material_list);
static void x_pv_game_split_auth_3d_material_list(x_pv_game* xpvgm,
std::vector<object_info>& object, std::vector<std::string>& material_list);
static void pv_game_dsc_data_find_playdata_item_anim(x_pv_game* xpvgm, int32_t chara_id);
static void pv_game_dsc_data_find_playdata_set_motion(x_pv_game* xpvgm, int32_t chara_id);
static void pv_game_dsc_data_find_set_motion(x_pv_game* xpvgm);
static void pv_game_dsc_data_set_motion_max_frame(x_pv_game* xpvgm,
int32_t chara_id, int32_t motion_index, int64_t disp_time);
bool x_pv_bar_beat_data::compare_bar_time_less(float_t time) {
return (time + 0.0001f) < bar_time;
}
x_pv_bar_beat::x_pv_bar_beat() : curr_time(), delta_time(), next_bar_time(),
curr_bar_time(), next_beat_time(), curr_beat_time(), bar(), counter() {
reset();
}
x_pv_bar_beat::~x_pv_bar_beat() {
}
float_t x_pv_bar_beat::get_bar_current_frame() {
return (curr_time - curr_bar_time) / (next_bar_time - curr_bar_time) * 120.0f;
}
float_t x_pv_bar_beat::get_delta_frame() {
return delta_time / (next_bar_time - curr_bar_time) * 120.0f;
}
int32_t x_pv_bar_beat::get_bar_beat_from_time(int32_t* beat, float_t time) {
if (!data.size()) {
int32_t bar = (int32_t)(float_t)(time / divisor);
if (beat)
*beat = (int32_t)(4.0f * (time - (float_t)(int32_t)(time / divisor) * divisor) / divisor) + 1;
return bar + 1;
}
x_pv_bar_beat_data* d = data.data();
const size_t size = data.size();
size_t length = size;
size_t temp;
while (length > 0)
if (d[temp = length / 2].compare_bar_time_less(time))
length = temp;
else {
d += temp + 1;
length -= temp + 1;
}
if (d == data.data() + size) {
float_t divisor = this->divisor;
float_t diff_time = time - data.back().bar_time;
if (size > 1)
divisor = data[size - 1].bar_time - data[size - 2].bar_time;
if (beat)
*beat = (int32_t)((float_t)data.back().beat_count * (diff_time
- (float_t)(int32_t)(diff_time / divisor) * divisor) / divisor) + 1;
return (int32_t)(diff_time / divisor) + data.back().bar;
}
int32_t bar = d->bar - 1;
if (beat) {
*beat = 1;
if (d == data.data())
*beat = (int32_t)((float_t)d->beat_count * time / d->bar_time) + 1;
else {
int32_t v18 = d[-1].beat_count - 1;
if (v18 >= 0) {
float_t* v19 = &d[-1].beat_time[v18];
for (; *v19 > time; v19--)
if (--v18 < 0)
return bar;
*beat = v18 + 1;
}
}
}
return bar;
}
float_t x_pv_bar_beat::get_next_beat_time(float_t time) {
x_pv_bar_beat_data* d = data.data();
const size_t size = data.size();
size_t length = size;
size_t temp;
while (length > 0)
if (d[temp = length / 2].compare_bar_time_less(time))
length = temp;
else {
d += temp + 1;
length -= temp + 1;
}
if (d == data.data() + size) {
float_t v12 = 0.0f;
float_t v13 = divisor * 0.25f;
if (size) {
v12 = data[size - 1].bar_time;
v13 = v12 - data[size - 2].beat_time[data[size - 2].beat_count - 1];
}
float_t beat_time = (float_t)((int32_t)((time - v12) / v13) + 1) * v13 + v12;
if (beat_time < time + 0.00001f)
beat_time += v13;
return beat_time;
}
else if (d != data.data()) {
int32_t v9 = d[-1].beat_count - 1;
if (v9 >= 0) {
float_t* beat_time = &d[-1].beat_time[v9];
for (; time >= *beat_time; beat_time--)
if (--v9 < 0)
return d->bar_time;
return *beat_time;
}
}
return d->bar_time;
}
float_t x_pv_bar_beat::get_time_from_bar_beat(int32_t bar, int32_t beat) {
if (bar < 0)
return 0.0f;
x_pv_bar_beat_data* d = data.data();
const size_t size = data.size();
int32_t beat_count;
if (size) {
int32_t bar_diff = bar - d->bar;
if (bar_diff < 0)
beat_count = d->beat_count;
else if (size > bar_diff)
beat_count = d[bar_diff].beat_count;
else
beat_count = d[size - 1].beat_count;
if (!beat_count)
beat_count = 4;
}
else
beat_count = 4;
beat--;
if (!size)
return (float_t)beat * divisor / (float_t)beat_count + (bar - 1) * divisor;
int32_t bar_diff = bar - d->bar;
if (bar_diff < 0)
return 0.0f;
if (size <= bar_diff) {
float_t divisor = this->divisor;
if (size > 1)
divisor = d[size - 1].bar_time - d[size - 2].bar_time;
return (float_t)beat * divisor / (float_t)beat_count
+ (bar - d[size - 1].bar) * divisor + d[size - 1].bar_time;
}
else if (beat < 0 || beat >= d[bar_diff].beat_count)
return d[bar_diff].bar_time;
else
return d[bar_diff].beat_time[beat];
}
void x_pv_bar_beat::reset() {
curr_time = 0.0f;
delta_time = 0.0f;
next_bar_time = 0.0f;
curr_bar_time = 0.0f;
next_beat_time = 0.0f;
curr_beat_time = 0.0f;
divisor = 2.0f;
bar = 0;
data.clear();
data.shrink_to_fit();
}
void x_pv_bar_beat::reset_time() {
curr_time = 0.0f;
delta_time = 0.0f;
x_pv_bar_beat_data* d = data.data();
const size_t size = data.size();
size_t length = size;
size_t temp;
while (length > 0)
if (d[temp = length / 2].compare_bar_time_less(next_bar_time))
length = temp;
else {
d += temp + 1;
length -= temp + 1;
}
float_t next_bar_time;
if (d == data.data() + data.size()) {
float_t bar_time = 0.0f;
float_t divisor = this->divisor;
if (data.size())
bar_time = data.back().bar_time;
next_bar_time = (float_t)((int32_t)((-bar_time) / divisor) + 1) * divisor + bar_time;
if (next_bar_time < 0.00001f)
next_bar_time += divisor;
}
else
next_bar_time = d->bar_time;
curr_bar_time = 0.0f;
this->next_bar_time = next_bar_time;
curr_beat_time = 0.0f;
next_beat_time = get_next_beat_time(0.0f);
bar = 1;
counter = 0;
}
void x_pv_bar_beat::set_frame(float_t curr_frame, float_t delta_frame) {
set_time(curr_frame * (float_t)(1.0 / 60.0), delta_frame * (float_t)(1.0 / 60.0));
}
void x_pv_bar_beat::set_time(float_t curr_time, float_t delta_time) {
if (next_bar_time <= 0.0f)
return;
this->curr_time = curr_time;
this->delta_time = delta_time;
counter = 0;
float_t next_bar_time = this->next_bar_time;
while (curr_time >= next_bar_time) {
curr_bar_time = next_bar_time;
bar++;
counter++;
x_pv_bar_beat_data* d = data.data();
const size_t size = data.size();
size_t length = size;
size_t temp;
while (length > 0)
if (d[temp = length / 2].compare_bar_time_less(next_bar_time))
length = temp;
else {
d += temp + 1;
length -= temp + 1;
}
if (d == data.data() + data.size()) {
float_t v11 = 0.0f;
float_t v12 = divisor;
if (data.size())
v11 = data.back().bar_time;
float_t _next_bar_time = (float_t)((int32_t)((next_bar_time - v11) / v12) + 1) * v12 + v11;
if (_next_bar_time < next_bar_time + 0.00001f)
_next_bar_time += v12;
next_bar_time = _next_bar_time;
}
else
next_bar_time = d->bar_time;
this->next_bar_time = next_bar_time;
}
while (curr_time >= next_beat_time) {
curr_beat_time = next_beat_time;
next_beat_time = get_next_beat_time(next_beat_time);
}
}
BPMFrameRateControl::BPMFrameRateControl() : bar_beat() {
}
BPMFrameRateControl::~BPMFrameRateControl() {
}
float_t BPMFrameRateControl::GetDeltaFrame() {
if (bar_beat)
return bar_beat->get_delta_frame();
return 0.0f;
}
void BPMFrameRateControl::Reset() {
bar_beat = 0;
SetFrameSpeed(1.0f);
}
XPVFrameRateControl::XPVFrameRateControl() {
}
XPVFrameRateControl::~XPVFrameRateControl() {
}
float_t XPVFrameRateControl::GetDeltaFrame() {
return get_delta_frame() * frame_speed;
}
void XPVFrameRateControl::Reset() {
frame_speed = 1.0f;
}
x_pv_play_data_motion_data::x_pv_play_data_motion_data() : rob_chr(), current_time(),
duration(), start_pos(), end_pos(), start_rot(), end_rot() {
mot_smooth_len = 12.0f;
}
x_pv_play_data_motion_data::~x_pv_play_data_motion_data() {
}
void x_pv_play_data_motion_data::reset() {
rob_chr = 0;
current_time = 0.0f;
duration = 0.0f;
start_pos = 0.0f;
end_pos = 0.0f;
start_rot = 0.0f;
end_rot = 0.0f;
mot_smooth_len = 12.0f;
set_motion.clear();
set_motion.shrink_to_fit();
set_item.clear();
set_item.shrink_to_fit();
}
x_pv_play_data::x_pv_play_data() : rob_chr(), disp() {
}
x_pv_play_data::~x_pv_play_data() {
}
void x_pv_play_data::reset() {
if (rob_chr) {
data_struct* aft_data = &data_list[DATA_AFT];
bone_database* aft_bone_data = &aft_data->data_ft.bone_data;
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
int32_t mottbl_index = hand_anim_id_to_mottbl_index(2);
rob_chr->reset_data(&rob_chr->pv_data, aft_bone_data, aft_mot_db);
rob_chr->set_hand_l_mottbl_motion(0, mottbl_index, 1.0f, 0, 0.0f, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
rob_chr->set_hand_r_mottbl_motion(0, mottbl_index, 1.0f, 0, 0.0f, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
rob_chr->set_visibility(false);
}
motion.clear();
motion.shrink_to_fit();
rob_chr = 0;
set_motion.clear();
disp = true;
motion_data.reset();
}
#if BAKE_PV826
x_pv_game_a3da_to_mot_keys::x_pv_game_a3da_to_mot_keys() {
}
x_pv_game_a3da_to_mot_keys::~x_pv_game_a3da_to_mot_keys() {
}
x_pv_game_a3da_to_mot::x_pv_game_a3da_to_mot(auth_3d_id id) {
this->id = id;
gblctr = -1;
n_hara = -1;
n_hara_y = -1;
j_hara_wj = -1;
n_kosi = -1;
j_mune_wj = -1;
n_mune_kl = -1;
j_mune_b_wj = -1;
j_kubi_wj = -1;
n_kao = -1;
j_kao_wj = -1;
j_kao_normal_wj = -1;
j_kao_close_wj = -1;
j_kao_smile_wj = -1;
j_kao_close_half_wj = -1;
j_kao_smile_half_wj = -1;
j_kuti_l_wj = -1;
j_kuti_u_wj = -1;
j_kuti_d_wj = -1;
j_kuti_r_wj = -1;
j_eye_r_wj = -1;
j_eye_l_wj = -1;
n_waki_l = -1;
j_waki_l_wj = -1;
n_kata_l = -1;
j_kata_l_wj = -1;
j_ude_l_wj = -1;
j_te_l_wj = -1;
j_te_sizen2_l_wj = -1;
j_te_close_l_wj = -1;
j_te_reset_l_wj = -1;
n_waki_r = -1;
j_waki_r_wj = -1;
n_kata_r = -1;
j_kata_r_wj = -1;
j_ude_r_wj = -1;
j_te_r_wj = -1;
j_te_sizen2_r_wj = -1;
j_te_close_r_wj = -1;
j_te_reset_r_wj = -1;
j_te_one_r_wj = -1;
j_kosi_wj = -1;
n_momo_l = -1;
j_momo_l_wj = -1;
j_sune_l_wj = -1;
j_asi_l_wj = -1;
n_momo_r = -1;
j_momo_r_wj = -1;
j_sune_r_wj = -1;
j_asi_r_wj = -1;
}
x_pv_game_a3da_to_mot::~x_pv_game_a3da_to_mot() {
}
static int32_t get_bone_index(auth_3d_object_hrc* oh, const char* name) {
uint32_t name_hash = hash_utf8_murmurhash(name);
for (auth_3d_object_node& i : oh->node)
if (hash_string_murmurhash(i.name) == name_hash)
return (int32_t)(&i - oh->node.data());
return -1;
}
void x_pv_game_a3da_to_mot::get_bone_indices(auth_3d_object_hrc* oh) {
gblctr = get_bone_index(oh, "gblctr");
n_hara = get_bone_index(oh, "n_hara");
n_hara_y = get_bone_index(oh, "n_hara_y");
j_hara_wj = get_bone_index(oh, "j_hara_wj");
n_kosi = get_bone_index(oh, "n_kosi");
j_mune_wj = get_bone_index(oh, "j_mune_wj");
n_mune_kl = get_bone_index(oh, "n_mune_kl");
j_mune_b_wj = get_bone_index(oh, "j_mune_b_wj");
j_kubi_wj = get_bone_index(oh, "j_kubi_wj");
n_kao = get_bone_index(oh, "n_kao");
j_kao_wj = get_bone_index(oh, "j_kao_wj");
j_kao_normal_wj = get_bone_index(oh, "j_kao_normal_wj");
j_kao_close_wj = get_bone_index(oh, "j_kao_close_wj");
j_kao_smile_wj = get_bone_index(oh, "j_kao_smile_wj");
j_kao_close_half_wj = get_bone_index(oh, "j_kao_close_half_wj");
j_kao_smile_half_wj = get_bone_index(oh, "j_kao_smile_half_wj");
j_kuti_l_wj = get_bone_index(oh, "j_kuti_l_wj");
j_kuti_u_wj = get_bone_index(oh, "j_kuti_u_wj");
j_kuti_d_wj = get_bone_index(oh, "j_kuti_d_wj");
j_kuti_r_wj = get_bone_index(oh, "j_kuti_r_wj");
j_eye_r_wj = get_bone_index(oh, "j_eye_r_wj");
j_eye_l_wj = get_bone_index(oh, "j_eye_l_wj");
n_waki_l = get_bone_index(oh, "n_waki_l");
j_waki_l_wj = get_bone_index(oh, "j_waki_l_wj");
n_kata_l = get_bone_index(oh, "n_kata_l");
j_kata_l_wj = get_bone_index(oh, "j_kata_l_wj");
j_ude_l_wj = get_bone_index(oh, "j_ude_l_wj");
j_te_l_wj = get_bone_index(oh, "j_te_l_wj");
j_te_sizen2_l_wj = get_bone_index(oh, "j_te_sizen2_l_wj");
j_te_close_l_wj = get_bone_index(oh, "j_te_close_l_wj");
j_te_reset_l_wj = get_bone_index(oh, "j_te_reset_l_wj");
n_waki_r = get_bone_index(oh, "n_waki_r");
j_waki_r_wj = get_bone_index(oh, "j_waki_r_wj");
n_kata_r = get_bone_index(oh, "n_kata_r");
j_kata_r_wj = get_bone_index(oh, "j_kata_r_wj");
j_ude_r_wj = get_bone_index(oh, "j_ude_r_wj");
j_te_r_wj = get_bone_index(oh, "j_te_r_wj");
j_te_sizen2_r_wj = get_bone_index(oh, "j_te_sizen2_r_wj");
j_te_close_r_wj = get_bone_index(oh, "j_te_close_r_wj");
j_te_reset_r_wj = get_bone_index(oh, "j_te_reset_r_wj");
j_te_one_r_wj = get_bone_index(oh, "j_te_one_r_wj");
j_kosi_wj = get_bone_index(oh, "j_kosi_wj");
n_momo_l = get_bone_index(oh, "n_momo_l");
j_momo_l_wj = get_bone_index(oh, "j_momo_l_wj");
j_sune_l_wj = get_bone_index(oh, "j_sune_l_wj");
j_asi_l_wj = get_bone_index(oh, "j_asi_l_wj");
n_momo_r = get_bone_index(oh, "n_momo_r");
j_momo_r_wj = get_bone_index(oh, "j_momo_r_wj");
j_sune_r_wj = get_bone_index(oh, "j_sune_r_wj");
j_asi_r_wj = get_bone_index(oh, "j_asi_r_wj");
}
#endif
x_pv_game_song_effect_auth_3d::x_pv_game_song_effect_auth_3d() {
}
x_pv_game_song_effect_auth_3d::x_pv_game_song_effect_auth_3d(auth_3d_id id) {
this->id = id;
}
void x_pv_game_song_effect_auth_3d::reset() {
id = {};
}
x_pv_game_song_effect_glitter::x_pv_game_song_effect_glitter() : scene_counter(), field_8(), field_9() {
reset();
}
void x_pv_game_song_effect_glitter::reset() {
name.clear();
scene_counter = 0;
field_8 = false;
for (bool& i : field_9)
i = false;
}
x_pv_game_song_effect::x_pv_game_song_effect() : enable(), chara_id(), time() {
reset();
}
x_pv_game_song_effect::~x_pv_game_song_effect() {
}
void x_pv_game_song_effect::reset() {
enable = false;
chara_id = -1;
time = -1;
auth_3d.clear();
auth_3d.shrink_to_fit();
glitter.clear();
glitter.shrink_to_fit();
}
x_pv_game_camera::x_pv_game_camera() : state() {
reset();
}
x_pv_game_camera::~x_pv_game_camera() {
}
void x_pv_game_camera::ctrl(float_t curr_time) {
switch (state) {
case 10: {
if (!auth_3d_data_check_category_loaded(category.hash_murmurhash))
break;
auth_3d_id id = auth_3d_data_load_hash(file.hash_murmurhash, &data_list[DATA_X], 0, 0);
if (id.check_not_empty()) {
id.read_file_modern();
id.set_enable(false);
id.set_repeat(false);
id.set_paused(false);
id.set_frame_rate(frame_rate_control);
}
this->id = id;
rctx_ptr->camera->reset();
state = 11;
} break;
case 11: {
if (id.check_not_empty() && id.check_loaded())
state = 20;
} break;
case 20: {
auth_3d_id& id = this->id;
id.set_enable(true);
id.set_repeat(false);
id.set_paused(false);
id.set_camera_root_update(true);
id.set_req_frame(curr_time * 60.0f);
} break;
}
}
void x_pv_game_camera::load(int32_t pv_id, int32_t stage_id, FrameRateControl* frame_rate_control) {
char buf[0x200];
sprintf_s(buf, sizeof(buf), "CAMPV%03d", pv_id);
category.assign(buf);
if ((pv_id % 100) >= 25 && (pv_id % 100) <= 30 && stage_id >= 25 && stage_id <= 30)
sprintf_s(buf, sizeof(buf), "CAMPV%03d_100", pv_id);
else
sprintf_s(buf, sizeof(buf), "CAMPV%03d_BASE", pv_id);
file.assign(buf);
this->frame_rate_control = frame_rate_control;
}
void x_pv_game_camera::load_data() {
if (state || !category.str.size())
return;
auth_3d_data_load_category(&data_list[DATA_X], category.c_str(), category.hash_murmurhash);
state = 10;
}
void x_pv_game_camera::reset() {
state = 0;
category.clear();
file.clear();
id = {};
}
void x_pv_game_camera::stop() {
if (id.check_not_empty())
id.set_enable(false);
}
void x_pv_game_camera::unload() {
if (state != 20)
return;
id.unload(rctx_ptr);
auth_3d_data_unload_category(category.hash_murmurhash);
state = 0;
}
x_pv_game_effect::x_pv_game_effect() : flags(), state(),
play_param(), change_fields(), frame_rate_control() {
reset();
}
x_pv_game_effect::~x_pv_game_effect() {
}
void x_pv_game_effect::ctrl(object_database* obj_db, texture_database* tex_db) {
switch (state) {
case 10: {
bool wait_load = false;
for (string_hash& i : pv_auth_3d)
if (!auth_3d_data_check_category_loaded(i.hash_murmurhash))
wait_load |= true;
for (string_hash& i : pv_obj_set)
if (object_storage_get_obj_set_handler(i.hash_murmurhash)
&& object_storage_load_obj_set_check_not_read(i.hash_murmurhash, obj_db, tex_db))
wait_load |= true;
if (wait_load)
break;
data_struct* x_data = &data_list[DATA_X];
pvpp* play_param = this->play_param;
size_t song_effect_count = song_effect.size();
for (size_t i = 0; i < song_effect_count; i++) {
x_pv_game_song_effect& song_effect = this->song_effect[i];
pvpp_effect& effect = play_param->effect[i];
for (string_hash& j : effect.auth_3d) {
auth_3d_id id = auth_3d_data_load_hash(j.hash_murmurhash, x_data, obj_db, tex_db);
if (!id.check_not_empty())
continue;
id.read_file_modern();
id.set_enable(false);
id.set_repeat(false);
id.set_paused(false);
id.set_visibility(false);
id.set_frame_rate(frame_rate_control);
song_effect.auth_3d.push_back(id);
}
}
state = 11;
} break;
case 11: {
bool wait_load = false;
for (x_pv_game_song_effect& i : song_effect)
for (x_pv_game_song_effect_auth_3d& j : i.auth_3d)
if (j.id.check_not_empty() && !j.id.check_loaded())
wait_load |= true;
for (string_hash& i : pv_glitter)
if (!Glitter::glt_particle_manager->CheckNoFileReaders(i.hash_murmurhash))
wait_load |= true;
if (wait_load)
break;
pvpp* play_param = this->play_param;
size_t chara_count = play_param->chara.size();
size_t song_effect_count = song_effect.size();
for (size_t i = 0; i < song_effect_count; i++) {
x_pv_game_song_effect& song_effect = this->song_effect[i];
pvpp_effect& effect = play_param->effect[i];
for (pvpp_glitter& j : effect.glitter) {
x_pv_game_song_effect_glitter v132;
v132.name.assign(j.name);
v132.scene_counter = 0;
v132.field_8 = !!(j.unk2 & 0x01);
for (bool& i : v132.field_9)
i = true;
for (int32_t k = 0; k < chara_count && k < ROB_CHARA_COUNT; k++) {
bool v121 = false;
if (k < play_param->chara.size()) {
pvpp_chara& chara = play_param->chara[k];
for (pvpp_glitter& l : chara.glitter)
if (j.name.hash_murmurhash == l.name.hash_murmurhash) {
v121 = true;
break;
}
}
v132.field_9[k] = v121;
}
song_effect.glitter.push_back(v132);
}
}
data_struct* x_data = &data_list[DATA_X];
for (string_hash& i : pv_glitter) {
Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash_murmurhash);
if (eff_group && eff_group->CheckModel())
eff_group->LoadModel(x_data);
}
state = 12;
break;
}
case 12: {
bool wait_load = false;
for (string_hash& i : pv_glitter) {
Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash_murmurhash);
if (eff_group && eff_group->CheckLoadModel())
wait_load |= true;
}
if (wait_load)
break;
state = 20;
}
case 20: {
for (x_pv_game_song_effect& i : song_effect)
if (i.enable)
for (x_pv_game_song_effect_auth_3d& j : i.auth_3d)
j.id.set_chara_id(i.chara_id);
} break;
}
}
void x_pv_game_effect::load(int32_t pv_id, pvpp* play_param, FrameRateControl* frame_rate_control) {
this->play_param = play_param;
this->frame_rate_control = frame_rate_control;
size_t effect_count = play_param->effect.size();
if (!effect_count)
return;
song_effect.resize(effect_count);
for (size_t i = 0; i < effect_count; i++) {
pvpp_effect& eff = play_param->effect[i];
if (!eff.auth_3d.size())
continue;
char buf[0x200];
size_t len = sprintf_s(buf, sizeof(buf), "A3D_EFFPV%03d", pv_id);
pv_auth_3d.push_back(std::string(buf, len));
len = sprintf_s(buf, sizeof(buf), "effpv%03d", 800 + (pv_id % 100));
pv_obj_set.push_back(std::string(buf, len));
break;
}
}
void x_pv_game_effect::load_data(int32_t pv_id) {
if (state)
return;
data_struct* x_data = &data_list[DATA_X];
for (string_hash& i : pv_obj_set)
object_storage_load_set_hash(x_data, i.hash_murmurhash);
for (string_hash& i : pv_auth_3d)
auth_3d_data_load_category(x_data, i.c_str(), i.hash_murmurhash);
size_t effect_count = play_param->effect.size();
for (size_t i = 0; i < effect_count; i++) {
pvpp_effect& eff = play_param->effect[i];
if (!eff.glitter.size())
continue;
char buf[0x200];
size_t len = sprintf_s(buf, sizeof(buf), "eff_pv%03d_main", pv_id);
uint32_t hash = (uint32_t)Glitter::glt_particle_manager->LoadFile(Glitter::X,
x_data, buf, 0, -1.0f, false);
if (hash != hash_murmurhash_empty)
pv_glitter.push_back(std::string(buf, len));
break;
}
state = 10;
}
void x_pv_game_effect::reset() {
flags = 0;
state = 0;
play_param = 0;
change_fields = 0;
pv_obj_set.clear();
pv_obj_set.shrink_to_fit();
pv_auth_3d.clear();
pv_auth_3d.shrink_to_fit();
pv_glitter.clear();
pv_glitter.shrink_to_fit();
song_effect.clear();
song_effect.shrink_to_fit();
frame_rate_control = 0;
}
void x_pv_game_effect::set_chara_id(int32_t index, int32_t chara_id, bool chara_item) {
if (index < 0 || index >= song_effect.size())
return;
x_pv_game_song_effect& song_effect = this->song_effect[index];
for (x_pv_game_song_effect_auth_3d& i : song_effect.auth_3d) {
i.id.set_chara_id(chara_id);
i.id.set_chara_item(chara_item);
}
song_effect.chara_id = chara_id;
}
void x_pv_game_effect::set_song_effect(int32_t index, int64_t time) {
if (state && state != 20)
return;
if (index < 0 || index >= song_effect.size())
return;
x_pv_game_song_effect& song_effect = this->song_effect[index];
if (song_effect.enable) {
set_song_effect_time_inner(index, time, false);
return;
}
pvpp* play_param = this->play_param;
size_t chara_count = play_param->chara.size();
int32_t chara_id = play_param->effect[index].chara_id;
if (chara_id < 0 && chara_id >= ROB_CHARA_COUNT)
chara_id = -1;
song_effect.chara_id = chara_id;
for (x_pv_game_song_effect_auth_3d& i : song_effect.auth_3d) {
i.id.set_enable(true);
i.id.set_repeat(false);
i.id.set_req_frame(0.0f);
i.id.set_visibility(true);
}
for (x_pv_game_song_effect_glitter& i : song_effect.glitter) {
i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(i.name.hash_murmurhash, i.name.c_str());
if (!i.scene_counter)
continue;
Glitter::glt_particle_manager->SetSceneFrameRate(i.scene_counter, 0);
}
song_effect.enable = true;
song_effect.time = time;
set_song_effect_time_inner(index, time, false);
for (x_pv_game_song_effect_auth_3d& i : song_effect.auth_3d)
i.id.set_chara_id(chara_id);
}
void x_pv_game_effect::set_song_effect_time(int32_t index, int64_t time, bool glitter) {
if (index >= 0 && index < song_effect.size() && song_effect[index].enable)
set_song_effect_time_inner(index, time, glitter);
}
void x_pv_game_effect::set_song_effect_time_inner(int32_t index, int64_t time, bool glitter) {
if (index < 0 || index >= song_effect.size())
return;
x_pv_game_song_effect& song_effect = this->song_effect[index];
float_t req_frame = (float_t)((double_t)(time - song_effect.time) * 0.000000001) * 60.0f;
float_t max_frame = -1.0f;
if (change_fields) {
int64_t* key = change_fields->data();
size_t length = change_fields->size();
size_t temp;
while (length > 0)
if (key[temp = length / 2] > time)
length = temp;
else {
key += temp + 1;
length -= temp + 1;
}
if (key != change_fields->data() + change_fields->size())
max_frame = (float_t)((double_t)(*key - song_effect.time) * 0.000000001) * 60.0f - 1.0f;
}
for (x_pv_game_song_effect_auth_3d& i : song_effect.auth_3d) {
i.id.set_req_frame(req_frame);
i.id.set_paused(false);
i.id.set_max_frame(max_frame);
}
if (glitter)
for (x_pv_game_song_effect_glitter& i : song_effect.glitter) {
if (!i.scene_counter)
continue;
float_t frame = Glitter::glt_particle_manager->GetSceneFrameLifeTime(i.scene_counter, 0);
Glitter::glt_particle_manager->SetSceneEffectReqFrame(i.scene_counter, req_frame - frame);
}
}
void x_pv_game_effect::set_time(int64_t time, bool glitter) {
size_t size = song_effect.size();
for (size_t i = 0; i < size; i++)
if (song_effect[i].enable)
set_song_effect_time_inner((int32_t)i, time, glitter);
}
void x_pv_game_effect::stop() {
size_t song_effect_count = song_effect.size();
for (size_t i = 0; i < song_effect_count; i++)
stop_song_effect((int32_t)i, false);
for (string_hash& i : pv_glitter)
Glitter::glt_particle_manager->FreeScene(i.hash_murmurhash);
}
void x_pv_game_effect::stop_song_effect(int32_t index, bool free_glitter) {
if ((state && state != 20) || index < 0 || index >= song_effect.size() || !song_effect[index].enable)
return;
x_pv_game_song_effect& song_effect = this->song_effect[index];
for (x_pv_game_song_effect_auth_3d& i : song_effect.auth_3d) {
auth_3d_id& id = i.id;
id.set_enable(false);
id.set_req_frame(0.0f);
id.set_visibility(false);
}
for (x_pv_game_song_effect_glitter& i : song_effect.glitter)
if (i.scene_counter) {
Glitter::glt_particle_manager->FreeSceneEffect(i.scene_counter, !free_glitter);
i.scene_counter = 0;
}
song_effect.chara_id = -1;
song_effect.enable = false;
}
void x_pv_game_effect::unload() {
if (state && state != 20)
return;
size_t song_effect_count = song_effect.size();
for (size_t i = 0; i < song_effect_count; i++)
stop_song_effect((int32_t)i, false);
for (string_hash& i : pv_glitter)
Glitter::glt_particle_manager->FreeScene(i.hash_murmurhash);
for (x_pv_game_song_effect& i : song_effect)
for (x_pv_game_song_effect_auth_3d& j : i.auth_3d) {
j.id.unload(rctx_ptr);
j.id = {};
}
for (string_hash& i : pv_auth_3d)
auth_3d_data_unload_category(i.hash_murmurhash);
for (string_hash& i : pv_obj_set)
object_storage_unload_set(i.hash_murmurhash);
for (string_hash& i : pv_glitter) {
Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i.hash_murmurhash);
if (eff_group)
eff_group->FreeModel();
Glitter::glt_particle_manager->UnloadEffectGroup(i.hash_murmurhash);
}
song_effect.clear();
song_effect.resize(song_effect_count);
state = 0;
}
x_pv_game_chara_effect_auth_3d::x_pv_game_chara_effect_auth_3d() : field_0(), src_chara(), dst_chara() {
id = {};
time = -1;
reset();
}
x_pv_game_chara_effect_auth_3d::~x_pv_game_chara_effect_auth_3d() {
}
void x_pv_game_chara_effect_auth_3d::reset() {
field_0 = false;
src_chara = CHARA_MAX;
dst_chara = CHARA_MAX;
file.clear();
category.clear();
object_set.clear();
id = {};
time = -1;
}
x_pv_game_chara_effect::x_pv_game_chara_effect() : state(), change_fields(), frame_rate_control() {
reset();
}
x_pv_game_chara_effect::~x_pv_game_chara_effect() {
}
#if BAKE_PV826
void x_pv_game_chara_effect::ctrl(object_database* obj_db, texture_database* tex_db,
int32_t pv_id, std::map<uint32_t, auth_3d_id>* effchrpv_auth_3d_mot_ids) {
#else
void x_pv_game_chara_effect::ctrl(object_database* obj_db, texture_database* tex_db) {
#endif
switch (state) {
case 20: {
bool wait_load = false;
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d j : i) {
if (!j.category.str.size())
continue;
if (!auth_3d_data_check_category_loaded(j.category.hash_murmurhash))
wait_load |= true;
if (object_storage_get_obj_set_handler(j.object_set.hash_murmurhash)
&& object_storage_load_obj_set_check_not_read(j.object_set.hash_murmurhash, obj_db, tex_db))
wait_load |= true;
}
if (wait_load)
break;
data_struct* x_data = &data_list[DATA_X];
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d& j : i) {
if (!j.category.str.size())
continue;
auth_3d_id id = auth_3d_data_load_hash(j.file.hash_murmurhash, x_data, obj_db, tex_db);
if (!id.check_not_empty()) {
j.id = {};
continue;
}
id.read_file_modern();
id.set_enable(false);
id.set_repeat(false);
id.set_paused(true);
id.set_visibility(false);
id.set_frame_rate(frame_rate_control);
if (j.field_0)
id.set_src_dst_chara(j.src_chara, j.dst_chara);
j.id = id;
#if BAKE_PV826
if (pv_id == 826 && effchrpv_auth_3d_mot_ids)
effchrpv_auth_3d_mot_ids->insert({ j.file.hash_murmurhash, id });
#endif
}
state = 21;
} break;
case 21: {
bool wait_load = false;
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d j : i) {
if (!j.category.str.size())
continue;
if (j.id.check_not_empty() && !j.id.check_loaded())
wait_load |= true;
}
if (!wait_load)
state = 30;
} break;
}
}
#if BAKE_PV826
void x_pv_game_chara_effect::load(int32_t pv_id, pvpp* play_param,
FrameRateControl* frame_rate_control, chara_index charas[6],
std::unordered_map<std::string, string_hash>* effchrpv_auth_3d_mot_names) {
#else
void x_pv_game_chara_effect::load(int32_t pv_id, pvpp* play_param,
FrameRateControl* frame_rate_control, chara_index charas[6]) {
#endif
if (state)
return;
this->play_param = play_param;
this->frame_rate_control = frame_rate_control;
size_t chara_count = play_param->chara.size();
for (int32_t i = 0; i < chara_count && i < ROB_CHARA_COUNT; i++) {
pvpp_chara& chara = play_param->chara[i];
pvpp_chara_effect& chara_effect = chara.chara_effect;
chara_index src_chara = (chara_index)chara_effect.base_chara;
chara_index dst_chara = charas[i];
/*if (dst_chara == CHARA_EXTRA)
dst_chara = src_chara;*/
std::string src_chara_str = chara_index_get_auth_3d_name(src_chara);
std::string dst_chara_str = chara_index_get_auth_3d_name(dst_chara);
#if BAKE_PV826
std::string mik_chara_str = chara_index_get_auth_3d_name(CHARA_MIKU);
#endif
for (pvpp_chara_effect_auth_3d& j : chara_effect.auth_3d) {
std::string file = j.auth_3d.str;
std::string object_set;
#if BAKE_PV826
if (pv_id != 826) {
#endif
if (!j.object_set.str.size()) {
size_t pos = file.find("_");
if (pos != -1)
object_set.assign(file.substr(0, pos));
else
object_set.assign(file);
}
else
object_set.assign(j.object_set.str);
if (src_chara != dst_chara) {
size_t pos = object_set.find(dst_chara_str);
if (pos && pos != -1)
object_set.replace(pos, dst_chara_str.size(), src_chara_str);
if (!j.u00) {
size_t pos = file.find(dst_chara_str);
if (pos != -1)
file.replace(pos, dst_chara_str.size(), src_chara_str);
}
}
#if BAKE_PV826
}
else {
char buf[0x200];
sprintf_s(buf, sizeof(buf), "EFFCHRPV%03d", pv_id);
if (j.auth_3d.str.find(buf) == std::string::npos)
continue;
file.assign(j.auth_3d.str);
file.replace(utf8_length(buf), mik_chara_str.size(), mik_chara_str);
sprintf_s(buf, sizeof(buf), "EFFCHRPV%03dMIK001", pv_id);
object_set.assign(buf);
}
#endif
std::string category = "A3D_";
size_t pos = file.find("_");
if (pos != -1)
category.append(file.substr(0, pos));
else
category.append(file);
x_pv_game_chara_effect_auth_3d auth_3d;
auth_3d.field_0 = j.u00;
auth_3d.src_chara = src_chara;
auth_3d.dst_chara = dst_chara;
auth_3d.file = file;
auth_3d.category = category;
auth_3d.object_set = object_set;
this->auth_3d[i].push_back(auth_3d);
#if BAKE_PV826
if (pv_id == 826 && effchrpv_auth_3d_mot_names)
effchrpv_auth_3d_mot_names->insert({ file, category });
#endif
}
}
state = 10;
}
void x_pv_game_chara_effect::load_data() {
if (state != 10)
return;
data_struct* x_data = &data_list[DATA_X];
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d& j : i) {
if (!j.category.str.size())
continue;
auth_3d_data_load_category(x_data, j.category.c_str(), j.category.hash_murmurhash);
object_storage_load_set_hash(x_data, j.object_set.hash_murmurhash);
}
state = 20;
}
void x_pv_game_chara_effect::reset() {
state = 0;
play_param = 0;
change_fields = 0;
frame_rate_control = 0;
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d) {
i.clear();
i.shrink_to_fit();
}
}
void x_pv_game_chara_effect::set_chara_effect(int32_t chara_id, int32_t index, int64_t time) {
if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
return;
std::vector<x_pv_game_chara_effect_auth_3d>& auth_3d = this->auth_3d[chara_id];
if (index < 0 || index >= auth_3d.size())
return;
auth_3d_id& id = auth_3d[index].id;
if (!id.check_not_empty())
return;
if (id.get_enable())
id.set_req_frame((float_t)((double_t)(time - auth_3d[index].time) * 0.000000001) * 60.0f);
else {
id.set_enable(true);
id.set_paused(false);
id.set_repeat(false);
id.set_req_frame(0.0f);
id.set_visibility(true);
auth_3d[index].time = time;
}
float_t max_frame = -1.0f;
if (change_fields) {
int64_t* key = change_fields->data();
size_t length = change_fields->size();
size_t temp;
while (length > 0)
if (key[temp = length / 2] > time)
length = temp;
else {
key += temp + 1;
length -= temp + 1;
}
if (key != change_fields->data() + change_fields->size())
max_frame = (float_t)((double_t)(*key - auth_3d[index].time) * 0.000000001) * 60.0f - 1.0f;
}
id.set_max_frame(max_frame);
}
void x_pv_game_chara_effect::set_chara_effect_time(int32_t chara_id, int32_t index, int64_t time) {
if (!state || chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
return;
for (x_pv_game_chara_effect_auth_3d& i : auth_3d[chara_id]) {
if (!i.id.check_not_empty() || !i.id.get_enable())
continue;
i.id.set_req_frame((float_t)((double_t)(time - i.time) * 0.000000001) * 60.0f);
i.id.set_paused(false);
}
}
void x_pv_game_chara_effect::set_time(int64_t time) {
if (!state)
return;
for (auto& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d& j : i) {
if (!j.id.check_not_empty() || !j.id.get_enable())
continue;
j.id.set_req_frame((float_t)((double_t)(time - j.time) * 0.000000001) * 60.0f);
j.id.set_paused(false);
}
}
void x_pv_game_chara_effect::stop() {
if (!state)
return;
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d& j : i)
if (j.id.check_not_empty())
j.id.set_enable(false);
}
void x_pv_game_chara_effect::stop_chara_effect(int32_t chara_id, int32_t index) {
if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
return;
for (x_pv_game_chara_effect_auth_3d& i : auth_3d[chara_id])
if (i.id.check_not_empty())
i.id.set_enable(false);
}
void x_pv_game_chara_effect::unload() {
if (!state)
return;
if (state == 10 || state == 30) {
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d)
for (x_pv_game_chara_effect_auth_3d& j : i) {
if (!j.category.str.size())
continue;
j.id.unload(rctx_ptr);
auth_3d_data_unload_category(j.category.hash_murmurhash);
object_storage_unload_set(j.object_set.hash_murmurhash);
}
state = 10;
}
for (std::vector<x_pv_game_chara_effect_auth_3d>& i : auth_3d) {
i.clear();
i.shrink_to_fit();
}
frame_rate_control = 0;
play_param = 0;
state = 0;
}
x_pv_game_music_args::x_pv_game_music_args() : type(), start(), field_2C() {
}
x_pv_game_music_args::~x_pv_game_music_args() {
}
x_pv_game_music_ogg::x_pv_game_music_ogg() {
playback = ogg_playback_data_get(0);
}
x_pv_game_music_ogg::~x_pv_game_music_ogg() {
if (playback) {
playback->Reset();
playback = 0;
}
}
x_pv_game_music::x_pv_game_music() : flags(), pause(), channel_pair_volume(), fade_in(),
fade_out(), no_fade(), no_fade_remain(), fade_out_time_req(), fade_out_action_req(),
type(), start(), end(), play_on_end(), fade_in_time(), field_9C(), loaded(), ogg() {
volume = 100;
master_volume = 100;
for (int32_t& i : channel_pair_volume)
i = 100;
fade_out_time = 3.0f;
}
x_pv_game_music::~x_pv_game_music() {
}
bool x_pv_game_music::check_args(int32_t type, std::string&& file_path, float_t start) {
return args.type == type && !args.file_path.compare(file_path) && args.start == start;
}
void x_pv_game_music::ctrl(float_t delta_time) {
if (no_fade && !pause) {
no_fade_remain -= delta_time;
if (no_fade_remain <= 0.0f) {
fade_out.enable = true;
fade_out.start = get_volume(0);
fade_out.value = 0;
fade_out.time = fade_out_time_req;
fade_out.remain = fade_out_time_req;
fade_out.action = fade_out_action_req;
no_fade = false;
no_fade_remain = 0.0f;
fade_out_time_req = 0.0f;
fade_out_action_req = X_PV_GAME_MUSIC_ACTION_NONE;
}
}
if (fade_in.enable && !pause) {
fade_in.remain -= delta_time;
if (fade_in.remain > 0.0f) {
int32_t value = fade_in.value;
if (fade_in.time > 0.0)
value = (int32_t)((float_t)value - (float_t)(value
- fade_in.start) * (fade_in.remain / fade_in.time));
set_volume_map(0, value);
}
else
fade_in_end();
}
if (fade_out.enable && !pause) {
fade_out.remain -= delta_time;
if (fade_out.remain > 0.0f) {
int32_t value = fade_out.value;
if (fade_out.time > 0.0f)
value = (int32_t)(value - ((float_t)(value
- fade_out.start) * (fade_out.remain / fade_out.time)));
set_volume_map(0, value);
}
else
fade_out_end();
}
if (flags & X_PV_GAME_MUSIC_OGG) {
OggPlayback* playback = ogg->playback;
if (playback->GetFileState() == OGG_FILE_HANDLER_FILE_STATE_STOPPED)
playback->Stop();
if (playback->GetFileState() == OGG_FILE_HANDLER_FILE_STATE_STOPPED)
play_or_stop();
OggPlayback::SetChannelPairVolumePan(playback);
}
}
void x_pv_game_music::exclude_flags(x_pv_game_music_flags flags) {
if ((this->flags & X_PV_GAME_MUSIC_OGG) && (flags & X_PV_GAME_MUSIC_OGG))
ogg_free();
enum_and(this->flags, ~flags);
}
void x_pv_game_music::fade_in_end() {
if (!fade_in.enable)
return;
fade_in.enable = false;
fade_in.remain = 0.0f;
set_volume_map(0, fade_in.value);
switch (fade_in.action) {
case X_PV_GAME_MUSIC_ACTION_STOP:
stop();
break;
case X_PV_GAME_MUSIC_ACTION_PAUSE:
set_pause(1);
break;
case X_PV_GAME_MUSIC_ACTION_PLAY:
play();
break;
}
}
void x_pv_game_music::fade_out_end() {
if (!fade_out.enable)
return;
fade_out.enable = false;
fade_out.remain = 0.0f;
set_volume_map(0, fade_out.value);
switch (fade_out.action) {
case X_PV_GAME_MUSIC_ACTION_STOP:
stop();
break;
case X_PV_GAME_MUSIC_ACTION_PAUSE:
set_pause(1);
break;
case X_PV_GAME_MUSIC_ACTION_PLAY:
play();
break;
}
}
void x_pv_game_music::file_load(int32_t type, std::string&& file_path, bool play_on_end,
float_t start, float_t end, float_t fade_in_time, float_t fade_out_time, bool a9) {
this->type = type;
this->file_path.assign(file_path);
this->start = start;
this->end = end;
this->play_on_end = play_on_end;
this->fade_out_time = fade_out_time;
this->fade_in_time = fade_in_time;
this->field_9C = a9;
if (fade_in_time > 0.0f) {
fade_in.start = 0;
fade_in.value = 100;
fade_in.time = fade_in_time;
fade_in.remain = fade_in_time;
fade_in.action = X_PV_GAME_MUSIC_ACTION_NONE;
fade_in.enable = true;
}
if (end <= 0.0f) {
fade_out.start = get_volume(0);
fade_out.value = 0;
fade_out.time = 0.0f;
fade_out.remain = 0.0;
fade_out.action = play_on_end
? X_PV_GAME_MUSIC_ACTION_PLAY : X_PV_GAME_MUSIC_ACTION_STOP;
}
else {
no_fade = true;
no_fade_remain = end + fade_in_time;
fade_out_time_req = fade_out_time;
fade_out_action_req = play_on_end
? X_PV_GAME_MUSIC_ACTION_PLAY : X_PV_GAME_MUSIC_ACTION_STOP;
}
}
int32_t x_pv_game_music::get_master_volume(int32_t index) {
if (!index)
return master_volume;
return 0;
}
int32_t x_pv_game_music::get_volume(int32_t index) {
if (!index)
return volume;
return 0;
}
int32_t x_pv_game_music::include_flags(x_pv_game_music_flags flags) {
if (!((this->flags & X_PV_GAME_MUSIC_OGG) || !(flags & X_PV_GAME_MUSIC_OGG)))
ogg_init();
enum_or(this->flags, flags);
return 0;
}
int32_t x_pv_game_music::load(int32_t type, std::string&& file_path, bool wait_load, float_t time, bool a6) {
if (type == 4 && set_ogg_args(std::string(file_path), time, wait_load) < 0)
return -6;
reset();
reset_args();
set_args(type, std::string(file_path), time, a6);
pause = true;
return 0;
}
void x_pv_game_music::ogg_free() {
if (ogg) {
delete ogg;
ogg = 0;
}
}
int32_t x_pv_game_music::ogg_init() {
if (ogg)
return 0;
ogg = new x_pv_game_music_ogg;
return ogg->playback ? 0 : -1;
}
int32_t x_pv_game_music::ogg_load(std::string&& file_path, float_t start) {
if (!(flags & X_PV_GAME_MUSIC_OGG))
return -2;
start = max_def(start, 0.0f);
OggPlayback* playback = ogg->playback;
OggFileHandlerFileState file_state = playback->GetFileState();
OggFileHandlerPauseState pause_state = playback->GetPauseState();
if (!check_args(4, std::string(file_path), start)
|| file_state != OGG_FILE_HANDLER_FILE_STATE_PLAYING
|| pause_state != OGG_FILE_HANDLER_PAUSE_STATE_PAUSE) {
playback->Stop();
playback->SetLoadTimeSeek(start);
playback->SetPath(file_path);
}
playback->SetPauseState(OGG_FILE_HANDLER_PAUSE_STATE_PLAY);
ogg->file_path.assign(file_path);
loaded = true;
return 0;
}
int32_t x_pv_game_music::ogg_reset() {
sound_stream_array_reset();
include_flags(X_PV_GAME_MUSIC_OGG);
return 0;
}
int32_t x_pv_game_music::ogg_stop() {
if (!(flags & X_PV_GAME_MUSIC_OGG))
return -2;
ogg->playback->Stop();
ogg->file_path.clear();
loaded = false;
return 0;
}
int32_t x_pv_game_music::play() {
return play(type, std::string(file_path), play_on_end, start, end, fade_in_time, fade_out_time, false);
}
int32_t x_pv_game_music::play(int32_t type, std::string&& file_path, bool play_on_end,
float_t start, float_t end, float_t fade_in_time, float_t fade_out_time, bool a9) {
set_volume_map(0, 100);
if (type == 4 && ogg_load(std::string(file_path), start) < 0)
return -7;
reset();
reset_args();
file_load(type, std::string(file_path), play_on_end, start, end, fade_in_time, fade_out_time, a9);
pause = false;
return 0;
}
void x_pv_game_music::play_fade_in(int32_t type, std::string&& file_path, float_t start,
float_t end, bool play_on_end, bool a7, float_t fade_out_time, bool a10) {
play(type, std::string(file_path), play_on_end, start, end, 0.0f, fade_out_time, a10);
}
int32_t x_pv_game_music::play_or_stop() {
if (play_on_end)
return play();
else
return stop();
}
void x_pv_game_music::reset() {
fade_in = {};
fade_out = {};
no_fade = false;
no_fade_remain = 0.0f;
fade_out_time_req = 0.0f;
fade_out_action_req = X_PV_GAME_MUSIC_ACTION_NONE;
type = 0;
file_path.clear();
start = 0.0f;
end = 0.0f;
play_on_end = false;
fade_in_time = 0.0f;
fade_out_time = 3.0f;
field_9C = false;
}
void x_pv_game_music::reset_args() {
args.type = 0;
args.file_path.clear();
args.start = 0.0f;
args.field_2C = false;
}
void x_pv_game_music::set_args(int32_t type, std::string&& file_path, float_t start, bool a5) {
args.type = type;
args.file_path.assign(file_path);
args.start = start;
args.field_2C = a5;
}
int32_t x_pv_game_music::set_channel_pair_volume(int32_t channel_pair, int32_t value) {
if (!(flags & X_PV_GAME_MUSIC_OGG))
return -2;
ogg->playback->SetChannelPairVolume(channel_pair, ratio_to_db((float_t)value * 0.01f));
return 0;
}
int32_t x_pv_game_music::set_channel_pair_volume_map(int32_t channel_pair, int32_t value) {
if (channel_pair >= 0 && channel_pair <= 3) {
set_channel_pair_volume(channel_pair, value);
if (!channel_pair)
set_channel_pair_volume_map(2, value);
else if (channel_pair == 1)
set_channel_pair_volume_map(3, value);
channel_pair_volume[channel_pair] = value;
return 0;
}
return -1;
}
int32_t x_pv_game_music::set_fade_out(float_t time, bool stop) {
reset();
if (time == 0.0f)
x_pv_game_music::stop();
else {
fade_out.start = get_volume(0);
fade_out.value = 0;
fade_out.time = time;
fade_out.remain = time;
fade_out.enable = true;
fade_out.action = stop ? X_PV_GAME_MUSIC_ACTION_STOP
: X_PV_GAME_MUSIC_ACTION_PAUSE;
}
return 0;
}
int32_t x_pv_game_music::set_master_volume(int32_t value) {
if (!(flags & X_PV_GAME_MUSIC_OGG))
return -2;
ogg->playback->SetMasterVolume(ratio_to_db(
(float_t)(value * get_master_volume(0) / 100) * 0.01f));
return 0;
}
int32_t x_pv_game_music::set_ogg_args(std::string&& file_path, float_t start, bool wait_load) {
if (!(flags & X_PV_GAME_MUSIC_OGG))
return -2;
start = max_def(start, 0.0f);
OggPlayback* playback = ogg->playback;
OggFileHandlerFileState file_state = playback->GetFileState();
OggFileHandlerPauseState pause_state = playback->GetPauseState();
if (!check_args(4, std::string(file_path), start)
|| file_state != OGG_FILE_HANDLER_FILE_STATE_PLAYING
|| pause_state != OGG_FILE_HANDLER_PAUSE_STATE_PAUSE) {
playback->Stop();
playback->SetLoadTimeSeek(start);
playback->SetPath(file_path);
playback->SetPauseState(OGG_FILE_HANDLER_PAUSE_STATE_PAUSE);
ogg->file_path.assign(file_path);
if (wait_load) {
OggFileHandlerFileState file_state = playback->GetFileState();
while (file_state != OGG_FILE_HANDLER_FILE_STATE_PLAYING
&& file_state != OGG_FILE_HANDLER_FILE_STATE_STOPPED
&& file_state != OGG_FILE_HANDLER_FILE_STATE_MAX)
file_state = playback->GetFileState();
}
}
return 0;
}
int32_t x_pv_game_music::set_ogg_pause_state(uint8_t pause_state) {
if (!(flags & X_PV_GAME_MUSIC_OGG))
return -2;
OggPlayback* playback = ogg->playback;
if (playback->GetFileState() == OGG_FILE_HANDLER_FILE_STATE_PLAYING)
playback->SetPauseState((OggFileHandlerPauseState)pause_state);
return 0;
}
int32_t x_pv_game_music::set_pause(int32_t pause) {
if (flags & X_PV_GAME_MUSIC_OGG)
set_ogg_pause_state(pause != 0);
this->pause = pause == 1;
return 0;
}
void x_pv_game_music::set_volume_map(int32_t index, int32_t value) {
if (!index) {
if (flags & X_PV_GAME_MUSIC_OGG)
set_master_volume(value);
volume = value;
}
}
int32_t x_pv_game_music::stop() {
if (flags & X_PV_GAME_MUSIC_OGG)
ogg_stop();
reset();
reset_args();
pause = false;
return 0;
}
void x_pv_game_music::stop_reset_flags() {
stop();
exclude_flags(X_PV_GAME_MUSIC_ALL);
}
x_pv_game_dsc_data::x_pv_game_dsc_data() : dsc_data_ptr(), dsc_data_ptr_end(), time() {
reset();
}
x_pv_game_dsc_data::~x_pv_game_dsc_data() {
}
void x_pv_game_dsc_data::ctrl(float_t curr_time, float_t delta_time) {
}
dsc_data* x_pv_game_dsc_data::find(int32_t func_name, int32_t* time,
int32_t* pv_branch_mode, dsc_data* start, dsc_data* end) {
int32_t _time = -1;
for (dsc_data* i = start; i != end; i++)
if (i->func == func_name) {
if (time)
*time = _time;
return i;
}
else if (i->func == DSC_X_END)
break;
else if (i->func == DSC_X_TIME) {
uint32_t* data = dsc.get_func_data(i);
_time = (int32_t)data[0];
}
else if (i->func == DSC_X_PV_END)
break;
else if (i->func == DSC_X_PV_BRANCH_MODE) {
if (pv_branch_mode) {
uint32_t* data = dsc.get_func_data(i);
*pv_branch_mode = (int32_t)data[0];
}
}
return 0;
}
void x_pv_game_dsc_data::find_bar_beat(x_pv_bar_beat& bar_beat) {
x_pv_bar_beat_data* bar_beat_data = 0;
int32_t beat_counter = 0;
int32_t time = -1;
for (dsc_data& i : dsc.data) {
if (i.func == DSC_X_END)
break;
uint32_t* data = dsc.get_func_data(&i);
switch (i.func) {
case DSC_X_TIME: {
time = (int32_t)data[0];
} break;
case DSC_X_BAR_POINT: {
bar_beat.data.push_back({});
bar_beat_data = &bar_beat.data.back();
*bar_beat_data = {};
bar_beat_data->bar = (int32_t)data[0];
bar_beat_data->bar_time = (float_t)time * (float_t)(1.0 / 100000.0);
bar_beat_data->beat_counter = beat_counter;
} break;
case DSC_X_BEAT_POINT: {
if (!bar_beat_data)
break;
bar_beat_data->beat_counter = ++beat_counter;
bar_beat_data->beat_time[bar_beat_data->beat_count++] = (float_t)time * (float_t)(1.0 / 100000.0);
} break;
}
}
}
void x_pv_game_dsc_data::find_change_fields(std::vector<int64_t>& change_fields) {
int32_t pv_branch_mode = 0;
int32_t time = -1;
int32_t prev_time = -1;
::dsc_data* i = dsc.data.data();
::dsc_data* i_end = dsc.data.data() + dsc.data.size();
while (i = find(DSC_X_CHANGE_FIELD, &time, &pv_branch_mode, i, i_end)) {
if (time < 0) {
time = prev_time;
if (prev_time < 0)
break;
}
change_fields.push_back((int64_t)time * 10000);
prev_time = time;
i++;
}
}
int64_t x_pv_game_dsc_data::find_pv_end() {
int32_t pv_branch_mode = 0;
int32_t pv_end_time = -1;
int32_t end_time = -1;
::dsc_data* i = dsc.data.data();
::dsc_data* i_end = dsc.data.data() + dsc.data.size();
find(DSC_X_PV_END, &pv_end_time, &pv_branch_mode, i, i_end);
pv_branch_mode = 0;
i = dsc.data.data();
i_end = dsc.data.data() + dsc.data.size();
find(DSC_X_END, &end_time, &pv_branch_mode, i, i_end);
return max_def(pv_end_time, end_time);
}
void x_pv_game_dsc_data::find_stage_effects(prj::vector_pair<int64_t, int32_t>& stage_effects) {
int32_t pv_branch_mode = 0;
int32_t time = -1;
int32_t prev_time = -1;
::dsc_data* i = dsc.data.data();
::dsc_data* i_end = dsc.data.data() + dsc.data.size();
while (i = find(DSC_X_STAGE_EFFECT, &time, &pv_branch_mode, i, i_end)) {
if (time < 0) {
time = prev_time;
if (prev_time < 0)
break;
}
uint32_t* data = dsc.get_func_data(i);
int32_t stage_effect = (int32_t)data[0];
if (stage_effect < 8 || stage_effect > 9)
stage_effects.push_back((int64_t)time * 10000, stage_effect);
prev_time = time;
i++;
}
}
void x_pv_game_dsc_data::reset() {
dsc.type = DSC_NONE;
dsc.signature = 0;
dsc.id = 0;
dsc.data.clear();
dsc.data.shrink_to_fit();
dsc.data_buffer.clear();
dsc.data_buffer.shrink_to_fit();
dsc_data_ptr = 0;
dsc_data_ptr_end = 0;
time = -1;
}
void x_pv_game_dsc_data::unload() {
dsc.type = DSC_NONE;
dsc.signature = 0;
dsc.id = 0;
dsc.data.clear();
dsc.data.shrink_to_fit();
dsc.data_buffer.clear();
dsc.data_buffer.shrink_to_fit();
dsc_data_ptr = 0;
dsc_data_ptr_end = 0;
time = -1;
}
x_pv_game_data::x_pv_game_data() : pv_id(), play_param(), curr_time(), delta_time(), pv_end_time(),
time_float(), frame(), field_1C(), state(), stage_effect_index(), next_stage_effect_bar(), stage() {
}
x_pv_game_data::~x_pv_game_data() {
if (play_param) {
delete play_param;
play_param = 0;
}
}
#if BAKE_PV826
void x_pv_game_data::ctrl(float_t curr_time, float_t delta_time,
std::map<uint32_t, auth_3d_id>* effchrpv_auth_3d_mot_ids) {
#else
void x_pv_game_data::ctrl(float_t curr_time, float_t delta_time) {
#endif
this->curr_time = curr_time;
this->delta_time = delta_time;
switch (state) {
case 10: {
if (field_1C & 0x08) {
state = 20;
field_1C &= ~0x08;
}
else
state = 0;
} break;
case 20: {
effect.load_data(pv_id);
chara_effect.load_data();
pv_expression_file_load(&data_list[DATA_X], "root+/pv_expression/", exp_file.hash_murmurhash);
state = 21;
} break;
case 21: {
if (stage->state != 20)
break;
camera.load_data();
state = 22;
} break;
case 22: {
bool wait_load = false;
wait_load |= pv_expression_file_check_not_ready(exp_file.hash_murmurhash);
wait_load |= camera.state && camera.state != 20;
wait_load |= effect.state && effect.state != 20;
wait_load |= chara_effect.state && chara_effect.state != 10 && chara_effect.state != 30;
if (wait_load)
break;
state = 23;
} break;
case 23: {
dsc_data.find_bar_beat(bar_beat);
bar_beat.reset_time();
stage->bpm_frame_rate_control.bar_beat = &bar_beat;
state = 24;
} break;
case 24: {
dsc_data.find_stage_effects(stage_effects);
int64_t pv_end_time = dsc_data.find_pv_end();
if (pv_end_time >= 0)
this->pv_end_time = (float_t)((double_t)pv_end_time * 0.000000001);
state = 25;
} break;
case 25: {
dsc_data.find_change_fields(change_fields);
effect.change_fields = &change_fields;
chara_effect.change_fields = &change_fields;
state = 30;
} break;
case 30: {
ctrl_stage_effect_index();
bar_beat.set_time(this->curr_time, this->delta_time);
frame++;
} break;
case 40: {
//if (!sub_81254B9E())
state = 0;
} break;
}
camera.ctrl(this->curr_time);
effect.ctrl(&obj_db, &tex_db);
#if BAKE_PV826
chara_effect.ctrl(&obj_db, &tex_db, pv_id, effchrpv_auth_3d_mot_ids);
#else
chara_effect.ctrl(&obj_db, &tex_db);
#endif
field_1C &= ~0x02;
}
void x_pv_game_data::ctrl_stage_effect_index() {
if (stage_effect_index >= stage_effects.size())
return;
std::pair<int64_t, int32_t>* curr_stage_effect = &stage_effects[stage_effect_index];
if (next_stage_effect_bar > bar_beat.bar)
return;
stage->set_stage_effect(curr_stage_effect->second);
stage_effect_index++;
if (stage_effect_index >= stage_effects.size())
return;
std::pair<int64_t, int32_t>* next_stage_effect = &stage_effects[stage_effect_index];
float_t time = (float_t)((double_t)next_stage_effect->first * 0.000000001);
int32_t bar = bar_beat.get_bar_beat_from_time(0, time);
next_stage_effect_bar = --bar;
int32_t v14 = bar / 2 - 1;
if (stage->check_stage_effect_has_change_effect(curr_stage_effect->second, next_stage_effect->second))
v14 = bar / 2 - 2;
if (v14 <= 0)
v14 = 0;
next_stage_effect_bar = 2 * v14 + 1;
}
#if BAKE_PV826
void x_pv_game_data::load(int32_t pv_id, FrameRateControl* frame_rate_control, chara_index charas[6],
std::unordered_map<std::string, string_hash>* effchrpv_auth_3d_mot_names) {
#else
void x_pv_game_data::load(int32_t pv_id, FrameRateControl* frame_rate_control, chara_index charas[6]) {
#endif
if (state)
return;
data_struct* x_data = &data_list[DATA_X];
effect.load(pv_id, play_param, frame_rate_control);
#if BAKE_PV826
chara_effect.load(pv_id, play_param, frame_rate_control, charas, effchrpv_auth_3d_mot_names);
#else
chara_effect.load(pv_id, play_param, frame_rate_control, charas);
#endif
char buf[0x200];
size_t len = sprintf_s(buf, sizeof(buf), "exp_PV%03d", pv_id);
exp_file = std::string(buf, len);
camera.load(pv_id, stage->stage_id, frame_rate_control);
sprintf_s(buf, sizeof(buf), "rom/sound/song/pv_%03d.ogg", pv_id == 832 ? 800 : pv_id);
x_pv_game_music_ptr->ogg_reset();
x_pv_game_music_ptr->load(4, buf, true, 0.0f, false);
state = 10;
}
void x_pv_game_data::reset() {
x_pv_game_music_ptr->stop();
x_pv_game_music_ptr->set_volume_map(0, 0);
pv_id = 0;
play_param_file_handler.reset();
if (play_param) {
delete play_param;
play_param = 0;
}
curr_time = 0.0f;
delta_time = 0.0f;
pv_end_time = 0.0f;
time_float = 0.0f;
frame = 0;
field_1C = 0;
state = 0;
change_fields.clear();
change_fields.shrink_to_fit();
bar_beat.reset();
stage_effect_index = 0;
next_stage_effect_bar = 0;
stage_effects.clear();
stage_effects.shrink_to_fit();
camera.reset();
effect.reset();
chara_effect.reset();
dsc_data.reset();
exp_file.clear();
//dof = {};
stage = 0;
obj_db.clear();
tex_db.clear();
}
void x_pv_game_data::stop() {
camera.stop();
stage->reset_stage_effect();
stage->reset_stage_env();
effect.stop();
chara_effect.stop();
dsc_data.reset();
field_1C &= ~0xC0;
if (state == 30)
state = 0;
}
void x_pv_game_data::unload() {
stop();
camera.unload();
effect.unload();
chara_effect.unload();
//dof = {};
dsc_data.unload();
pv_expression_file_unload(exp_file.hash_murmurhash);
obj_db.clear();
tex_db.clear();
x_pv_game_music_ptr->stop();
x_pv_game_music_ptr->set_channel_pair_volume_map(0, 100);
x_pv_game_music_ptr->set_channel_pair_volume_map(1, 100);
x_pv_game_music_ptr->exclude_flags(X_PV_GAME_MUSIC_OGG);
state = 40;
}
void x_pv_game_data::unload_if_state_is_0() {
if (!state)
unload();
}
PVStageFrameRateControl::PVStageFrameRateControl() {
delta_frame = 1.0f;
}
PVStageFrameRateControl::~PVStageFrameRateControl() {
}
float_t PVStageFrameRateControl::GetDeltaFrame() {
return delta_frame;
}
aet_obj_data::aet_obj_data() : field_20(), loop(), hidden(), field_2A(), frame_rate_control() {
hash = hash_murmurhash_empty;
reset();
}
aet_obj_data::~aet_obj_data() {
reset();
}
bool aet_obj_data::check_disp() {
return aet_manager_get_obj_end(id);
}
uint32_t aet_obj_data::init(AetArgs& args, const aet_database* aet_db) {
reset();
hash = args.id.id;
layer_name.assign(args.layer_name);
id = aet_manager_init_aet_object(args, aet_db);
if (!id)
return 0;
aet_manager_set_obj_frame_rate_control(id, frame_rate_control);
aet_manager_set_obj_visible(id, !hidden);
field_2A = true;
loop = !!(args.flags & AET_LOOP);
return id;
}
void aet_obj_data::reset() {
field_2A = false;
if (id) {
aet_manager_free_aet_object(id);
id = 0;
}
hash = hash_murmurhash_empty;
layer_name.clear();
layer_name.shrink_to_fit();
if (field_20) {
delete field_20;
field_20 = 0;
}
}
x_pv_game_stage_env_data::x_pv_game_stage_env_data() {
}
x_pv_game_stage_env_aet::x_pv_game_stage_env_aet() : state(), prev(), next() {
duration = 1.0f;
}
x_pv_game_stage_env::x_pv_game_stage_env() : flags(),
state(), stage_resource(), trans_duration(), trans_remain() {
env_index = -1;
aet_gam_stgpv_id_hash = hash_murmurhash_empty;
spr_gam_stgpv_id_hash = hash_murmurhash_empty;
aet_gam_stgpv_id_main_hash = hash_murmurhash_empty;
for (auto& i : data)
for (auto& j : i.data)
for (auto& k : j)
k.frame_rate_control = &frame_rate_control;
}
x_pv_game_stage_env::~x_pv_game_stage_env() {
}
void x_pv_game_stage_env::ctrl(float_t delta_time) {
frame_rate_control.delta_frame = delta_time * 60.0f;
switch (state) {
case 10:
state = 11;
case 11:
if ((aet_gam_stgpv_id_hash == hash_murmurhash_empty
|| !aet_manager_load_file_modern(aet_gam_stgpv_id_hash, &aet_db))
&& (spr_gam_stgpv_id_hash == hash_murmurhash_empty
|| !sprite_manager_load_file_modern(spr_gam_stgpv_id_hash, &spr_db))) {
spr_set* set = sprite_manager_get_set(spr_gam_stgpv_id_hash, &spr_db);
if (set) {
SpriteData* sprdata = set->sprdata;
for (uint32_t i = set->num_of_sprite; i; i--, sprdata++)
sprdata->resolution_mode = RESOLUTION_MODE_HD;
}
state = 20;
}
break;
case 20:
if (env_index != -1 && !sub_810EE198(delta_time))
sub_810EE03E();
break;
}
}
pvsr_auth_2d* x_pv_game_stage_env::get_aet(int32_t env_index, int32_t type, int32_t index) {
if (env_index < 0 || env_index >= stage_resource->stage_effect_env.size())
return 0;
pvsr_stage_effect_env* env = &stage_resource->stage_effect_env[env_index];
switch (type) {
case 0:
default:
if (index < env->aet_front.size())
return &env->aet_front[index];
break;
case 1:
if (index < env->aet_front_low.size())
return &env->aet_front_low[index];
break;
case 2:
if (index < env->aet_back.size())
return &env->aet_back[index];
break;
case 3:
if (index < env->unk03.size())
return &env->unk03[index];
break;
case 4:
if (index < env->unk04.size())
return &env->unk04[index];
break;
}
return 0;
}
void x_pv_game_stage_env::load(int32_t stage_id, pvsr* stage_resource) {
if (this->stage_resource || !stage_resource || stage_resource->stage_effect_env.size() > 64)
return;
this->stage_resource = stage_resource;
bool aet = false;
for (pvsr_stage_effect_env& i : stage_resource->stage_effect_env)
if (i.aet_front.size() || i.aet_front_low.size()
|| i.aet_back.size() || i.unk03.size() || i.unk04.size()) {
aet = true;
break;
}
if (aet) {
char buf[0x40];
sprintf_s(buf, sizeof(buf), "AET_GAM_STGPV%03d", stage_id);
aet_gam_stgpv_id_hash = hash_utf8_murmurhash(buf);
sprintf_s(buf, sizeof(buf), "SPR_GAM_STGPV%03d", stage_id);
spr_gam_stgpv_id_hash = hash_utf8_murmurhash(buf);
aet_manager_read_file_modern(aet_gam_stgpv_id_hash, &data_list[DATA_X], &aet_db);
sprite_manager_read_file_modern(spr_gam_stgpv_id_hash, &data_list[DATA_X], &spr_db);
sprintf_s(buf, sizeof(buf), "AET_GAM_STGPV%03d_MAIN", stage_id);
aet_gam_stgpv_id_main_hash = hash_utf8_murmurhash(buf);
}
state = 10;
}
void x_pv_game_stage_env::reset() {
flags = 0;
state = 0;
stage_resource = 0;
env_index = -1;
aet_gam_stgpv_id_hash = hash_murmurhash_empty;
spr_gam_stgpv_id_hash = hash_murmurhash_empty;
aet_gam_stgpv_id_main_hash = hash_murmurhash_empty;
frame_rate_control.delta_frame = 1.0f;
aet_db.clear();
spr_db.clear();
}
void x_pv_game_stage_env::reset_env() {
if (env_index == -1)
return;
for (auto& i : data[env_index].data)
for (auto& j : i)
j.reset();
trans_duration = 0.0f;
trans_remain = 0.0f;
aet = {};
env_index = -1;
}
static const float_t env_aet_opacity = 0.65f;
#pragma warning(push)
#pragma warning(disable: 6385)
void x_pv_game_stage_env::set(int32_t env_index, float_t end_time, float_t start_time) {
if (!stage_resource || env_index < 0 || env_index >= 64
|| env_index >= stage_resource->stage_effect_env.size() || this->env_index == env_index)
return;
float_t duration = max_def(end_time - start_time, 0.0f);
if (trans_duration > 0.0f) {
if (fabsf(end_time) > 0.000001f)
return;
trans_duration = 0.0f;
trans_remain = 0.0f;
aet = {};
}
if (this->env_index == -1 || fabsf(duration) <= 0.000001f) {
float_t frame = start_time * 60.0f;
if (this->env_index != -1)
for (auto& i : data[this->env_index].data)
for (auto& j : i)
j.reset();
if (!(flags & 0x04))
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++) {
pvsr_auth_2d* aet = get_aet(env_index, type, index);
if (!aet)
break;
aet_obj_data& aet_obj = data[env_index].data[type][index];
AetArgs args;
args.id.id = aet_gam_stgpv_id_main_hash;
args.layer_name = aet->name.c_str();
args.mode = RESOLUTION_MODE_HD;
args.flags = AET_PLAY_ONCE;
switch (type) {
case 0:
args.index = 0;
args.prio = spr::SPR_PRIO_01;
break;
case 1:
args.index = 0;
args.prio = spr::SPR_PRIO_00;
break;
case 2:
args.index = 2;
args.prio = spr::SPR_PRIO_00;
break;
case 3:
args.index = 1;
args.prio = spr::SPR_PRIO_00;
break;
case 4:
args.index = 1;
args.prio = spr::SPR_PRIO_01;
break;
}
args.start_marker = 0;
args.end_marker = 0;
//args.color = bright_scale_get(aet_index_table[type], aet->bright_scale);
args.color = vec4(1.0f, 1.0f, 1.0f, env_aet_opacity);
args.spr_db = &spr_db;
aet_obj.init(args, &aet_db);
if (aet_obj.id)
aet_manager_set_obj_frame(aet_obj.id, frame);
}
}
else {
trans_duration = duration;
trans_remain = duration;
bool has_prev = false;
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++)
if (data[this->env_index].data[type][index].id) {
aet.prev[type][index] = &data[this->env_index].data[type][index];
has_prev = true;
}
else
break;
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++)
if (get_aet(env_index, type, index))
aet.next[type][index] = &data[env_index].data[type][index];
else
break;
if (has_prev) {
aet.state = 1;
aet.duration = duration * 0.5f;
}
else {
aet.state = 2;
aet.duration = duration;
}
}
this->env_index = env_index;
}
void x_pv_game_stage_env::unload() {
if (!state)
return;
if (aet_gam_stgpv_id_hash != hash_murmurhash_empty) {
aet_manager_unload_set_modern(aet_gam_stgpv_id_hash, &aet_db);
aet_gam_stgpv_id_hash = hash_murmurhash_empty;
}
if (spr_gam_stgpv_id_hash != hash_murmurhash_empty) {
sprite_manager_unload_set_modern(spr_gam_stgpv_id_hash, &spr_db);
spr_gam_stgpv_id_hash = hash_murmurhash_empty;
}
aet_gam_stgpv_id_main_hash = hash_murmurhash_empty;
state = 0;
stage_resource = 0;
aet_db.clear();
spr_db.clear();
}
void x_pv_game_stage_env::sub_810EE03E() {
if (env_index < 0 || env_index >= 64)
return;
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++) {
aet_obj_data& aet_obj = data[env_index].data[type][index];
if (!aet_obj.id || !aet_obj.check_disp())
continue;
AetArgs args;
if (stage_resource && env_index >= 0 && env_index < 64) {
pvsr_auth_2d* aet = get_aet(env_index, type, index);
if (aet) {
args.id.id = aet_gam_stgpv_id_main_hash;
args.layer_name = aet->name.c_str();
args.mode = RESOLUTION_MODE_HD;
args.flags = AET_PLAY_ONCE;
switch (type) {
case 0:
args.index = 0;
args.prio = spr::SPR_PRIO_01;
break;
case 1:
args.index = 0;
args.prio = spr::SPR_PRIO_00;
break;
case 2:
args.index = 2;
args.prio = spr::SPR_PRIO_00;
break;
case 3:
args.index = 1;
args.prio = spr::SPR_PRIO_00;
break;
case 4:
args.index = 1;
args.prio = spr::SPR_PRIO_01;
break;
}
args.start_marker = 0;
args.end_marker = 0;
//args.color = bright_scale_get(aet_index_table[type], aet->bright_scale);
args.color = vec4(1.0f, 1.0f, 1.0f, env_aet_opacity);
}
}
args.spr_db = &spr_db;
aet_obj.init(args, &aet_db);
}
}
bool x_pv_game_stage_env::sub_810EE198(float_t delta_time) {
if (trans_remain <= 0.0f)
return false;
trans_remain = max_def(trans_remain - delta_time, 0.0f);
float_t t = 1.0f - trans_remain / trans_duration;
switch (aet.state) {
case 1: {
float_t alpha = 1.0f - t * 2.0f;
if (alpha > 0.0f) {
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++) {
aet_obj_data* aet_obj = aet.prev[type][index];
if (!aet_obj)
break;
aet_manager_set_obj_alpha(aet_obj->id, alpha * env_aet_opacity);
}
break;
}
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++) {
aet_obj_data* aet_obj = aet.prev[type][index];
if (!aet_obj)
break;
aet_obj->reset();
}
aet.state = 2;
}
case 2: {
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++) {
aet_obj_data* aet_obj = aet.next[type][index];
if (!aet_obj)
break;
AetArgs args;
if (stage_resource && env_index >= 0 && env_index < 64) {
pvsr_auth_2d* aet = get_aet(env_index, type, index);
if (aet) {
args.id.id = aet_gam_stgpv_id_main_hash;
args.layer_name = aet->name.c_str();
args.mode = RESOLUTION_MODE_HD;
args.flags = AET_PLAY_ONCE;
switch (type) {
case 0:
args.index = 0;
args.prio = spr::SPR_PRIO_01;
break;
case 1:
args.index = 0;
args.prio = spr::SPR_PRIO_00;
break;
case 2:
args.index = 2;
args.prio = spr::SPR_PRIO_00;
break;
case 3:
args.index = 1;
args.prio = spr::SPR_PRIO_00;
break;
case 4:
args.index = 1;
args.prio = spr::SPR_PRIO_01;
break;
}
args.start_marker = 0;
args.end_marker = 0;
//args.color = bright_scale_get(aet_index_table[type], aet->bright_scale);
args.color = vec4(1.0f, 1.0f, 1.0f, env_aet_opacity);
}
}
args.spr_db = &spr_db;
aet_obj->init(args, &aet_db);
aet_manager_set_obj_alpha(aet_obj->id, 0.0f);
}
aet.state = 3;
} break;
case 3: {
float_t alpha = 1.0f - trans_remain / aet.duration;
for (int32_t type = 0; type < 5; type++)
for (int32_t index = 0; index < 8; index++) {
aet_obj_data* aet_obj = aet.next[type][index];
if (!aet_obj)
break;
aet_manager_set_obj_alpha(aet_obj->id, alpha * env_aet_opacity);
}
} break;
}
if (trans_remain <= 0.0f) {
trans_duration = 0.0f;
trans_remain = 0.0f;
aet = {};
}
return false;
}
#pragma warning(pop)
x_pv_game_stage_effect_auth_3d::x_pv_game_stage_effect_auth_3d() : repeat(), field_1(), id() {
reset();
}
void x_pv_game_stage_effect_auth_3d::reset() {
repeat = false;
field_1 = true;
id = {};
}
x_pv_game_stage_effect_glitter::x_pv_game_stage_effect_glitter() :
scene_counter(), fade_time(), fade_time_left(), force_disp() {
reset();
}
void x_pv_game_stage_effect_glitter::reset() {
name.clear();
scene_counter = 0;
fade_time = 0.0f;
fade_time_left = 0.0f;
force_disp = false;
}
x_pv_game_stage_change_effect::x_pv_game_stage_change_effect() : enable(), bars_left(), bar_count() {
}
x_pv_game_stage_change_effect::~x_pv_game_stage_change_effect() {
}
void x_pv_game_stage_change_effect::reset() {
enable = false;
auth_3d.clear();
auth_3d.shrink_to_fit();
glitter.clear();
glitter.shrink_to_fit();
bars_left = 0;
bar_count = 0;
}
x_pv_game_stage_effect::x_pv_game_stage_effect() : stage_effect(), set() {
main_auth_3d_index = -1;
}
x_pv_game_stage_effect::~x_pv_game_stage_effect() {
}
void x_pv_game_stage_effect::reset() {
stage_effect = 0;
auth_3d.clear();
auth_3d.shrink_to_fit();
glitter.clear();
glitter.shrink_to_fit();
main_auth_3d_index = -1;
set = false;
}
x_pv_game_stage_data::x_pv_game_stage_data() : flags(), state(), frame_rate_control() {
reset();
}
x_pv_game_stage_data::~x_pv_game_stage_data() {
}
bool x_pv_game_stage_data::check_not_loaded() {
return file_handler.check_not_ready() || (state && state != 2);
}
void x_pv_game_stage_data::ctrl(object_database* obj_db, texture_database* tex_db) {
switch (state) {
case 1: {
if (task_stage_modern_check_not_loaded())
break;
bool wait_load = false;
for (uint32_t& i : objhrc_hash)
if (object_storage_get_obj_set_handler(i)
&& object_storage_load_obj_set_check_not_read(i, obj_db, tex_db))
wait_load |= true;
if (wait_load)
break;
state = 2;
} break;
}
}
void x_pv_game_stage_data::load(int32_t stage_id, FrameRateControl* frame_rate_control) {
if (flags & 0x02)
return;
this->frame_rate_control = frame_rate_control;
char buf[0x200];
sprintf_s(buf, sizeof(buf), "pv_stgpv%03d.stg", stage_id);
file_handler.read_file(&data_list[DATA_X], "root+/stage/", buf);
task_stage_modern_load_task("X_PV_STAGE");
size_t len = sprintf_s(buf, sizeof(buf), "STGPV%03d.stg", stage_id);
obj_hash.push_back(hash_murmurhash(buf, len));
flags |= 0x02;
}
void x_pv_game_stage_data::load_objects(object_database* obj_db, texture_database* tex_db) {
if (!(flags & 0x02) || file_handler.check_not_ready() || state && state != 2)
return;
const void* stg_data = file_handler.get_data();
size_t stg_size = file_handler.get_size();
stage_database_file stage_data_file;
stage_data_file.read(stg_data, stg_size, true);
stg_db.add(&stage_data_file);
std::vector<stage_data_modern*> stage_data;
obj_hash.clear();
objhrc_hash.clear();
for (stage_data_modern& i : stg_db.stage_modern) {
stage_data.push_back(&i);
std::string objhrc = i.name + "HRC";
obj_hash.push_back(i.hash);
objhrc_hash.push_back(hash_string_murmurhash(objhrc));
}
data_struct* x_data = &data_list[DATA_X];
task_stage_modern_set_data(x_data, obj_db, tex_db, &stg_db);
task_stage_modern_set_stage_hashes(obj_hash, stage_data);
task_effect_parent_set_data(x_data, obj_db, tex_db, &stg_db);
for (uint32_t& i : objhrc_hash)
object_storage_load_set_hash(x_data, i);
state = 1;
flags |= 0x01;
}
void x_pv_game_stage_data::reset() {
flags = 0x04;
state = 0;
file_handler.reset();
stg_db.clear();
frame_rate_control = 0;
obj_hash.clear();
obj_hash.shrink_to_fit();
stage_info.clear();
stage_info.shrink_to_fit();
objhrc_hash.clear();
objhrc_hash.shrink_to_fit();
}
void x_pv_game_stage_data::set_default_stage() {
if (!(flags & 0x02) || state && state != 2)
return;
set_stage(hash_utf8_murmurhash("STGAETBACK"));
}
void x_pv_game_stage_data::set_stage(uint32_t hash) {
if (!(flags & 0x02) || state && state != 2)
return;
if (flags & 0x01) {
task_stage_modern_get_loaded_stage_infos(stage_info);
flags &= ~0x01;
}
task_stage_modern_info stg_info;
for (task_stage_modern_info& i : stage_info)
if (i.check() && i.get_stage_hash() == hash) {
stg_info = i;
break;
}
stg_info.set_stage();
if (stg_info.check())
stg_info.set_stage_display(!!(flags & 0x04), true);
else
task_stage_modern_current_set_stage_display(false, true);
}
void x_pv_game_stage_data::unload() {
for (uint32_t& i : objhrc_hash)
object_storage_unload_set(i);
task_stage_modern_unload_task();
flags &= ~0x02;
state = 0;
file_handler.reset();
frame_rate_control = 0;
obj_hash.clear();
obj_hash.shrink_to_fit();
stage_info.clear();
stage_info.shrink_to_fit();
objhrc_hash.clear();
objhrc_hash.shrink_to_fit();
}
x_pv_game_stage::x_pv_game_stage() : flags(), stage_id(), field_8(), state(), stage_resource(),
curr_stage_effect(), next_stage_effect(), stage_effect_transition_state() {
reset();
}
x_pv_game_stage::~x_pv_game_stage() {
if (stage_resource) {
delete stage_resource;
stage_resource = 0;
}
}
bool x_pv_game_stage::check_stage_effect_has_change_effect(int32_t curr_stage_effect, int32_t next_stage_effect) {
if (curr_stage_effect == 7)
return false;
curr_stage_effect--;
next_stage_effect--;
if (curr_stage_effect < 0 || next_stage_effect < 0)
return false;
size_t stage_effect_count = stage_resource->stage_effect.size();
if (curr_stage_effect >= stage_effect_count || next_stage_effect >= stage_effect_count)
return false;
pvsr_stage_change_effect& stg_chg_eff = stage_resource->
stage_change_effect[curr_stage_effect][next_stage_effect];
if (stg_chg_eff.enable)
return true;
return false;
}
void x_pv_game_stage::ctrl(float_t delta_time) {
switch (state) {
case 10: {
if (stage_data.check_not_loaded() || stage_resource_file_handler.check_not_ready())
break;
if (stage_data.flags & 0x02)
stage_data.load_objects(&obj_db, &tex_db);
const void* pvsr_data = stage_resource_file_handler.get_data();
size_t pvsr_size = stage_resource_file_handler.get_size();
pvsr* sr = new pvsr;
sr->read(pvsr_data, pvsr_size);
stage_resource = sr;
if (sr->stage_effect.size() > 12)
break;
bool has_auth_3d = false;
for (pvsr_stage_effect& i : sr->stage_effect)
if (i.auth_3d.size()) {
has_auth_3d = true;
break;
}
if (has_auth_3d) {
char buf[0x200];
size_t len = sprintf_s(buf, sizeof(buf), "EFFSTGPV%03d", stage_id);
stage_auth_3d.push_back(std::string(buf, len));
}
data_struct* x_data = &data_list[DATA_X];
for (pvsr_effect& i : sr->effect) {
uint32_t hash = (uint32_t)Glitter::glt_particle_manager->LoadFile(Glitter::X,
x_data, i.name.c_str(), 0, i.emission, false);
if (hash != hash_murmurhash_empty)
stage_glitter.push_back(hash);
}
for (string_hash& i : stage_auth_3d)
auth_3d_data_load_category(x_data, i.c_str(), i.hash_murmurhash);
env.load(stage_id, stage_resource);
state = 11;
} break;
case 11: {
if (stage_data.check_not_loaded())
break;
bool wait_load = false;
for (string_hash& i : stage_auth_3d)
if (!auth_3d_data_check_category_loaded(i.hash_murmurhash))
wait_load |= true;
for (uint32_t& i : stage_glitter)
if (!Glitter::glt_particle_manager->CheckNoFileReaders(i))
wait_load |= true;
if (wait_load)
break;
data_struct* x_data = &data_list[DATA_X];
for (uint32_t& i : stage_glitter) {
Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i);
if (eff_group && eff_group->CheckModel())
eff_group->LoadModel(x_data);
}
size_t stage_effect_count = stage_resource->stage_effect.size();
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT && i < stage_effect_count; i++) {
pvsr_stage_effect& stg_eff = stage_resource->stage_effect[i];
x_pv_game_stage_effect& eff = effect[i];
eff.stage_effect = &stg_eff;
size_t auth_3d_count = stg_eff.auth_3d.size();
size_t glitter_count = stg_eff.glitter.size();
eff.auth_3d.resize(auth_3d_count);
eff.glitter.resize(glitter_count);
for (size_t j = 0; j < auth_3d_count; j++) {
pvsr_auth_3d& stg_eff_auth_3d = stg_eff.auth_3d[j];
x_pv_game_stage_effect_auth_3d& eff_auth_3d = eff.auth_3d[j];
eff_auth_3d.reset();
int32_t stage_effect = i + 1;
auto elem = auth_3d_ids.find(stg_eff_auth_3d.name.hash_murmurhash);
if (elem == auth_3d_ids.end()) {
auth_3d_id id = auth_3d_data_load_hash(stg_eff_auth_3d
.name.hash_murmurhash, x_data, &obj_db, &tex_db);
if (!id.check_not_empty()) {
eff_auth_3d.id = {};
continue;
}
id.read_file_modern();
id.set_enable(false);
id.set_repeat(true);
id.set_paused(false);
id.set_visibility(false);
id.set_frame_rate(&bpm_frame_rate_control);
eff_auth_3d.id = id;
auth_3d_ids.insert({ stg_eff_auth_3d.name.hash_murmurhash, id });
}
else
eff_auth_3d.id = elem->second;
if (stage_effect >= 8 && stage_effect <= 9)
eff_auth_3d.repeat = false;
else if (stage_effect == 7)
eff_auth_3d.repeat = !!(stg_eff_auth_3d.flags & PVSR_AUTH_3D_REPEAT);
else
eff_auth_3d.repeat = true;
if (stg_eff_auth_3d.flags & PVSR_AUTH_3D_MAIN)
eff.main_auth_3d_index = (int32_t)j;
}
for (size_t i = 0; i < glitter_count; i++) {
pvsr_glitter& stg_eff_glt = stg_eff.glitter[i];
x_pv_game_stage_effect_glitter& eff_glt = eff.glitter[i];
eff_glt.reset();
eff_glt.name.assign(stg_eff_glt.name);
eff_glt.fade_time = (float_t)stg_eff_glt.fade_time;
eff_glt.force_disp = !!(stg_eff_glt.flags & PVSR_GLITTER_FORCE_DISP);
}
}
for (int32_t i = 1; i <= X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 1; j <= X_PV_GAME_STAGE_EFFECT_COUNT; j++)
load_change_effect(i, j);
stage_data.set_default_stage();
state = 12;
}
case 12: {
if (env.state && env.state != 20)
break;
bool wait_load = false;
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = effect[i];
for (x_pv_game_stage_effect_auth_3d& j : eff.auth_3d)
if (j.id.check_not_empty() && !j.id.check_loaded())
wait_load |= true;
}
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = change_effect[i][j];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
if (k.id.check_not_empty() && !k.id.check_loaded())
wait_load |= true;
}
for (uint32_t& i : stage_glitter) {
Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i);
if (eff_group && eff_group->CheckLoadModel())
wait_load |= true;
}
if (wait_load)
break;
state = 20;
}
case 20:
ctrl_inner();
break;
case 30:
if (!task_stage_modern_check_task_ready()) {
stage_data.stg_db.clear();
state = 0;
}
break;
}
stage_data.ctrl(&obj_db, &tex_db);
env.ctrl(delta_time);
}
void x_pv_game_stage::ctrl_inner() {
if (next_stage_effect && curr_stage_effect) {
x_pv_bar_beat* bar_beat = bpm_frame_rate_control.bar_beat;
if (!bar_beat)
return;
bool v6 = bar_beat && fabsf(bar_beat->delta_time) > 0.000001f
&& bar_beat->counter > 0 && !((bar_beat->bar - 1) % 2);
int32_t curr_stg_eff = curr_stage_effect;
if (curr_stg_eff >= 1 && curr_stg_eff <= 12)
curr_stg_eff--;
else
curr_stg_eff = 0;
int32_t next_stg_eff = next_stage_effect;
if (next_stg_eff >= 1 && next_stg_eff <= 12)
next_stg_eff--;
else
next_stg_eff = 0;
x_pv_game_stage_effect& eff = effect[curr_stg_eff];
x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stg_eff][next_stg_eff];
switch (stage_effect_transition_state) {
case 0: {
if (v6) {
if (set_change_effect_frame_part_1()) {
chg_eff.bars_left = chg_eff.bar_count;
stage_effect_transition_state = 1;
stop_stage_effect_auth_3d(curr_stage_effect);
set_change_effect_frame_part_2(bar_beat->get_bar_current_frame());
}
else {
stop_stage_effect_auth_3d(curr_stage_effect);
stop_stage_effect_glitter(curr_stage_effect);
set_stage_effect_auth_3d_frame(next_stage_effect, -1.0f);
set_stage_effect_glitter_frame(next_stage_effect, -1.0f);
curr_stage_effect = next_stage_effect;
next_stage_effect = 0;
stage_effect_transition_state = 0;
}
}
else if (bar_beat->counter > 0) {
std::vector<x_pv_game_stage_effect_auth_3d>& auth_3d = eff.auth_3d;
for (x_pv_game_stage_effect_auth_3d& i : auth_3d) {
auth_3d_id& id = i.id;
id.set_repeat(false);
}
}
} break;
case 1: {
if (v6) {
chg_eff.bars_left -= 2;
v6 = chg_eff.bars_left <= 0;
}
if (v6) {
stop_stage_change_effect();
stop_stage_effect_glitter(curr_stage_effect);
set_stage_effect_auth_3d_frame(next_stage_effect, -1.0f);
set_stage_effect_glitter_frame(next_stage_effect, -1.0f);
curr_stage_effect = next_stage_effect;
next_stage_effect = 0;
stage_effect_transition_state = 0;
}
else {
float_t delta_time_bar_beat = bar_beat->delta_time / (bar_beat->next_bar_time - bar_beat->curr_bar_time);
std::vector<x_pv_game_stage_effect_glitter>& glitter = eff.glitter;
for (x_pv_game_stage_effect_glitter& i : glitter) {
if (fabsf(i.fade_time) <= 0.000001f) {
Glitter::glt_particle_manager->SetSceneEffectExtColor(i.scene_counter, 0,
hash_murmurhash_empty, -1.0f, -1.0f, -1.0f, 0.0f);
}
else if (i.fade_time > 0.001f) {
i.fade_time_left -= delta_time_bar_beat * 4.0f;
if (i.fade_time_left < 0.0f)
i.fade_time_left = 0.0f;
Glitter::glt_particle_manager->SetSceneEffectExtColor(i.scene_counter, 0,
hash_murmurhash_empty, -1.0f, -1.0f, -1.0f, i.fade_time_left / i.fade_time);
}
}
}
} break;
}
}
else if (next_stage_effect)
return;
for (int32_t i = 8; i <= 9; i++) {
if (!(flags & (1 << i)))
continue;
int32_t stage_effect;
if (i > 0)
stage_effect = i - 1;
else
stage_effect = 0;
x_pv_game_stage_effect& eff = effect[stage_effect];
std::vector<x_pv_game_stage_effect_auth_3d>& auth_3d = eff.auth_3d;
std::vector<x_pv_game_stage_effect_glitter>& glitter = eff.glitter;
bool stop = false;
if (auth_3d.size())
stop = auth_3d[eff.main_auth_3d_index].id.get_ended();
if (!stop) {
for (x_pv_game_stage_effect_glitter& j : glitter)
if (Glitter::glt_particle_manager->CheckSceneEnded(j.scene_counter)) {
stop = true;
break;
}
}
if (stop) {
stop_stage_effect_auth_3d(i);
stop_stage_effect_glitter(i);
flags &= ~(1 << i);
}
}
}
void x_pv_game_stage::load(int32_t stage_id, FrameRateControl* frame_rate_control, bool a4) {
if (!stage_id)
return;
flags &= ~0x02;
if (a4)
flags |= 0x02;
field_8 = 1;
this->stage_id = stage_id;
stage_data.load(stage_id, frame_rate_control);
char buf[0x200];
sprintf_s(buf, sizeof(buf), "stgpv%03d_param.pvsr", stage_id);
stage_resource_file_handler.read_file(&data_list[DATA_X], "root+/pv_stage_rsrc/", buf);
state = 10;
}
void x_pv_game_stage::load_change_effect(int32_t curr_stage_effect, int32_t next_stage_effect) {
curr_stage_effect--;
next_stage_effect--;
if (curr_stage_effect < 0 || next_stage_effect < 0)
return;
size_t stage_effect_count = stage_resource->stage_effect.size();
if (curr_stage_effect >= stage_effect_count || next_stage_effect >= stage_effect_count)
return;
pvsr_stage_change_effect& stg_chg_eff = stage_resource->
stage_change_effect[curr_stage_effect][next_stage_effect];
x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stage_effect][next_stage_effect];
if (!stg_chg_eff.enable) {
chg_eff.enable = false;
return;
}
chg_eff.enable = true;
chg_eff.bars_left = 0;
chg_eff.bar_count = stg_chg_eff.bar_count > -1 ? stg_chg_eff.bar_count : 2;
size_t auth_3d_count = stg_chg_eff.auth_3d.size();
size_t glitter_count = stg_chg_eff.glitter.size();
chg_eff.auth_3d.resize(auth_3d_count);
chg_eff.glitter.resize(glitter_count);
data_struct* x_data = &data_list[DATA_X];
for (size_t i = 0; i < auth_3d_count; i++) {
pvsr_auth_3d& stg_chg_eff_auth_3d = stg_chg_eff.auth_3d[i];
x_pv_game_stage_effect_auth_3d& chg_eff_auth_3d = chg_eff.auth_3d[i];
chg_eff_auth_3d.reset();
auto elem = auth_3d_ids.find(stg_chg_eff_auth_3d.name.hash_murmurhash);
if (elem == auth_3d_ids.end()) {
auth_3d_id id = auth_3d_data_load_hash(stg_chg_eff_auth_3d
.name.hash_murmurhash, x_data, &obj_db, &tex_db);
if (!id.check_not_empty()) {
chg_eff_auth_3d.id = {};
continue;
}
id.read_file_modern();
id.set_enable(false);
id.set_repeat(false);
id.set_paused(false);
id.set_visibility(false);
id.set_frame_rate(&bpm_frame_rate_control);
chg_eff_auth_3d.id = id;
auth_3d_ids.insert({ stg_chg_eff_auth_3d.name.hash_murmurhash, id });
}
else
chg_eff_auth_3d.id = elem->second;
chg_eff_auth_3d.field_1 = true;
chg_eff_auth_3d.repeat = !!(stg_chg_eff_auth_3d.flags & PVSR_AUTH_3D_REPEAT);
}
for (size_t i = 0; i < glitter_count; i++) {
pvsr_glitter& stg_chg_eff_glt = stg_chg_eff.glitter[i];
x_pv_game_stage_effect_glitter& chg_eff_glt = chg_eff.glitter[i];
chg_eff_glt.reset();
chg_eff_glt.name.assign(stg_chg_eff_glt.name);
chg_eff_glt.force_disp = !!(stg_chg_eff_glt.flags & PVSR_GLITTER_FORCE_DISP);
}
}
void x_pv_game_stage::reset() {
flags = 0x01;
stage_id = 0;
field_8 = 0;
state = 0;
stage_resource_file_handler.reset();
if (stage_resource) {
delete stage_resource;
stage_resource = 0;
}
bpm_frame_rate_control.Reset();
stage_auth_3d.clear();
stage_auth_3d.shrink_to_fit();
stage_glitter.clear();
stage_glitter.shrink_to_fit();
curr_stage_effect = 0;
next_stage_effect = 0;
stage_effect_transition_state = 0;
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
effect[i].reset();
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++)
change_effect[i][j].reset();
obj_db.clear();
tex_db.clear();
auth_3d_ids.clear();
}
void x_pv_game_stage::reset_stage_effect() {
stop_stage_effect(true);
for (int32_t i = 8; i <= 9; i++) {
if (!(flags & (1 << i)))
continue;
stop_stage_effect_auth_3d(i);
stop_stage_effect_glitter(i);
}
for (uint32_t& i : stage_glitter)
Glitter::glt_particle_manager->FreeScene(i);
}
void x_pv_game_stage::reset_stage_env() {
env.reset_env();
}
bool x_pv_game_stage::set_change_effect_frame_part_1() {
if (!curr_stage_effect || !next_stage_effect)
return false;
int32_t curr_stg_eff = curr_stage_effect;
if (curr_stg_eff >= 1 && curr_stg_eff <= 12)
curr_stg_eff--;
else
curr_stg_eff = 0;
int32_t next_sta_eff = next_stage_effect;
if (next_sta_eff >= 1 && next_sta_eff <= 12)
next_sta_eff--;
else
next_sta_eff = 0;
x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stg_eff][next_sta_eff];
if (!chg_eff.enable)
return false;
return true;
}
void x_pv_game_stage::set_change_effect_frame_part_2(float_t frame) {
if (!curr_stage_effect || !next_stage_effect)
return;
int32_t curr_stg_eff = curr_stage_effect;
if (curr_stg_eff >= 1 && curr_stg_eff <= 12)
curr_stg_eff--;
else
curr_stg_eff = 0;
int32_t next_sta_eff = next_stage_effect;
if (next_sta_eff >= 1 && next_sta_eff <= 12)
next_sta_eff--;
else
next_sta_eff = 0;
x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stg_eff][next_sta_eff];
if (!chg_eff.enable)
return;
for (x_pv_game_stage_effect_auth_3d& i : chg_eff.auth_3d) {
auth_3d_id& id = i.id;
id.set_camera_root_update(false);
id.set_enable(true);
id.set_repeat(i.repeat);
id.set_req_frame(frame);
id.set_max_frame(id.get_last_frame() - 1.0f);
id.set_paused(false);
id.set_visibility(!!(flags & 0x01));
id.set_frame_rate(&bpm_frame_rate_control);
}
for (x_pv_game_stage_effect_glitter& i : chg_eff.glitter) {
if (i.name.hash_murmurhash == hash_murmurhash_empty)
continue;
i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(
i.name.hash_murmurhash, i.name.c_str(), 0x01);
if (!i.scene_counter)
continue;
Glitter::glt_particle_manager->SetSceneFrameRate(i.scene_counter, &bpm_frame_rate_control);
Glitter::glt_particle_manager->SetSceneEffectReqFrame(i.scene_counter, frame);
}
}
void x_pv_game_stage::set_env(int32_t env_index, float_t end_time, float_t start_time) {
env.set(env_index, end_time, start_time);
}
void x_pv_game_stage::set_stage_effect(int32_t stage_effect) {
if (stage_effect < 1 || stage_effect > 12)
return;
if (stage_effect >= 8 && stage_effect <= 9) {
if (flags & (1 << stage_effect)) {
stop_stage_effect_auth_3d(stage_effect);
stop_stage_effect_glitter(stage_effect);
}
set_stage_effect_auth_3d_frame(stage_effect, 0.0f);
set_stage_effect_glitter_frame(stage_effect, 0.0f);
flags |= 1 << stage_effect;
return;
}
if (curr_stage_effect == stage_effect && !next_stage_effect || next_stage_effect)
return;
else if (curr_stage_effect) {
if (!(flags & 0x10)) {
next_stage_effect = stage_effect;
stage_effect_transition_state = 0;
return;
}
else if (curr_stage_effect >= 1 && curr_stage_effect <= 12) {
stop_stage_effect_auth_3d(curr_stage_effect);
stop_stage_effect_glitter(curr_stage_effect);
}
}
if (stage_data.obj_hash.size())
stage_data.set_stage(stage_data.obj_hash.front());
curr_stage_effect = stage_effect;
set_stage_effect_auth_3d_frame(stage_effect, -1.0f);
set_stage_effect_glitter_frame(stage_effect, -1.0f);
}
void x_pv_game_stage::set_stage_effect_auth_3d_frame(int32_t stage_effect, float_t frame) {
if (stage_effect < 1 || stage_effect > 12)
return;
if (frame < 0.0f)
frame = bpm_frame_rate_control.bar_beat->get_bar_current_frame();
std::vector<x_pv_game_stage_effect_auth_3d>& auth_3d = effect[stage_effect - 1ULL].auth_3d;
for (x_pv_game_stage_effect_auth_3d& i : auth_3d) {
auth_3d_id& id = i.id;
id.set_camera_root_update(false);
id.set_enable(true);
id.set_repeat(true);
float_t last_frame = id.get_last_frame();
if (i.repeat && last_frame <= frame) {
int32_t frame_offset = (int32_t)id.get_frame_offset();
int32_t _frame = frame_offset + (int32_t)(frame - (float_t)frame_offset) % (int32_t)last_frame;
frame = (float_t)_frame + (frame - (float_t)(int32_t)frame);
}
id.set_req_frame(frame);
id.set_max_frame(-1.0f);
id.set_paused(false);
id.set_visibility(true);
id.set_frame_rate(&bpm_frame_rate_control);
}
}
void x_pv_game_stage::set_stage_effect_glitter_frame(int32_t stage_effect, float_t frame) {
if (stage_effect < 1 || stage_effect > 12)
return;
if (frame < 0.0f)
frame = bpm_frame_rate_control.bar_beat->get_bar_current_frame();
std::vector<x_pv_game_stage_effect_glitter>& glitter = effect[stage_effect - 1ULL].glitter;
for (x_pv_game_stage_effect_glitter& i : glitter) {
i.scene_counter = Glitter::glt_particle_manager->LoadSceneEffect(
i.name.hash_murmurhash, i.name.c_str(), 0x01);
if (!i.scene_counter)
continue;
Glitter::glt_particle_manager->SetSceneFrameRate(i.scene_counter, &bpm_frame_rate_control);
int32_t life_time = 0;
Glitter::glt_particle_manager->GetSceneFrameLifeTime(i.scene_counter, &life_time);
if (life_time <= 0)
continue;
if (stage_effect < 8 || stage_effect > 9) {
float_t _life_time = (float_t)life_time;
while (frame >= _life_time)
frame -= _life_time;
Glitter::glt_particle_manager->SetSceneEffectReqFrame(i.scene_counter, frame);
}
else if (frame < (float_t)life_time)
Glitter::glt_particle_manager->SetSceneEffectReqFrame(i.scene_counter, frame);
else
Glitter::glt_particle_manager->FreeSceneEffect(i.scene_counter, false);
i.fade_time_left = i.fade_time;
}
}
void x_pv_game_stage::stop_stage_change_effect() {
if (!next_stage_effect)
return;
int32_t curr_stg_eff = curr_stage_effect;
if (curr_stg_eff >= 1 && curr_stg_eff <= 12)
curr_stg_eff--;
else
curr_stg_eff = 0;
int32_t next_stg_eff = next_stage_effect;
if (next_stg_eff >= 1 && next_stg_eff <= 12)
next_stg_eff--;
else
next_stg_eff = 0;
x_pv_game_stage_change_effect& chg_eff = change_effect[curr_stg_eff][next_stg_eff];
for (x_pv_game_stage_effect_auth_3d& i : chg_eff.auth_3d) {
auth_3d_id& id = i.id;
id.set_visibility(false);
id.set_enable(false);
}
for (x_pv_game_stage_effect_glitter& i : chg_eff.glitter)
if (i.scene_counter) {
Glitter::glt_particle_manager->FreeSceneEffect(i.scene_counter, false);
i.scene_counter = 0;
}
}
void x_pv_game_stage::stop_stage_effect(bool reset_stage) {
if (curr_stage_effect < 1 || curr_stage_effect > 12)
return;
if (next_stage_effect) {
switch (stage_effect_transition_state) {
case 0:
stop_stage_effect_auth_3d(curr_stage_effect);
break;
case 1:
stop_stage_change_effect();
break;
}
stop_stage_effect_glitter(curr_stage_effect);
}
else {
stop_stage_effect_auth_3d(curr_stage_effect);
stop_stage_effect_glitter(curr_stage_effect);
}
if (reset_stage)
stage_data.set_default_stage();
curr_stage_effect = 0;
next_stage_effect = 0;
}
void x_pv_game_stage::stop_stage_effect_auth_3d(int32_t stage_effect) {
if (stage_effect < 1 || stage_effect > 12)
return;
std::vector<x_pv_game_stage_effect_auth_3d>& auth_3d = effect[stage_effect - 1ULL].auth_3d;
for (x_pv_game_stage_effect_auth_3d& i : auth_3d) {
auth_3d_id& id = i.id;
id.set_visibility(false);
id.set_enable(false);
}
}
void x_pv_game_stage::stop_stage_effect_glitter(int32_t stage_effect) {
if (stage_effect < 1 || stage_effect > 12)
return;
std::vector<x_pv_game_stage_effect_glitter>& glitter = effect[stage_effect - 1ULL].glitter;
for (x_pv_game_stage_effect_glitter& i : glitter)
if (i.scene_counter) {
Glitter::glt_particle_manager->FreeSceneEffect(i.scene_counter, false);
i.scene_counter = 0;
}
}
void x_pv_game_stage::unload() {
if (!stage_resource || !stage_id)
return;
for (std::pair<uint32_t, auth_3d_id> i : auth_3d_ids)
i.second.unload(rctx_ptr);
auth_3d_ids.clear();
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = effect[i];
for (x_pv_game_stage_effect_glitter& j : eff.glitter)
if (j.scene_counter) {
Glitter::glt_particle_manager->FreeSceneEffect(j.scene_counter, false);
j.scene_counter = 0;
}
}
if (stage_effect_transition_state == 1)
stop_stage_change_effect();
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = change_effect[i][j];
for (x_pv_game_stage_effect_glitter& k : chg_eff.glitter)
if (k.scene_counter) {
Glitter::glt_particle_manager->FreeSceneEffect(k.scene_counter, false);
k.scene_counter = 0;
}
chg_eff.enable = false;
chg_eff.auth_3d.clear();
chg_eff.auth_3d.shrink_to_fit();
chg_eff.glitter.clear();
chg_eff.glitter.shrink_to_fit();
chg_eff.bars_left = 0;
chg_eff.bar_count = 0;
}
for (uint32_t& i : stage_glitter) {
Glitter::EffectGroup* eff_group = Glitter::glt_particle_manager->GetEffectGroup(i);
if (eff_group)
eff_group->FreeModel();
Glitter::glt_particle_manager->UnloadEffectGroup(i);
}
stage_glitter.clear();
for (string_hash& i : stage_auth_3d)
auth_3d_data_unload_category(i.hash_murmurhash);
stage_auth_3d.clear();
env.unload();
delete stage_resource;
stage_resource = 0;
stage_data.unload();
stage_id = 0;
state = 30;
}
x_pv_game::x_pv_game() : state(), pv_count(), pv_index(), state_old(), frame(), frame_float(),
time(), rob_chara_ids(), play(), success(), chara_id(), pv_end(), playdata(), scene_rot_y(),
branch_mode(), task_effect_init(), pause(), step_frame(), pv_id(), stage_id(), charas(), modules() {
light_auth_3d_id = {};
target_anim_fps = 60.0f;
anim_frame_speed = 1.0f;
scene_rot_mat = mat4_identity;
for (chara_index& i : charas)
i = CHARA_MAX;
for (int32_t& i : modules)
i = 0;
}
x_pv_game::~x_pv_game() {
}
bool x_pv_game::Init() {
task_rob_manager_add_task();
return true;
}
#if BAKE_PNG || BAKE_VIDEO
static bool img_write = false;
#endif
#if BAKE_VIDEO
extern ID3D11Device* d3d_device;
extern ID3D11DeviceContext* d3d_device_context;
extern HANDLE d3d_gl_handle;
const int32_t d3d_in_flight_num = 3;
bool d3d_tex_write[d3d_in_flight_num];
int32_t d3d_curr_tex = 0;
int32_t d3d_tex_in_queue = 0;
ID3D11Texture2D* d3d_texture[d3d_in_flight_num];
GLuint d3d_query[d3d_in_flight_num];
GLuint d3d_gl_fbo[d3d_in_flight_num];
GLuint d3d_gl_rbo[d3d_in_flight_num];
HANDLE d3d_gl_rbo_handle[d3d_in_flight_num];
waitable_timer d3d_timer;
const size_t nvenc_src_pixel_size = 8;
const size_t nvenc_dst_pixel_size = 4;
std::vector<uint8_t> nvenc_temp_pixels;
nvenc_encoder* nvenc_enc;
file_stream* nvenc_stream;
#endif
#if DOF_BAKE
static void a3da_key_rev(a3da_key& k, std::vector<float_t>& values_src) {
std::vector<kft3> values;
int32_t type = interpolate_chs_reverse_sequence(values_src, values);
k = {};
switch (type) {
case 0:
default:
k.type = A3DA_KEY_NONE;
return;
case 1:
k.value = values[0].value;
k.type = A3DA_KEY_STATIC;
return;
case 2:
k.type = A3DA_KEY_LINEAR;
break;
case 3:
k.type = A3DA_KEY_HERMITE;
break;
}
k.keys.assign(values.begin(), values.end());
k.max_frame = (float_t)(values_src.size() + 1);
}
#endif
#if BAKE_PNG || BAKE_VIDEO
static int32_t frame_prev = -1;
#endif
bool x_pv_game::Ctrl() {
#if BAKE_VIDEO
auto write_frame = [&](int32_t idx) {
int32_t res = 0;
glGetQueryObjectiv(d3d_query[idx], GL_QUERY_RESULT_AVAILABLE, &res);
if (res) {
nvenc_enc->write_frame(d3d_texture[idx], nvenc_stream);
nvenc_stream->flush();
d3d_tex_in_queue--;
d3d_tex_write[idx] = false;
}
};
if (GLAD_WGL_NV_DX_interop2 && d3d_tex_in_queue) {
if (frame_prev == x_pv_game_ptr->frame)
for (int32_t i = 0; i < d3d_in_flight_num && !d3d_tex_write[d3d_curr_tex]; i++)
d3d_curr_tex = (d3d_curr_tex + 1) % d3d_in_flight_num;
if (d3d_tex_write[d3d_curr_tex])
write_frame(d3d_curr_tex);
}
#endif
#if BAKE_PNG || BAKE_VIDEO
if (img_write && frame_prev != x_pv_game_ptr->frame) {
texture* tex = rctx_ptr->post_process.screen_texture.color_texture;
int32_t width = tex->width;
int32_t height = tex->height;
#if BAKE_VIDEO
if (GLAD_WGL_NV_DX_interop2) {
shaders_dev.primitive_restart = shaders_ft.primitive_restart;
shaders_dev.primitive_restart_index = shaders_ft.primitive_restart_index;
int32_t idx = (d3d_curr_tex + 1) % d3d_in_flight_num;
d3d_curr_tex = idx;
int32_t next_idx = (idx + 2) % d3d_in_flight_num;
while (d3d_tex_write[next_idx]) {
d3d_timer.sleep_float(1.0);
write_frame(next_idx);
}
wglDXLockObjectsNV(d3d_gl_handle, 1, &d3d_gl_rbo_handle[next_idx]);
gl_state_bind_framebuffer(d3d_gl_fbo[next_idx]);
gl_state_active_bind_texture_2d(0, tex->tex);
glViewport(0, 0, width, height);
shaders_dev.set(SHADER_DEV_CLAMP_COLORS);
glBeginQuery(GL_SAMPLES_PASSED, d3d_query[next_idx]);
render_texture::draw(&shaders_dev);
glEndQuery(GL_SAMPLES_PASSED);
gl_state_bind_texture_2d(0);
gl_state_bind_framebuffer(0);
wglDXUnlockObjectsNV(d3d_gl_handle, 1, &d3d_gl_rbo_handle[next_idx]);
d3d_tex_in_queue++;
d3d_tex_write[next_idx] = true;
shaders_ft.primitive_restart = shaders_dev.primitive_restart;
shaders_ft.primitive_restart_index = shaders_dev.primitive_restart_index;
}
else {
D3D11_MAPPED_SUBRESOURCE mapped_res = {};
if (SUCCEEDED(d3d_device_context->Map(d3d_texture[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_res))) {
gl_state_bind_texture_2d(tex->tex);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_HALF_FLOAT, nvenc_temp_pixels.data());
gl_state_bind_texture_2d(0);
uint8_t* src = (uint8_t*)nvenc_temp_pixels.data();
uint8_t* dst = (uint8_t*)mapped_res.pData;
__m128 rgb_f32;
vec4i rgb_u10;
extern bool f16c;
if (f16c)
for (size_t y = 0, i = height; i; y++, i--) {
uint8_t* src1 = &src[y * width * nvenc_src_pixel_size];
uint8_t* dst1 = &dst[(height - y - 1) * width * nvenc_dst_pixel_size];
for (size_t x = 0, j = width; j; x++, j--, src1 += nvenc_src_pixel_size, dst1 += nvenc_dst_pixel_size) {
rgb_f32 = _mm_cvtph_ps(_mm_loadl_epi64((__m128i*)src1));
rgb_f32 = _mm_min_ps(_mm_max_ps(rgb_f32, vec4::load_xmm(0.0f)), vec4::load_xmm(1.0f));
rgb_f32 = _mm_mul_ps(rgb_f32, vec4::load_xmm((float_t)((1 << 10) - 1)));
rgb_u10 = vec4i::store_xmm(_mm_cvtps_epi32(rgb_f32));
*(uint32_t*)dst1 = (uint32_t)rgb_u10.x | ((uint32_t)rgb_u10.y << 10)
| ((uint32_t)rgb_u10.z << 20) | (0x03 << 30);
}
}
else
for (size_t y = 0, i = height; i; y++, i--) {
uint8_t* src1 = &src[y * width * nvenc_src_pixel_size];
uint8_t* dst1 = &dst[(height - y - 1) * width * nvenc_dst_pixel_size];
for (size_t x = 0, j = width; j; x++, j--, src1 += nvenc_src_pixel_size, dst1 += nvenc_dst_pixel_size) {
rgb_f32.m128_f32[0] = half_to_float_convert(((half_t*)src1)[0]);
rgb_f32.m128_f32[1] = half_to_float_convert(((half_t*)src1)[1]);
rgb_f32.m128_f32[2] = half_to_float_convert(((half_t*)src1)[2]);
rgb_f32.m128_f32[3] = half_to_float_convert(((half_t*)src1)[3]);
rgb_f32 = _mm_min_ps(_mm_max_ps(rgb_f32, vec4::load_xmm(0.0f)), vec4::load_xmm(1.0f));
rgb_f32 = _mm_mul_ps(rgb_f32, vec4::load_xmm((float_t)((1 << 10) - 1)));
rgb_u10 = vec4i::store_xmm(_mm_cvtps_epi32(rgb_f32));
*(uint32_t*)dst1 = (uint32_t)rgb_u10.x | ((uint32_t)rgb_u10.y << 10)
| ((uint32_t)rgb_u10.z << 20) | (0x03 << 30);
}
}
d3d_device_context->Unmap(d3d_texture[0], 0);
nvenc_enc->write_frame(d3d_texture[0], nvenc_stream);
nvenc_stream->flush();
}
}
#elif BAKE_PNG
std::vector<uint8_t> temp_pixels;
temp_pixels.resize((size_t)width * (size_t)height * 4 * sizeof(uint8_t));
gl_state_bind_texture_2d(tex->tex);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels.data());
gl_state_bind_texture_2d(0);
std::vector<uint8_t> pixels;
pixels.resize((size_t)width * (size_t)height * 4 * sizeof(uint8_t));
uint8_t* src = (uint8_t*)temp_pixels.data();
uint8_t* dst = (uint8_t*)pixels.data();
for (size_t y = 0; y < height; y++) {
uint8_t* src1 = &src[y * width * 4];
uint8_t* dst1 = &dst[(height - y - 1) * width * 4];
for (size_t x = 0; x < width; x++) {
*dst1++ = *src1++;
*dst1++ = *src1++;
*dst1++ = *src1++;
*dst1++ = *src1++;
//*dst1++ = reverse_endianness_uint16_t(*src1++);
//*dst1++ = reverse_endianness_uint16_t(*src1++);
//*dst1++ = reverse_endianness_uint16_t(*src1++);
//*dst1++ = reverse_endianness_uint16_t(*src1++);
}
}
temp_pixels.clear();
temp_pixels.shrink_to_fit();
std::vector<uint8_t> png;
uint32_t error = lodepng::encode(png, pixels, (uint32_t)width, (uint32_t)height, LCT_RGBA, 8);
if (!error) {
char buf[0x200];
sprintf_s(buf, sizeof(buf), "G:\\ReDIVA\\Photos\\pv%03d",
x_pv_game_ptr->pv_data[x_pv_game_ptr->pv_index].pv_id);
CreateDirectoryA(buf, 0);
sprintf_s(buf, sizeof(buf), "G:\\ReDIVA\\Photos\\pv%03d\\%05d.png",
x_pv_game_ptr->pv_data[x_pv_game_ptr->pv_index].pv_id, x_pv_game_ptr->frame);
lodepng::save_file(png, buf);
}
#endif
frame_prev = x_pv_game_ptr->frame;
img_write = false;
}
#endif
if (state_old == 20)
ctrl((float_t)((frame_float + get_delta_frame()) * (1.0 / 60.0)), get_delta_frame() * (float_t)(1.0 / 60.0));
else
ctrl(0.0f, 0.0f);
switch (state_old) {
case 0:
return false;
case 1: {
pv_index = 0;
pv_count = 1;
pv_data[pv_index].pv_id = pv_id;
char buf[0x200];
for (int32_t i = 0; i < pv_count; i++) {
x_pv_game_data& pv_data = this->pv_data[i];
sprintf_s(buf, sizeof(buf), "pv%03d.pvpp", pv_data.pv_id);
pv_data.play_param_file_handler.read_file(&data_list[DATA_X], "root+/pv/", buf);
pv_data.stage = &stage_data;
}
state_old = 2;
} break;
case 2: {
bool wait_load = false;
for (int32_t i = 0; i < pv_count; i++)
if (pv_data[i].play_param_file_handler.check_not_ready())
wait_load |= true;
if (wait_load)
break;
stage_data.load(stage_id, &field_71994, false);
for (int32_t i = 0; i < pv_count; i++) {
x_pv_game_data& pv_data = this->pv_data[i];
const void* pvpp_data = pv_data.play_param_file_handler.get_data();
size_t pvpp_size = pv_data.play_param_file_handler.get_size();
pv_data.play_param = new pvpp;
pv_data.play_param->read(pvpp_data, pvpp_size);
#if BAKE_PV826
pv_data.load(pv_id, &field_71994, charas,
pv_id == 826 ? &effchrpv_auth_3d_mot_names : 0);
#else
pv_data.load(pv_id, &field_71994, charas);
#endif
int32_t chara_index = 0;
for (pvpp_chara& i : pv_data.play_param->chara) {
if (i.motion.size() && rob_chara_ids[chara_index] == -1) {
rob_chara_pv_data pv_data;
pv_data.chara_size_index = chara_init_data_get_chara_size_index(charas[chara_index]);
rob_sleeve_handler_data_get_sleeve_data(
charas[chara_index], modules[chara_index] + 1, pv_data.sleeve_l, pv_data.sleeve_r);
int32_t chara_id = rob_chara_array_init_chara_index(
charas[chara_index], pv_data, modules[chara_index], true);
if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT)
rob_chara_ids[chara_index] = chara_id;
}
if (++chara_index >= ROB_CHARA_COUNT)
break;
}
#if BAKE_PV826
if (pv_id == 826) {
for (int32_t i = (int32_t)pv_data.play_param->chara.size(); i < ROB_CHARA_COUNT; i++) {
rob_chara_pv_data pv_data;
pv_data.chara_size_index = chara_init_data_get_chara_size_index(charas[i]);
int32_t chara_id = rob_chara_array_init_chara_index(charas[i], pv_data, modules[i], true);
if (chara_id >= 0 && chara_id < ROB_CHARA_COUNT)
rob_chara_ids[i] = chara_id;
effchrpv_rob_mot_ids.push_back(chara_id);
}
char buf[0x100];
pv_data.play_param->chara.resize(6);
pvpp_chara* chara = pv_data.play_param->chara.data();
for (int32_t i = 1; i < 6; i++) {
switch (i) {
case 1:
chara[i].chara_effect.base_chara = PVPP_CHARA_RIN;
chara[i].chara_effect_init = true;
break;
case 2:
chara[i].chara_effect.base_chara = PVPP_CHARA_LEN;
chara[i].chara_effect_init = true;
break;
case 3:
chara[i].chara_effect.base_chara = PVPP_CHARA_LUKA;
chara[i].chara_effect_init = true;
break;
case 4:
chara[i].chara_effect.base_chara = PVPP_CHARA_MEIKO;
chara[i].chara_effect_init = true;
break;
case 5:
chara[i].chara_effect.base_chara = PVPP_CHARA_KAITO;
chara[i].chara_effect_init = true;
break;
}
sprintf_s(buf, sizeof(buf), "PV%03d_%s_P%d_00", 826, "OST", i + 1);
chara[i].motion.push_back(buf);
}
}
#endif
}
state_old = 3;
} break;
case 3: {
bool wait_load = false;
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++)
if (rob_chara_ids[i] != -1)
wait_load |= !task_rob_manager_check_chara_loaded(rob_chara_ids[i]);
if (wait_load)
break;
data_struct* x_data = &data_list[DATA_X];
light_param_data_storage_data_set_pv_id(pv_data[pv_index].pv_id);
auth_3d_data_load_category(light_category.c_str());
state_old = 7;
} break;
case 7: {
bool wait_load = false;
if (!auth_3d_data_check_category_loaded(light_category.c_str()))
wait_load |= true;
if (wait_load)
break;
data_struct* x_data = &data_list[DATA_X];
light_auth_3d_id = {};
{
data_struct* aft_data = &data_list[DATA_AFT];
auth_3d_database* aft_auth_3d_db = &aft_data->data_ft.auth_3d_db;
char buf[0x200];
sprintf_s(buf, sizeof(buf), "STGPV%03d_EFF_LT_000",
pv_data[pv_index].pv_id == 832 ? 800 : pv_data[pv_index].pv_id);
uint32_t light_auth_3d_hash = hash_utf8_murmurhash(buf);
for (auth_3d_database_uid& i : aft_auth_3d_db->uid)
if (hash_string_murmurhash(i.name) == light_auth_3d_hash) {
light_auth_3d_id = auth_3d_data_load_uid(
(int32_t)(&i - aft_auth_3d_db->uid.data()), aft_auth_3d_db);
if (!light_auth_3d_id.check_not_empty()) {
light_auth_3d_id = {};
break;
}
light_auth_3d_id.read_file(aft_auth_3d_db);
light_auth_3d_id.set_enable(false);
light_auth_3d_id.set_visibility(false);
break;
}
}
state_old = 8;
} break;
case 8: {
bool wait_load = false;
if (light_auth_3d_id.check_not_empty() && !light_auth_3d_id.check_loaded())
wait_load |= true;
if (wait_load)
break;
x_pv_game_dsc_data& dsc_data = pv_data[pv_index].dsc_data;
pv_param_task::post_process_task_add_task();
{
data_struct* x_data = &data_list[DATA_X];
dsc dsc_mouth;
dsc dsc_scene;
dsc dsc_system;
dsc dsc_easy;
char path_buf[0x200];
char file_buf[0x200];
farc dsc_common_farc;
sprintf_s(path_buf, sizeof(path_buf), "root+/pv_script/pv%03d/", pv_data[pv_index].pv_id);
sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_common.farc", pv_data[pv_index].pv_id);
x_data->load_file(&dsc_common_farc, path_buf, file_buf, farc::load_file);
sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_mouth.dsc", pv_data[pv_index].pv_id);
farc_file* dsc_mouth_ff = dsc_common_farc.read_file(file_buf);
if (dsc_mouth_ff)
dsc_mouth.parse(dsc_mouth_ff->data, dsc_mouth_ff->size, DSC_X);
sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_scene.dsc", pv_data[pv_index].pv_id);
farc_file* dsc_scene_ff = dsc_common_farc.read_file(file_buf);
if (dsc_scene_ff)
dsc_scene.parse(dsc_scene_ff->data, dsc_scene_ff->size, DSC_X);
sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_system.dsc", pv_data[pv_index].pv_id);
farc_file* dsc_system_ff = dsc_common_farc.read_file(file_buf);
if (dsc_system_ff)
dsc_system.parse(dsc_system_ff->data, dsc_system_ff->size, DSC_X);
sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_easy.dsc", pv_data[pv_index].pv_id);
dsc_easy.type = DSC_X;
x_data->load_file(&dsc_easy, path_buf, file_buf, dsc::load_file);
if (pv_id == 826) {
dsc dsc_hand_keys[5];
char file_buf[0x200];
for (int32_t i = 2; i <= 6; i++) {
file_stream s;
sprintf_s(file_buf, sizeof(file_buf), "pv826\\pv_826_hand_%d.txt", i);
s.open(file_buf, "rb");
size_t length = s.length;
uint8_t* data = force_malloc_s(uint8_t, length);
s.read(data, length);
s.close();
dsc& d = dsc_hand_keys[i - 2];
d.parse_text(data, length, DSC_X);
d.signature = 0x13120420;
free(data);
{
int32_t hand_l_time = -1;
int32_t hand_l_id = -1;
int32_t hand_l_duration = -1;
::dsc_data* hand_l_data = 0;
int32_t time = -1;
for (::dsc_data& j : d.data) {
if (j.func == DSC_X_END)
break;
uint32_t* data = d.get_func_data(&j);
switch (j.func) {
case DSC_X_TIME:
time = (int32_t)data[0];
break;
case DSC_X_HAND_ANIM: {
if (data[1] == 0) {
if (hand_l_time > -1 && hand_l_duration > time - hand_l_time)
data[3] = (time - hand_l_time) / 100;
hand_l_time = time;
hand_l_id = (int32_t)data[2];
hand_l_duration = (int32_t)data[3] * 100;
hand_l_data = &j;
}
} break;
}
}
}
{
int32_t hand_r_time = -1;
int32_t hand_r_id = -1;
int32_t hand_r_duration = -1;
::dsc_data* hand_r_data = 0;
int32_t time = -1;
for (::dsc_data& j : d.data) {
if (j.func == DSC_X_END)
break;
uint32_t* data = d.get_func_data(&j);
switch (j.func) {
case DSC_X_TIME:
time = (int32_t)data[0];
break;
case DSC_X_HAND_ANIM: {
if (data[1] == 1) {
if (hand_r_time > -1 && hand_r_duration > time - hand_r_time)
data[3] = (time - hand_r_time) / 100;
hand_r_time = time;
hand_r_id = (int32_t)data[2];
hand_r_duration = (int32_t)data[3] * 100;
hand_r_data = &j;
}
} break;
}
}
}
}
dsc_data.dsc.merge(9, &dsc_mouth, &dsc_scene, &dsc_system, &dsc_easy,
&dsc_hand_keys[0], &dsc_hand_keys[1], &dsc_hand_keys[2], &dsc_hand_keys[3], dsc_hand_keys[4]);
}
else
dsc_data.dsc.merge(4, &dsc_mouth, &dsc_scene, &dsc_system, &dsc_easy);
struct miku_state {
bool disp;
int32_t disp_time;
int32_t set_motion_time;
uint32_t set_motion_data_offset;
} state[6];
for (miku_state& i : state) {
i.disp = true;
i.disp_time = -1;
i.set_motion_time = -1;
i.set_motion_data_offset = 0;
}
std::vector<miku_state> state_vec;
x_pv_bar_beat_data* bar_beat_data = 0;
int32_t beat_counter = 0;
prj::vector_pair<int32_t, uint32_t> miku_disp;
prj::vector_pair<int32_t, uint32_t> set_motion;
prj::vector_pair<int32_t, uint32_t> set_playdata;
int32_t time = -1;
int32_t frame = -1;
for (::dsc_data& i : dsc_data.dsc.data) {
if (i.func == DSC_X_END)
break;
uint32_t* data = dsc_data.dsc.get_func_data(&i);
switch (i.func) {
case DSC_X_TIME: {
for (miku_state& i : state)
if (state[chara_id].disp && i.disp_time == time && i.set_motion_time != time)
state_vec.push_back(i);
time = (int32_t)data[0];
frame = (int32_t)roundf((float_t)time * (float_t)(60.0 / 100000.0));
} break;
case DSC_X_MIKU_DISP: {
int32_t chara_id = (int32_t)data[0];
state[chara_id].disp = (int32_t)data[1] == 1;
if (state[chara_id].disp)
state[chara_id].disp_time = time;
miku_disp.push_back(time, i.data_offset);
} break;
case DSC_X_SET_MOTION: {
int32_t chara_id = (int32_t)data[0];
state[chara_id].set_motion_time = time;
state[chara_id].set_motion_data_offset = i.data_offset;
set_motion.push_back(time, i.data_offset);
} break;
case DSC_X_SET_PLAYDATA: {
set_playdata.push_back(time, i.data_offset);
} break;
}
}
if (state_vec.size() || miku_disp.size() || set_motion.size() || set_playdata.size()) {
int32_t time = -1;
for (miku_state& i : state_vec) {
if (i.disp_time != time) {
uint32_t* data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_TIME),
DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME));
data[0] = i.disp_time;
time = i.disp_time;
}
uint32_t* new_data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_SET_MOTION),
DSC_X_SET_MOTION, dsc_x_get_func_length(DSC_X_SET_MOTION));
uint32_t* data = dsc_data.dsc.data_buffer.data() + i.set_motion_data_offset;
memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_SET_MOTION));
}
time = -1;
for (std::pair<int32_t, uint32_t>& i : miku_disp) {
if (i.first != time) {
uint32_t* data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_TIME),
DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME));
data[0] = i.first;
time = i.first;
}
for (int32_t j = 1; j < 6; j++) {
uint32_t* new_data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_MIKU_DISP),
DSC_X_MIKU_DISP, dsc_x_get_func_length(DSC_X_MIKU_DISP));
uint32_t* data = dsc_data.dsc.data_buffer.data() + i.second;
memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_MIKU_DISP));
new_data[0] = j;
}
}
time = -1;
for (std::pair<int32_t, uint32_t>& i : set_motion) {
if (i.first != time) {
uint32_t* data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_TIME),
DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME));
data[0] = i.first;
time = i.first;
}
for (int32_t j = 1; j < 6; j++) {
uint32_t* new_data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_SET_MOTION),
DSC_X_SET_MOTION, dsc_x_get_func_length(DSC_X_SET_MOTION));
uint32_t* data = dsc_data.dsc.data_buffer.data() + i.second;
memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_SET_MOTION));
new_data[0] = j;
}
}
time = -1;
for (std::pair<int32_t, uint32_t>& i : set_playdata) {
if (i.first != time) {
uint32_t* data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_TIME),
DSC_X_TIME, dsc_x_get_func_length(DSC_X_TIME));
data[0] = i.first;
time = i.first;
}
for (int32_t j = 1; j < 6; j++) {
uint32_t* new_data = dsc_data.dsc.add_func(dsc_x_get_func_name(DSC_X_SET_PLAYDATA),
DSC_X_SET_PLAYDATA, dsc_x_get_func_length(DSC_X_SET_PLAYDATA));
uint32_t* data = dsc_data.dsc.data_buffer.data() + i.second;
memcpy(new_data, data, sizeof(uint32_t) * dsc_x_get_func_length(DSC_X_SET_PLAYDATA));
new_data[0] = j;
}
}
dsc_data.dsc.rebuild();
}
/*sprintf_s(file_buf, sizeof(file_buf), "pv_%03d_easy.dsc", pv_data.pv_id);
void* data = 0;
size_t size = 0;
dsc.unparse(&data, &size);
stream s;
s.open(file_buf, "wb");
s.write(data, size);
free_def(data);*/
}
pv_expression_array_reset();
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) {
playdata[i].reset();
if (rob_chara_ids[i] == -1)
continue;
rob_chara* rob_chr = rob_chara_array_get(rob_chara_ids[i]);
if (rob_chr) {
playdata[i].rob_chr = rob_chr;
rob_chr->frame_speed = anim_frame_speed;
rob_chr->data.motion.step_data.step = anim_frame_speed;
pv_expression_array_set(i, rob_chr, anim_frame_speed);
}
pv_game_dsc_data_find_playdata_set_motion(this, i);
pv_game_dsc_data_find_playdata_item_anim(this, i);
}
pv_game_dsc_data_find_set_motion(this);
dsc_data.dsc_data_ptr = dsc_data.dsc.data.data();
dsc_data.dsc_data_ptr_end = dsc_data.dsc_data_ptr + dsc_data.dsc.data.size();
state_old = 9;
} break;
case 9: {
if (skin_param_manager_array_check_task_ready())
break;
bool wait_load = false;
for (int32_t i = 0; i < pv_count; i++)
if (!pv_data[i].state || pv_data[i].state == 10) {
pv_data[i].state = 10;
pv_data[i].field_1C |= 0x08;
wait_load |= true;
}
if (wait_load)
break;
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) {
if (rob_chara_ids[i] == -1)
continue;
int32_t chara_id = rob_chara_ids[i];
rob_chara* rob_chr = rob_chara_array_get(chara_id);
if (!rob_chr)
continue;
pv_osage_manager_array_reset(chara_id);
pv_osage_manager_array_set_pv_set_motion(chara_id, set_motion[chara_id]);
pv_osage_manager_array_set_pv_id(chara_id, pv_data[pv_index].pv_id, true);
}
state = 10;
state_old = 10;
} break;
case 10: {
if (pv_osage_manager_array_get_disp() || osage_play_data_manager_check_task_ready())
break;
bool wait_load = false;
for (int32_t i = 0; i < pv_count; i++)
if (pv_data[i].state != 30)
wait_load |= true;
if (wait_load)
break;
state_old = 18;
} break;
case 18: {
std::vector<object_info> object_hrc;
std::vector<std::string> material_list;
auto check_for_material_list_object_hrc = [&](auth_3d_id& id) {
if (!id.check_not_empty() || !id.check_loaded())
return;
auth_3d* auth = id.get_auth_3d();
if (!auth || !auth->material_list.size() || !auth->object_hrc.size())
return;
for (auth_3d_material_list& i : auth->material_list)
if (i.flags & (AUTH_3D_MATERIAL_LIST_BLEND_COLOR | AUTH_3D_MATERIAL_LIST_EMISSION))
material_list.push_back(i.name);
for (auth_3d_object_hrc& i : auth->object_hrc)
object_hrc.push_back(i.object_info);
};
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = stage_data.effect[i];
for (x_pv_game_stage_effect_auth_3d& j : eff.auth_3d)
check_for_material_list_object_hrc(j.id);
}
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = stage_data.change_effect[i][j];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
check_for_material_list_object_hrc(k.id);
}
prj::sort_unique(object_hrc);
prj::sort_unique(material_list);
if (material_list.size())
x_pv_game_split_auth_3d_hrc_material_list(this, object_hrc, material_list);
std::vector<object_info> object;
material_list.clear();
auto check_for_material_list_object = [&](auth_3d_id& id) {
if (!id.check_not_empty() || !id.check_loaded())
return;
auth_3d* auth = id.get_auth_3d();
if (!auth || !auth->material_list.size() || !auth->object.size())
return;
for (auth_3d_material_list& i : auth->material_list)
if (i.flags & (AUTH_3D_MATERIAL_LIST_BLEND_COLOR | AUTH_3D_MATERIAL_LIST_EMISSION))
material_list.push_back(i.name);
for (auth_3d_object& i : auth->object)
object.push_back(i.object_info);
};
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = stage_data.effect[i];
for (x_pv_game_stage_effect_auth_3d& j : eff.auth_3d)
check_for_material_list_object(j.id);
}
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = stage_data.change_effect[i][j];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
check_for_material_list_object(k.id);
}
prj::sort_unique(object);
prj::sort_unique(material_list);
if (material_list.size())
x_pv_game_split_auth_3d_material_list(this, object, material_list);
state_old = 19;
} break;
case 19: {
x_pv_game_change_field(this, 1, -1, -1);
Glitter::glt_particle_manager->SetPause(false);
extern float_t frame_speed;
frame_speed = 1.0f;
pause = false;
step_frame = false;
frame_float = 0.0;
this->frame = (int32_t)frame_float;
this->time = (int64_t)round(frame_float * (100000.0 / 60.0) * 10000.0);
while (pv_data[pv_index].dsc_data.dsc_data_ptr != pv_data[pv_index].dsc_data.dsc_data_ptr_end
&& x_pv_game_dsc_process(this, this->time))
pv_data[pv_index].dsc_data.dsc_data_ptr++;
light_auth_3d_id.set_enable(true);
light_auth_3d_id.set_camera_root_update(false);
light_auth_3d_id.set_paused(false);
light_auth_3d_id.set_repeat(false);
light_auth_3d_id.set_visibility(true);
light_auth_3d_id.set_req_frame(0.0f);
#if BAKE_PV826
if (pv_id == 826) {
data_struct* aft_data = &data_list[DATA_AFT];
bone_database* aft_bone_data = &aft_data->data_ft.bone_data;
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
for (int32_t& i : effchrpv_rob_mot_ids) {
char buf[0x100];
sprintf_s(buf, sizeof(buf), "PV826_OST_P%d_00", i + 1);
uint32_t motion_id = aft_mot_db->get_motion_id(buf);
rob_chara* rob_chr = rob_chara_array_get(rob_chara_ids[i]);
rob_chr->set_motion_id(motion_id, 0.0f,
0.0f, false, false, MOTION_BLEND_CROSS, aft_bone_data, aft_mot_db);
rob_chr->set_motion_reset_data(motion_id, 0.0f);
rob_chr->set_motion_skin_param(motion_id, 0.0f);
sprintf_s(buf, sizeof(buf), "A3D_EFFCHRPV%03dMIK%03d", pv_id, i);
uint32_t hash = hash_utf8_murmurhash(buf);
for (auto j : effchrpv_auth_3d_mot_names)
if (j.second.hash_murmurhash == hash) {
uint32_t hash = hash_string_murmurhash(j.first);
effchrpv_auth_3d_rob_mot_ids.insert({ i, { effchrpv_auth_3d_mot_ids[hash] } });
break;
}
}
for (auto& i : effchrpv_auth_3d_rob_mot_ids) {
x_pv_game_a3da_to_mot& a2m = i.second;
auth_3d* auth = a2m.id.get_auth_3d();
a2m.get_bone_indices(&auth->object_hrc[0]);
}
for (auto& i : effchrpv_auth_3d_mot_ids) {
auth_3d_id& id = i.second;
id.set_repeat(false);
id.set_camera_root_update(false);
id.set_enable(true);
id.set_paused(false);
id.set_visibility(false);
id.set_req_frame(0.0f);
}
}
#endif
#if BAKE_PNG || BAKE_VIDEO
extern bool disable_cursor;
disable_cursor = true;
const int32_t width = BAKE_BASE_WIDTH * BAKE_RES_SCALE;
const int32_t height = BAKE_BASE_HEIGHT * BAKE_RES_SCALE;
#if BAKE_VIDEO
if (GLAD_WGL_NV_DX_interop2) {
glGenRenderbuffers(d3d_in_flight_num, d3d_gl_rbo);
glGenFramebuffers(d3d_in_flight_num, d3d_gl_fbo);
glGenQueries(d3d_in_flight_num, d3d_query);
D3D11_TEXTURE2D_DESC tex_desc = { };
tex_desc.Width = width;
tex_desc.Height = height;
tex_desc.MipLevels = 1;
tex_desc.ArraySize = 1;
tex_desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
tex_desc.SampleDesc.Count = 1;
tex_desc.SampleDesc.Quality = 0;
tex_desc.Usage = D3D11_USAGE_DEFAULT;
tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
tex_desc.CPUAccessFlags = 0;
tex_desc.MiscFlags = 0;
for (int32_t i = 0; i < d3d_in_flight_num; i++)
d3d_device->CreateTexture2D(&tex_desc, 0, &d3d_texture[i]);
for (int32_t i = 0; i < d3d_in_flight_num; i++)
d3d_gl_rbo_handle[i] = wglDXRegisterObjectNV(d3d_gl_handle, d3d_texture[i],
d3d_gl_rbo[i], GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV);
for (int32_t i = 0; i < d3d_in_flight_num; i++) {
wglDXLockObjectsNV(d3d_gl_handle, 1, &d3d_gl_rbo_handle[i]);
gl_state_bind_framebuffer(d3d_gl_fbo[i]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, d3d_gl_rbo[i]);
gl_state_bind_framebuffer(0);
wglDXUnlockObjectsNV(d3d_gl_handle, 1, &d3d_gl_rbo_handle[i]);
}
}
else {
D3D11_TEXTURE2D_DESC tex_desc = { };
tex_desc.Width = width;
tex_desc.Height = height;
tex_desc.MipLevels = 1;
tex_desc.ArraySize = 1;
tex_desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
tex_desc.SampleDesc.Count = 1;
tex_desc.SampleDesc.Quality = 0;
tex_desc.Usage = D3D11_USAGE_DYNAMIC;
tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
tex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
tex_desc.MiscFlags = 0;
d3d_device->CreateTexture2D(&tex_desc, 0, &d3d_texture[0]);
nvenc_temp_pixels.resize((size_t)width* (size_t)height* nvenc_src_pixel_size);
}
nvenc_enc = new nvenc_encoder(width, height, d3d_device);
char buf[0x100];
sprintf_s(buf, sizeof(buf), "G:\\ReDIVA\\Videos\\ReDIVA_pv%03d.265", pv_data[pv_index].pv_id);
nvenc_stream = new file_stream();
nvenc_stream->open(buf, "wb");
#endif
#endif
#if BAKE_PV826
x_pv_game_map_auth_3d_to_mot(this, true);
#endif
pause = true;
state_old = 20;
//sound_work_release_se("load01_2", false);
} break;
case 20: {
float_t delta_frame = get_delta_frame();
frame_float += delta_frame;
frame = (int32_t)frame_float;
time = (int64_t)round(frame_float * (100000.0 / 60.0) * 10000.0);
while (pv_data[pv_index].dsc_data.dsc_data_ptr != pv_data[pv_index].dsc_data.dsc_data_ptr_end
&& x_pv_game_dsc_process(this, time))
pv_data[pv_index].dsc_data.dsc_data_ptr++;
x_pv_game_music_ptr->set_pause(pause ? 1 : 0);
#if BAKE_PV826
x_pv_game_map_auth_3d_to_mot(this, delta_frame != 0.0f);
#endif
#if BAKE_PNG || BAKE_VIDEO
img_write = true;
#endif
if (!play || pv_end)
state_old = 21;
} break;
case 21: {
#if BAKE_PNG || BAKE_VIDEO
extern bool disable_cursor;
disable_cursor = false;
#if BAKE_VIDEO
if (GLAD_WGL_NV_DX_interop2) {
bool wait = false;
for (int32_t i = 0; i < d3d_in_flight_num; i++)
if (d3d_tex_write[i])
wait |= true;
if (wait)
break;
}
nvenc_stream->close();
delete nvenc_stream;
nvenc_stream = 0;
delete nvenc_enc;
nvenc_enc = 0;
if (GLAD_WGL_NV_DX_interop2) {
for (int32_t i = 0; i < d3d_in_flight_num; i++) {
wglDXUnregisterObjectNV(d3d_gl_handle, d3d_gl_rbo_handle[i]);
d3d_gl_rbo_handle[i] = 0;
}
for (int32_t i = 0; i < d3d_in_flight_num; i++) {
d3d_texture[i]->Release();
d3d_texture[i] = 0;
}
glDeleteQueries(d3d_in_flight_num, d3d_query);
glDeleteFramebuffers(d3d_in_flight_num, d3d_gl_fbo);
memset(d3d_gl_fbo, 0, sizeof(d3d_gl_fbo));
glDeleteRenderbuffers(d3d_in_flight_num, d3d_gl_rbo);
memset(d3d_gl_rbo, 0, sizeof(d3d_gl_rbo));
}
else {
nvenc_temp_pixels.clear();
nvenc_temp_pixels.shrink_to_fit();
d3d_texture[0]->Release();
d3d_texture[0] = 0;
}
#endif
#endif
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++)
pv_expression_array_reset_motion(i);
#if DOF_BAKE
{
x_pv_game_data& pv_data = this->pv_data[pv_index];
data_struct* x_data = &data_list[DATA_X];
char buf[0x200];
sprintf_s(buf, sizeof(buf), "CAMPV%03d", pv_data.pv_id);
farc* f = new farc;
x_data->load_file(f, "root+/auth_3d/", hash_utf8_murmurhash(buf), ".farc", farc::load_file);
if ((pv_data.pv_id % 100) >= 25 && (pv_data.pv_id % 100) <= 30
&& stage_data.stage_id >= 25 && stage_data.stage_id <= 30)
sprintf_s(buf, sizeof(buf), "CAMPV%03d_100.a3da", pv_data.pv_id);
else
sprintf_s(buf, sizeof(buf), "CAMPV%03d_BASE.a3da", pv_data.pv_id);
a3da a;
farc_file* ff = f->read_file(buf);
if (ff)
a.read(ff->data, ff->size);
delete f;
if ((pv_data.pv_id % 100) >= 25 && (pv_data.pv_id % 100) <= 30
&& stage_data.stage_id >= 25 && stage_data.stage_id <= 30)
sprintf_s(buf, sizeof(buf), "DOF\\auth_3d\\CAMPV%03d_100", pv_data.pv_id);
else
sprintf_s(buf, sizeof(buf), "DOF\\auth_3d\\CAMPV%03d_BASE", pv_data.pv_id);
a.ready = true;
a.compressed = true;
a.format = A3DA_FORMAT_AFT;
a.dof = {};
a.dof.has_dof = true;
a3da_key_rev(a.dof.model_transform.translation.x, dof_cam_data.position_x);
a3da_key_rev(a.dof.model_transform.translation.y, dof_cam_data.position_y);
a3da_key_rev(a.dof.model_transform.translation.z, dof_cam_data.position_z);
a.dof.model_transform.translation.x.raw_data = true;
a.dof.model_transform.translation.y.raw_data = true;
a.dof.model_transform.translation.z.raw_data = true;
a3da_key_rev(a.dof.model_transform.scale.x, dof_cam_data.focus_range);
a3da_key_rev(a.dof.model_transform.rotation.x, dof_cam_data.fuzzing_range);
a3da_key_rev(a.dof.model_transform.rotation.y, dof_cam_data.ratio);
a3da_key& rot_z = a.dof.model_transform.rotation.z;
if (dof_cam_data.enable_frame.size() > 1) {
rot_z.type = A3DA_KEY_HOLD;
rot_z.keys.reserve(dof_cam_data.enable_frame.size());
for (std::pair<int32_t, bool>& i : dof_cam_data.enable_frame)
rot_z.keys.push_back({ (float_t)i.first, i.second ? 1.00051f : 0.0f });
rot_z.max_frame = a.play_control.size;
}
else if (dof_cam_data.enable_frame.size()) {
rot_z.type = A3DA_KEY_STATIC;
rot_z.value = dof_cam_data.enable_frame[0].second ? 1.00051f : 0.0f;
}
else
rot_z.type = A3DA_KEY_NONE;
a.write(buf);
dof_cam_data.reset();
}
#endif
unload();
state_old = 22;
} break;
case 22: {
if (state)
break;
Glitter::glt_particle_manager->FreeScenes();
DelTask();
} break;
}
return false;
}
bool x_pv_game::Dest() {
if (!Unload())
return false;
task_rob_manager_del_task();
light_param_data_storage_data_reset();
rctx_ptr->post_process.tone_map->set_saturate_coeff(1.0f);
rctx_ptr->post_process.tone_map->set_scene_fade(0.0f);
rctx_ptr->post_process.tone_map->set_scene_fade_blend_func(0);
rctx_ptr->post_process.dof->data.pv.enable = false;
rctx_ptr->disp_manager.object_culling = true;
rctx_ptr->render_manager.shadow_ptr->range = 1.0f;
Glitter::glt_particle_manager->SetPause(false);
extern float_t frame_speed;
frame_speed = 1.0f;
extern bool close;
//close = true;
return true;
}
void x_pv_game::Disp() {
if (state_old != 20)
return;
}
void x_pv_game::Basic() {
if (state_old != 20 && state_old != 21)
return;
#if DOF_BAKE
if (dof_cam_data.frame != frame) {
camera* cam = rctx_ptr->camera;
post_process_dof* dof = rctx_ptr->post_process.dof;
dof_pv pv;
dof->get_dof_pv(&pv);
vec3 interest;
vec3 view_point;
cam->get_interest(interest);
cam->get_view_point(view_point);
bool enable = false;
if (pv.enable && pv.f2.ratio > 0.0f) {
if (pv.f2.focus > 0.0f) {
vec3 direction = vec3::normalize(interest - view_point);
interest = direction * pv.f2.focus + view_point;
}
else
interest = view_point;
enable = true;
}
dof_cam_data.position_x.push_back(interest.x);
dof_cam_data.position_y.push_back(interest.y);
dof_cam_data.position_z.push_back(interest.z);
dof_cam_data.focus.push_back(pv.f2.focus);
dof_cam_data.focus_range.push_back(pv.f2.focus_range);
dof_cam_data.fuzzing_range.push_back(pv.f2.fuzzing_range);
dof_cam_data.ratio.push_back(pv.f2.ratio);
if (dof_cam_data.enable != enable) {
dof_cam_data.enable_frame.push_back(frame, enable);
dof_cam_data.enable = enable;
}
dof_cam_data.frame = frame;
}
#endif
if (step_frame)
if (pause)
pause = false;
else {
pause = true;
step_frame = false;
}
Glitter::glt_particle_manager->SetPause(pause);
extern float_t frame_speed;
frame_speed = pause ? 0.0f : 1.0f;
#if BAKE_PV826
for (auto& i : effchrpv_auth_3d_rob_mot_ids) {
rob_chara* rob_chr = rob_chara_array_get(rob_chara_ids[i.first]);
x_pv_game_a3da_to_mot& a2m = i.second;
rob_chara_bone_data* rob_bone_data = rob_chr->bone_data;
bone_database_skeleton_type skeleton_type = rob_bone_data->base_skeleton_type;
motion_blend_mot* mot = rob_bone_data->motion_loaded.front();
std::vector<bone_data>* bones = &mot->bone_data.bones;
std::vector<uint16_t>* bone_indices = &mot->bone_data.bone_indices;
bone_data* bones_data = bones->data();
for (uint16_t& i : *bone_indices) {
bone_data* data = &bones_data[i];
::motion_bone_index motion_bone_index = (::motion_bone_index)data->motion_bone_index;
if (!(motion_bone_index >= MOTION_BONE_N_HITO_L_EX
&& motion_bone_index <= MOTION_BONE_NL_OYA_C_L_WJ
|| motion_bone_index >= MOTION_BONE_N_HITO_R_EX
&& motion_bone_index <= MOTION_BONE_NL_OYA_C_R_WJ))
continue;
auto elem = a2m.bone_keys.find(motion_bone_index);
if (elem == a2m.bone_keys.end())
elem = a2m.bone_keys.insert({ motion_bone_index, {} }).first;
vec3 rotation;
mat4_get_rotation(&data->rot_mat[0], &rotation);
if (elem->second.x.size() == frame)
elem->second.x.push_back(rotation.x);
if (elem->second.y.size() == frame)
elem->second.y.push_back(rotation.y);
if (elem->second.z.size() == frame)
elem->second.z.push_back(rotation.z);
}
}
#endif
}
void x_pv_game::Window() {
if (state_old != 20)
return;
if (Input::IsKeyTapped(GLFW_KEY_K, GLFW_MOD_CONTROL))
state_old = 21;
else if (Input::IsKeyTapped(GLFW_KEY_K))
pause ^= true;
if (Input::IsKeyTapped(GLFW_KEY_L)) {
pause = true;
step_frame = true;
}
if (!pause) {
Basic();
return;
}
ImGuiIO& io = ImGui::GetIO();
ImGuiStyle& style = ImGui::GetStyle();
ImFont* font = ImGui::GetFont();
float_t w = 240.0f;
float_t h = 86.0f;
extern int32_t width;
ImGui::SetNextWindowPos({ (float_t)width - w, 0.0f }, ImGuiCond_Always);
ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always);
ImGuiWindowFlags window_flags = 0;
window_flags |= ImGuiWindowFlags_NoResize;
bool collapsed = !ImGui::Begin("X PV GAME", 0, window_flags);
if (collapsed) {
ImGui::End();
return;
}
w = ImGui::GetContentRegionAvailWidth();
if (ImGui::BeginTable("buttons", 2)) {
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, w * 0.5f);
ImGui::TableNextColumn();
w = ImGui::GetContentRegionAvailWidth();
if (ImGui::ButtonEnterKeyPressed(pause || (!pause && step_frame) ? "Play (K)" : "Pause (K)", { w, 0.0f }))
pause ^= true;
ImGui::TableNextColumn();
w = ImGui::GetContentRegionAvailWidth();
if (ImGui::ButtonEnterKeyPressed("Step Frame (L)", { w, 0.0f })) {
pause = true;
step_frame = true;
}
ImGui::TableNextColumn();
w = ImGui::GetContentRegionAvailWidth();
if (ImGui::ButtonEnterKeyPressed("Stop (Ctrl+K)", { w, 0.0f }))
state_old = 21;
ImGui::TableNextColumn();
w = ImGui::GetContentRegionAvailWidth();
char buf[0x200];
sprintf_s(buf, sizeof(buf), "%d/%d", frame, (int32_t)(time / 10000));
ImGui::PushStyleColor(ImGuiCol_Button, { 0.0f, 0.0f, 0.0f, 0.0f });
ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.0f, 0.0f, 0.0f, 0.0f });
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.0f, 0.0f, 0.0f, 0.0f });
ImGui::ButtonExEnterKeyPressed(buf, { w, 0.0f }, ImGuiButtonFlags_DontClosePopups
| ImGuiButtonFlags_NoNavFocus | ImGuiButtonFlags_NoHoveredOnFocus);
ImGui::PopStyleColor(3);
ImGui::EndTable();
}
extern bool input_locked;
input_locked |= ImGui::IsWindowFocused();
ImGui::End();
Basic();
}
void x_pv_game::Load(int32_t pv_id, int32_t stage_id, chara_index charas[6], int32_t modules[6]) {
data_struct* aft_data = &data_list[DATA_AFT];
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
this->pv_id = pv_id;
this->stage_id = stage_id;
memmove(this->charas, charas, sizeof(this->charas));
memmove(this->modules, modules, sizeof(this->modules));
data_struct* x_data = &data_list[DATA_X];
char buf[0x200];
sprintf_s(buf, sizeof(buf), "PV%03d", pv_id);
uint32_t mot_set = aft_mot_db->get_motion_set_id(buf);
motion_set_load_motion(mot_set, "", aft_mot_db);
motion_set_load_mothead(mot_set, "", aft_mot_db);
pv_param::light_data_load_files(pv_id, "");
pv_param::post_process_data_load_files(pv_id, "");
{
dof d;
sprintf_s(buf, sizeof(buf), "pv%03d", pv_id);
x_data->load_file(&d, "root+/post_process_table/", hash_utf8_murmurhash(buf), ".dft", dof::load_file);
pv_param::post_process_data_set_dof(d);
}
sprintf_s(buf, sizeof(buf), "EFFSTGPV%03d", 800 + stage_id);
light_category = buf;
int32_t chara_index = 0;
play = true;
success = true;
chara_id = 0;
target_anim_fps = get_target_anim_fps();
anim_frame_speed = get_anim_frame_speed();
pv_end = false;
for (x_pv_play_data& i : playdata)
i.reset();
scene_rot_y = 0.0f;
scene_rot_mat = mat4_identity;
branch_mode = 0;
task_effect_init = false;
pause = false;
step_frame = false;
for (int32_t& i : rob_chara_ids)
i = -1;
state = 10;
state_old = 1;
this->frame = 0;
frame_float = 0.0;
time = 0;
for (std::vector<pv_data_set_motion>& i : set_motion) {
i.clear();
i.shrink_to_fit();
}
Glitter::glt_particle_manager->draw_all = false;
//sound_work_play_se(1, "load01_2", 1.0f);
}
#if BAKE_PV826
static void fix_rotation(std::vector<float_t>& vec) {
if (vec.size() < 2)
return;
const float_t half_pi = (float_t)(M_PI / 2.0);
int32_t curr_rot = 0;
float_t rot_fix = 0.0f;
float_t rot_prev = vec.data()[0];
float_t* i_begin = vec.data() + 1;
float_t* i_end = vec.data() + vec.size();
for (float_t* i = i_begin; i != i_end; i++) {
float_t rot = *i;
if (rot < -half_pi && rot_prev > half_pi && fabsf(rot - rot_prev) > half_pi) {
curr_rot++;
rot_fix = (float_t)(M_PI * 2.0 * (double_t)curr_rot);
}
else if (rot > half_pi && rot_prev < -half_pi && fabsf(rot - rot_prev) > half_pi) {
curr_rot--;
rot_fix = (float_t)(M_PI * 2.0 * (double_t)curr_rot);
}
if (curr_rot)
*i = rot + rot_fix;
rot_prev = rot;
}
}
struct mot_data_bake {
int32_t performer;
x_pv_game_a3da_to_mot* data;
lock<uint32_t> state;
mot_data_bake() : performer(), data() {
}
};
const int32_t bake_pv826_threads_count = 2;
const motion_set_info* bake_pv826_set_info;
std::thread* bake_pv826_thread;
mot_data_bake* bake_pv826_mot_data;
int32_t bake_pv826_performer;
std::mutex* bake_pv826_alloc_mutex;
prj::shared_ptr<prj::stack_allocator>* bake_pv826_alloc;
::mot_set* bake_pv826_mot_set;
static mot_key_set_type mot_write_motion_fit_keys_into_curve(std::vector<float_t>& values_src,
prj::shared_ptr<prj::stack_allocator> alloc, uint16_t*& frames, float_t*& values, size_t& keys_count) {
std::vector<uint16_t> _frames;
std::vector<float_t> _values;
mot_key_set_type type = mot_set::fit_keys_into_curve(values_src, _frames, _values);
switch (type) {
case MOT_KEY_SET_NONE:
keys_count = 0;
frames = 0;
values = 0;
break;
case MOT_KEY_SET_STATIC:
keys_count = 1;
{
std::unique_lock<std::mutex> u_lock(*bake_pv826_alloc_mutex);
frames = 0;
values = (*bake_pv826_alloc)->allocate<float_t>(1);
}
memcpy(values, _values.data(), sizeof(float_t));
break;
case MOT_KEY_SET_HERMITE:
keys_count = _frames.size();
{
std::unique_lock<std::mutex> u_lock(*bake_pv826_alloc_mutex);
frames = (*bake_pv826_alloc)->allocate<uint16_t>(_frames.data(), keys_count);
values = (*bake_pv826_alloc)->allocate<float_t>(keys_count);
}
memcpy(frames, _frames.data(), sizeof(uint16_t) * keys_count);
memcpy(values, _values.data(), sizeof(float_t) * keys_count);
break;
case MOT_KEY_SET_HERMITE_TANGENT:
keys_count = _frames.size();
{
std::unique_lock<std::mutex> u_lock(*bake_pv826_alloc_mutex);
frames = (*bake_pv826_alloc)->allocate<uint16_t>(keys_count);
values = (*bake_pv826_alloc)->allocate<float_t>(keys_count * 2);
}
memcpy(frames, _frames.data(), sizeof(uint16_t) * keys_count);
memcpy(values, _values.data(), sizeof(float_t) * keys_count * 2);
break;
}
return type;
}
static void mot_write_motion(mot_data_bake* bake) {
data_struct* aft_data = &data_list[DATA_AFT];
bone_database* aft_bone_data = &aft_data->data_ft.bone_data;
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
char buf[0x200];
sprintf_s(buf, sizeof(buf), "PV826_OST_P%d_00", bake->performer);
uint32_t motion_id = aft_mot_db->get_motion_id(buf);
size_t motion_index = -1;
const motion_set_info* set_info = bake_pv826_set_info;
for (const motion_info& j : set_info->motion)
if (j.id == motion_id) {
motion_index = &j - set_info->motion.data();
break;
}
mot_data* mot_data = &bake_pv826_mot_set->mot_data[motion_index];
uint16_t key_set_count = mot_data->key_set_count - 1;
if (!key_set_count)
return;
const char* name = bone_database_skeleton_type_to_string(BONE_DATABASE_SKELETON_COMMON);
std::string* bone_names = aft_mot_db->bone_name.data();
const std::vector<bone_database_bone>* bones = aft_bone_data->get_skeleton_bones(name);
if (!bones)
return;
prj::shared_ptr<prj::stack_allocator>& alloc = *bake_pv826_alloc;
x_pv_game_a3da_to_mot& a2m = *bake->data;
const mot_bone_info* bone_info = mot_data->bone_info_array;
for (size_t key_set_offset = 0, i = 0; key_set_offset < key_set_count; i++) {
motion_bone_index bone_index = (motion_bone_index)aft_bone_data->get_skeleton_bone_index(
name, bone_names[bone_info[i].index].c_str());
if (bone_index == -1) {
i++;
bone_index = (motion_bone_index)aft_bone_data->get_skeleton_bone_index(
name, bone_names[bone_info[i].index].c_str());
if (bone_index == -1)
break;
}
const bone_database_bone* bone = &(*bones)[bone_index];
auto elem = a2m.bone_keys.find(bone_index);
if (elem != a2m.bone_keys.end()) {
x_pv_game_a3da_to_mot_keys& keys = elem->second;
if (bone->type == BONE_DATABASE_BONE_ROTATION) {
fix_rotation(keys.x);
fix_rotation(keys.y);
fix_rotation(keys.z);
}
mot_key_set_data& key_set_data_x = mot_data->key_set_array[key_set_offset];
key_set_data_x.frames = 0;
key_set_data_x.values = 0;
size_t keys_x_count = 0;
key_set_data_x.type = mot_write_motion_fit_keys_into_curve(keys.x, alloc,
key_set_data_x.frames, key_set_data_x.values, keys_x_count);
key_set_data_x.keys_count = (uint16_t)keys_x_count;
key_set_data_x.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_y = mot_data->key_set_array[key_set_offset + 1];
key_set_data_y.frames = 0;
key_set_data_y.values = 0;
size_t keys_y_count = 0;
key_set_data_y.type = mot_write_motion_fit_keys_into_curve(keys.y, alloc,
key_set_data_y.frames, key_set_data_y.values, keys_y_count);
key_set_data_y.keys_count = (uint16_t)keys_y_count;
key_set_data_y.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_z = mot_data->key_set_array[key_set_offset + 2];
key_set_data_z.frames = 0;
key_set_data_z.values = 0;
size_t keys_z_count = 0;
key_set_data_z.type = mot_write_motion_fit_keys_into_curve(keys.z, alloc,
key_set_data_z.frames, key_set_data_z.values, keys_z_count);
key_set_data_z.keys_count = (uint16_t)keys_z_count;
key_set_data_z.data_type = MOT_KEY_SET_DATA_F32;
}
elem = a2m.sec_bone_keys.find(bone_index);
if (elem != a2m.sec_bone_keys.end()) {
x_pv_game_a3da_to_mot_keys& keys = elem->second;
fix_rotation(keys.x);
fix_rotation(keys.y);
fix_rotation(keys.z);
mot_key_set_data& key_set_data_x = mot_data->key_set_array[key_set_offset + 3];
key_set_data_x.frames = 0;
key_set_data_x.values = 0;
size_t keys_x_count = 0;
key_set_data_x.type = mot_write_motion_fit_keys_into_curve(keys.x, alloc,
key_set_data_x.frames, key_set_data_x.values, keys_x_count);
key_set_data_x.keys_count = (uint16_t)keys_x_count;
key_set_data_x.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_y = mot_data->key_set_array[key_set_offset + 4];
key_set_data_y.frames = 0;
key_set_data_y.values = 0;
size_t keys_y_count = 0;
key_set_data_y.type = mot_write_motion_fit_keys_into_curve(keys.y, alloc,
key_set_data_y.frames, key_set_data_y.values, keys_x_count);
key_set_data_y.keys_count = (uint16_t)keys_y_count;
key_set_data_y.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_z = mot_data->key_set_array[key_set_offset + 5];
key_set_data_z.frames = 0;
key_set_data_z.values = 0;
size_t keys_z_count = 0;
key_set_data_z.type = mot_write_motion_fit_keys_into_curve(keys.z, alloc,
key_set_data_z.frames, key_set_data_z.values, keys_z_count);
key_set_data_z.keys_count = (uint16_t)keys_z_count;
key_set_data_z.data_type = MOT_KEY_SET_DATA_F32;
}
if (bone_index == MOTION_BONE_KL_AGO_WJ) {
mot_key_set_data& key_set_data_x = mot_data->key_set_array[key_set_offset];
key_set_data_x.frames = 0;
{
std::unique_lock<std::mutex> u_lock(*bake_pv826_alloc_mutex);
key_set_data_x.values = alloc->allocate<float_t>(1);
key_set_data_x.values[0] = 0.0491406508f;
}
key_set_data_x.type = MOT_KEY_SET_STATIC;
key_set_data_x.keys_count = 1;
key_set_data_x.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_y = mot_data->key_set_array[key_set_offset + 1];
key_set_data_y.frames = 0;
key_set_data_y.values = 0;
key_set_data_y.type = MOT_KEY_SET_NONE;
key_set_data_y.keys_count = 0;
key_set_data_y.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_z = mot_data->key_set_array[key_set_offset + 2];
key_set_data_z.frames = 0;
key_set_data_z.values = 0;
key_set_data_z.type = MOT_KEY_SET_NONE;
key_set_data_z.keys_count = 0;
key_set_data_z.data_type = MOT_KEY_SET_DATA_F32;
}
else if (bone_index == MOTION_BONE_N_KUBI_WJ_EX) {
mot_key_set_data& key_set_data_x = mot_data->key_set_array[key_set_offset];
key_set_data_x.frames = 0;
key_set_data_x.values = 0;
key_set_data_x.type = MOT_KEY_SET_NONE;
key_set_data_x.keys_count = 1;
key_set_data_x.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_y = mot_data->key_set_array[key_set_offset + 1];
key_set_data_y.frames = 0;
{
std::unique_lock<std::mutex> u_lock(*bake_pv826_alloc_mutex);
key_set_data_y.values = alloc->allocate<float_t>(1);
key_set_data_y.values[0] = 0.0331281610f;
}
key_set_data_y.type = MOT_KEY_SET_STATIC;
key_set_data_y.keys_count = 0;
key_set_data_y.data_type = MOT_KEY_SET_DATA_F32;
mot_key_set_data& key_set_data_z = mot_data->key_set_array[key_set_offset + 2];
key_set_data_z.frames = 0;
key_set_data_z.values = 0;
key_set_data_z.type = MOT_KEY_SET_NONE;
key_set_data_z.keys_count = 0;
key_set_data_z.data_type = MOT_KEY_SET_DATA_F32;
}
if (bone->type >= BONE_DATABASE_BONE_POSITION_ROTATION)
key_set_offset += 6;
else
key_set_offset += 3;
}
bake->state.set(0);
}
static bool mot_write_motion_set(void* data, const char* path, const char* file, uint32_t hash) {
x_pv_game* xpvgm = (x_pv_game*)data;
data_struct* aft_data = &data_list[DATA_AFT];
bone_database* aft_bone_data = &aft_data->data_ft.bone_data;
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
char buf[0x200];
sprintf_s(buf, sizeof(buf), "PV%03d", xpvgm->pv_id);
bake_pv826_set_info = aft_mot_db->get_motion_set_by_name(buf);
if (!bake_pv826_set_info)
return true;
bake_pv826_alloc = new prj::shared_ptr<prj::stack_allocator>(new prj::stack_allocator);
bake_pv826_alloc_mutex = 0;
bake_pv826_thread = 0;
bake_pv826_mot_data = 0;
bake_pv826_performer = 1;
bake_pv826_mot_set = (*bake_pv826_alloc)->allocate<::mot_set>();
{
std::string mot_file;
mot_file.append("mot_");
mot_file.append(bake_pv826_set_info->name);
mot_file.append(".bin");
farc f;
farc::load_file(&f, path, file, hash);
farc_file* ff = f.read_file(mot_file.c_str());
if (!ff) {
delete bake_pv826_alloc;
bake_pv826_alloc = 0;
bake_pv826_mot_set = 0;
return true;
}
bake_pv826_mot_set->unpack_file(*bake_pv826_alloc, ff->data, ff->size, false);
}
if (!bake_pv826_mot_set->ready) {
delete bake_pv826_alloc;
bake_pv826_alloc = 0;
bake_pv826_mot_set = 0;
return true;
}
bake_pv826_alloc_mutex = new std::mutex;
bake_pv826_thread = new std::thread[bake_pv826_threads_count];
bake_pv826_mot_data = new mot_data_bake[bake_pv826_threads_count];
return true;
}
static void mot_write_motion_set(x_pv_game* xpvgm) {
if (!bake_pv826_set_info)
return;
data_struct* aft_data = &data_list[DATA_AFT];
bone_database* aft_bone_data = &aft_data->data_ft.bone_data;
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
{
std::string mot_file;
mot_file.append("mot_");
mot_file.append(bake_pv826_set_info->name);
mot_file.append(".bin");
farc f;
f.add_file(mot_file.c_str());
farc_file* ff = &f.files.back();
bake_pv826_mot_set->pack_file(&ff->data, &ff->size);
std::string mot_farc;
mot_farc.append("pv826\\mot_");
mot_farc.append(bake_pv826_set_info->name);
f.write(mot_farc.c_str(), FARC_COMPRESS_FArC, false);
}
delete[] bake_pv826_thread;
delete[] bake_pv826_mot_data;
delete bake_pv826_alloc_mutex;
delete bake_pv826_alloc;
bake_pv826_thread = 0;
bake_pv826_mot_data = 0;
bake_pv826_alloc_mutex = 0;
bake_pv826_mot_set = 0;
bake_pv826_alloc = 0;
bake_pv826_set_info = 0;
}
#endif
bool x_pv_game::Unload() {
pv_osage_manager_array_set_not_reset_true();
if (pv_osage_manager_array_get_disp())
return false;
#if BAKE_PV826
if (pv_data[pv_index].pv_id == 826) {
data_struct* aft_data = &data_list[DATA_AFT];
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
char buf[0x200];
sprintf_s(buf, sizeof(buf), "PV%03d", pv_data[pv_index].pv_id);
const motion_set_info* set_info = aft_mot_db->get_motion_set_by_name(buf);
if (set_info) {
std::string farc_file = "mot_" + set_info->name + ".farc";
aft_data->load_file(this, "rom/rob/", farc_file.c_str(), mot_write_motion_set);
}
if (bake_pv826_set_info) {
waitable_timer timer;
while (true) {
int32_t free_thread_count = 0;
for (int32_t i = 0; i < bake_pv826_threads_count; i++)
if (!bake_pv826_mot_data[i].state.get())
free_thread_count++;
if (free_thread_count && bake_pv826_performer < 6)
for (auto& i : effchrpv_auth_3d_rob_mot_ids) {
if (!free_thread_count)
break;
else if (bake_pv826_performer != i.first)
continue;
std::thread* thread = 0;
int32_t thread_index = -1;
for (int32_t j = 0; j < bake_pv826_threads_count; j++)
if (!bake_pv826_mot_data[j].state.get()) {
thread = &bake_pv826_thread[j];
thread_index = j;
break;
}
if (!thread)
break;
mot_data_bake* bake = &bake_pv826_mot_data[thread_index];
bake->performer = bake_pv826_performer + 1;
bake->data = &i.second;
bake->state.set(1);
if (thread->joinable())
thread->join();
*thread = std::thread(mot_write_motion, bake);
wchar_t buf[0x80];
swprintf_s(buf, sizeof(buf) / sizeof(wchar_t),
L"X PV GAME BAKE PV826 P%d", bake->performer);
SetThreadDescription((HANDLE)thread->native_handle(), buf);
bake_pv826_performer++;
free_thread_count--;
}
if (free_thread_count == 2)
break;
timer.sleep_float(1.0);
}
for (int32_t i = 0; i < bake_pv826_threads_count; i++)
bake_pv826_thread[i].join();
mot_write_motion_set(this);
}
}
#endif
for (int32_t& i : rob_chara_ids)
skin_param_manager_reset(i);
data_struct* aft_data = &data_list[DATA_AFT];
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
pv_param::light_data_clear_data();
pv_param::post_process_data_clear_data();
char buf[0x200];
sprintf_s(buf, sizeof(buf), "PV%03d", pv_data[pv_index].pv_id);
uint32_t mot_set = aft_mot_db->get_motion_set_id(buf);
motion_set_unload_motion(mot_set);
motion_set_unload_mothead(mot_set);
state_old = 0;
frame = 0;
frame_float = 0.0;
time = 0;
for (int32_t& i : rob_chara_ids)
if (i != -1) {
rob_chara_array_free_chara_id(i);
i = -1;
}
light_auth_3d_id.unload(rctx_ptr);
light_auth_3d_id = {};
auth_3d_data_unload_category(light_category.c_str());
light_category.clear();
light_category.shrink_to_fit();
for (int32_t i = 0; i < pv_count; i++)
pv_data[i].reset();
stage_data.reset();
for (std::vector<pv_data_set_motion>& i : set_motion) {
i.clear();
i.shrink_to_fit();
}
pv_data[pv_index].bar_beat.reset();
pv_data[pv_index].stage_effects.clear();
pv_data[pv_index].stage_effects.shrink_to_fit();
pv_data[pv_index].stage_effect_index = 0;
play = true;
success = true;
chara_id = 0;
target_anim_fps = get_target_anim_fps();
anim_frame_speed = get_anim_frame_speed();
pv_end = false;
for (x_pv_play_data& i : playdata)
i.reset();
scene_rot_y = 0.0f;
scene_rot_mat = mat4_identity;
branch_mode = 0;
task_effect_init = false;
pv_id = 0;
stage_id = 0;
for (chara_index& i : charas)
i = CHARA_MAX;
for (int32_t& i : modules)
i = 0;
Glitter::glt_particle_manager->draw_all = true;
pv_param_task::post_process_task_del_task();
return true;
}
void x_pv_game::ctrl(float_t curr_time, float_t delta_time) {
x_pv_game_music_ptr->ctrl(delta_time);
#if BAKE_PV826
for (int32_t i = 0; i < pv_count; i++)
pv_data[i].ctrl(curr_time, delta_time,
pv_data[i].pv_id == 826 ? &effchrpv_auth_3d_mot_ids : 0);
#else
for (int32_t i = 0; i < pv_count; i++)
pv_data[i].ctrl(curr_time, delta_time);
#endif
switch (state) {
case 10:
if (stage_data.state == 20)
state = 20;
break;
case 30: {
bool v38 = true;
for (int32_t i = 0; i < pv_count; i++)
if (pv_data[i].state == 10 || pv_data[i].state == 20) {
v38 = false;
break;
}
if (!v38)
break;
stop_current_pv();
this->pv_data[pv_index].unload_if_state_is_0();
pv_index++;
state = 20;
} break;
case 40: {
bool v19 = true;
for (int32_t i = 0; i < pv_count; i++)
if (pv_data[i].state == 10 || pv_data[i].state == 20) {
v19 = false;
break;
}
if (!v19)
break;
stop_current_pv();
x_pv_game_data* pv_data = this->pv_data;
for (int32_t i = 0; i < pv_count; i++, pv_data++) {
if (!pv_data->state) {
rctx_ptr->camera->reset();
pv_data->field_1C &= ~0xD1;
pv_data->state = 0;
pv_data->stage_effect_index = 0;
pv_data->next_stage_effect_bar = 0;
pv_data->dsc_data.reset();
}
if (i > 0)
pv_data->unload_if_state_is_0();
}
if (pv_index) {
pv_index = 0;
if (!pv_data->state)
pv_data->state = 20;
else if (pv_data->state == 10)
pv_data->field_1C |= 0x08;
}
state = 20;
}
case 50: {
bool v16 = false;
for (int32_t i = 0; i < pv_count; i++)
if (pv_data[i].state)
v16 = true;
if (!v16 && stage_data.state != 20)
state = 0;
} break;
}
stage_data.ctrl(delta_time);
}
void x_pv_game::stop_current_pv() {
if (pv_count <= 0)
return;
pv_data[pv_index].stop();
field_7198C.Reset();
field_71994.Reset();
}
void x_pv_game::unload() {
for (int32_t i = 0; i < pv_count; i++)
pv_data[i].unload();
stage_data.unload();
state = 50;
}
XPVGameSelector::XPVGameSelector() : charas(), modules(), start(), exit() {
pv_id = 823;
stage_id = 23;
for (chara_index& i : charas)
i = CHARA_MIKU;
for (int32_t& i : modules)
i = 0;
pv_id = 816;
stage_id = 16;
charas[0] = CHARA_LEN;
modules[0] = 0;
pv_id = 811;
stage_id = 11;
charas[0] = CHARA_MIKU;
modules[0] = 0;
#if BAKE_PV826
pv_id = 826;
stage_id = 26;
charas[0] = CHARA_MIKU;
charas[1] = CHARA_RIN;
charas[2] = CHARA_LEN;
charas[3] = CHARA_LUKA;
charas[4] = CHARA_KAITO;
charas[5] = CHARA_MEIKO;
modules[0] = 168;
modules[1] = 46;
modules[2] = 39;
modules[3] = 41;
modules[4] = 40;
modules[5] = 31;
#endif
const prj::vector_pair_combine<int32_t, module>& modules = module_table_handler_data_get_modules();
for (const auto& i : modules)
modules_data[i.second.chara].push_back(&i.second);
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++)
for (const auto& j : modules_data[charas[i]])
if (this->modules[i] == j->cos) {
module_names[i].assign(j->name);
break;
}
}
XPVGameSelector::~XPVGameSelector() {
}
bool XPVGameSelector::Init() {
start = false;
exit = false;
return true;
}
bool XPVGameSelector::Ctrl() {
return false;
}
bool XPVGameSelector::Dest() {
return true;
}
void XPVGameSelector::Window() {
static const char* pv_names[] = {
u8"801. Strangers",
u8"802. Ai Dee",
u8"803. Streaming Heart",
u8"804. Babylon",
u8"805. The Lost One's Weeping",
u8"806. Slow Motion",
u8"807. Tale of the Deep-sea Lily",
u8"808. Love Trial",
u8"809. Love Song",
u8"810. The First Sound",
u8"811. LOL - lots of laugh -",
u8"812. Patchwork Staccato",
u8"813. Even a Kunoichi Needs Love",
u8"814. Calc.",
u8"815. A Single Red Leaf",
u8"816. Holy Lance Explosion Boy",
u8"817. Urotander, Underhanded Rangers",
u8"818. Humorous Dream of Mrs. Pumpkin",
u8"819. Solitary Envy",
u8"820. Raspberry * Monster",
u8"821. Brain Revolution Girl",
u8"822. Amazing Dolce",
u8"823. Name of the Sin",
u8"824. Satisfaction",
u8"825. Cute Medley - Idol Sounds",
u8"826. Beginning Medley - Primary Colors",
u8"827. Cool Medley - Cyber Rock Jam",
u8"828. Elegant Medley - Glossy Mixture",
u8"829. Quirky Medley - Giga-Remix",
u8"830. Ending Medley - Ultimate Exquisite Rampage",
u8"831. Sharing The World",
u8"832. Hand in Hand",
};
static const char* stage_names[] = {
u8"001. Nighttime Curb Stage",
u8"002. Digital Concert Stage",
u8"003. Secret Ruins Stage",
u8"004. Utopia Stage",
u8"005. Classroom Concert Stage",
u8"006. Capsule Room Stage",
u8"007. Deep Sea Stage",
u8"008. Verdict Stage",
u8"009. Sky Garden Stage",
u8"010. Musical Dawn Stage",
u8"011. Sweet Dreams Stage",
u8"012. Heart's Playroom Stage",
u8"013. Ninja Village Stage",
u8"014. Park of Promises Stage",
u8"015. Autumn Sakura Stage",
u8"016. Classy Lounge Stage",
u8"017. Secret Base Stage",
u8"018. Halloween Party Stage",
u8"019. Twilight Shrine Stage",
u8"020. Raspberry Stage",
u8"021. Cabaret Stage",
u8"022. Witch's House Stage",
u8"023. Lilies & Shadows Stage",
u8"024. Techno Club Stage",
u8"025. Cute Concert Hall",
u8"026. First Concert Hall",
u8"027. Cool Concert Hall",
u8"028. Elegant Concert Hall",
u8"029. Quirky Concert Hall",
u8"030. Ultimate Concert Hall",
u8"031. Highrise Stage",
u8"032. Mirai Concert Stage",
};
ImGuiIO& io = ImGui::GetIO();
ImGuiStyle& style = ImGui::GetStyle();
ImFont* font = ImGui::GetFont();
extern int32_t height;
extern int32_t width;
float_t w = 400.0f;
float_t h = (float_t)height;
h = min_def(h, 438.0f);
ImGui::SetNextWindowPos({ (float_t)width - w, 0.0f }, ImGuiCond_Always);
ImGui::SetNextWindowSize({ w, h }, ImGuiCond_Always);
ImGuiWindowFlags window_flags = 0;
window_flags |= ImGuiWindowFlags_NoResize;
window_focus = false;
bool open = true;
if (!ImGui::Begin("X PV Game Selector", &open, window_flags)) {
ImGui::End();
return;
}
else if (!open) {
start = false;
exit = true;
ImGui::End();
return;
}
pv_id -= 801;
pv_id = max_def(pv_id, 0);
ImGui::ColumnComboBox("PV", pv_names, 32, &pv_id, 0, false, &window_focus);
pv_id += 801;
stage_id--;
stage_id = max_def(stage_id, 0);
ImGui::ColumnComboBox("Stage", stage_names, 32, &stage_id, 0, false, &window_focus);
stage_id++;
char buf[0x200];
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) {
chara_index chara_old = charas[i];
sprintf_s(buf, sizeof(buf), "Chara %dP", i + 1);
ImGui::ColumnComboBox(buf, chara_full_names, CHARA_MAX,
(int32_t*)&charas[i], 0, false, &window_focus);
if (chara_old != charas[i]) {
modules[i] = 0;
module_names[i].clear();
for (const auto& j : modules_data[charas[i]])
if (modules[i] == j->cos) {
module_names[i].assign(j->name);
break;
}
}
}
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) {
sprintf_s(buf, sizeof(buf), "Module %dP", i + 1);
ImGui::StartPropertyColumn(buf);
extern ImFont* imgui_font_arial;
if (imgui_font_arial)
ImGui::PushFont(imgui_font_arial);
if (ImGui::BeginCombo("", module_names[i].c_str(), 0)) {
for (const auto& j : modules_data[charas[i]]) {
if (j->cos == 499)
continue;
ImGui::PushID(&j);
if (ImGui::Selectable(j->name.c_str(), modules[i] == j->cos)
|| ImGui::ItemKeyPressed(ImGuiKey_Enter)
|| (ImGui::IsItemFocused() && modules[i] != j->cos)) {
modules[i] = j->cos;
module_names[i].assign(j->name);
}
ImGui::PopID();
if (modules[i] == j->cos)
ImGui::SetItemDefaultFocus();
}
window_focus |= true;
ImGui::EndCombo();
}
if (imgui_font_arial)
ImGui::PopFont();
ImGui::EndPropertyColumn();
}
if (ImGui::Button("Start")) {
start = true;
exit = true;
}
ImGui::End();
}
bool x_pv_game_init() {
x_pv_game_ptr = new x_pv_game;
x_pv_game_music_ptr = new x_pv_game_music;
return true;
}
x_pv_game* x_pv_game_get() {
return x_pv_game_ptr;
}
bool x_pv_game_free() {
if (x_pv_game_ptr) {
switch (x_pv_game_ptr->state_old) {
case 0:
break;
case 21:
case 22:
return false;
default:
x_pv_game_ptr->state_old = 21;
return false;
}
if (app::TaskWork::HasTask(x_pv_game_ptr))
return false;
delete x_pv_game_ptr;
x_pv_game_ptr = 0;
x_pv_game_music_ptr->stop_reset_flags();
delete x_pv_game_music_ptr;
x_pv_game_music_ptr = 0;
}
return true;
}
bool x_pv_game_selector_init() {
if (!x_pv_game_selector_ptr)
x_pv_game_selector_ptr = new XPVGameSelector;
return true;
}
XPVGameSelector* x_pv_game_selector_get() {
return x_pv_game_selector_ptr;
}
bool x_pv_game_selector_free() {
if (x_pv_game_selector_ptr) {
delete x_pv_game_selector_ptr;
x_pv_game_selector_ptr = 0;
}
return true;
}
#if DOF_BAKE
dof_cam::dof_cam() {
frame = -999999;
enable = false;
}
dof_cam::~dof_cam() {
}
void dof_cam::reset() {
position_x.clear();
position_y.clear();
position_z.clear();
focus.clear();
focus_range.clear();
fuzzing_range.clear();
ratio.clear();
enable_frame.clear();
frame = -999999;
enable = false;
}
#endif
static vec4 bright_scale_get(int32_t index, float_t value) {
static const float_t bright_scale_table[] = {
1.0f, 1.176f, 0.85f, 1.0f,
1.0f, 1.176f, 1.176f, 1.176f
};
value = bright_scale_table[index] * value;
return { value, value, value, 1.0f };
}
static float_t dsc_time_to_frame(int64_t time) {
return roundf((float_t)time / 1000000000.0f * 60.0f);
}
static void x_pv_game_chara_item_alpha_callback(void* data, int32_t chara_id, int32_t type, float_t alpha) {
if (!data)
return;
x_pv_game* xpvgm = (x_pv_game*)data;
x_pv_game_data& pv_data = xpvgm->pv_data[xpvgm->pv_index];
if (chara_id < 0 || chara_id >= pv_data.play_param->chara.size())
return;
mdl::ObjFlags flags;
switch (type) {
case 0:
default:
flags = mdl::OBJ_ALPHA_ORDER_1;
break;
case 1:
flags = mdl::OBJ_ALPHA_ORDER_2;
break;
case 2:
flags = mdl::OBJ_ALPHA_ORDER_3;
break;
}
for (x_pv_game_song_effect& i : pv_data.effect.song_effect) {
if (i.chara_id != chara_id)
continue;
for (x_pv_game_song_effect_auth_3d& j : i.auth_3d)
j.id.set_alpha_obj_flags(alpha, flags);
for (x_pv_game_song_effect_glitter& j : i.glitter)
Glitter::glt_particle_manager->SetSceneEffectExtColor(j.scene_counter,
false, hash_murmurhash_empty, -1.0f, -1.0f, -1.0f, alpha);
}
}
static void x_pv_game_change_field(x_pv_game* xpvgm, int32_t field, int64_t dsc_time, int64_t curr_time) {
if (!xpvgm->task_effect_init && (dsc_time > -1 || curr_time > -1)) {
rand_state_array_4_set_seed_1393939();
task_effect_parent_reset();
xpvgm->task_effect_init = true;
}
light_param_data_storage_data_set_pv_cut(field);
}
static bool x_pv_game_dsc_process(x_pv_game* a1, int64_t curr_time) {
x_pv_game_data& pv_data = a1->pv_data[a1->pv_index];
dsc_x_func func = (dsc_x_func)pv_data.dsc_data.dsc_data_ptr->func;
uint32_t* data = pv_data.dsc_data.dsc.get_func_data(
pv_data.dsc_data.dsc_data_ptr);
if (a1->branch_mode) {
bool v19;
if (a1->success)
v19 = a1->branch_mode == 2;
else
v19 = a1->branch_mode == 1;
if (!v19) {
if (func < 0 || func >= DSC_X_MAX) {
a1->play = false;
return false;
}
else if ((data[0] < 0 || data[0] > 1)
&& func != DSC_X_PV_END && func != DSC_X_PV_BRANCH_MODE)
return true;
}
}
data_struct* aft_data = &data_list[DATA_AFT];
bone_database* aft_bone_data = &aft_data->data_ft.bone_data;
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
x_pv_play_data* playdata = &a1->playdata[a1->chara_id];
rob_chara* rob_chr = playdata->rob_chr;
switch (func) {
case DSC_X_END: {
a1->play = false;
a1->state_old = 21;
return false;
} break;
case DSC_X_TIME: {
pv_data.dsc_data.time = (int64_t)(int32_t)data[0] * 10000;
if (pv_data.dsc_data.time > curr_time)
return false;
} break;
case DSC_X_MIKU_MOVE: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
vec3 pos;
pos.x = (float_t)(int32_t)data[1] * 0.001f;
pos.y = (float_t)(int32_t)data[2] * 0.001f;
pos.z = (float_t)(int32_t)data[3] * 0.001f;
if (!rob_chr)
break;
mat4_mult_vec3_trans(&a1->scene_rot_mat, &pos, &pos);
rob_chr->set_data_miku_rot_position(pos);
rob_chr->set_osage_reset();
} break;
case DSC_X_MIKU_ROT: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t rot_y = (float_t)(int32_t)data[0] * 0.001f;
if (!rob_chr)
break;
int16_t rot_y_int16 = (int32_t)((rot_y + a1->scene_rot_y) * 32768.0f * (float_t)(1.0 / 180.0));
rob_chr->data.miku_rot.rot_y_int16 = rot_y_int16;
rob_chr->set_osage_reset();
} break;
case DSC_X_MIKU_DISP: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t disp = (int32_t)data[1];
playdata->disp = disp == 1;
if (!rob_chr)
break;
if (disp == 1) {
rob_chr->set_visibility(true);
if (rob_chr->check_for_ageageagain_module()) {
rob_chara_age_age_array_set_skip(rob_chr->chara_id, 1);
rob_chara_age_age_array_set_skip(rob_chr->chara_id, 2);
}
for (x_pv_play_data_set_motion& i : playdata->set_motion) {
bool set = rob_chr->set_motion_id(i.motion_id, i.frame, i.blend_duration,
i.blend, false, i.blend_type, aft_bone_data, aft_mot_db);
rob_chr->set_motion_reset_data(i.motion_id, i.dsc_frame);
rob_chr->bone_data->disable_eye_motion = i.disable_eye_motion;
rob_chr->data.motion.step_data.step = i.frame_speed;
if (set)
pv_expression_array_set_motion(pv_data.exp_file.hash_murmurhash, a1->chara_id, i.motion_id);
pv_game_dsc_data_set_motion_max_frame(a1, a1->chara_id, i.motion_index, i.dsc_time);
}
playdata->set_motion.clear();
}
else
rob_chr->set_visibility(false);
} break;
case DSC_X_MIKU_SHADOW: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
} break;
case DSC_X_TARGET: {
} break;
case DSC_X_SET_MOTION: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
if (!rob_chr)
break;
int32_t motion_index = (int32_t)data[1];
int32_t blend_duration_int = (int32_t)data[2];
int32_t frame_speed_int = (int32_t)data[3];
float_t blend_duration;
if (blend_duration_int != -1){
blend_duration = (float_t)blend_duration_int * 0.001f * 60.0f;
if (blend_duration < 0.0f)
blend_duration = 0.0f;
}
else
blend_duration = 0.0f;
float_t frame_speed;
if (frame_speed_int != -1) {
frame_speed = (float_t)frame_speed_int * 0.001f;
if (frame_speed < 0.0f)
frame_speed = 0.0f;
}
else
frame_speed = 1.0f;
float_t frame = 0.0f;
float_t dsc_frame = 0.0f;
bool blend = false;
x_pv_play_data_motion* motion = 0;
for (x_pv_play_data_motion& i : playdata->motion)
if (i.motion_index == motion_index) {
motion = &i;
break;
}
if (motion && motion->enable && (motion_index == motion->motion_index || !motion->motion_index)) {
if (pv_data.dsc_data.time != motion->time) {
frame = dsc_time_to_frame(curr_time - motion->time);
dsc_frame = roundf(dsc_time_to_frame(pv_data.dsc_data.time - motion->time));
if (frame < dsc_frame)
frame = dsc_frame;
blend = curr_time > motion->time;
}
else
frame = 0.0f;
}
uint32_t motion_id = -1;
int32_t chara_id = 0;
for (pvpp_chara& i : pv_data.play_param->chara) {
if (chara_id++ != a1->chara_id)
continue;
int32_t mot_idx = 1;
for (string_hash& j : i.motion) {
if (mot_idx++ != motion_index)
continue;
motion_id = aft_mot_db->get_motion_id(j.c_str());
break;
}
break;
}
if (motion_index) {
if (motion_id == -1)
motion_id = rob_chr->get_rob_cmn_mottbl_motion_id(0);
}
else if (motion_id == -1) {
motion_id = rob_chr->get_rob_cmn_mottbl_motion_id(5);
if (motion_id == -1)
motion_id = rob_chr->get_rob_cmn_mottbl_motion_id(0);
}
if (blend)
blend_duration = 0.0f;
else
blend_duration /= a1->anim_frame_speed;
x_pv_play_data_set_motion set_motion;
set_motion.frame_speed = frame_speed * a1->anim_frame_speed;
set_motion.motion_id = motion_id;
set_motion.frame = frame;
set_motion.blend_duration = blend_duration;
set_motion.blend = blend;
set_motion.blend_type = MOTION_BLEND_CROSS;
set_motion.disable_eye_motion = true;
set_motion.motion_index = motion_index;
set_motion.dsc_time = motion ? motion->time : pv_data.dsc_data.time;
set_motion.dsc_frame = dsc_frame;
if (playdata->disp) {
bool set = rob_chr->set_motion_id(motion_id, frame, blend_duration,
blend, false, MOTION_BLEND_CROSS, aft_bone_data, aft_mot_db);
rob_chr->set_motion_reset_data(motion_id, dsc_frame);
rob_chr->set_motion_skin_param(motion_id, dsc_frame);
rob_chr->bone_data->disable_eye_motion = true;
rob_chr->data.motion.step_data.step = set_motion.frame_speed;
if (set)
pv_expression_array_set_motion(pv_data.exp_file.hash_murmurhash, a1->chara_id, motion_id);
pv_game_dsc_data_set_motion_max_frame(a1, a1->chara_id, motion_index, motion ? motion->time : 0);
}
else {
playdata->set_motion.clear();
playdata->set_motion.push_back(set_motion);
rob_chr->data.motion.step_data.step = set_motion.frame_speed;
}
} break;
case DSC_X_SET_PLAYDATA: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t motion_index = (int32_t)data[1];
if (motion_index < 0) {
playdata->motion.clear();
break;
}
x_pv_play_data_motion* motion = 0;
for (x_pv_play_data_motion& i : playdata->motion)
if (i.motion_index == motion_index) {
motion = &i;
break;
}
if (motion) {
motion->enable = true;
motion->motion_index = motion_index;
motion->time = pv_data.dsc_data.time;
}
else {
x_pv_play_data_motion motion;
motion.enable = true;
motion.motion_index = motion_index;
motion.time = pv_data.dsc_data.time;
playdata->motion.push_back(motion);
}
} break;
case DSC_X_EFFECT: {
} break;
case DSC_X_FADEIN_FIELD: {
} break;
case DSC_X_EFFECT_OFF: {
} break;
case DSC_X_SET_CAMERA: {
} break;
case DSC_X_DATA_CAMERA: {
} break;
case DSC_X_CHANGE_FIELD: {
int32_t field = (int32_t)data[0];
if (field > 0)
x_pv_game_change_field(a1, field, pv_data.dsc_data.time, curr_time);
else
x_pv_game_reset_field(a1);
pv_data.effect.set_time(pv_data.dsc_data.time, false);
pv_data.chara_effect.set_time(pv_data.dsc_data.time);
} break;
case DSC_X_HIDE_FIELD: {
} break;
case DSC_X_MOVE_FIELD: {
} break;
case DSC_X_FADEOUT_FIELD: {
} break;
case DSC_X_EYE_ANIM: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t v115 = (int32_t)data[1];
int32_t blend_duration_int = (int32_t)data[2];
float_t blend_duration;
if (blend_duration_int != -1)
blend_duration = (float_t)blend_duration_int * 0.001f * 60.0f;
else
blend_duration = 6.0f;
if (!rob_chr)
break;
blend_duration /= a1->anim_frame_speed;
rob_chr->set_eyelid_mottbl_motion_from_face(v115, blend_duration, -1.0f, 0.0f, aft_mot_db);
} break;
case DSC_X_MOUTH_ANIM: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t mouth_anim_id = (int32_t)data[2];
int32_t blend_duration_int = (int32_t)data[3];
int32_t value_int = (int32_t)data[4];
float_t blend_duration;
if (blend_duration_int != -1) {
blend_duration = (float_t)blend_duration_int * 0.001f * 60.0f;
if (blend_duration < 0.0f)
blend_duration = 0.0f;
}
else
blend_duration = 6.0f;
float_t value;
if (value_int != -1) {
value = (float_t)value_int * 0.001f;
if (value < 0.0f || value > 1.0f)
value = 1.0f;
}
else
value = 1.0f;
if (!rob_chr)
break;
switch (mouth_anim_id) {
case 4: mouth_anim_id = 34; break;
case 5: mouth_anim_id = 35; break;
case 6: mouth_anim_id = 36; break;
case 7: mouth_anim_id = 37; break;
case 8: mouth_anim_id = 38; break;
case 9: mouth_anim_id = 39; break;
case 10: mouth_anim_id = 4; break;
case 11: mouth_anim_id = 5; break;
case 12: mouth_anim_id = 6; break;
case 13: mouth_anim_id = 7; break;
case 14: mouth_anim_id = 8; break;
case 15: mouth_anim_id = 9; break;
case 16: mouth_anim_id = 10; break;
case 17: mouth_anim_id = 11; break;
case 18: mouth_anim_id = 12; break;
case 19: mouth_anim_id = 13; break;
case 20: mouth_anim_id = 14; break;
case 21: mouth_anim_id = 15; break;
case 22: mouth_anim_id = 16; break;
case 23: mouth_anim_id = 17; break;
case 24: mouth_anim_id = 18; break;
case 25: mouth_anim_id = 19; break;
case 26: mouth_anim_id = 20; break;
case 27: mouth_anim_id = 21; break;
case 28: mouth_anim_id = 22; break;
case 29: mouth_anim_id = 40; break;
case 30: mouth_anim_id = 41; break;
case 31: mouth_anim_id = 42; break;
}
int32_t mottbl_index = mouth_anim_id_to_mottbl_index(mouth_anim_id);
blend_duration /= a1->anim_frame_speed;
rob_chr->set_mouth_mottbl_motion(0, mottbl_index, value,
0, blend_duration, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
} break;
case DSC_X_HAND_ANIM: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t hand_index = (int32_t)data[1];
int32_t hand_anim_id = (int32_t)data[2];
int32_t blend_duration_int = (int32_t)data[3];
int32_t value_int = (int32_t)data[4];
float_t blend_duration;
if (blend_duration_int != -1) {
blend_duration = (float_t)blend_duration_int * 0.001f * 60.0f;
if (blend_duration < 0.0f)
blend_duration = 0.0f;
}
else
blend_duration = 0.0f;
float_t value;
if (value_int != -1) {
value = (float_t)value_int * 0.001f;
if (value < 0.0f || value > 1.0f)
value = 1.0f;
}
else
value = 1.0f;
if (!rob_chr)
break;
int32_t mottbl_index = hand_anim_id_to_mottbl_index(hand_anim_id);
blend_duration /= a1->anim_frame_speed;
switch (hand_index) {
case 0:
rob_chr->set_hand_l_mottbl_motion(0, mottbl_index, value,
0, blend_duration, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
break;
case 1:
rob_chr->set_hand_r_mottbl_motion(0, mottbl_index, value,
0, blend_duration, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
break;
}
} break;
case DSC_X_LOOK_ANIM: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t look_anim_id = (int32_t)data[1];
int32_t blend_duration_int = (int32_t)data[2];
int32_t value_int = (int32_t)data[3];
float_t blend_duration;
if (blend_duration_int != -1) {
blend_duration = (float_t)blend_duration_int * 0.001f * 60.0f;
if (blend_duration < 0.0f)
blend_duration = 0.0f;
}
else
blend_duration = 6.0f;
float_t value;
if (value_int != -1) {
value = (float_t)value_int * 0.001f;
if (value < 0.0f || value > 1.0f)
value = 1.0f;
}
else
value = 1.0f;
if (!rob_chr)
break;
int32_t mottbl_index = look_anim_id_to_mottbl_index(look_anim_id);
blend_duration /= a1->anim_frame_speed;
rob_chr->set_eyes_mottbl_motion(0, mottbl_index, value,
mottbl_index == 224 ? 1 : 0, blend_duration, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
return 1;
} break;
case DSC_X_EXPRESSION: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t expression_id = (int32_t)data[1];
int32_t blend_duration_int = (int32_t)data[2];
int32_t value_int = (int32_t)data[3];
float_t blend_duration;
if (blend_duration_int != -1) {
blend_duration = (float_t)blend_duration_int * 0.001f * 60.0f;
if (blend_duration < 0.0f)
blend_duration = 0.0f;
}
else
blend_duration = 0.0f;
float_t value;
if (value_int != -1) {
value = (float_t)value_int * 0.001f;
if (value < 0.0f || value > 1.0f)
value = 1.0f;
}
else
value = 1.0f;
if (!rob_chr)
break;
int32_t mottbl_index = expression_id_to_mottbl_index(expression_id);
blend_duration /= a1->anim_frame_speed;
rob_chr->set_face_mottbl_motion(0, mottbl_index, value, mottbl_index >= 214
&& mottbl_index <= 223 ? 1 : 0, blend_duration, 0.0f, 1.0f, -1, 0.0f, true, aft_mot_db);
} break;
case DSC_X_LOOK_CAMERA: {
} break;
case DSC_X_LYRIC: {
} break;
case DSC_X_MUSIC_PLAY: {
char buf[0x200];
sprintf_s(buf, sizeof(buf), "rom/sound/song/pv_%03d.ogg",
a1->pv_data[a1->pv_index].pv_id == 832 ? 800 : a1->pv_data[a1->pv_index].pv_id);
x_pv_game_music_ptr->play(4, buf, false, 0.0f, 0.0f, 0.0f, 3.0f, false);
x_pv_game_music_ptr->set_channel_pair_volume_map(1, 100);
x_pv_game_music_ptr->set_channel_pair_volume_map(0, 100);
} break;
case DSC_X_MODE_SELECT: {
} break;
case DSC_X_EDIT_MOTION: {
} break;
case DSC_X_BAR_TIME_SET: {
} break;
case DSC_X_SHADOWHEIGHT: {
a1->chara_id = data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
} break;
case DSC_X_EDIT_FACE: {
int32_t expression_id = (int32_t)data[0];
if (!rob_chr)
break;
int32_t mottbl_index = expression_id_to_mottbl_index(expression_id);
rob_chr->set_face_mottbl_motion(0, mottbl_index, 1.0f, mottbl_index >= 214
&& mottbl_index <= 223 ? 1 : 0, 0.0f, 0.0f, 1.0f, -1, 0.0f, true, aft_mot_db);
} break;
case DSC_X_DUMMY: {
} break;
case DSC_X_PV_END: {
a1->pv_end = true;
break;
} break;
case DSC_X_SHADOWPOS: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
} break;
case DSC_X_EDIT_LYRIC: {
} break;
case DSC_X_EDIT_TARGET: {
} break;
case DSC_X_EDIT_MOUTH: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t mouth_anim_id = (int32_t)data[1];
if (!rob_chr)
break;
int32_t mottbl_index = mouth_anim_id_to_mottbl_index(mouth_anim_id);
rob_chr->set_mouth_mottbl_motion(0, mottbl_index, 1.0f,
0, 0.1f, 0.0f, 1.0f, -1, 0.0f, aft_mot_db);
} break;
case DSC_X_SET_CHARA: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
} break;
case DSC_X_EDIT_MOVE: {
} break;
case DSC_X_EDIT_SHADOW: {
} break;
case DSC_X_EDIT_EYELID: {
} break;
case DSC_X_EDIT_EYE: {
} break;
case DSC_X_EDIT_ITEM: {
} break;
case DSC_X_EDIT_EFFECT: {
} break;
case DSC_X_EDIT_DISP: {
} break;
case DSC_X_EDIT_HAND_ANIM: {
} break;
case DSC_X_AIM: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
} break;
case DSC_X_HAND_ITEM: {
} break;
case DSC_X_EDIT_BLUSH: {
} break;
case DSC_X_NEAR_CLIP: {
} break;
case DSC_X_CLOTH_WET: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t value = (float_t)(int32_t)data[1] * 0.001f;
if (!rob_chr)
break;
rob_chr->item_equip->wet = clamp_def(value, 0.0f, 1.0f);
} break;
case DSC_X_LIGHT_ROT: {
} break;
case DSC_X_SCENE_FADE: {
} break;
case DSC_X_TONE_TRANS: {
vec3 start;
vec3 end;
start.x = (float_t)(int32_t)data[0] * 0.001f;
start.y = (float_t)(int32_t)data[1] * 0.001f;
start.z = (float_t)(int32_t)data[2] * 0.001f;
end.x = (float_t)(int32_t)data[3] * 0.001f;
end.y = (float_t)(int32_t)data[4] * 0.001f;
end.z = (float_t)(int32_t)data[5] * 0.001f;
rctx_ptr->post_process.tone_map->set_tone_trans(start, end);
} break;
case DSC_X_SATURATE: {
float_t value = (float_t)(int32_t)data[0] * 0.001f;
rctx_ptr->post_process.tone_map->set_saturate_coeff(value);
} break;
case DSC_X_FADE_MODE: {
int32_t value = data[0];
rctx_ptr->post_process.tone_map->set_scene_fade_blend_func(value);
} break;
case DSC_X_AUTO_BLINK: {
} break;
case DSC_X_PARTS_DISP: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
item_id id = (item_id)data[1];
int32_t disp = (int32_t)data[2];
if (!rob_chr)
break;
rob_chr->set_parts_disp(id, disp == 1);
} break;
case DSC_X_TARGET_FLYING_TIME: {
} break;
case DSC_X_CHARA_SIZE: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t chara_size = (int32_t)data[1];
if (!rob_chr)
return 1;
int32_t chara_size_index;
if (chara_size == 0)
chara_size_index = chara_init_data_get_chara_size_index(rob_chr->chara_index);
else if (chara_size == 1) {
::chara_index chara_index = CHARA_MIKU;
if (a1->chara_id < pv_data.play_param->chara.size())
chara_index = (::chara_index)a1->pv_data[a1->pv_index]
.play_param->chara[a1->chara_id].chara_effect.base_chara;
else if (pv_data.pv_id == 826 && false)
chara_index = rob_chara_array_get(a1->chara_id)->chara_index;
chara_size_index = chara_init_data_get_chara_size_index(chara_index);
}
else if (chara_size == 2)
chara_size_index = 1;
else if (chara_size == 3)
chara_size_index = rob_chr->pv_data.chara_size_index;
else {
rob_chr->set_chara_size((float_t)chara_size / 1000.0f);
break;
}
if (chara_size_index < 0 || chara_size_index > 4)
break;
rob_chr->set_chara_size(chara_size_table_get_value(chara_size_index));
rob_chr->set_chara_pos_adjust_y(chara_pos_adjust_y_table_get_value(chara_size_index));
} break;
case DSC_X_CHARA_HEIGHT_ADJUST: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
int32_t height_adjust = (int32_t)data[1];
if (rob_chr)
rob_chr->set_chara_height_adjust(height_adjust != 0);
} break;
case DSC_X_ITEM_ANIM: {
printf_debug("");
} break;
case DSC_X_CHARA_POS_ADJUST: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
vec3 pos;
pos.x = (float_t)(int32_t)data[2] * 0.001f;
pos.y = (float_t)(int32_t)data[3] * 0.001f;
pos.z = (float_t)(int32_t)data[4] * 0.001f;
if (!rob_chr)
break;
mat4_mult_vec3_trans(&a1->scene_rot_mat, &pos, &pos);
rob_chr->set_chara_pos_adjust(pos);
if (rob_chr->check_for_ageageagain_module()) {
rob_chara_age_age_array_set_skip(rob_chr->chara_id, 1);
rob_chara_age_age_array_set_skip(rob_chr->chara_id, 2);
}
} break;
case DSC_X_SCENE_ROT: {
float_t scene_rot_y = (float_t)(int32_t)data[0] * 0.001f;
a1->scene_rot_y = scene_rot_y;
mat4_rotate_y(scene_rot_y * DEG_TO_RAD_FLOAT, &a1->scene_rot_mat);
} break;
case DSC_X_EDIT_MOT_SMOOTH_LEN: {
} break;
case DSC_X_PV_BRANCH_MODE: {
int32_t branch_mode = (int32_t)data[0];
if (branch_mode >= 0 && branch_mode <= 2)
a1->branch_mode = branch_mode;
} break;
case DSC_X_DATA_CAMERA_START: {
} break;
case DSC_X_MOVIE_PLAY: {
} break;
case DSC_X_MOVIE_DISP: {
} break;
case DSC_X_WIND: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t wind_strength_kami = (float_t)(int32_t)data[1] * 0.001f;
float_t wind_strength_outer = (float_t)(int32_t)data[2] * 0.001f;
if (!rob_chr)
break;
rob_chr->set_wind_strength(wind_strength_outer);
} break;
case DSC_X_OSAGE_STEP: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t osage_step_kami = (float_t)(int32_t)data[1] * 0.001f;
float_t osage_step_outer = (float_t)(int32_t)data[2] * 0.001f;
if (!rob_chr)
break;
rob_chr->set_osage_step(osage_step_outer);
} break;
case DSC_X_OSAGE_MV_CCL: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t osage_mv_ccl_kami = (float_t)(int32_t)data[1] * 0.001f;
float_t osage_mv_ccl_outer = (float_t)(int32_t)data[2] * 0.001f;
if (!rob_chr)
break;
rob_chr->set_osage_move_cancel(1, osage_mv_ccl_kami);
rob_chr->set_osage_move_cancel(2, osage_mv_ccl_outer);
} break;
case DSC_X_CHARA_COLOR: {
} break;
case DSC_X_SE_EFFECT: {
} break;
case DSC_X_CHARA_SHADOW_QUALITY: {
} break;
case DSC_X_STAGE_SHADOW_QUALITY: {
} break;
case DSC_X_COMMON_LIGHT: {
} break;
case DSC_X_TONE_MAP: {
} break;
case DSC_X_IBL_COLOR: {
} break;
case DSC_X_REFLECTION: {
} break;
case DSC_X_CHROMATIC_ABERRATION: {
} break;
case DSC_X_STAGE_SHADOW: {
} break;
case DSC_X_REFLECTION_QUALITY: {
} break;
case DSC_X_PV_END_FADEOUT: {
} break;
case DSC_X_CREDIT_TITLE: {
} break;
case DSC_X_BAR_POINT: {
} break;
case DSC_X_BEAT_POINT: {
} break;
case DSC_X_RESERVE1: {
} break;
case DSC_X_PV_AUTH_LIGHT_PRIORITY: {
} break;
case DSC_X_PV_CHARA_LIGHT: {
} break;
case DSC_X_PV_STAGE_LIGHT: {
} break;
case DSC_X_TARGET_EFFECT: {
} break;
case DSC_X_FOG: {
} break;
case DSC_X_BLOOM: {
int32_t id = (int32_t)data[0];
float_t duration = (float_t)(int32_t)data[1];
pv_param_task::post_process_task_set_bloom_data(
pv_param::post_process_data_get_bloom_data(id), duration);
} break;
case DSC_X_COLOR_CORRECTION: {
int32_t enable = (int32_t)data[0];
int32_t id = (int32_t)data[1];
float_t duration = (float_t)(int32_t)data[2];
if (enable == 1)
pv_param_task::post_process_task_set_color_correction_data(
pv_param::post_process_data_get_color_correction_data(id), duration);
} break;
case DSC_X_DOF: {
int32_t enable = (int32_t)data[0];
int32_t id = (int32_t)data[1];
float_t duration = (float_t)(int32_t)data[2];
rctx_ptr->post_process.dof->data.pv.enable = enable == 1;
if (enable == 1)
pv_param_task::post_process_task_set_dof_data(
pv_param::post_process_data_get_dof_data(id), duration);
} break;
case DSC_X_CHARA_ALPHA: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t alpha = (float_t)(int32_t)data[1] * 0.001f;
float_t duration = (float_t)(int32_t)data[2];
int32_t type = (int32_t)data[3];
if (a1->chara_id >= 0 && a1->chara_id < ROB_CHARA_COUNT)
pv_param_task::post_process_task_set_chara_alpha(
a1->chara_id, type, alpha, duration * 2.0f);
} break;
case DSC_X_AUTO_CAPTURE_BEGIN: {
} break;
case DSC_X_MANUAL_CAPTURE: {
} break;
case DSC_X_TOON_EDGE: {
} break;
case DSC_X_SHIMMER: {
} break;
case DSC_X_ITEM_ALPHA: {
a1->chara_id = (int32_t)data[0];
playdata = &a1->playdata[a1->chara_id];
rob_chr = playdata->rob_chr;
float_t alpha = (float_t)(int32_t)data[1] * 0.001f;
float_t duration = (float_t)(int32_t)data[2];
int32_t type = (int32_t)data[3];
if (a1->chara_id >= 0 && a1->chara_id < ROB_CHARA_COUNT) {
pv_param_task::post_process_task_set_chara_item_alpha(
a1->chara_id, type, alpha, duration * 2.0f,
x_pv_game_chara_item_alpha_callback, a1);
}
} break;
case DSC_X_MOVIE_CUT: {
} break;
case DSC_X_EDIT_CAMERA_BOX: {
} break;
case DSC_X_EDIT_STAGE_PARAM: {
} break;
case DSC_X_EDIT_CHANGE_FIELD: {
} break;
case DSC_X_MIKUDAYO_ADJUST: {
} break;
case DSC_X_LYRIC_2: {
} break;
case DSC_X_LYRIC_READ: {
} break;
case DSC_X_LYRIC_READ_2: {
} break;
case DSC_X_ANNOTATION: {
} break;
case DSC_X_STAGE_EFFECT: {
int32_t stage_effect = (int32_t)data[0];
if (stage_effect >= 8 && stage_effect <= 9)
a1->stage_data.set_stage_effect(stage_effect);
} break;
case DSC_X_SONG_EFFECT: {
bool enable = data[0] ? true : false;
int32_t index = (int32_t)data[1];
int32_t unk2 = (int32_t)data[2];
if (unk2 && !(pv_data.field_1C & 0x10))
break;
if (enable) {
pv_data.effect.set_song_effect(index, pv_data.dsc_data.time);
//if (a2->field_18)
// pv_data.effect.set_song_effect_time(index/*, a2->field_20*/, true);
//else
pv_data.effect.set_song_effect_time(index, a1->time, false);
}
else
pv_data.effect.stop_song_effect(index, true);
} break;
case DSC_X_SONG_EFFECT_ATTACH: {
int32_t index = (int32_t)data[0];
int32_t chara_id = (int32_t)data[1];
int32_t chara_item = (int32_t)data[2];
pv_data.effect.set_chara_id(index, chara_id, !!chara_item);
} break;
case DSC_X_LIGHT_AUTH: {
} break;
case DSC_X_FADE: {
} break;
case DSC_X_SET_STAGE_EFFECT_ENV: {
int32_t env_index = (int32_t)data[0];
int32_t trans = (int32_t)data[1];
a1->stage_data.set_env(env_index, (float_t)trans * (float_t)(1.0f / 60.0f), 0.0f);
printf_debug("Time: %8d; Frame %5d; Env: %2d; Trans: %3d\n",
(int32_t)(curr_time / 10000), a1->frame, env_index, trans);
} break;
case DSC_X_RESERVE2: {
} break;
case DSC_X_COMMON_EFFECT_AET_FRONT: {
} break;
case DSC_X_COMMON_EFFECT_AET_FRONT_LOW: {
} break;
case DSC_X_COMMON_EFFECT_PARTICLE: {
} break;
case DSC_X_SONG_EFFECT_ALPHA_SORT: {
} break;
case DSC_X_LOOK_CAMERA_FACE_LIMIT: {
} break;
case DSC_X_ITEM_LIGHT: {
} break;
case DSC_X_CHARA_EFFECT: {
data_struct* aft_data = &data_list[DATA_AFT];
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
int32_t chara_id = (int32_t)data[0];
bool enable = data[1] ? true : false;
int32_t index = (int32_t)data[2];
if (enable) {
pv_data.chara_effect.set_chara_effect(chara_id, index, pv_data.dsc_data.time);
//if (a2->field_18)
// pv_data.chara_effect.set_chara_effect_time(chara_id, index/*, a2->field_20*/);
//else
pv_data.chara_effect.set_chara_effect_time(chara_id, index, a1->time);
}
else
pv_data.chara_effect.stop_chara_effect(chara_id, index);
} break;
case DSC_X_MARKER: {
} break;
case DSC_X_CHARA_EFFECT_CHARA_LIGHT: {
} break;
case DSC_X_ENABLE_COMMON_LIGHT_TO_CHARA: {
} break;
case DSC_X_ENABLE_FXAA: {
} break;
case DSC_X_ENABLE_TEMPORAL_AA: {
} break;
case DSC_X_ENABLE_REFLECTION: {
} break;
case DSC_X_BANK_BRANCH: {
} break;
case DSC_X_BANK_END: {
} break;
case DSC_X_NULL1: {
} break;
case DSC_X_NULL2: {
} break;
case DSC_X_NULL3: {
} break;
case DSC_X_NULL4: {
} break;
case DSC_X_NULL5: {
} break;
case DSC_X_NULL6: {
} break;
case DSC_X_NULL7: {
} break;
case DSC_X_NULL8: {
} break;
case DSC_X_VR_LIVE_MOVIE: {
} break;
case DSC_X_VR_CHEER: {
} break;
case DSC_X_VR_CHARA_PSMOVE: {
} break;
case DSC_X_VR_MOVE_PATH: {
} break;
case DSC_X_VR_SET_BASE: {
} break;
case DSC_X_VR_TECH_DEMO_EFFECT: {
} break;
case DSC_X_VR_TRANSFORM: {
} break;
case DSC_X_GAZE: {
} break;
case DSC_X_TECH_DEMO_GESUTRE: {
} break;
case DSC_X_VR_CHEMICAL_LIGHT_COLOR: {
} break;
case DSC_X_VR_LIVE_MOB: {
} break;
case DSC_X_VR_LIVE_HAIR_OSAGE: {
} break;
case DSC_X_VR_LIVE_LOOK_CAMERA: {
} break;
case DSC_X_VR_LIVE_CHEER: {
} break;
case DSC_X_VR_LIVE_GESTURE: {
} break;
case DSC_X_VR_LIVE_CLONE: {
} break;
case DSC_X_VR_LOOP_EFFECT: {
} break;
case DSC_X_VR_LIVE_ONESHOT_EFFECT: {
} break;
case DSC_X_VR_LIVE_PRESENT: {
} break;
case DSC_X_VR_LIVE_TRANSFORM: {
} break;
case DSC_X_VR_LIVE_FLY: {
} break;
case DSC_X_VR_LIVE_CHARA_VOICE: {
} break;
}
return true;
}
#if BAKE_PV826
static void set_bone_key_set_data(bone_data* bone_data,
std::map<motion_bone_index, x_pv_game_a3da_to_mot_keys>& bone_keys,
std::map<motion_bone_index, x_pv_game_a3da_to_mot_keys>& second_bone_keys, bool add_keys,
motion_bone_index motion_bone_index, mot_key_set* key_set, vec3* data, int32_t count = 1) {
if (add_keys) {
auto elem = bone_keys.find(motion_bone_index);
if (elem == bone_keys.end())
elem = bone_keys.insert({ motion_bone_index, {} }).first;
x_pv_game_a3da_to_mot_keys& keys = elem->second;
keys.x.push_back(data[0].x);
keys.y.push_back(data[0].y);
keys.z.push_back(data[0].z);
if (count == 2) {
auto elem = second_bone_keys.find(motion_bone_index);
if (elem == second_bone_keys.end())
elem = second_bone_keys.insert({ motion_bone_index, {} }).first;
x_pv_game_a3da_to_mot_keys& keys = elem->second;
keys.x.push_back(data[1].x);
keys.y.push_back(data[1].y);
keys.z.push_back(data[1].z);
}
}
bone_data += motion_bone_index;
key_set += bone_data->key_set_offset;
while (count > 0) {
if (key_set[0].type == MOT_KEY_SET_STATIC && key_set[0].values)
*(float_t*)&key_set[0].values[0] = data->x;
if (key_set[1].type == MOT_KEY_SET_STATIC && key_set[1].values)
*(float_t*)&key_set[1].values[0] = data->y;
if (key_set[2].type == MOT_KEY_SET_STATIC && key_set[2].values)
*(float_t*)&key_set[2].values[0] = data->z;
key_set += 3;
data++;
count--;
}
}
static void x_pv_game_map_auth_3d_to_mot(x_pv_game* xpvgm, bool add_keys) {
for (auto& i : xpvgm->effchrpv_auth_3d_rob_mot_ids) {
rob_chara* rob_chr = rob_chara_array_get(xpvgm->rob_chara_ids[i.first]);
x_pv_game_a3da_to_mot& a2m = i.second;
auth_3d* auth = a2m.id.get_auth_3d();
auth_3d_object_hrc* oh = &auth->object_hrc[0];
float_t auth_frame = auth->frame;
bool auth_frame_changed = auth->frame_changed;
bool auth_paused = auth->paused;
auth->frame = (float_t)xpvgm->frame_float;
auth->frame_changed = false;
auth->paused = true;
auth->ctrl(rctx_ptr);
rob_chr->set_visibility(oh->node[0].model_transform.visible);
motion_blend_mot* mot = rob_chr->bone_data->motion_loaded.front();
::bone_data* bone_data = mot->bone_data.bones.data();
mot_key_set* key_set = mot->mot_key_data.mot.key_sets;
vec3 data[2];
data[0] = oh->node[a2m.gblctr].model_transform.translation_value;
data[0].y = oh->node[a2m.n_hara].model_transform.translation_value.y;
data[1] = 0.0f;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_N_HARA_CP, key_set, data, 2);
data[0] = oh->node[a2m.n_hara_y].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KG_HARA_Y, key_set, data);
data[0] = oh->node[a2m.j_hara_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_HARA_XZ, key_set, data);
data[0] = oh->node[a2m.n_kosi].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_N_HARA, key_set, data);
data[0] = { 0.0f, 0.945f, 0.0f };
mat4_mult_vec3(&oh->node[a2m.j_mune_wj].model_transform.mat, &data[0], &data[1]);
mat4_get_translation(&oh->node[a2m.j_mune_wj].model_transform.mat, &data[0]);
data[0] += data[1];
data[1] = 0.0f;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_CL_MUNE, key_set, data, 2);
data[0] = oh->node[a2m.j_mune_b_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_MUNE_B_WJ, key_set, data);
data[0] = oh->node[a2m.j_kubi_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_KUBI, key_set, data);
data[0] = { (float_t)(M_PI / 2.0), 0.0f, -(float_t)M_PI };
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_N_KAO, key_set, data);
data[0] = { 0.0f, 0.40f, 0.0f };
mat4_mult_vec3(&oh->node[a2m.j_kao_wj].model_transform.mat, &data[0], &data[1]);
mat4_get_translation(&oh->node[a2m.j_kao_wj].model_transform.mat, &data[0]);
data[0] += data[1];
data[1] = oh->node[a2m.j_kao_wj].model_transform.rotation_value;
data[1].x = -data[1].x;
data[1].z = -data[1].z;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_CL_KAO, key_set, data, 2);
data[0] = oh->node[a2m.j_eye_r_wj].model_transform.rotation_value;
data[0].x += (float_t)(M_PI / 2.0);
data[0].y = -data[0].z;
data[0].z = 0.0f;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_EYE_R, key_set, data);
data[0] = oh->node[a2m.j_eye_l_wj].model_transform.rotation_value;
data[0].x += (float_t)(M_PI / 2.0);
data[0].y = -data[0].z;
data[0].z = 0.0f;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_EYE_L, key_set, data);
data[0] = oh->node[a2m.n_waki_l].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_N_WAKI_L, key_set, data);
data[0] = oh->node[a2m.j_waki_l_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_WAKI_L_WJ, key_set, data);
{
vec3 pos_j_kata_l_wj;
vec3 pos_j_ude_l_wj;
vec3 pos_j_te_l_wj;
mat4_get_translation(&oh->node[a2m.j_kata_l_wj].model_transform.mat, &pos_j_kata_l_wj);
mat4_get_translation(&oh->node[a2m.j_ude_l_wj].model_transform.mat, &pos_j_ude_l_wj);
mat4_get_translation(&oh->node[a2m.j_te_l_wj].model_transform.mat, &pos_j_te_l_wj);
vec3 tl_up_kata_dir = pos_j_ude_l_wj - vec3::lerp(pos_j_kata_l_wj, pos_j_te_l_wj, 0.5f);
float_t pos_middle_dist = vec3::length(tl_up_kata_dir);
if (pos_middle_dist == 0.0f) {
mat4& mat = oh->node[a2m.j_kata_l_wj].model_transform.mat;
data[0] = { 0.0f, 0.3f, 0.0f };
mat4_mult_vec3(&mat, &data[0], &tl_up_kata_dir);
}
else
tl_up_kata_dir *= 0.3f / pos_middle_dist;
vec3 tl_up_kata_pos = tl_up_kata_dir + pos_j_ude_l_wj;
mat4& mat = oh->node[a2m.j_mune_b_wj].model_transform.mat;
mat4_mult_vec3_inv_trans(&mat, &tl_up_kata_pos, &data[0]);
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_TL_UP_KATA_L, key_set, data);
}
mat4_get_translation(&oh->node[a2m.j_te_l_wj].model_transform.mat, &data[0]);
data[1] = { -(float_t)(M_PI / 2.0), -(float_t)(M_PI / 2.0), -(float_t)(M_PI / 2.0) };
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_C_KATA_L, key_set, data, 2);
data[0] = oh->node[a2m.j_te_l_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_TE_L_WJ, key_set, data);
data[0] = oh->node[a2m.n_waki_r].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_N_WAKI_R, key_set, data);
data[0] = oh->node[a2m.j_waki_l_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_WAKI_R_WJ, key_set, data);
{
vec3 pos_j_kata_r_wj;
vec3 pos_j_ude_r_wj;
vec3 pos_j_te_r_wj;
mat4_get_translation(&oh->node[a2m.j_kata_r_wj].model_transform.mat, &pos_j_kata_r_wj);
mat4_get_translation(&oh->node[a2m.j_ude_r_wj].model_transform.mat, &pos_j_ude_r_wj);
mat4_get_translation(&oh->node[a2m.j_te_r_wj].model_transform.mat, &pos_j_te_r_wj);
vec3 tl_up_kata_dir = pos_j_ude_r_wj - vec3::lerp(pos_j_kata_r_wj, pos_j_te_r_wj, 0.5f);
float_t pos_middle_dist = vec3::length(tl_up_kata_dir);
if (pos_middle_dist == 0.0f) {
mat4& mat = oh->node[a2m.j_kata_r_wj].model_transform.mat;
data[0] = { 0.0f, 0.3f, 0.0f };
mat4_mult_vec3(&mat, &data[0], &tl_up_kata_dir);
}
else
tl_up_kata_dir *= 0.3f / pos_middle_dist;
vec3 tl_up_kata_pos = tl_up_kata_dir + pos_j_ude_r_wj;
mat4& mat = oh->node[a2m.j_mune_b_wj].model_transform.mat;
mat4_mult_vec3_inv_trans(&mat, &tl_up_kata_pos, &data[0]);
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_TL_UP_KATA_R, key_set, data);
}
mat4_get_translation(&oh->node[a2m.j_te_r_wj].model_transform.mat, &data[0]);
data[1] = { -(float_t)(M_PI / 2.0), (float_t)(M_PI / 2.0), (float_t)(M_PI / 2.0) };
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_C_KATA_R, key_set, data, 2);
data[0] = oh->node[a2m.j_te_r_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_TE_R_WJ, key_set, data);
mat4_get_translation(&oh->node[a2m.j_asi_l_wj].model_transform.mat, &data[0]);
data[0].y -= 0.033f;
if (data[0].y < 0.103f)
data[0].y = 0.103f;
data[1] = oh->node[a2m.j_momo_l_wj].model_transform.rotation_value;
data[1].z -= (float_t)(M_PI / 2.0);
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_CL_MOMO_L, key_set, data, 2);
mat4_get_translation(&oh->node[a2m.j_asi_r_wj].model_transform.mat, &data[0]);
data[0].y -= 0.033f;
if (data[0].y < 0.103f)
data[0].y = 0.103f;
data[1] = oh->node[a2m.j_momo_r_wj].model_transform.rotation_value;
data[1].z -= (float_t)(M_PI / 2.0);
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_CL_MOMO_R, key_set, data, 2);
data[0] = oh->node[a2m.j_asi_l_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_ASI_L_WJ_CO, key_set, data);
data[0] = oh->node[a2m.j_asi_r_wj].model_transform.rotation_value;
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_ASI_R_WJ_CO, key_set, data);
data[0] = { 0.0491406508f, 0.0f, 0.0f };
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_KL_AGO_WJ, key_set, data);
data[0] = { 0.0f, 0.0331281610f, 0.0f };
set_bone_key_set_data(bone_data, a2m.bone_keys, a2m.sec_bone_keys, add_keys,
MOTION_BONE_N_KUBI_WJ_EX, key_set, data);
auth->frame = auth_frame;
auth->frame_changed = auth_frame_changed;
auth->paused = auth_paused;
}
}
#endif
static void x_pv_game_reset_field(x_pv_game* xpvgm) {
task_stage_modern_info().set_stage();
Glitter::glt_particle_manager->FreeScenes();
}
struct x_pv_game_split_auth_3d_hrc_obj_sub_mesh {
std::vector<uint32_t> indices;
x_pv_game_split_auth_3d_hrc_obj_sub_mesh() {
}
~x_pv_game_split_auth_3d_hrc_obj_sub_mesh() {
}
};
struct x_pv_game_split_auth_3d_hrc_obj_mesh {
std::vector<x_pv_game_split_auth_3d_hrc_obj_sub_mesh> sub_meshes;
std::vector<uint32_t> vertex_indices;
std::vector<obj_vertex_data> vertices;
x_pv_game_split_auth_3d_hrc_obj_mesh() {
}
~x_pv_game_split_auth_3d_hrc_obj_mesh() {
}
};
struct x_pv_game_split_auth_3d_hrc_obj_bone {
uint32_t src_id;
std::string dst_name;
int32_t index;
std::vector<x_pv_game_split_auth_3d_hrc_obj_mesh> meshes;
x_pv_game_split_auth_3d_hrc_obj_bone() {
src_id = -1;
index = -1;
}
~x_pv_game_split_auth_3d_hrc_obj_bone() {
}
};
static int x_pv_game_split_auth_3d_hrc_obj_bone_compare_func(void const* src1, void const* src2) {
x_pv_game_split_auth_3d_hrc_obj_bone* bone1 = (x_pv_game_split_auth_3d_hrc_obj_bone*)src1;
x_pv_game_split_auth_3d_hrc_obj_bone* bone2 = (x_pv_game_split_auth_3d_hrc_obj_bone*)src2;
return bone1->dst_name.compare(bone2->dst_name);
}
static void auth_3d_key_rev(auth_3d_key& k, std::vector<float_t>& values_src) {
std::vector<kft3> values;
int32_t type = interpolate_chs_reverse_sequence(values_src, values);
k = {};
switch (type) {
case A3DA_KEY_NONE:
k.type = AUTH_3D_KEY_NONE;
k.value = 0.0f;
return;
case A3DA_KEY_STATIC:
k.type = values[0].value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
k.value = values[0].value;
return;
case A3DA_KEY_LINEAR:
k.type = AUTH_3D_KEY_LINEAR;
break;
case A3DA_KEY_HERMITE:
default:
k.type = AUTH_3D_KEY_HERMITE;
break;
case A3DA_KEY_HOLD:
k.type = AUTH_3D_KEY_HOLD;
break;
}
k.max_frame = (float_t)(values_src.size() + 1);
k.frame_delta = k.max_frame;
k.value_delta = 0.0f;
size_t length = values.size();
if (length > 1) {
k.keys_vec.assign(values.begin(), values.end());
k.length = length;
k.keys = k.keys_vec.data();
kft3* first_key = &k.keys[0];
kft3* last_key = &k.keys[length - 1];
if (first_key->frame < last_key->frame
&& last_key->frame > 0.0f && k.max_frame > first_key->frame) {
k.ep_type_pre = AUTH_3D_EP_NONE;
k.ep_type_post = AUTH_3D_EP_NONE;
k.frame_delta = last_key->frame - first_key->frame;
k.value_delta = last_key->value - first_key->value;
}
}
else if (length == 1) {
float_t value = values.front().value;
k.type = value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
k.value = value;
}
else {
k.type = AUTH_3D_KEY_NONE;
k.value = 0.0f;
}
}
static std::string x_pv_game_split_auth_3d_get_object_name(
const std::string& str1, const char* str2, const object_database& obj_db, bool uid_name = false) {
if (!str1.size())
return {};
std::string str;
size_t str_len;
if (!str_utils_compare_length(str1.c_str(), str1.size(), "OBJHRC_", 7)) {
str_len = 0;
str.assign(str1.c_str() + 7, str1.size() - 7);
}
else if (!str_utils_compare_length(str1.c_str(), str1.size(), "gblctr", 6)) {
str.assign(str2, utf8_length(str2) - 7);
str_len = str.size();
str.append(str1);
}
else {
str.assign(str2, utf8_length(str2) - 7);
str_len = str.size();
str.append(str1.c_str() + 2, str1.size() - 5);
}
size_t str_len_new = str.size();
for (size_t i = str_len; i < str_len_new; i++) {
char c = str[i];
if (c >= 'a' && c <= 'z')
str[i] -= 0x20;
}
bool null = obj_db.get_object_info(str.c_str()).is_null();
if (!uid_name)
str.insert(0, null ? "|OBJ_NULL__" : "|OBJ_");
else if (null)
return "NULL";
return str;
}
static void x_pv_game_split_auth_3d_update_object_set(obj_set_handler* handler) {
prj::shared_ptr<prj::stack_allocator> old_alloc = handler->alloc_handler;
prj::shared_ptr<prj::stack_allocator>& alloc = handler->alloc_handler;
alloc = prj::shared_ptr<prj::stack_allocator>(new prj::stack_allocator);
obj_set* set = alloc->allocate<obj_set>();
set->move_data(handler->obj_set, alloc);
handler->obj_set = set;
}
static void x_pv_game_split_auth_3d_write_object_set(obj_set_handler* handler) {
obj_set* set = handler->obj_set;
char name[0x200];
strcpy_s(name, sizeof(name), handler->name.c_str());
for (size_t j = 0; j < sizeof(name); j++) {
char c = name[j];
if (c >= 'A' && c <= 'Z')
name[j] += 0x20;
}
char buf[0x200];
file_stream s;
strcpy_s(buf, sizeof(buf), "patch\\!temp\\");
strcat_s(buf, sizeof(buf), name);
strcat_s(buf, sizeof(buf), "_obj.bin");
uint32_t obj_num = set->obj_num;
for (uint32_t j = 0; j < obj_num; j++) {
obj* obj = set->obj_data[j];
uint32_t num_material = obj->num_material;
for (uint32_t k = 0; k < num_material; k++) {
obj_material& material = obj->material_array[k].material;
if (*(int32_t*)&material.shader.name[4] == 0xDEADFF) {
*(int32_t*)&material.shader.name[4] = 0;
const char* shader_name = shaders_ft.get_name_by_index(material.shader.index);
strcpy_s(material.shader.name, sizeof(material.shader.name), shader_name);
}
}
}
bool modern = set->modern;
set->modern = false;
void* obj_data = 0;
size_t obj_length = 0;
set->pack_file(&obj_data, &obj_length);
set->modern = modern;
for (uint32_t j = 0; j < obj_num; j++) {
obj* obj = set->obj_data[j];
uint32_t num_material = obj->num_material;
for (uint32_t k = 0; k < num_material; k++) {
obj_material& material = obj->material_array[k].material;
if (*(int32_t*)&material.shader.name[4] != 0xDEADFF) {
material.shader.index = shaders_ft.get_index_by_name(material.shader.name);
*(int32_t*)&material.shader.name[4] = 0xDEADFF;
}
}
}
s.open(buf, "wb");
s.write(obj_data, obj_length);
s.close();
free_def(obj_data);
strcpy_s(buf, sizeof(buf), "patch\\!temp\\");
strcat_s(buf, sizeof(buf), name);
strcat_s(buf, sizeof(buf), "_tex.bin");
uint32_t tex_num = handler->tex_num;
texture** gentex = handler->gentex.data();
txp_set txp;
txp.textures.resize(tex_num);
for (uint32_t j = 0; j < tex_num; j++)
texture_txp_store(gentex[j], &txp.textures[j]);
void* tex_data = 0;
size_t tex_length = 0;
txp.pack_file(&tex_data, &tex_length, false);
s.open(buf, "wb");
s.write(tex_data, tex_length);
s.close();
free_def(tex_data);
}
static void x_pv_game_split_auth_3d_hrc_material_list(x_pv_game* xpvgm,
std::vector<object_info>& object_hrc, std::vector<std::string>& material_list) {
object_database& obj_db = xpvgm->stage_data.obj_db;
std::map<object_info, std::vector<std::string>> object_hrc_material_list;
for (const object_info i : object_hrc) {
obj* obj = object_storage_get_obj(i);
if (!obj)
continue;
uint32_t num_material = obj->num_material;
for (uint32_t j = 0; j < num_material; j++) {
obj_material* material = &obj->material_array[j].material;
for (const std::string k : material_list) {
if (k.compare(material->name))
continue;
auto elem = object_hrc_material_list.find(i);
if (elem == object_hrc_material_list.end())
elem = object_hrc_material_list.insert({ i, {} }).first;
elem->second.push_back(k);
}
}
}
for (auto& i : object_hrc_material_list)
prj::sort_unique(i.second);
std::vector<uint32_t> object_set_ids;
for (auto& i : object_hrc_material_list) {
obj_set_handler* handler = object_storage_get_obj_set_handler(i.first.set_id);
if (!handler)
continue;
object_set_ids.push_back(i.first.set_id);
obj_set* set = handler->obj_set;
std::vector<x_pv_game_split_auth_3d_hrc_obj_bone> bones_vertices;
uint32_t obj_num = set->obj_num;
for (uint32_t j = 0; j < obj_num; j++) {
obj* obj = set->obj_data[j];
if (obj->id != i.first.id)
continue;
obj_skin* skin = obj->skin;
if (!skin)
continue;
obj_mesh* mesh = obj->mesh_array;
uint32_t num_mesh = obj->num_mesh;
obj_skin_bone* bone_array = skin->bone_array;
uint32_t num_bone = skin->num_bone;
bones_vertices.resize(skin->num_bone);
for (uint32_t k = 0; k < num_bone; k++) {
std::string dst_name;
dst_name.assign(obj->name, utf8_length(obj->name) - 7);
size_t dst_name_len = dst_name.size();
dst_name.append(bone_array[k].name + 2, utf8_length(bone_array[k].name) - 5);
size_t dst_name_len_new = dst_name.size();
for (size_t i = dst_name_len; i < dst_name_len_new; i++) {
char c = dst_name[i];
if (c >= 'a' && c <= 'z')
dst_name[i] -= 0x20;
}
x_pv_game_split_auth_3d_hrc_obj_bone& bone_vertices = bones_vertices[k];
bone_vertices.src_id = i.first.id;
bone_vertices.index = k;
bone_vertices.dst_name.assign(dst_name);
bone_vertices.meshes.resize(num_mesh);
obj_mesh* mesh = obj->mesh_array;
for (uint32_t l = 0; l < num_mesh; l++, mesh++) {
x_pv_game_split_auth_3d_hrc_obj_mesh& bone_vertices_mesh = bone_vertices.meshes[l];
bone_vertices_mesh.sub_meshes.resize(mesh->num_submesh);
obj_sub_mesh* sub_mesh = mesh->submesh_array;
uint32_t num_submesh = mesh->num_submesh;
for (uint32_t m = 0; m < num_submesh; m++, sub_mesh++) {
x_pv_game_split_auth_3d_hrc_obj_sub_mesh& bone_vertices_sub_mesh
= bone_vertices_mesh.sub_meshes[m];
bone_vertices_mesh.vertices.reserve(sub_mesh->num_index);
}
}
}
mesh = obj->mesh_array;
for (uint32_t k = 0; k < num_mesh; k++, mesh++) {
obj_vertex_data* vertex_array = mesh->vertex_array;
uint32_t num_vertex = mesh->num_vertex;
std::vector<uint32_t> vtx_idx(skin->num_bone);
obj_sub_mesh* sub_mesh = mesh->submesh_array;
uint32_t num_submesh = mesh->num_submesh;
for (uint32_t l = 0; l < num_submesh; l++, sub_mesh++) {
uint16_t* bone_index_array = sub_mesh->bone_index_array;
uint16_t num_bone_index = sub_mesh->num_bone_index;
uint32_t* index = sub_mesh->index_array;
uint32_t num_index = sub_mesh->num_index;
for (uint32_t m = 0; m < num_index; m++, index++) {
obj_vertex_data vertex = vertex_array[*index];
if (vertex.bone_index.x < 0 || vertex.bone_index.x >= num_bone_index)
continue;
int32_t bone_index = bone_index_array[vertex.bone_index.x];
x_pv_game_split_auth_3d_hrc_obj_mesh& bone_vertices_mesh
= bones_vertices[bone_index].meshes[k];
x_pv_game_split_auth_3d_hrc_obj_sub_mesh& bone_vertices_sub_mesh
= bone_vertices_mesh.sub_meshes[l];
bool found = false;
uint32_t idx = *index;
for (uint32_t& n : bone_vertices_mesh.vertex_indices)
if (n == idx) {
bone_vertices_sub_mesh.indices.push_back(
(uint32_t)(&n - bone_vertices_mesh.vertex_indices.data()));
found = true;
break;
}
if (found)
continue;
mat4& mat = bone_array[bone_index].inv_bind_pose_mat;
vertex.bone_index = -1;
vertex.bone_weight = 0;
vec3 normal = vertex.normal;
vec3 tangent = *(vec3*)&vertex.tangent;
vec3 binormal = vec3::cross(normal, tangent) * vertex.tangent.w;
mat4_mult_vec3_trans(&mat, &vertex.position, &vertex.position);
mat4_mult_vec3(&mat, &normal, &normal);
mat4_mult_vec3(&mat, &tangent, &tangent);
mat4_mult_vec3(&mat, &binormal, &binormal);
tangent = vec3::normalize(tangent - normal * vec3::dot(normal, tangent));
vertex.normal = normal;
*(vec3*)&vertex.tangent = tangent;
vertex.tangent.w = vec3::dot(vec3::cross(normal, tangent), binormal) < 0.0f ? -1.0f : 1.0f;
bone_vertices_mesh.vertex_indices.push_back(*index);
bone_vertices_mesh.vertices.push_back(vertex);
bone_vertices_sub_mesh.indices.push_back(vtx_idx[bone_index]++);
}
}
}
quicksort_custom(bones_vertices.data(), bones_vertices.size(),
sizeof(x_pv_game_split_auth_3d_hrc_obj_bone), x_pv_game_split_auth_3d_hrc_obj_bone_compare_func);
}
prj::shared_ptr<prj::stack_allocator>& alloc = handler->alloc_handler;
std::vector<uint32_t> used_material_indices;
uint32_t obj_num_new = (uint32_t)bones_vertices.size();
obj** obj_data_new = alloc->allocate<::obj*>((size_t)obj_num + obj_num_new);
memcpy(obj_data_new, set->obj_data, sizeof(obj*) * obj_num);
set->obj_data = obj_data_new;
set->obj_num = obj_num + obj_num_new;
obj_data_new += obj_num;
for (uint32_t j = 0; j < obj_num_new; j++) {
x_pv_game_split_auth_3d_hrc_obj_bone& bone_vertices = bones_vertices[j];
uint32_t src_id = bone_vertices.src_id;
obj_data_new[j] = alloc->allocate<::obj>();
obj* src_obj = 0;
obj* dst_obj = obj_data_new[j];
for (uint32_t k = 0; k < obj_num; k++)
if (set->obj_data[k]->id == src_id) {
src_obj = set->obj_data[k];
break;
}
dst_obj->id = hash_murmurhash_empty;
dst_obj->hash = hash_murmurhash_empty;
if (!src_obj)
continue;
vec3 aabb_min_obj = 9999999.0f;
vec3 aabb_max_obj = -100000000.0f;
obj_mesh* mesh_array = src_obj->mesh_array;
uint32_t num_mesh = src_obj->num_mesh;
uint32_t act_num_mesh = 0;
for (uint32_t k = 0; k < num_mesh; k++) {
x_pv_game_split_auth_3d_hrc_obj_mesh& bone_vertices_mesh
= bone_vertices.meshes[k];
if (bone_vertices_mesh.vertices.size())
act_num_mesh++;
}
used_material_indices.clear();
obj_mesh* mesh_array_new = alloc->allocate<obj_mesh>(act_num_mesh);
for (uint32_t k = 0, k1 = 0; k < num_mesh; k++) {
x_pv_game_split_auth_3d_hrc_obj_mesh& bone_vertices_mesh
= bone_vertices.meshes[k];
if (!bone_vertices_mesh.vertices.size())
continue;
obj_mesh* src_mesh = &mesh_array[k];
obj_mesh* dst_mesh = &mesh_array_new[k1++];
dst_mesh->flags = src_mesh->flags;
vec3 aabb_min_mesh = 9999999.0f;
vec3 aabb_max_mesh = -100000000.0f;
used_material_indices.reserve(src_mesh->num_submesh);
obj_sub_mesh* submesh_array = src_mesh->submesh_array;
uint32_t num_submesh = src_mesh->num_submesh;
obj_sub_mesh* submesh_array_new = alloc->allocate<obj_sub_mesh>(num_submesh);
for (uint32_t l = 0; l < num_submesh; l++) {
x_pv_game_split_auth_3d_hrc_obj_sub_mesh& bone_vertices_sub_mesh
= bone_vertices_mesh.sub_meshes[l];
obj_sub_mesh* src_submesh = &submesh_array[l];
obj_sub_mesh* dst_submesh = &submesh_array_new[l];
dst_submesh->flags = src_submesh->flags;
dst_submesh->material_index = src_submesh->material_index;
memcpy(dst_submesh->uv_index, src_submesh->uv_index, 0x08);
dst_submesh->bone_index_array = 0;
dst_submesh->num_bone_index = 0;
dst_submesh->bones_per_vertex = src_submesh->bones_per_vertex;
dst_submesh->primitive_type = src_submesh->primitive_type;
dst_submesh->index_format = src_submesh->index_format;
uint32_t num_index = (uint32_t)bone_vertices_sub_mesh.indices.size();
dst_submesh->index_array = alloc->allocate<uint32_t>(
bone_vertices_sub_mesh.indices.data(), num_index);
dst_submesh->num_index = num_index;
dst_submesh->attrib = src_submesh->attrib;
vec3 aabb_min_submesh = 9999999.0f;
vec3 aabb_max_submesh = -100000000.0f;
uint32_t* index = dst_submesh->index_array;
obj_vertex_data* vertex_array = bone_vertices_mesh.vertices.data();
for (uint32_t l = 0; l < num_index; l++, index++) {
vec3 pos = vertex_array[*index].position;
aabb_min_submesh = vec3::min(aabb_min_submesh, pos);
aabb_max_submesh = vec3::max(aabb_max_submesh, pos);
}
aabb_min_mesh = vec3::min(aabb_min_mesh, aabb_min_submesh);
aabb_max_mesh = vec3::max(aabb_max_mesh, aabb_max_submesh);
vec3 center = (aabb_max_submesh + aabb_min_submesh) * 0.5f;
dst_submesh->bounding_sphere.center = center;
dst_submesh->bounding_sphere.radius = vec3::length(aabb_max_submesh - aabb_min_submesh) * 0.5f;
dst_submesh->axis_aligned_bounding_box.center = center;
dst_submesh->axis_aligned_bounding_box.size = aabb_max_submesh - center;
dst_submesh->first_index = 0;
dst_submesh->last_index = 0;
dst_submesh->index_offset = 0;
used_material_indices.push_back(dst_submesh->material_index);
}
dst_mesh->submesh_array = submesh_array_new;
dst_mesh->num_submesh = num_submesh;
aabb_min_obj = vec3::min(aabb_min_obj, aabb_min_mesh);
aabb_max_obj = vec3::max(aabb_max_obj, aabb_max_mesh);
vec3 center = (aabb_max_mesh + aabb_min_mesh) * 0.5f;
vec3 size = aabb_max_mesh - center;
dst_mesh->bounding_sphere.center = (aabb_max_mesh + aabb_min_mesh) * 0.5f;
dst_mesh->bounding_sphere.radius = vec3::length(aabb_max_mesh - aabb_min_mesh) * 0.5f;
dst_mesh->vertex_format = src_mesh->vertex_format;
if (src_mesh->vertex_format & OBJ_VERTEX_BONE_DATA) {
enum_and(dst_mesh->vertex_format, ~OBJ_VERTEX_BONE_DATA);
dst_mesh->size_vertex = src_mesh->size_vertex - 0x20;
}
else
dst_mesh->size_vertex = src_mesh->size_vertex;
uint32_t num_vertex = (uint32_t)bone_vertices_mesh.vertices.size();
dst_mesh->vertex_array = alloc->allocate<obj_vertex_data>(
bone_vertices_mesh.vertices.data(), num_vertex);
dst_mesh->num_vertex = num_vertex;
dst_mesh->attrib = src_mesh->attrib;
memcpy(dst_mesh->reserved, src_mesh->reserved, sizeof(uint32_t) * 6);
memcpy(dst_mesh->name, src_mesh->name, 0x40);
}
dst_obj->mesh_array = mesh_array_new;
dst_obj->num_mesh = act_num_mesh;
prj::sort_unique(used_material_indices);
dst_obj->bounding_sphere.center = (aabb_max_obj + aabb_min_obj) * 0.5f;
dst_obj->bounding_sphere.radius = vec3::length(aabb_max_obj - aabb_min_obj) * 0.5f;
obj_material_data* material_array = src_obj->material_array;
uint32_t num_material = (uint32_t)used_material_indices.size();
obj_material_data* material_array_new = alloc->allocate<obj_material_data>(num_material);
for (uint32_t k = 0; k < num_material; k++) {
material_array_new[k] = material_array[used_material_indices[k]];
for (uint32_t l = 0; l < act_num_mesh; l++) {
obj_mesh* mesh = &mesh_array_new[l];
obj_sub_mesh* submesh_array = mesh->submesh_array;
uint32_t num_submesh = mesh->num_submesh;
for (uint32_t m = 0; m < num_submesh; m++) {
obj_sub_mesh* submesh = &submesh_array[m];
uint32_t material_index = submesh->material_index;
uint32_t n = 0;
for (uint32_t& o : used_material_indices)
if (o == material_index) {
submesh->material_index = n;
break;
}
else
n++;
}
}
}
dst_obj->material_array = material_array_new;
dst_obj->num_material = num_material;
dst_obj->flags = src_obj->flags;
memcpy(dst_obj->reserved, src_obj->reserved, sizeof(uint32_t) * 10);
dst_obj->skin = 0;
std::string& dst_name = bone_vertices.dst_name;
dst_obj->name = alloc->allocate<char>(dst_name.c_str(), dst_name.size() + 1);
uint32_t hash = hash_string_murmurhash(dst_name);
dst_obj->id = hash;
dst_obj->hash = hash;
object_set_info* set_info = (object_set_info*)obj_db.get_object_set_info(i.first.set_id);
if (set_info) {
object_info_data* info = (object_info_data*)obj_db.get_object_info_data_by_murmurhash(hash);
if (!info) {
set_info->object.push_back({});
info = &set_info->object.back();
info->id = hash;
info->name.assign(dst_obj->name);
info->name_hash_fnv1a64m = hash_string_fnv1a64m(info->name);
info->name_hash_fnv1a64m_upper = hash_string_fnv1a64m(info->name, true);
info->name_hash_murmurhash = hash_string_murmurhash(info->name);
}
}
}
obj_db.update();
handler->obj_id_data.reserve(obj_num_new);
for (uint32_t j = 0; j < obj_num_new; j++)
handler->obj_id_data.push_back(obj_data_new[j]->id, obj_num + j);
uint32_t _obj_num = obj_num + obj_num_new;
handler->vertex_buffer_num = _obj_num;
obj_vertex_buffer* vertex_buffer_data = new obj_vertex_buffer[_obj_num];
handler->index_buffer_num = _obj_num;
obj_index_buffer* index_buffer_data = new obj_index_buffer[_obj_num];
memcpy(vertex_buffer_data, handler->vertex_buffer_data, sizeof(obj_vertex_buffer) * obj_num);
memcpy(index_buffer_data, handler->index_buffer_data, sizeof(obj_index_buffer) * obj_num);
delete[] handler->vertex_buffer_data;
delete[] handler->index_buffer_data;
handler->vertex_buffer_data = vertex_buffer_data;
handler->index_buffer_data = index_buffer_data;
for (uint32_t j = 0; j < obj_num_new; j++) {
vertex_buffer_data[obj_num + j].load(obj_data_new[j]);
index_buffer_data[obj_num + j].load(obj_data_new[j]);
}
for (uint32_t j = 0; j < obj_num; j++) {
obj* obj = set->obj_data[j];
if (obj->id != i.first.id)
continue;
obj_skin* skin = obj->skin;
if (!skin)
continue;
std::vector<std::string> hrc_nodes;
prj::vector_pair<std::string, obj_skin_bone*> hrc_bones;
obj_skin_bone* bone_array = skin->bone_array;
uint32_t num_bone = skin->num_bone;
for (std::pair<uint32_t, auth_3d_id> k : xpvgm->stage_data.auth_3d_ids) {
auth_3d* auth = k.second.get_auth_3d();
if (!auth || !auth->object_hrc.size())
continue;
auth_3d_object_hrc* obj_hrc = 0;
for (auth_3d_object_hrc& n : auth->object_hrc)
if (n.object_info == i.first) {
obj_hrc = &n;
break;
}
if (!obj_hrc)
continue;
for (auth_3d_object_hrc*& l : auth->object_hrc_list)
if (l->object_info == i.first) {
auth->object_hrc_list.erase(auth->object_hrc_list.begin()
+ (&l - auth->object_hrc_list.data()));
break;
}
for (uint32_t l = 0; l < num_bone; l++) {
x_pv_game_split_auth_3d_hrc_obj_bone& bone_vertices = bones_vertices[l];
const char* bone_name = bone_array[bone_vertices.index].name;
hrc_bones.push_back(bone_name, &bone_array[bone_vertices.index]);
int32_t node_index = obj_hrc->get_node_index(bone_name);
while (node_index >= 0) {
auth_3d_object_node* node = &obj_hrc->node[node_index];
int32_t _node_index = node_index;
node_index = node->parent;
if (!node->name.compare("BONE"))
continue;
hrc_nodes.push_back(node->name);
}
}
}
prj::sort_unique(hrc_nodes);
prj::sort_unique(hrc_bones);
for (std::pair<uint32_t, auth_3d_id> k : xpvgm->stage_data.auth_3d_ids) {
auth_3d* auth = k.second.get_auth_3d();
if (!auth || !auth->object_hrc.size())
continue;
auth_3d_object_hrc* obj_hrc = 0;
for (auth_3d_object_hrc& n : auth->object_hrc)
if (n.object_info == i.first) {
obj_hrc = &n;
break;
}
if (!obj_hrc)
continue;
size_t object_base = (size_t)auth->object.data();
for (const std::string& l : hrc_nodes) {
auth->object.push_back({});
auth_3d_object& object = auth->object.back();
object.name.assign(l);
}
size_t object_new_base = (size_t)auth->object.data();
for (auth_3d_object*& l : auth->object_list)
l = (auth_3d_object*)((size_t)l - object_base + object_new_base);
}
for (std::pair<uint32_t, auth_3d_id> l : xpvgm->stage_data.auth_3d_ids) {
auth_3d* auth = l.second.get_auth_3d();
if (!auth || !auth->object_hrc.size())
continue;
auth_3d_object_hrc* obj_hrc = 0;
for (auth_3d_object_hrc& m : auth->object_hrc)
if (m.object_info == i.first) {
obj_hrc = &m;
break;
}
if (!obj_hrc)
continue;
for (const std::string& m : hrc_nodes)
for (auth_3d_object& n : auth->object) {
if (n.name.compare(m))
continue;
auth_3d_object_node* node = 0;
for (auth_3d_object_node& o : obj_hrc->node)
if (!o.name.compare(m)) {
node = &o;
break;
}
if (!node)
continue;
if (!str_utils_compare_length(m.c_str(), m.size(), "OBJHRC_", 7))
auth->object_list.push_back(&n);
std::string name = x_pv_game_split_auth_3d_get_object_name(
m, obj->name, obj_db);
std::string parent_name;
std::string uid_name = x_pv_game_split_auth_3d_get_object_name(
m, obj->name, obj_db, true);
auth_3d_object_node* _node = node;
int32_t parent = _node->parent;
while (parent >= 0) {
parent = _node->parent;
if (parent < 0)
break;
_node = &obj_hrc->node[parent];
if (!_node->name.compare("BONE"))
continue;
std::string _parent_name = x_pv_game_split_auth_3d_get_object_name(
_node->name, obj->name, obj_db);
name.insert(0, _parent_name);
parent_name.insert(0, _parent_name);
}
n.model_transform.translation = node->model_transform.translation;
n.model_transform.rotation = node->model_transform.rotation;
n.model_transform.scale = node->model_transform.scale;
n.model_transform.visibility = node->model_transform.visibility;
n.name.assign(name);
n.parent_name.assign(parent_name);
n.uid_name.assign(uid_name);
n.object_info = obj_db.get_object_info(n.uid_name.c_str());
n.object_hash = hash_string_murmurhash(n.uid_name);
auto hrc_bones_elem = hrc_bones.find(node->name);
if (hrc_bones_elem == hrc_bones.end())
break;
//n.model_transform.rotation = {};
break;
obj_skin_bone* hrc_bone = hrc_bones_elem->second;
mat4 rot_mat;
mat4_clear_trans(&hrc_bone->inv_bind_pose_mat, &rot_mat);
mat4_invrot(&rot_mat, &rot_mat);
vec3 rot_mat_rot;
mat4_get_rotation(&rot_mat, &rot_mat_rot);
if (fabsf(rot_mat_rot.x) < 0.00001f
&& fabsf(rot_mat_rot.x) < 0.00001f
&& fabsf(rot_mat_rot.x) < 0.00001f)
break;
std::vector<float_t> rotation_x;
std::vector<float_t> rotation_y;
std::vector<float_t> rotation_z;
float_t last_frame = auth->last_frame;
for (float_t o = 0.0f; o < last_frame; o++) {
node->interpolate(o);
mat4 mat;
mat4_mult(&node->model_transform.mat_inner, &node->joint_orient_mat, &mat);
mat4_mult(&rot_mat, &mat, &mat);
vec3 rotation;
mat4_get_rotation(&mat, &rotation);
rotation_x.push_back(rotation.x);
rotation_y.push_back(rotation.y);
rotation_z.push_back(rotation.z);
}
auth_3d_key_rev(n.model_transform.rotation.x, rotation_x);
auth_3d_key_rev(n.model_transform.rotation.y, rotation_y);
auth_3d_key_rev(n.model_transform.rotation.z, rotation_z);
break;
}
}
}
for (uint32_t j = 0; j < obj_num_new; j++) {
x_pv_game_split_auth_3d_hrc_obj_bone& bone_vertices = bones_vertices[j];
uint32_t src_id = bone_vertices.src_id;
uint32_t src = -1;
for (uint32_t k = 0; k < obj_num; k++)
if (set->obj_data[k]->id == src_id) {
src = k;
break;
}
if (src == -1)
continue;
uint32_t size = --set->obj_num - src;
memmove(&set->obj_data[src], &set->obj_data[src + 1], sizeof(obj*) * size);
memset(&set->obj_data[src + size], 0, sizeof(obj*));
handler->vertex_buffer_num--;
handler->vertex_buffer_data[src].unload();
memmove(&handler->vertex_buffer_data[src],
&handler->vertex_buffer_data[src + 1], sizeof(obj_vertex_buffer) * size);
memset(&handler->vertex_buffer_data[src + size], 0, sizeof(obj_vertex_buffer));
handler->index_buffer_num--;
handler->index_buffer_data[src].unload();
memmove(&handler->index_buffer_data[src],
&handler->index_buffer_data[src + 1], sizeof(obj_index_buffer) * size);
memset(&handler->index_buffer_data[src + size], 0, sizeof(obj_index_buffer));
}
}
prj::sort_unique(object_set_ids);
for (uint32_t& i : object_set_ids) {
obj_set_handler* handler = object_storage_get_obj_set_handler(i);
if (!handler)
continue;
x_pv_game_split_auth_3d_update_object_set(handler);
x_pv_game_split_auth_3d_write_object_set(handler);
}
for (std::pair<uint32_t, auth_3d_id> i : xpvgm->stage_data.auth_3d_ids) {
auth_3d* auth = i.second.get_auth_3d();
if (!auth || !auth->object_hrc.size())
continue;
for (auth_3d_object& j : auth->object) {
j.children_object.clear();
j.children_object.shrink_to_fit();
j.children_object_hrc.clear();
j.children_object_hrc.shrink_to_fit();
}
for (auth_3d_object_hrc& j : auth->object_hrc) {
j.children_object.clear();
j.children_object.shrink_to_fit();
j.children_object_hrc.clear();
j.children_object_hrc.shrink_to_fit();
j.children_object_parent_node.clear();
j.children_object_parent_node.shrink_to_fit();
j.children_object_hrc_parent_node.clear();
j.children_object_hrc_parent_node.shrink_to_fit();
}
for (auth_3d_object& j : auth->object) {
if (!j.parent_name.size())
continue;
if (j.parent_node.size())
for (auth_3d_object_hrc& k : auth->object_hrc) {
if (j.parent_name.compare(k.name))
continue;
int32_t node_index = k.get_node_index(j.parent_node.c_str());
if (node_index > -1) {
k.children_object_parent_node.push_back(node_index);
k.children_object.push_back(&j);
}
break;
}
else
for (auth_3d_object& k : auth->object) {
if (j.parent_name.compare(k.name))
continue;
k.children_object.push_back(&j);
break;
}
}
for (auth_3d_object_hrc& j : auth->object_hrc) {
if (!j.parent_name.size())
continue;
if (j.parent_node.size())
for (auth_3d_object_hrc& k : auth->object_hrc) {
if (j.parent_name.compare(k.name))
continue;
int32_t node_index = k.get_node_index(j.parent_node.c_str());
if (node_index > -1) {
k.children_object_hrc_parent_node.push_back(node_index);
k.children_object_hrc.push_back(&j);
}
break;
}
else
for (auth_3d_object& k : auth->object) {
if (j.parent_name.compare(k.name))
continue;
k.children_object_hrc.push_back(&j);
break;
}
}
}
}
typedef std::pair<vec4, vec4> material_list_color;
inline bool operator ==(const material_list_color& left, const material_list_color& right) {
return !memcmp(&left, &right, sizeof(material_list_color));
}
inline bool operator !=(const material_list_color& left, const material_list_color& right) {
return !!memcmp(&left, &right, sizeof(material_list_color));
}
struct material_list_data {
std::string name;
std::vector<material_list_color> color;
std::vector<material_list_color> color_opt;
std::vector<int32_t> color_opt_idx;
union {
uint16_t has_color;
struct {
uint8_t has_color_a : 4;
uint8_t has_color_b : 4;
uint8_t has_color_g : 4;
uint8_t has_color_r : 4;
};
};
std::vector<kft3> morph;
std::vector<kft3> morph_opt;
int32_t type;
bool cycle;
float_t start_time;
float_t end_time;
bool has_data[8];
inline material_list_data() : has_color(), type(), cycle(),
start_time(), end_time(), has_data() {
}
inline ~material_list_data() {
}
bool optimize();
};
struct material_list_color_data {
std::string name;
std::vector<material_list_color> data;
bool has_data[8];
std::vector<std::pair<material_list_color, std::vector<int32_t>>> same_data;
inline material_list_color_data() : has_data() {
}
inline ~material_list_color_data() {
}
};
bool material_list_data::optimize() {
color_opt.assign(color.begin(), color.end());
color_opt_idx.resize(color_opt.size());
morph_opt.assign(morph.begin(), morph.end());
if (type < A3DA_KEY_LINEAR)
return true;
// Find and optimize 0123456 to 01230123
auto optimize_func_1 = [&](std::vector<material_list_color>& color, std::vector<kft3>& morph) {
kft3* keys = morph.data();
size_t length = morph.size();
if (color.size() > 2)
for (size_t i = 0; i < length - 2; i++)
for (size_t j = i + 2; j < length; j++) {
size_t count = j - i;
if (j + count >= length)
break;
material_list_color* color_data = color.data();
bool equal = true;
for (size_t k = 0, l = count; k <= count; k++, l++)
if (memcmp(&color_data[(int64_t)keys[i + k].value],
&color_data[(int64_t)keys[i + l].value],
sizeof(material_list_color))) {
equal = false;
break;
}
if (!equal)
continue;
bool has_descending = false;
for (size_t k = 0; k < count * 2; k++)
if (keys[i + k].value > keys[i + k + 1].value) {
has_descending = true;
break;
}
if (has_descending)
break;
morph.insert(morph.begin() + j, morph.data()[j]);
keys = morph.data();
length = morph.size();
float_t start_value = keys[j].value - keys[j - count].value;
for (size_t k = j + 1; k < length; k++)
keys[k].value -= start_value;
auto elem = color.begin() + ((size_t)(int64_t)start_value + 1);
color.erase(elem, elem + count);
break;
}
};
// Find and optimize 01234 to 01210
auto optimize_func_2_asc = [&](std::vector<material_list_color>& color, std::vector<kft3>& morph) {
kft3* keys = morph.data();
size_t length = morph.size();
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++) {
size_t count = j - i;
if (j + count > length || i + count * 2 >= length)
break;
material_list_color* color_data = color.data();
bool equal = true;
for (size_t k = 0, l = count * 2; k < count; k++, l--)
if (memcmp(&color_data[(int32_t)keys[i + k].value],
&color_data[(int32_t)keys[i + l].value],
sizeof(material_list_color))) {
equal = false;
break;
}
if (!equal)
continue;
float_t start_value = keys[i].value;
float_t end_value = keys[i + count * 2].value;
if (*(uint32_t*)&start_value == *(uint32_t*)&end_value)
break;
else if (i + count * 2 + 1 < length
&& *(uint32_t*)&keys[i + count * 2].frame != *(uint32_t*)&keys[i + count * 2 + 1].frame)
break;
for (size_t k = count, l = count - 1; k < count * 2; k++, l--) {
if (keys[i + k].value < keys[i + k + 1].value && keys[i + l + 1].value > keys[i + l].value
|| keys[i + k].value > keys[i + k + 1].value && keys[i + l + 1].value < keys[i + l].value) {
keys[i + k + 0].tangent2 = -keys[i + k + 0].tangent2;
keys[i + k + 1].tangent1 = -keys[i + k + 1].tangent1;
}
keys[i + k + 1].value = keys[i + l].value;
}
i += count * 2;
break;
}
};
// Find and optimize 01234 to 01210
auto optimize_func_2_desc = [&](std::vector<material_list_color>& color, std::vector<kft3>& morph) {
kft3* keys = morph.data();
size_t length = morph.size();
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++) {
size_t count = j - i;
if (j + count > length || i + count * 2 >= length)
break;
material_list_color* color_data = color.data();
bool equal = true;
for (size_t k = 0, l = count * 2; k < count; k++, l--)
if (memcmp(&color_data[(int32_t)keys[i + k].value],
&color_data[(int32_t)keys[i + l].value],
sizeof(material_list_color))) {
equal = false;
break;
}
if (!equal)
continue;
float_t start_value = keys[i].value;
float_t end_value = keys[i + count * 2].value;
if (*(uint32_t*)&start_value == *(uint32_t*)&end_value)
break;
else if (i + count * 2 + 1 < length
&& *(uint32_t*)&keys[i + count * 2].frame != *(uint32_t*)&keys[i + count * 2 + 1].frame)
break;
for (size_t k = count, l = count - 1; k < count * 2; k++, l--) {
if (keys[i + k].value > keys[i + k + 1].value && keys[i + l + 1].value < keys[i + l].value
|| keys[i + k].value < keys[i + k + 1].value && keys[i + l + 1].value > keys[i + l].value) {
keys[i + k + 0].tangent1 = -keys[i + k + 0].tangent1;
keys[i + k + 1].tangent2 = -keys[i + k + 1].tangent2;
}
keys[i + k + 1].value = keys[i + l].value;
}
i += count * 2;
break;
}
};
// Find and optimize 012345 to 012210
auto optimize_func_3_asc = [&](std::vector<material_list_color>& color, std::vector<kft3>& morph) {
kft3* keys = morph.data();
size_t length = morph.size();
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++) {
size_t count = j - i;
if (j + count > length || i + count * 2 + 1 >= length)
break;
material_list_color* color_data = color.data();
bool equal = true;
for (size_t k = 0, l = count * 2 + 1; k <= count; k++, l--)
if (memcmp(&color_data[(int64_t)keys[i + k].value],
&color_data[(int64_t)keys[i + l].value],
sizeof(material_list_color))) {
equal = false;
break;
}
if (!equal)
continue;
float_t start_value = keys[i].value;
float_t end_value = keys[i + count * 2 + 1].value;
if (*(uint32_t*)&start_value == *(uint32_t*)&end_value)
break;
else if (i + count * 2 + 2 < length
&& *(uint32_t*)&keys[i + count * 2 + 1].frame != *(uint32_t*)&keys[i + count * 2 + 2].frame)
break;
for (size_t k = count, l = count - 1; k < count * 2; k++, l--) {
if (keys[i + k + 1].value < keys[i + k + 2].value && keys[i + l + 1].value > keys[i + l].value
|| keys[i + k + 1].value > keys[i + k + 2].value && keys[i + l + 1].value < keys[i + l].value) {
keys[i + k + 1].tangent2 = -keys[i + k + 1].tangent2;
keys[i + k + 2].tangent1 = -keys[i + k + 2].tangent1;
}
keys[i + k + 2].value = keys[i + l].value;
}
i += count * 2;
break;
}
};
// Find and optimize 012345 to 012210
auto optimize_func_3_desc = [&](std::vector<material_list_color>& color, std::vector<kft3>& morph) {
kft3* keys = morph.data();
size_t length = morph.size();
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++) {
size_t count = j - i;
if (j + count > length || i + count * 2 + 1 >= length)
break;
material_list_color* color_data = color.data();
bool equal = true;
for (size_t k = 0, l = count * 2 + 1; k <= count; k++, l--)
if (memcmp(&color_data[(int64_t)keys[i + k].value],
&color_data[(int64_t)keys[i + l].value],
sizeof(material_list_color))) {
equal = false;
break;
}
if (!equal)
continue;
float_t start_value = keys[i].value;
float_t end_value = keys[i + count * 2 + 1].value;
if (*(uint32_t*)&start_value == *(uint32_t*)&end_value)
break;
else if (i + count * 2 + 2 < length
&& *(uint32_t*)&keys[i + count * 2 + 1].frame != *(uint32_t*)&keys[i + count * 2 + 2].frame)
break;
for (size_t k = count, l = count - 1; k < count * 2; k++, l--) {
if (keys[i + k + 1].value > keys[i + k + 2].value && keys[i + l + 1].value < keys[i + l].value
|| keys[i + k + 1].value < keys[i + k + 2].value && keys[i + l + 1].value > keys[i + l].value) {
keys[i + k + 1].tangent1 = -keys[i + k + 1].tangent1;
keys[i + k + 2].tangent2 = -keys[i + k + 2].tangent2;
}
keys[i + k + 2].value = keys[i + l].value;
}
i += count * 2;
break;
}
};
if (color_opt.size() > 1) {
// Remove duplicate color entries
kft3* keys = morph_opt.data();
size_t length = morph_opt.size();
{
auto i_begin = color_opt.begin();
auto i_end = color_opt.end() - 1;
for (auto i = i_begin; i != i_end;)
if (!memcmp(&i[0], &i[1], sizeof(material_list_color))) {
float_t value = (float_t)(int64_t)(i - i_begin + 1);
for (size_t k = i - i_begin + 1; k < length; k++)
if (keys[k].value >= value)
keys[k].value -= 1.0f;
i = color_opt.erase(i);
i_begin = color_opt.begin();
i_end = color_opt.end() - 1;
}
else
i++;
}
// Remove duplicate at start
if (length > 1 && *(uint32_t*)&keys[0].frame != *(uint32_t*)&keys[1].frame
&& *(uint32_t*)&keys[0].value == *(uint32_t*)&keys[1].value)
morph_opt.erase(morph_opt.begin());
// Remove duplicate at end
if (length > 1 && *(uint32_t*)&keys[length - 2].frame != *(uint32_t*)&keys[length - 1].frame
&& *(uint32_t*)&keys[length - 2].value == *(uint32_t*)&keys[length - 1].value)
morph_opt.erase(morph_opt.end() - 1);
while (true) {
std::vector<material_list_color> color(color_opt);
std::vector<kft3> morph(morph_opt);
optimize_func_1(color, morph);
optimize_func_2_asc(color, morph);
optimize_func_3_asc(color, morph);
int32_t max_value = 0;
for (kft3& i : morph)
max_value = max_def(max_value, (int32_t)i.value);
max_value++;
if (max_value < color.size())
color.resize(max_value);
if (color.size() > 2) {
std::reverse(morph.begin(), morph.end());
optimize_func_2_desc(color, morph);
optimize_func_3_desc(color, morph);
int32_t min_value = INT32_MAX;
for (kft3& i : morph)
min_value = min_def(min_value, (int32_t)i.value);
int32_t max_value = 0;
for (kft3& i : morph)
max_value = max_def(max_value, (int32_t)i.value);
max_value++;
if (min_value && min_value != INT32_MAX) {
color.erase(color.begin(), color.begin() + min_value);
max_value -= min_value;
for (kft3& i : morph)
i.value -= (float_t)min_value;
}
if (max_value < color.size())
color.resize(max_value);
std::reverse(morph.begin(), morph.end());
}
if (color.size() < color_opt.size() || morph.size() < morph_opt.size()) {
color_opt.assign(color.begin(), color.end());
morph_opt.assign(morph.begin(), morph.end());
continue;
}
break;
}
}
color_opt_idx.resize(color_opt.size());
/*if (color_opt.size() > 2) {
material_list_color* color_data = color_opt.data();
size_t color_length = color_opt.size();
kft3* keys = morph_opt.data();
size_t length = morph_opt.size();
for (size_t i = 0, j = 2; j < color_length; i++, j++) {
if (memcmp(&color_data[i], &color_data[j], sizeof(material_list_color)))
continue;
float_t src_value = (float_t)(int64_t)j;
float_t dst_value = (float_t)(int64_t)i;
bool removed = false;
for (size_t k = 0, l = 1, m = 2; l < length; k++, l++, m++) {
if (*(uint32_t*)&keys[l].value != *(uint32_t*)&src_value)
continue;
keys[k].tangent2 = -keys[k].tangent2;
keys[l].tangent1 = -keys[l].tangent1;
keys[l].value = dst_value;
if (m < length) {
keys[l].tangent2 = -keys[l].tangent2;
keys[m].tangent1 = -keys[m].tangent1;
}
removed = true;
}
if (removed) {
color_opt.erase(color_opt.begin() + (i + 2));
color_length = color_opt.size();
}
}
int32_t max_value = 0;
for (kft3& i : morph_opt)
max_value = max_def(max_value, (int32_t)i.value);
max_value++;
if (max_value < color_opt.size())
color_opt.resize(max_value);
}*/
if (morph_opt.size() > 1) {
auto i_begin = morph_opt.begin();
auto i_end = morph_opt.end() - 1;
for (auto i = i_begin; i != i_end;)
if (*(uint32_t*)&i[0].frame == *(uint32_t*)&i[1].frame
&& *(uint32_t*)&i[0].value == *(uint32_t*)&i[1].value) {
i[1].tangent1 = i[0].tangent1;
i = morph_opt.erase(i);
i_begin = morph_opt.begin();
i_end = morph_opt.end() - 1;
}
else
i++;
}
if (type == 2)
for (kft3& i : morph_opt) {
i.tangent1 = 0.0f;
i.tangent2 = 0.0f;
}
size_t count = (size_t)(int32_t)morph.back().frame + 1;
auth_3d_key morph_key;
{
morph_key.max_frame = (float_t)(int64_t)count;
morph_key.frame_delta = morph_key.max_frame;
morph_key.value_delta = 0.0f;
switch (type) {
case A3DA_KEY_LINEAR:
morph_key.type = AUTH_3D_KEY_LINEAR;
break;
case A3DA_KEY_HERMITE:
default:
morph_key.type = AUTH_3D_KEY_HERMITE;
break;
}
size_t length = morph.size();
if (length > 1) {
morph_key.keys_vec.assign(morph.begin(), morph.end());
morph_key.length = length;
morph_key.keys = morph_key.keys_vec.data();
kft3* first_key = &morph_key.keys[0];
kft3* last_key = &morph_key.keys[length - 1];
if (first_key->frame < last_key->frame
&& last_key->frame > 0.0f && morph_key.max_frame > first_key->frame) {
morph_key.frame_delta = last_key->frame - first_key->frame;
morph_key.value_delta = last_key->value - first_key->value;
}
}
else if (length == 1) {
float_t value = morph.front().value;
morph_key.type = value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
morph_key.value = value;
}
else {
morph_key.type = AUTH_3D_KEY_NONE;
morph_key.value = 0.0f;
}
}
auth_3d_key morph_opt_key;
{
morph_opt_key.max_frame = (float_t)(int64_t)count;
morph_opt_key.frame_delta = morph_opt_key.max_frame;
morph_opt_key.value_delta = 0.0f;
switch (type) {
case A3DA_KEY_LINEAR:
morph_opt_key.type = AUTH_3D_KEY_LINEAR;
break;
case A3DA_KEY_HERMITE:
default:
morph_opt_key.type = AUTH_3D_KEY_HERMITE;
break;
}
size_t length = morph_opt.size();
if (length > 1) {
morph_opt_key.keys_vec.assign(morph_opt.begin(), morph_opt.end());
morph_opt_key.length = length;
morph_opt_key.keys = morph_opt_key.keys_vec.data();
kft3* first_key = &morph_opt_key.keys[0];
kft3* last_key = &morph_opt_key.keys[length - 1];
if (first_key->frame < last_key->frame
&& last_key->frame > 0.0f && morph_opt_key.max_frame > first_key->frame) {
morph_opt_key.frame_delta = last_key->frame - first_key->frame;
morph_opt_key.value_delta = last_key->value - first_key->value;
}
}
else if (length == 1) {
float_t value = morph_opt.front().value;
morph_opt_key.type = value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
morph_opt_key.value = value;
}
else {
morph_opt_key.type = AUTH_3D_KEY_NONE;
morph_opt_key.value = 0.0f;
}
}
material_list_color* color_data = color.data();
material_list_color* color_opt_data = color_opt.data();
const float_t reverse_bias = 0.0001f;
for (size_t i = 0; i < count; i++) {
float_t morph = morph_key.interpolate((float_t)(int64_t)i);
float_t morph_opt = morph_opt_key.interpolate((float_t)(int64_t)i);
int32_t morph_int = (int32_t)morph;
int32_t morph_int_opt = (int32_t)morph_opt;
morph = fmodf(morph, 1.0f);
morph_opt = fmodf(morph_opt, 1.0f);
vec4 v_first = vec4::abs(
(morph == 0.0f ? color_data[morph_int].first
: vec4::lerp(color_data[morph_int].first,
color_data[morph_int + 1].first, morph))
- (morph_opt == 0.0f ? color_opt_data[morph_int_opt].first
: vec4::lerp(color_opt_data[morph_int_opt].first,
color_opt_data[morph_int_opt + 1].first, morph_opt)));
vec4 v_second = vec4::abs(
(morph == 0.0f ? color_data[morph_int].second
: vec4::lerp(color_data[morph_int].second,
color_data[morph_int + 1].second, morph))
- (morph_opt == 0.0f ? color_opt_data[morph_int_opt].second
: vec4::lerp(color_opt_data[morph_int_opt].second,
color_opt_data[morph_int_opt + 1].second, morph_opt)));
if (v_first.x > reverse_bias
|| v_first.y > reverse_bias
|| v_first.z > reverse_bias
|| v_first.w > reverse_bias
|| v_second.x > reverse_bias
|| v_second.y > reverse_bias
|| v_second.z > reverse_bias
|| v_second.w > reverse_bias) {
printf_debug("");
return false;
}
}
return true;
}
static void x_pv_game_split_auth_3d_material_list(auth_3d_material_list& ml,
float_t play_control_size, material_list_data& data, vec4 emission, bool fast = false) {
if (!ml.blend_color.flags && !ml.emission.flags) {
data.type = 0;
return;
}
data.has_color_r = (ml.blend_color.flags | ml.emission.flags) & AUTH_3D_RGBA_R ? 1 : 0;
data.has_color_g = (ml.blend_color.flags | ml.emission.flags) & AUTH_3D_RGBA_G ? 1 : 0;
data.has_color_b = (ml.blend_color.flags | ml.emission.flags) & AUTH_3D_RGBA_B ? 1 : 0;
data.has_color_a = (ml.blend_color.flags | ml.emission.flags) & AUTH_3D_RGBA_A ? 1 : 0;
bool has_data[8];
has_data[0] = (ml.blend_color.flags & AUTH_3D_RGBA_R)
&& ml.blend_color.r.type >= AUTH_3D_KEY_LINEAR && ml.blend_color.r.type <= AUTH_3D_KEY_HOLD;
has_data[1] = (ml.blend_color.flags & AUTH_3D_RGBA_G)
&& ml.blend_color.g.type >= AUTH_3D_KEY_LINEAR && ml.blend_color.g.type <= AUTH_3D_KEY_HOLD;
has_data[2] = (ml.blend_color.flags & AUTH_3D_RGBA_B)
&& ml.blend_color.b.type >= AUTH_3D_KEY_LINEAR && ml.blend_color.b.type <= AUTH_3D_KEY_HOLD;
has_data[3] = (ml.blend_color.flags & AUTH_3D_RGBA_A)
&& ml.blend_color.a.type >= AUTH_3D_KEY_LINEAR && ml.blend_color.a.type <= AUTH_3D_KEY_HOLD;
has_data[4] = (ml.emission.flags & AUTH_3D_RGBA_R)
&& ml.emission.r.type >= AUTH_3D_KEY_LINEAR && ml.emission.r.type <= AUTH_3D_KEY_HOLD;
has_data[5] = (ml.emission.flags & AUTH_3D_RGBA_G)
&& ml.emission.g.type >= AUTH_3D_KEY_LINEAR && ml.emission.g.type <= AUTH_3D_KEY_HOLD;
has_data[6] = (ml.emission.flags & AUTH_3D_RGBA_B)
&& ml.emission.b.type >= AUTH_3D_KEY_LINEAR && ml.emission.b.type <= AUTH_3D_KEY_HOLD;
has_data[7] = (ml.emission.flags & AUTH_3D_RGBA_A)
&& ml.emission.a.type >= AUTH_3D_KEY_LINEAR && ml.emission.a.type <= AUTH_3D_KEY_HOLD;
float_t start_time = FLT_MAX;
float_t end_time = FLT_MIN;
auth_3d_ep_type ep_type_post = AUTH_3D_EP_NONE;
auth_3d_key_type type = AUTH_3D_KEY_NONE;
uint64_t hash0 = hash_fnv1a64m_empty;
uint32_t hash1 = hash_murmurhash_empty;
bool same_data = true;
int32_t first_same_data_index = -1;
int32_t count_same_data = 0;
auto check_ep_cycle = [&](auth_3d_key& k, int32_t index) {
type = max_def(k.type, type);
if (!has_data[index])
return;
if (same_data) {
uint64_t _hash0 = hash_fnv1a64m(k.keys_vec.data(), sizeof(kft3) * k.keys_vec.size());
uint32_t _hash1 = hash_murmurhash(k.keys_vec.data(), sizeof(kft3) * k.keys_vec.size(), 0, true);
if (hash0 == hash_fnv1a64m_empty) {
hash0 = _hash0;
hash1 = _hash1;
first_same_data_index = index;
count_same_data = 1;
}
else if (hash0 != _hash0 || hash1 != _hash1) {
same_data = false;
first_same_data_index = -1;
count_same_data = 0;
}
else
count_same_data++;
}
if ((!ep_type_post || ep_type_post == AUTH_3D_EP_CYCLE) && k.ep_type_post == AUTH_3D_EP_CYCLE
&& (start_time == FLT_MAX || start_time == k.keys_vec.front().frame)
&& (end_time == FLT_MIN || end_time == k.keys_vec.back().frame + 1.0f)) {
ep_type_post = AUTH_3D_EP_CYCLE;
start_time = k.keys_vec.front().frame;
end_time = k.keys_vec.back().frame + 1.0f;
if (end_time == k.max_frame) {
ep_type_post = AUTH_3D_EP_NONE;
start_time = 0.0f;
end_time = max_def(end_time, k.max_frame);
}
}
else {
ep_type_post = AUTH_3D_EP_NONE;
start_time = 0.0f;
end_time = max_def(end_time, k.max_frame);
end_time = max_def(end_time, k.keys_vec.back().frame + 1.0f);
}
};
check_ep_cycle(ml.blend_color.r, 0);
check_ep_cycle(ml.blend_color.g, 1);
check_ep_cycle(ml.blend_color.b, 2);
check_ep_cycle(ml.blend_color.a, 3);
check_ep_cycle(ml.emission.r, 4);
check_ep_cycle(ml.emission.g, 5);
check_ep_cycle(ml.emission.b, 6);
check_ep_cycle(ml.emission.a, 7);
if (start_time == FLT_MAX && end_time == FLT_MIN) {
start_time = 0.0f;
end_time = play_control_size;
}
auto set_value = [&](material_list_color& dst, const vec4 src0, const vec4 src1) {
for (int32_t j = 0; j < 4; j++)
(&dst.first.x)[j] = has_data[0 + j] ? (&src0.x)[j] : 1.0f;
for (int32_t j = 0; j < 4; j++)
(&dst.second.x)[j] = has_data[4 + j] ? (&src1.x)[j] : (&emission.x)[j];
};
if (type >= AUTH_3D_KEY_NONE && type <= AUTH_3D_KEY_STATIC) {
ml.blend_color.interpolate(0.0f);
ml.emission.interpolate(0.0f);
material_list_color color;
set_value(color, ml.blend_color.value, ml.emission.value);
data.morph.push_back({ 0, (float_t)(int64_t)data.color.size() });
data.color.push_back(color);
data.type = type;
memcpy(data.has_data, has_data, sizeof(has_data));
return;
}
#pragma warning(suppress: 26451)
size_t count = (size_t)(int64_t)(end_time - start_time);
auto get_max_count = [&](auth_3d_key& k, int32_t index) {
if (ep_type_post || !has_data[index] || k.ep_type_post != AUTH_3D_EP_CYCLE)
return;
size_t _count = (size_t)k.keys_vec.back().frame;
if (_count + 1) {
while (_count + 1 < count)
_count *= 2;
count = _count + 1;
}
};
get_max_count(ml.blend_color.r, 0);
get_max_count(ml.blend_color.g, 1);
get_max_count(ml.blend_color.b, 2);
get_max_count(ml.blend_color.a, 3);
get_max_count(ml.emission.r, 4);
get_max_count(ml.emission.g, 5);
get_max_count(ml.emission.b, 6);
get_max_count(ml.emission.a, 7);
std::vector<material_list_color> values(count);
material_list_color* values_src = values.data();
for (size_t i = 0; i < count; i++) {
ml.blend_color.interpolate(start_time + (float_t)(int64_t)i);
ml.emission.interpolate(start_time + (float_t)(int64_t)i);
set_value(values_src[i], ml.blend_color.value, ml.emission.value);
}
{
material_list_color val = *(material_list_color*)&values_src[0];
material_list_color* arr = (material_list_color*)&values_src[1];
for (size_t i = count - 1; i; i--)
if (val != *arr++)
break;
if (arr == (material_list_color*)(values_src + count)) {
if (values_src[0].first != 0.0f || values_src[0].second != 0.0f) {
data.morph.push_back({ 0, (float_t)(int64_t)data.color.size() });
data.color.push_back(values_src[0]);
data.type = AUTH_3D_KEY_STATIC;
}
else
data.type = AUTH_3D_KEY_NONE;
memcpy(data.has_data, has_data, sizeof(has_data));
return;
}
}
float_t* arr = force_malloc_s(float_t, count);
material_list_color* val = values_src;
const float_t reverse_bias = 0.0001f;
const int32_t reverse_min_count = 4;
float_t* a = arr;
material_list_color* v = val;
size_t left_count = count;
int32_t frame = 0;
int32_t prev_frame = 0;
float_t t2_old = 0.0f;
while (left_count > 0) {
if (left_count < reverse_min_count) {
if (left_count > 1) {
data.morph.push_back({ start_time + (float_t)frame,
(float_t)(int64_t)data.color.size(), t2_old, 0.0f });
data.color.push_back(v[0]);
for (size_t j = 1; j < left_count - 1; j++) {
data.morph.push_back({ start_time + (float_t)(int64_t)(frame + j),
(float_t)(int64_t)data.color.size() });
data.color.push_back(v[j]);
}
t2_old = 0.0f;
}
break;
}
size_t i = 0;
size_t i_prev = 0;
float_t t1 = 0.0f;
float_t t2 = 0.0f;
float_t t1_prev = 0.0f;
float_t t2_prev = 0.0f;
bool has_prev_succeded = false;
bool has_error = false;
bool has_prev_error = false;
int32_t c = 0;
for (i = reverse_min_count - 1, i_prev = i; i < left_count; i++) {
bool constant[8];
bool all_constant = true;
int32_t has_data_count = 0;
for (size_t o = 0; o < 8; o++) {
constant[o] = true;
if (!has_data[o])
continue;
for (size_t j = 1; j <= i; j++)
if (((uint32_t*)&v[0])[o] != ((uint32_t*)&v[j])[o]) {
constant[o] = false;
break;
}
if (!constant[o]) {
all_constant = false;
has_data_count++;
}
}
t1 = 0.0f;
t2 = 0.0f;
if (type == AUTH_3D_KEY_HERMITE) {
float_t start[8];
float_t end[8];
float_t _t1[8];
float_t _t2[8];
*(material_list_color*)start = v[0];
*(material_list_color*)end = v[i];
for (size_t o = 0; o < 8; o++) {
if (!has_data[o] || constant[o])
continue;
float_t scale = fabsf(end[o] - start[o]) > 0.0f ? 1.0f / (end[o] - start[o]) : 0.0f;
float_t offset = -start[o];
for (size_t j = 0; j <= i; j++)
a[j] = (((float_t*)&v[j])[o] - offset) * scale;
if (!fast) {
double_t t1_accum = 0.0;
double_t t2_accum = 0.0;
for (size_t j = 1; j < i - 1; j++) {
float_t t1 = 0.0f;
float_t t2 = 0.0f;
interpolate_chs_reverse_value(a, left_count, t1, t2, 0, i, j);
t1_accum += t1;
t2_accum += t2;
}
_t1[o] = (float_t)(t1_accum / (double_t)(i - 2));
_t2[o] = (float_t)(t2_accum / (double_t)(i - 2));
}
else
interpolate_chs_reverse_value(a, left_count, _t1[o], _t2[o], 0, i, 1);
t1 += _t1[o];
t2 += _t2[o];
}
if (has_data_count) {
t1 /= (float_t)has_data_count;
t2 /= (float_t)has_data_count;
}
has_error = false;
for (size_t j = 1; j < i; j++) {
float_t val = interpolate_chs_value(0.0f, 1.0f, t1, t2, 0.0f, (float_t)i, (float_t)j);
vec4 v_first = vec4::abs(vec4::lerp(v[0].first, v[i].first, val) - v[j].first);
vec4 v_second = vec4::abs(vec4::lerp(v[0].second, v[i].second, val) - v[j].second);
if (val < 0.0f || val > 1.0f
|| has_data[0] && v_first.x > reverse_bias
|| has_data[1] && v_first.y > reverse_bias
|| has_data[2] && v_first.z > reverse_bias
|| has_data[3] && v_first.w > reverse_bias
|| has_data[4] && v_second.x > reverse_bias
|| has_data[5] && v_second.y > reverse_bias
|| has_data[6] && v_second.z > reverse_bias
|| has_data[7] && v_second.w > reverse_bias) {
has_error = true;
break;
}
}
if (fabsf(t1) > 0.5f || fabsf(t2) > 0.5f)
has_error = true;
}
else {
has_error = false;
for (size_t j = 1; j < i; j++) {
float_t val = interpolate_linear_value(0.0f, 1.0f, 0.0f, (float_t)i, (float_t)j);
vec4 v_first = vec4::abs(vec4::lerp(v[0].first, v[i].first, val) - v[j].first);
vec4 v_second = vec4::abs(vec4::lerp(v[0].second, v[i].second, val) - v[j].second);
if (val < 0.0f || val > 1.0f
|| has_data[0] && v_first.x > reverse_bias
|| has_data[1] && v_first.y > reverse_bias
|| has_data[2] && v_first.z > reverse_bias
|| has_data[3] && v_first.w > reverse_bias
|| has_data[4] && v_second.x > reverse_bias
|| has_data[5] && v_second.y > reverse_bias
|| has_data[6] && v_second.z > reverse_bias
|| has_data[7] && v_second.w > reverse_bias) {
has_error = true;
break;
}
}
}
if (!has_error) {
i_prev = i;
t1_prev = t1;
t2_prev = t2;
has_prev_error = false;
has_prev_succeded = true;
if (i < left_count)
continue;
}
if (has_prev_succeded) {
i = i_prev;
t1 = t1_prev;
t2 = t2_prev;
has_error = false;
has_prev_succeded = false;
}
if (!has_error) {
if (all_constant) {
t1 = 0.0f;
t2 = 0.0f;
}
c = (int32_t)i;
data.morph.push_back({ start_time + (float_t)frame,
(float_t)(int64_t)data.color.size(), t2_old, t1 });
data.color.push_back(v[0]);
t2_old = t2;
has_prev_error = false;
break;
}
has_prev_error = true;
}
if (has_prev_succeded) {
if (has_error) {
data.morph.push_back({ start_time + (float_t)frame,
(float_t)(int64_t)data.color.size(), t2_old, 0.0f });
data.color.push_back(v[0]);
for (size_t j = 1; j < c; j++) {
data.morph.push_back({ start_time + (float_t)(frame + j),
(float_t)(int64_t)data.color.size() });
data.color.push_back(v[j]);
}
t2_old = 0.0f;
}
else {
data.morph.push_back({ start_time + (float_t)frame,
(float_t)(int64_t)data.color.size(), t2_old, t1_prev });
data.color.push_back(v[0]);
t2_old = t2_prev;
}
c = (int32_t)i;
}
else if (has_prev_error) {
data.morph.push_back({ start_time + (float_t)frame,
(float_t)(int64_t)data.color.size(), t2_old, 0.0f });
data.color.push_back(v[0]);
t2_old = 0.0f;
c = 1;
}
prev_frame = frame;
frame += c;
a += c;
v += c;
left_count -= c;
}
free_def(arr);
data.morph.push_back({ start_time + (float_t)(int64_t)(count - 1),
(float_t)(int64_t)data.color.size(), t2_old, 0.0f });
data.color.push_back(val[count - 1]);
if (type == AUTH_3D_KEY_HERMITE) {
type = AUTH_3D_KEY_LINEAR;
kft3* keys = data.morph.data();
size_t length = data.morph.size();
for (size_t i = 0; i < count; i++) {
float_t frame = start_time + (float_t)(int64_t)i;
kft3* first_key = keys;
kft3* key = keys;
size_t _length = length;
size_t temp;
while (_length > 0)
if (frame < key[temp = _length / 2].frame)
_length = temp;
else {
key += temp + 1;
_length -= temp + 1;
}
if (key != first_key && key != &first_key[length]) {
float_t l_val = interpolate_linear_value(key[-1].value, key[0].value,
key[-1].frame, key[0].frame, frame);
float_t h_val = interpolate_chs_value(key[-1].value, key[0].value,
key[-1].tangent2, key[0].tangent1,
key[-1].frame, key[0].frame, frame);
if (fabsf(l_val - h_val) > reverse_bias) {
type = AUTH_3D_KEY_HERMITE;
break;
}
}
}
}
data.type = type;
data.cycle = ep_type_post == AUTH_3D_EP_CYCLE;
data.start_time = start_time;
data.end_time = end_time;
memcpy(data.has_data, has_data, sizeof(has_data));
}
#pragma warning(push)
#pragma warning(disable: 6385)
static void x_pv_game_split_auth_3d_material_list(x_pv_game* xpvgm,
std::vector<object_info>& object, std::vector<std::string>& material_list) {
object_database& obj_db = xpvgm->stage_data.obj_db;
prj::vector_pair<auth_3d*, prj::vector_pair<uint32_t, material_list_data>> stage_data_effect_auth_3ds;
prj::vector_pair<auth_3d*, prj::vector_pair<uint32_t, material_list_data>> stage_data_change_effect_auth_3ds;
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = xpvgm->stage_data.effect[i];
for (x_pv_game_stage_effect_auth_3d& j : eff.auth_3d)
if (j.id.check_not_empty() && j.id.check_loaded()) {
auth_3d* auth = j.id.get_auth_3d();
if (auth && auth->material_list.size() && auth->object.size())
stage_data_effect_auth_3ds.push_back(auth, {});
}
}
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = xpvgm->stage_data.change_effect[i][j];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
if (k.id.check_not_empty() && k.id.check_loaded()) {
auth_3d* auth = k.id.get_auth_3d();
if (auth && auth->material_list.size() && auth->object.size())
stage_data_change_effect_auth_3ds.push_back(auth, {});
}
}
stage_data_effect_auth_3ds.sort_unique();
stage_data_change_effect_auth_3ds.sort_unique();
for (auto& i : stage_data_effect_auth_3ds) {
auto elem = stage_data_change_effect_auth_3ds.find(i.first);
if (elem != stage_data_change_effect_auth_3ds.end())
stage_data_change_effect_auth_3ds.erase(elem);
}
prj::vector_pair<uint32_t, material_list_color_data> material_colors;
std::vector<uint32_t> object_set_ids;
auto convert_material_list = [&](auth_3d* auth,
prj::vector_pair<uint32_t, material_list_data>& material_lists) {
printf_debug("%s\n", auth->file_name.c_str());
prj::vector_pair<std::pair<uint32_t, int32_t>, std::pair<bool, bool>> material_shaders;
for (auth_3d_object& i : auth->object) {
obj* obj = object_storage_get_obj(i.object_info);
if (!obj)
continue;
uint32_t material_list_count = 0;
uint32_t material_index = -1;
for (auth_3d_material_list& j : auth->material_list) {
if (!(j.flags & (AUTH_3D_MATERIAL_LIST_BLEND_COLOR | AUTH_3D_MATERIAL_LIST_EMISSION)))
continue;
uint32_t num_material = obj->num_material;
for (uint32_t k = 0; k < num_material; k++) {
obj_material* material = &obj->material_array[k].material;
if (j.name.compare(material->name))
continue;
if (material_list_count)
printf_debug("%s has more than one material_list!\n", obj->name);
else {
material_index = k;
material_shaders.push_back({ {j.hash, material->shader.index}, {
!!material->shader_info.m.is_lgt_diffuse,
!!material->shader_info.m.is_lgt_specular
} });
}
material_list_count++;
break;
}
}
if (material_index == -1)
continue;
uint32_t num_mesh = obj->num_mesh;
for (uint32_t j = 0; j < num_mesh; j++) {
obj_mesh* mesh = obj->mesh_array;
uint32_t num_mesh = obj->num_mesh;
for (uint32_t k = 0; k < num_mesh; k++, mesh++) {
obj_sub_mesh* sub_mesh = mesh->submesh_array;
uint32_t num_submesh = mesh->num_submesh;
uint32_t same_material_count = 0;
for (uint32_t l = 0; l < num_submesh; l++, sub_mesh++) {
if (sub_mesh->material_index != material_index)
continue;
if (same_material_count)
printf_debug("%s's %s has more than one submesh with material %s!\n",
obj->name, mesh->name, obj->material_array[material_index].material.name);
same_material_count++;
}
}
}
}
material_shaders.sort_unique();
material_lists.reserve(auth->material_list.size());
for (auth_3d_material_list& i : auth->material_list) {
if (!(i.flags & (AUTH_3D_MATERIAL_LIST_BLEND_COLOR | AUTH_3D_MATERIAL_LIST_EMISSION)))
continue;
bool found = false;
vec4 emission = 0.0f;
for (auth_3d_object& j : auth->object) {
obj* obj = object_storage_get_obj(j.object_info);
if (!obj)
continue;
uint32_t num_material = obj->num_material;
for (uint32_t k = 0; k < num_material; k++)
if (!i.name.compare(obj->material_array[k].material.name)) {
found = true;
emission = obj->material_array[k].material.color.emission;
object_set_ids.push_back(j.object_info.set_id);
break;
}
}
if (!found)
continue;
material_lists.push_back(i.hash, {});
material_list_data& data = material_lists.back().second;
data.name.assign(i.name);
x_pv_game_split_auth_3d_material_list(i, auth->play_control.size, data, emission);
bool same = data.optimize();
printf_debug(" %c%c%c%c%c%c%c%c %d %32s %08X %3llu %3llu %3llu %3llu%s%s\n",
i.blend_color.flags & AUTH_3D_RGBA_R ? 'R' : ' ',
i.blend_color.flags & AUTH_3D_RGBA_G ? 'G' : ' ',
i.blend_color.flags & AUTH_3D_RGBA_B ? 'B' : ' ',
i.blend_color.flags & AUTH_3D_RGBA_A ? 'A' : ' ',
i.emission.flags & AUTH_3D_RGBA_R ? 'R' : ' ',
i.emission.flags & AUTH_3D_RGBA_G ? 'G' : ' ',
i.emission.flags & AUTH_3D_RGBA_B ? 'B' : ' ',
i.emission.flags & AUTH_3D_RGBA_A ? 'A' : ' ',
data.type, i.name.c_str(), i.hash,
data.color.size(), data.morph.size(),
data.color_opt.size(), data.morph_opt.size(),
data.cycle ? "; Cycle" : "", same ? "" : "; Not same");
auto elem = material_colors.find(i.hash);
if (elem == material_colors.end()) {
material_colors.push_back({ i.hash, {} });
elem = material_colors.end() - 1;
elem->second.name.assign(i.name);
memcpy(elem->second.has_data, data.has_data, sizeof(data.has_data));
}
for (int32_t j = 0; j < 8; j++)
elem->second.has_data[j] |= data.has_data[j];
}
material_colors.sort();
for (auto& i : material_lists) {
auto elem = material_colors.find(i.first);
if (elem == material_colors.end())
continue;
material_list_data& data = i.second;
if (!elem->second.data.size()) {
int32_t k = (int32_t)elem->second.data.size();
for (int32_t& j : data.color_opt_idx)
j = k++;
elem->second.data.insert(elem->second.data.end(),
data.color_opt.begin(), data.color_opt.end());
continue;
}
bool found = false;
const material_list_color* color_data = elem->second.data.data();
size_t color_count = elem->second.data.size();
const material_list_color* color_opt_data = data.color_opt.data();
size_t color_opt_count = data.color_opt.size();
size_t first_temp = -1;
size_t count_temp = -1;
size_t first = -1;
size_t count = -1;
for (size_t j = 0; j < color_count; j++) {
for (size_t k = count_temp != -1 ? count_temp : 0; k < color_opt_count; k++)
if (color_data[j] != color_opt_data[k]
|| first_temp == -1 && k != 0) {
first_temp = -1;
count_temp = -1;
}
else if (first_temp == -1) {
first_temp = j;
count_temp = 1;
break;
}
else {
count_temp++;
break;
}
if (first_temp != -1
&& (first_temp + count_temp >= color_count || count_temp == color_opt_count)
&& (count == -1 || count_temp > count)) {
first = first_temp;
count = count_temp;
}
}
first_temp = -1;
count_temp = -1;
size_t first_reverse = -1;
size_t count_reverse = -1;
for (size_t j = 0; j < color_count; j++) {
for (size_t k = count_temp != -1 ? count_temp : 0; k < color_opt_count; k++)
if (color_data[j] != color_opt_data[color_opt_count - k - 1]
|| first_temp == -1 && k != 0) {
first_temp = -1;
count_temp = -1;
}
else if (first_temp == -1) {
first_temp = j;
count_temp = 1;
break;
}
else {
count_temp++;
break;
}
if (first_temp != -1
&& (first_temp + count_temp >= color_count || count_temp == color_opt_count)
&& (count_reverse == -1 || count_temp > count_reverse)) {
first_reverse = first_temp;
count_reverse = count_temp;
}
}
if (first != -1 && first < first_reverse) {
int32_t k = (int32_t)first;
for (int32_t& j : data.color_opt_idx)
j = k++;
if (first + count >= color_count)
elem->second.data.insert(elem->second.data.begin() + first + 1,
data.color_opt.begin() + count, data.color_opt.end());
}
else if (first_reverse != -1) {
int32_t k = (int32_t)(color_opt_count + first_reverse - 1);
for (int32_t& j : data.color_opt_idx)
j = k--;
if (first_reverse + count_reverse >= color_count)
elem->second.data.insert(elem->second.data.begin() + first_reverse + 1,
data.color_opt.rbegin() + count_reverse, data.color_opt.rend());
}
else {
int32_t k = (int32_t)elem->second.data.size();
for (int32_t& j : data.color_opt_idx)
j = k++;
elem->second.data.insert(elem->second.data.end(),
data.color_opt.begin(), data.color_opt.end());
}
}
};
for (auto& i : stage_data_effect_auth_3ds)
convert_material_list(i.first, i.second);
for (auto& i : stage_data_change_effect_auth_3ds)
convert_material_list(i.first, i.second);
prj::sort_unique(object_set_ids);
for (auto& i : material_colors) {
auto& same_data = i.second.same_data;
for (material_list_color& j : i.second.data) {
std::vector<int32_t>* same_data_indices = 0;
for (auto& k : same_data)
if (k.first == j) {
same_data_indices = &k.second;
break;
}
if (!same_data_indices) {
same_data.push_back({ j, {} });
same_data_indices = &same_data.back().second;
}
same_data_indices->push_back((int32_t)(&j - i.second.data.data()));
}
for (auto& j : same_data)
prj::sort_unique(j.second);
}
std::vector<std::pair<std::string, uint32_t>> material_objects;
for (uint32_t& i : object_set_ids) {
obj_set_handler* handler = object_storage_get_obj_set_handler(i);
if (!handler)
continue;
obj_set* set = handler->obj_set;
uint32_t obj_num_new = 0;
uint32_t obj_num = set->obj_num;
for (uint32_t j = 0; j < obj_num; j++) {
obj* obj = set->obj_data[j];
for (auto& k : material_colors) {
uint32_t material_index = -1;
uint32_t num_material = obj->num_material;
for (uint32_t l = 0; l < num_material; l++)
if (!k.second.name.compare(obj->material_array[l].material.name)) {
material_index = l;
break;
}
if (material_index == -1)
continue;
obj_material* material = &obj->material_array[material_index].material;
uint32_t shader = material->shader.index;
bool* has_data = k.second.has_data;
if ((shader == SHADER_FT_ITEM || shader == SHADER_FT_STAGE)
&& (has_data[4] || has_data[5] || has_data[6] || has_data[7])) {
printf_debug("");
continue;
}
material_objects.push_back({ obj->name, k.first });
obj_num_new += (uint32_t)(k.second.data.size() - 1);
}
}
prj::shared_ptr<prj::stack_allocator>& alloc = handler->alloc_handler;
uint32_t _obj_num = obj_num + obj_num_new;
obj** obj_data = set->obj_data;
obj** obj_data_new = alloc->allocate<::obj*>(_obj_num);
set->obj_data = obj_data_new;
set->obj_num = _obj_num;
obj_vertex_buffer* vertex_buffer_data = handler->vertex_buffer_data;
handler->vertex_buffer_num = _obj_num;
obj_vertex_buffer* vertex_buffer_data_new = new obj_vertex_buffer[_obj_num];
handler->vertex_buffer_data = vertex_buffer_data_new;
obj_index_buffer* index_buffer_data = handler->index_buffer_data;
handler->index_buffer_num = _obj_num;
obj_index_buffer* index_buffer_data_new = new obj_index_buffer[_obj_num];
handler->index_buffer_data = index_buffer_data_new;
for (uint32_t j = 0; j < obj_num; j++, obj_data++, obj_data_new++,
vertex_buffer_data_new++, index_buffer_data_new++) {
*obj_data_new = *obj_data;
bool init_buffer = false;
*vertex_buffer_data_new = vertex_buffer_data[j];
*index_buffer_data_new = index_buffer_data[j];
obj* obj = *obj_data;
for (auto& k : material_colors) {
uint32_t material_index = -1;
uint32_t num_material = obj->num_material;
for (uint32_t l = 0; l < num_material; l++)
if (!k.second.name.compare(obj->material_array[l].material.name)) {
material_index = l;
break;
}
if (material_index == -1)
continue;
obj_material* material = &obj->material_array[material_index].material;
uint32_t shader = material->shader.index;
if (shader == SHADER_FT_BLINN)
if (!material->shader_info.m.is_lgt_diffuse && !material->shader_info.m.is_lgt_specular)
shader = SHADER_FT_CONSTANT;
else if (!material->shader_info.m.is_lgt_specular)
shader = SHADER_FT_LAMBERT;
bool* has_data = k.second.has_data;
if ((shader == SHADER_FT_ITEM || shader == SHADER_FT_STAGE)
&& (has_data[4] || has_data[5] || has_data[6] || has_data[7])) {
printf_debug("");
continue;
}
material->color.emission = 1.0f;
if (!init_buffer) {
vertex_buffer_data_new->unload();
index_buffer_data_new->unload();
init_buffer = true;
}
uint32_t index = 0;
for (auto& l : k.second.data) {
::obj* obj_new = alloc->allocate<::obj>();
obj_new->bounding_sphere = obj->bounding_sphere;
obj_mesh* mesh_array = obj->mesh_array;
uint32_t num_mesh = obj->num_mesh;
obj_mesh* mesh_array_new = alloc->allocate<obj_mesh>(num_mesh);
for (uint32_t m = 0; m < num_mesh; m++) {
obj_mesh* src_mesh = &mesh_array[m];
obj_mesh* dst_mesh = &mesh_array_new[m];
dst_mesh->flags = src_mesh->flags;
dst_mesh->bounding_sphere = src_mesh->bounding_sphere;
obj_sub_mesh* submesh_array = src_mesh->submesh_array;
uint32_t num_submesh = src_mesh->num_submesh;
obj_sub_mesh* submesh_array_new = alloc->allocate<obj_sub_mesh>(num_submesh);
for (uint32_t n = 0; n < num_submesh; n++) {
obj_sub_mesh* src_submesh = &submesh_array[n];
obj_sub_mesh* dst_submesh = &submesh_array_new[n];
dst_submesh->flags = src_submesh->flags;
dst_submesh->bounding_sphere = src_submesh->bounding_sphere;
dst_submesh->material_index = src_submesh->material_index;
memcpy(dst_submesh->uv_index, src_submesh->uv_index, 0x08);
uint32_t num_bone_index = src_submesh->num_bone_index;
dst_submesh->bone_index_array = alloc->allocate<uint16_t>(
src_submesh->bone_index_array, num_bone_index);
dst_submesh->num_bone_index = num_bone_index;
dst_submesh->bones_per_vertex = src_submesh->bones_per_vertex;
dst_submesh->primitive_type = src_submesh->primitive_type;
dst_submesh->index_format = src_submesh->index_format;
uint32_t num_index = src_submesh->num_index;
dst_submesh->index_array = alloc->allocate<uint32_t>(
src_submesh->index_array, num_index);
dst_submesh->num_index = num_index;
dst_submesh->attrib = src_submesh->attrib;
dst_submesh->axis_aligned_bounding_box = src_submesh->axis_aligned_bounding_box;
dst_submesh->first_index = 0;
dst_submesh->last_index = 0;
dst_submesh->index_offset = 0;
}
dst_mesh->submesh_array = submesh_array_new;
dst_mesh->num_submesh = num_submesh;
dst_mesh->vertex_format = src_mesh->vertex_format;
dst_mesh->size_vertex = src_mesh->size_vertex;
uint32_t num_vertex = src_mesh->num_vertex;
dst_mesh->vertex_array = alloc->allocate<obj_vertex_data>(
src_mesh->vertex_array, num_vertex);
dst_mesh->num_vertex = num_vertex;
if (!(dst_mesh->vertex_format & OBJ_VERTEX_COLOR0)) {
enum_or(dst_mesh->vertex_format, OBJ_VERTEX_COLOR0);
obj_vertex_data* vertex_array = dst_mesh->vertex_array;
for (uint32_t n = dst_mesh->num_vertex; n; n--, vertex_array++)
vertex_array->color0 = 1.0f;
}
dst_mesh->attrib = src_mesh->attrib;
memcpy(dst_mesh->reserved, src_mesh->reserved, sizeof(uint32_t) * 6);
memcpy(dst_mesh->name, src_mesh->name, 0x40);
vec4 color_mult = 1.0f;
for (int32_t n = 0; n < 4; n++)
if (has_data[n])
(&color_mult.x)[n] *= (&l.first.x)[n];
switch (shader) {
case SHADER_FT_BLINN:
case SHADER_FT_ITEM:
case SHADER_FT_STAGE:
case SHADER_FT_LAMBERT:
break;
case SHADER_FT_SKY:
case SHADER_FT_CONSTANT:
for (int32_t n = 0; n < 4; n++)
if (has_data[4 + n])
(&color_mult.x)[n] *= (&l.second.x)[n];
break;
}
obj_vertex_data* vertex_array = dst_mesh->vertex_array;
for (uint32_t n = dst_mesh->num_vertex; n; n--, vertex_array++)
vertex_array->color0 *= color_mult;
}
obj_new->mesh_array = mesh_array_new;
obj_new->num_mesh = num_mesh;
uint32_t num_material = obj->num_material;
obj_new->material_array = alloc->allocate<obj_material_data>(obj->material_array, num_material);
obj_new->num_material = num_material;
obj_new->flags = obj->flags;
char buf[0x100];
sprintf_s(buf, sizeof(buf), "%s_%03d", obj->name, index);
obj_new->name = alloc->allocate<char>(buf, utf8_length(buf) + 1);
uint32_t hash = hash_string_murmurhash(buf);
obj_new->id = hash;
obj_new->hash = hash;
*obj_data_new++ = obj_new;
vertex_buffer_data_new++->load(obj_new);
index_buffer_data_new++->load(obj_new);
index++;
object_set_info* set_info = (object_set_info*)obj_db.get_object_set_info(i);
if (set_info) {
object_info_data* info = (object_info_data*)obj_db.get_object_info_data_by_murmurhash(hash);
if (!info) {
set_info->object.push_back({});
info = &set_info->object.back();
info->id = hash;
info->name.assign(obj_new->name);
info->name_hash_fnv1a64m = hash_string_fnv1a64m(info->name);
info->name_hash_fnv1a64m_upper = hash_string_fnv1a64m(info->name, true);
info->name_hash_murmurhash = hash_string_murmurhash(info->name);
}
}
}
obj_data_new--;
vertex_buffer_data_new--;
index_buffer_data_new--;
break;
}
}
obj_db.update();
delete[] vertex_buffer_data;
delete[] index_buffer_data;
obj_data = set->obj_data;
handler->obj_id_data.clear();
handler->obj_id_data.reserve(_obj_num);
for (uint32_t j = 0; j < _obj_num; j++)
handler->obj_id_data.push_back(obj_data[j]->id, j);
}
for (uint32_t& i : object_set_ids) {
obj_set_handler* handler = object_storage_get_obj_set_handler(i);
if (!handler)
continue;
x_pv_game_split_auth_3d_update_object_set(handler);
x_pv_game_split_auth_3d_write_object_set(handler);
}
prj::sort(material_objects);
typedef std::pair<float_t, float_t> morph_index_pair;
struct morph_indices {
morph_index_pair effect[X_PV_GAME_STAGE_EFFECT_COUNT];
morph_index_pair change_effect
[X_PV_GAME_STAGE_EFFECT_COUNT][X_PV_GAME_STAGE_EFFECT_COUNT];
inline morph_indices() {
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
effect[i] = { -1.0f, -1.0f };
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++)
change_effect[i][j] = { -1.0f, -1.0f };
}
};
std::vector<morph_indices> morph_indices_data;
morph_indices_data.resize(material_objects.size());
auto replace_material_list = [&](auth_3d* auth,
prj::vector_pair<uint32_t, material_list_data>& material_lists) {
auth->material_list.clear();
auth->material_list.shrink_to_fit();
auto get_index_pair = [&](size_t index) {
auto& morph_indices = morph_indices_data[index];
x_pv_game_stage& stage = xpvgm->stage_data;
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = stage.effect[i];
for (x_pv_game_stage_effect_auth_3d& j : eff.auth_3d)
if (auth == j.id.get_auth_3d())
return &morph_indices.effect[i];
}
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = stage.change_effect[i][j];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
if (auth == k.id.get_auth_3d())
return &morph_indices.change_effect[i][j];
}
return (morph_index_pair*)0;
};
for (auto& i : material_objects) {
morph_index_pair* index_pair = get_index_pair(&i - material_objects.data());
if (!index_pair)
continue;
for (auth_3d_object& j : auth->object)
if (!i.first.compare(j.uid_name)) {
*index_pair = { -2.0f, -2.0f };
break;
}
}
if (!material_lists.size())
return;
for (auto& i : material_lists) {
for (auto& j : material_objects) {
if (i.first != j.second)
continue;
auth_3d_object* object = 0;
for (auth_3d_object& k : auth->object)
if (!j.first.compare(k.uid_name)) {
object = &k;
break;
}
if (!object)
continue;
material_list_data& data = i.second;
object->uid_name.append("_000");
object->object_info = obj_db.get_object_info(object->name.c_str());
object->object_hash = object->object_info.id;
auth_3d_object_curve& morph = object->morph;
morph.name.assign(data.name);
morph.frame_offset = 0;
auth->curve.push_back({});
auth_3d_curve& curve = auth->curve.back();
auth_3d_key* ex_key = 0;
for (auth_3d_curve& k : auth->curve)
if (!morph.name.compare(k.name)) {
ex_key = &k.curve;
break;
}
curve.name.assign(data.name);
auth_3d_key& key = curve.curve;
key.max_frame = auth->max_frame;
key.frame_delta = key.max_frame;
key.value_delta = 0.0f;
bool desc = data.color_opt_idx.front() > data.color_opt_idx.back();
auto replace_value = [&](float_t value) {
if (desc)
return (float_t)data.color_opt_idx[(int64_t)value] - fmodf(value, 1.0f);
else
return (float_t)data.color_opt_idx[(int64_t)value] + fmodf(value, 1.0f);
};
morph_index_pair* index_pair = get_index_pair(&j - material_objects.data());
switch (data.type) {
case AUTH_3D_KEY_NONE:
key.type = AUTH_3D_KEY_NONE;
key.value = 0.0f;
if (index_pair)
*index_pair = { 0.0f, 0.0f };
continue;
case AUTH_3D_KEY_STATIC:
key.value = replace_value(data.morph_opt.front().value);
key.type = key.value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
if (index_pair)
*index_pair = { key.value, key.value };
continue;
case AUTH_3D_KEY_LINEAR:
key.type = AUTH_3D_KEY_LINEAR;
break;
case AUTH_3D_KEY_HERMITE:
default:
key.type = AUTH_3D_KEY_HERMITE;
break;
}
size_t length = data.morph_opt.size();
if (length > 1) {
key.keys_vec.assign(data.morph_opt.begin(), data.morph_opt.end());
for (kft3& k : key.keys_vec)
k.value = replace_value(k.value);
key.length = length;
key.keys = key.keys_vec.data();
kft3* first_key = &key.keys[0];
kft3* last_key = &key.keys[length - 1];
if (first_key->frame < last_key->frame
&& last_key->frame > 0.0f && key.max_frame > first_key->frame) {
key.ep_type_post = data.cycle ? AUTH_3D_EP_CYCLE : AUTH_3D_EP_NONE;
key.frame_delta = last_key->frame - first_key->frame;
key.value_delta = last_key->value - first_key->value;
}
if (index_pair)
*index_pair = { first_key->value, last_key->value };
}
else if (length == 1) {
key.value = replace_value(data.morph_opt.front().value);
key.type = key.value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
if (index_pair)
*index_pair = { key.value, key.value };
}
else {
key.type = AUTH_3D_KEY_NONE;
key.value = 0.0f;
if (index_pair)
*index_pair = { 0.0f, 0.0f };
}
if (ex_key)
if (ex_key->type != key.type
|| ex_key->value != key.value
|| ex_key->max_frame != key.max_frame
|| ex_key->ep_type_pre != key.ep_type_pre
|| ex_key->ep_type_post != key.ep_type_post
|| ex_key->frame_delta != key.frame_delta
|| ex_key->value_delta != key.value_delta
|| ex_key->length != key.length
|| memcmp(ex_key->keys_vec.data(), key.keys_vec.data(), sizeof(kft3) * key.length))
printf_debug("");
else
auth->curve.pop_back();
}
}
};
for (auto& i : stage_data_effect_auth_3ds)
replace_material_list(i.first, i.second);
for (auto& i : stage_data_change_effect_auth_3ds)
replace_material_list(i.first, i.second);
for (auto& i : morph_indices_data) {
auto& material_object = material_objects[&i - morph_indices_data.data()];
auto write_morph = [&](auth_3d* auth, float_t morph_value) {
auth_3d_object* object = 0;
for (auth_3d_object& k : auth->object)
if (!material_object.first.compare(k.uid_name)) {
object = &k;
break;
}
if (!object)
return;;
auto elem = material_colors.find(material_object.second);
if (elem == material_colors.end())
return;
object->uid_name.append("_000");
object->object_info = obj_db.get_object_info(object->name.c_str());
object->object_hash = object->object_info.id;
auth_3d_object_curve& morph = object->morph;
morph.name.assign(elem->second.name);
morph.frame_offset = 0;
auth->curve.push_back({});
auth_3d_curve& curve = auth->curve.back();
auth_3d_key* ex_key = 0;
for (auth_3d_curve& k : auth->curve)
if (!morph.name.compare(k.name)) {
ex_key = &k.curve;
break;
}
curve.name.assign(elem->second.name);
auth_3d_key& key = curve.curve;
key.max_frame = auth->max_frame;
key.frame_delta = key.max_frame;
key.value_delta = 0.0f;
key.value = morph_value;
key.type = key.value != 0.0f ? AUTH_3D_KEY_STATIC : AUTH_3D_KEY_NONE;
if (ex_key)
if (ex_key->type != key.type
|| ex_key->value != key.value
|| ex_key->max_frame != key.max_frame
|| ex_key->ep_type_pre != key.ep_type_pre
|| ex_key->ep_type_post != key.ep_type_post
|| ex_key->frame_delta != key.frame_delta
|| ex_key->value_delta != key.value_delta
|| ex_key->length != key.length
|| memcmp(ex_key->keys_vec.data(), key.keys_vec.data(), sizeof(kft3) * key.length))
printf_debug("");
else
auth->curve.pop_back();
};
x_pv_game_stage& stage = xpvgm->stage_data;
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
if (i.effect[j].first != -2.0f)
continue;
float_t morph_value = -1.0f;
for (int32_t k = 0; k < X_PV_GAME_STAGE_EFFECT_COUNT; k++)
if (i.change_effect[k][j].first >= 0.0f) {
morph_value = i.change_effect[k][j].second;
break;
}
else if (i.change_effect[j][k].first >= 0.0f) {
morph_value = i.change_effect[j][k].first;
break;
}
else if (j != k && i.effect[k].first >= 0.0f) {
morph_value = i.effect[k].first;
break;
}
if (morph_value == -1.0f)
continue;
x_pv_game_stage_effect& eff = stage.effect[j];
for (x_pv_game_stage_effect_auth_3d& k : eff.auth_3d)
write_morph(k.id.get_auth_3d(), morph_value);
}
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++)
for (int32_t k = 0; k < X_PV_GAME_STAGE_EFFECT_COUNT; k++) {
if (i.change_effect[j][k].first != -2.0f)
continue;
float_t morph_value = -1.0f;
if (i.effect[j].second >= 0.0f)
morph_value = i.effect[j].second;
else if (i.effect[k].first >= 0.0f)
morph_value = i.effect[k].first;
if (morph_value == -1.0f)
continue;
x_pv_game_stage_change_effect& chg_eff = stage.change_effect[j][k];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
write_morph(k.id.get_auth_3d(), morph_value);
}
}
auto fix_object_morphs = [&](auth_3d* auth) {
for (auth_3d_curve& i : auth->curve)
if (i.curve.keys_vec.size() > 1)
i.curve.keys = i.curve.keys_vec.data();
for (auth_3d_object& i : auth->object) {
auth_3d_object_curve& morph = i.morph;
if (!morph.name.size())
continue;
morph.curve = 0;
morph.value = 0.0f;
for (auth_3d_curve& i : auth->curve)
if (!morph.name.compare(i.name)) {
morph.curve = &i;
break;
}
}
};
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++) {
x_pv_game_stage_effect& eff = xpvgm->stage_data.effect[i];
for (x_pv_game_stage_effect_auth_3d& j : eff.auth_3d)
fix_object_morphs(j.id.get_auth_3d());
}
for (int32_t i = 0; i < X_PV_GAME_STAGE_EFFECT_COUNT; i++)
for (int32_t j = 0; j < X_PV_GAME_STAGE_EFFECT_COUNT; j++) {
x_pv_game_stage_change_effect& chg_eff = xpvgm->stage_data.change_effect[i][j];
for (x_pv_game_stage_effect_auth_3d& k : chg_eff.auth_3d)
fix_object_morphs(k.id.get_auth_3d());
}
}
#pragma warning(pop)
static void pv_game_dsc_data_find_playdata_item_anim(x_pv_game* xpvgm, int32_t chara_id) {
if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
return;
x_pv_play_data* playdata = &xpvgm->playdata[chara_id];
playdata->motion_data.set_item.clear();
int32_t pv_branch_mode = 0;
int32_t time = -1;
int32_t prev_time = -1;
x_pv_game_dsc_data& dsc_data = xpvgm->pv_data[xpvgm->pv_index].dsc_data;
::dsc_data* i = dsc_data.dsc.data.data();
::dsc_data* i_end = dsc_data.dsc.data.data() + dsc_data.dsc.data.size();
while (true) {
i = dsc_data.find(DSC_X_ITEM_ANIM, &time, &pv_branch_mode, i, i_end);
if (!i)
break;
if (time < 0) {
time = prev_time;
if (prev_time < 0)
break;
}
uint32_t* data = dsc_data.dsc.get_func_data(i);
if (chara_id == data[0] && data[2] == 2) {
x_dsc_set_item item;
item.item_index = data[1];
item.time = time;
item.pv_branch_mode = pv_branch_mode;
playdata->motion_data.set_item.push_back(item);
}
prev_time = time;
i++;
}
}
static void pv_game_dsc_data_find_playdata_set_motion(x_pv_game* xpvgm, int32_t chara_id) {
if (chara_id < 0 || chara_id >= ROB_CHARA_COUNT)
return;
x_pv_play_data* playdata = &xpvgm->playdata[chara_id];
playdata->motion_data.set_motion.clear();
int32_t pv_branch_mode = 0;
int32_t time = -1;
int32_t prev_time = -1;
x_pv_game_dsc_data& dsc_data = xpvgm->pv_data[xpvgm->pv_index].dsc_data;
::dsc_data* i = dsc_data.dsc.data.data();
::dsc_data* i_end = dsc_data.dsc.data.data() + dsc_data.dsc.data.size();
while (true) {
i = dsc_data.find(DSC_X_SET_MOTION, &time, &pv_branch_mode, i, i_end);
if (!i)
break;
if (time < 0) {
time = prev_time;
if (prev_time < 0)
break;
}
uint32_t* data = dsc_data.dsc.get_func_data(i);
if (chara_id == data[0]) {
x_dsc_set_motion motion;
motion.motion_index = data[1];
motion.time = time;
motion.pv_branch_mode = pv_branch_mode;
playdata->motion_data.set_motion.push_back(motion);
}
prev_time = time;
i++;
}
}
static void pv_game_dsc_data_find_set_motion(x_pv_game* xpvgm) {
for (std::vector<pv_data_set_motion>& i : xpvgm->set_motion)
i.clear();
std::vector<x_dsc_set_motion> v98[6];
int32_t pv_branch_mode = 0;
int32_t time = -1;
int32_t prev_time = -1;
x_pv_game_dsc_data& dsc_data = xpvgm->pv_data[xpvgm->pv_index].dsc_data;
::dsc_data* i = dsc_data.dsc.data.data();
::dsc_data* i_end = dsc_data.dsc.data.data() + dsc_data.dsc.data.size();
while (true) {
i = dsc_data.find(DSC_X_SET_PLAYDATA, &time, &pv_branch_mode, i, i_end);
if (!i)
break;
if (time < 0)
time = prev_time;
uint32_t* data = dsc_data.dsc.get_func_data(i);
int32_t chara_id = (int32_t)data[0];
int32_t motion_index = (int32_t)data[1];
v98[chara_id].push_back({ time, motion_index, pv_branch_mode });
prev_time = time;
i++;
}
pv_branch_mode = 0;
time = -1;
prev_time = -1;
i = dsc_data.dsc.data.data();
i_end = dsc_data.dsc.data.data() + dsc_data.dsc.data.size();
while (true) {
i = dsc_data.find(DSC_X_CHANGE_FIELD, &time, &pv_branch_mode, i, i_end);
if (!i)
break;
if (time < 0)
time = prev_time;
prev_time = time;
i++;
}
data_struct* aft_data = &data_list[DATA_AFT];
motion_database* aft_mot_db = &aft_data->data_ft.mot_db;
pvpp* play_param = xpvgm->pv_data[xpvgm->pv_index].play_param;
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) {
x_pv_play_data& playdata = xpvgm->playdata[i];
std::vector<pv_data_set_motion>& set_motion = xpvgm->set_motion[i];
for (x_dsc_set_motion& j : playdata.motion_data.set_motion) {
int32_t time = -1;
int32_t v56 = 0;
x_dsc_set_motion* i_begin = v98[i].data() + v98[i].size();
x_dsc_set_motion* i_end = v98[i].data();
for (x_dsc_set_motion* i = i_begin; i != i_end; ) {
i--;
if (i->motion_index == j.motion_index && i->time <= j.time) {
time = i->time;
break;
}
}
if (time < 0)
time = j.time;
float_t frame = dsc_time_to_frame(((int64_t)j.time - time) * 10000);
float_t v61 = frame;
if (frame >= 0.0f)
v61 = frame + 0.5f;
else
v61 = frame - 0.5f;
int32_t frame_int = (int32_t)v61;
if (v61 != -0.0f && (float_t)frame_int != v61)
v61 = (float_t)(v61 < 0.0f ? frame_int - 1 : frame_int);
uint32_t motion_id = -1;
if (i >= 0 && i < play_param->chara.size()) {
pvpp_chara& chara = play_param->chara[i];
if (j.motion_index > 0 && j.motion_index <= chara.motion.size()) {
string_hash& motion = chara.motion[(size_t)j.motion_index - 1];
motion_id = aft_mot_db->get_motion_id(motion.c_str());
}
}
if (motion_id != -1)
set_motion.push_back({ motion_id, { v61, -1 } });
}
}
for (int32_t i = 0; i < ROB_CHARA_COUNT; i++) {
if (i < 0 || i >= play_param->chara.size())
continue;
rob_chara* rob_chr = rob_chara_array_get(i);
int32_t pv_id = xpvgm->pv_data[xpvgm->pv_index].pv_id;
std::vector<pv_data_set_motion>& set_motion = xpvgm->set_motion[i];
std::vector<osage_init_data> vec;
vec.reserve(set_motion.size());
for (pv_data_set_motion& j : set_motion) {
osage_init_data osage_init;
osage_init.rob_chr = rob_chr;
osage_init.pv_id = pv_id;
osage_init.motion_id = j.motion_id;
osage_init.frame = (int32_t)j.frame_stage_index.first;
vec.push_back(osage_init);
}
skin_param_manager_add_task(i, vec);
}
}
static void pv_game_dsc_data_set_motion_max_frame(x_pv_game* xpvgm,
int32_t chara_id, int32_t motion_index, int64_t disp_time) {
if (chara_id < 0 || chara_id > ROB_CHARA_COUNT || motion_index < 0)
return;
x_pv_play_data* playdata = &xpvgm->playdata[chara_id];
int64_t dsc_time = xpvgm->pv_data[xpvgm->pv_index].dsc_data.time;
for (x_dsc_set_motion& i : playdata->motion_data.set_motion) {
int64_t time = (int64_t)i.time * 10000;
if (time > dsc_time && i.motion_index == motion_index
&& (!xpvgm->branch_mode || xpvgm->branch_mode == i.pv_branch_mode)) {
playdata->rob_chr->bone_data->set_motion_max_frame(
roundf(dsc_time_to_frame(time - disp_time)) - 1.0f);
break;
}
}
}
#endif