From 773cce03ebe3a7e9059b3e7bc1dbed793bf763bc Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 1 Oct 2022 09:27:10 +0900 Subject: [PATCH] ReignEngine: Implement camera quake effect --- include/reign.h | 3 +++ src/3d/3d_internal.h | 4 ++-- src/3d/particle.c | 27 ++++++++++++++++++++++++++- src/3d/reign.c | 15 +++++++++++++++ src/3d/renderer.c | 7 ++++--- src/hll/ReignEngine.c | 20 ++++++++++++++------ 6 files changed, 64 insertions(+), 12 deletions(-) diff --git a/include/reign.h b/include/reign.h index 184b9fd..c4326ed 100644 --- a/include/reign.h +++ b/include/reign.h @@ -55,6 +55,7 @@ extern struct RE_options RE_options; struct RE_camera { vec3 pos; float pitch, roll, yaw; // in degrees + float quake_pitch, quake_yaw; }; struct RE_back_cg { @@ -183,6 +184,8 @@ bool RE_motion_set_frame_range(struct motion *motion, float begin, float end); bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float end); int RE_effect_get_num_object(struct particle_effect *effect); +bool RE_effect_get_camera_quake_flag(struct particle_effect *effect); +bool RE_effect_set_camera_quake_flag(struct particle_effect *effect, bool enable); struct particle_object *RE_get_effect_object(struct particle_effect *effect, unsigned object); int RE_particle_get_type(struct particle_object *po); int RE_particle_get_move_type(struct particle_object *po); diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index cb2325a..e93aeaf 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -190,7 +190,7 @@ enum particle_type { PARTICLE_TYPE_BILLBOARD = 0, PARTICLE_TYPE_POLYGON_OBJECT = 1, PARTICLE_TYPE_SWORD_BLUR = 2, - PARTICLE_TYPE_CAMERA_VIBRATION = 3, + PARTICLE_TYPE_CAMERA_QUAKE = 3, }; enum particle_move_type { @@ -331,9 +331,9 @@ struct particle_instance { struct particle_effect { char *path; struct hash_table *textures; // name -> struct billboard_texture* - int nr_objects; struct particle_object *objects; + bool camera_quake_enabled; }; struct particle_effect *particle_effect_load(struct archive *aar, const char *path); diff --git a/src/3d/particle.c b/src/3d/particle.c index 7c3d625..9f39009 100644 --- a/src/3d/particle.c +++ b/src/3d/particle.c @@ -46,7 +46,7 @@ static enum particle_type parse_particle_type(const char *s) else if (!strcmp(s, "剣ブラー")) return PARTICLE_TYPE_SWORD_BLUR; else if (!strcmp(s, "カメラ振動")) - return PARTICLE_TYPE_CAMERA_VIBRATION; + return PARTICLE_TYPE_CAMERA_QUAKE; WARNING("unknown object type \"%s\"", s); return (enum particle_type)-1; } @@ -663,6 +663,7 @@ struct particle_effect *particle_effect_load(struct archive *aar, const char *pa archive_free_data(dfile); effect->path = strdup(path); + effect->camera_quake_enabled = true; load_textures(effect, aar); for (int i = 0; i < effect->nr_objects; i++) { struct particle_object *po = &effect->objects[i]; @@ -744,6 +745,25 @@ void particle_effect_calc_frame_range(struct particle_effect *effect, struct mot motion->frame_end = end_frame; } +static void update_camera_quake(struct RE_instance *inst, struct particle_object *po) +{ + float frame = inst->motion->current_frame - po->begin_frame; + float total_frames = po->end_frame - po->begin_frame; + if (frame < 0 || frame >= total_frames) + return; + + const float ease_in_duration = 4.0f; + const float ease_out_duration = 4.0f; + float amplitude = 1.0f; + if (total_frames - frame < ease_out_duration) + amplitude *= (total_frames - frame) / ease_out_duration; + else if (frame < ease_in_duration) + amplitude *= frame / ease_in_duration; + + inst->plugin->camera.quake_pitch = sinf(frame * 1.1) * amplitude * -8.0f; + inst->plugin->camera.quake_yaw = sinf(frame * 1.7) * amplitude * 12.0f; +} + void particle_effect_update(struct RE_instance *inst) { struct particle_effect *effect = inst->effect; @@ -751,6 +771,11 @@ void particle_effect_update(struct RE_instance *inst) return; for (int i = 0; i < effect->nr_objects; i++) { struct particle_object *po = &effect->objects[i]; + if (po->type == PARTICLE_TYPE_CAMERA_QUAKE) { + if (effect->camera_quake_enabled) + update_camera_quake(inst, po); + continue; + } // These cannot be precomputed, because they may depend on the target's // *current* bone matrix. eval_pos_for_object(inst, po->position[0], po->pos.begin); diff --git a/src/3d/reign.c b/src/3d/reign.c index ba6aeb8..b3e5d8a 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -236,6 +236,8 @@ bool RE_build_model(struct RE_plugin *plugin, int elapsed_ms) if (!plugin) return false; + plugin->camera.quake_pitch = plugin->camera.quake_yaw = 0.0; + for (int i = 0; i < plugin->nr_instances; i++) { struct RE_instance *inst = plugin->instances[i]; if (!inst) @@ -521,6 +523,19 @@ int RE_effect_get_num_object(struct particle_effect *effect) return effect ? effect->nr_objects : 0; } +bool RE_effect_get_camera_quake_flag(struct particle_effect *effect) +{ + return effect && effect->camera_quake_enabled; +} + +bool RE_effect_set_camera_quake_flag(struct particle_effect *effect, bool enable) +{ + if (!effect) + return false; + effect->camera_quake_enabled = enable; + return true; +} + struct particle_object *RE_get_effect_object(struct particle_effect *effect, unsigned object) { if (!effect || object >= (unsigned)effect->nr_objects) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 88885d3..7c2c956 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -259,8 +259,8 @@ void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out) { vec3 front = { 0.0, 0.0, -1.0 }; vec3 euler = { - glm_rad(camera->pitch), - glm_rad(camera->yaw), + glm_rad(camera->pitch + camera->quake_pitch), + glm_rad(camera->yaw + camera->quake_yaw), glm_rad(camera->roll) }; mat4 rot; @@ -538,7 +538,8 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer case PARTICLE_TYPE_POLYGON_OBJECT: render_polygon_particles(r, inst, po, inst->motion->current_frame); break; - case PARTICLE_TYPE_SWORD_BLUR: // unused + case PARTICLE_TYPE_SWORD_BLUR: // unused + case PARTICLE_TYPE_CAMERA_QUAKE: // handled in particle_effect_update() break; } } diff --git a/src/hll/ReignEngine.c b/src/hll/ReignEngine.c index 4bf8a93..e2836b7 100644 --- a/src/hll/ReignEngine.c +++ b/src/hll/ReignEngine.c @@ -1022,10 +1022,18 @@ static float ReignEngine_GetEffectObjectOffsetY(int plugin, int instance, int ob //bool ReignEngine_SetEffectObjectOffsetX(int plugin, int instance, int nObject, float fOffsetX); //bool ReignEngine_SetEffectObjectOffsetY(int plugin, int instance, int nObject, float fOffsetY); -HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, GetCameraQuakeEffectFlag, int plugin, int instance); -HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetCameraQuakeEffectFlag, int plugin, int instance, bool flag); -bool ReignEngine_SetCameraPos(int plugin, float x, float y, float z) +static bool ReignEngine_GetCameraQuakeEffectFlag(int plugin, int instance) +{ + return RE_effect_get_camera_quake_flag(get_effect(plugin, instance)); +} + +static bool ReignEngine_SetCameraQuakeEffectFlag(int plugin, int instance, bool flag) +{ + return RE_effect_set_camera_quake_flag(get_effect(plugin, instance), flag); +} + +static bool ReignEngine_SetCameraPos(int plugin, float x, float y, float z) { struct RE_plugin *p = get_plugin(plugin); if (!p) @@ -1036,7 +1044,7 @@ bool ReignEngine_SetCameraPos(int plugin, float x, float y, float z) return true; } -bool ReignEngine_SetCameraAngle(int plugin, float angle) +static bool ReignEngine_SetCameraAngle(int plugin, float angle) { struct RE_plugin *p = get_plugin(plugin); if (!p) @@ -1045,7 +1053,7 @@ bool ReignEngine_SetCameraAngle(int plugin, float angle) return true; } -bool ReignEngine_SetCameraAngleP(int plugin, float angle_p) +static bool ReignEngine_SetCameraAngleP(int plugin, float angle_p) { struct RE_plugin *p = get_plugin(plugin); if (!p) @@ -1054,7 +1062,7 @@ bool ReignEngine_SetCameraAngleP(int plugin, float angle_p) return true; } -bool ReignEngine_SetCameraAngleB(int plugin, float angle_b) +static bool ReignEngine_SetCameraAngleB(int plugin, float angle_b) { struct RE_plugin *p = get_plugin(plugin); if (!p)