Implement ReignEngine.BuildModel

Instance motions are updated with this function.
This commit is contained in:
kichikuou
2022-07-17 16:20:02 +09:00
parent b1f3e85c4d
commit 3343efbcb9
5 changed files with 94 additions and 90 deletions
+1
View File
@@ -131,6 +131,7 @@ struct RE_plugin *RE_plugin_new(void);
void RE_plugin_free(struct RE_plugin *plugin);
bool RE_plugin_bind(struct RE_plugin *plugin, int sprite);
bool RE_plugin_unbind(struct RE_plugin *plugin);
bool RE_build_model(struct RE_plugin *plugin, int elapsed_ms);
bool RE_set_projection(struct RE_plugin *plugin, float width, float height, float near, float far, float deg);
int RE_create_instance(struct RE_plugin *plugin);
bool RE_release_instance(struct RE_plugin *plugin, int instance);
-2
View File
@@ -112,11 +112,9 @@ struct RE_renderer {
GLint vertex_bone_index;
GLint vertex_bone_weight;
mat4 bone_transforms[MAX_BONES];
GLuint billboard_vao;
GLuint billboard_attr_buffer;
struct hash_table *billboard_textures; // cg_no -> struct billboard_texture*
uint32_t last_frame_timestamp;
};
struct billboard_texture {
+83
View File
@@ -30,6 +30,7 @@
#include "asset_manager.h"
#include "reign.h"
#include "sact.h"
#include "vm.h"
#include "xsystem4.h"
static struct RE_instance *create_instance(struct RE_plugin *plugin)
@@ -86,6 +87,74 @@ static void RE_back_cg_destroy(struct RE_back_cg *bcg)
free_string(bcg->name);
}
static void interpolate_motion_frame(struct mot_frame *m1, struct mot_frame *m2, float t, struct mot_frame *out)
{
glm_vec3_lerp(m1->pos, m2->pos, t, out->pos);
glm_quat_nlerp(m1->rotq, m2->rotq, t, out->rotq);
}
static void update_motion(struct motion *m, float delta_frame)
{
if (!m || m->state == RE_MOTION_STATE_STOP)
return;
m->current_frame += delta_frame;
switch (m->state) {
case RE_MOTION_STATE_NOLOOP:
if (m->current_frame > m->frame_end) {
m->current_frame = m->frame_end;
m->state = RE_MOTION_STATE_STOP;
}
break;
case RE_MOTION_STATE_LOOP:
if (m->current_frame > m->loop_frame_end)
m->current_frame = m->loop_frame_begin + fmodf(m->current_frame - m->loop_frame_begin, m->loop_frame_end - m->loop_frame_begin);
break;
default:
VM_ERROR("Invalid motion state %d", m->state);
}
}
static void calc_motion_frame(struct motion *m, int bone, struct mot_frame *out)
{
int cur_frame = m->current_frame;
int next_frame = ceilf(m->current_frame);
float t = m->current_frame - cur_frame;
struct mot_frame *frames = m->mot->motions[bone]->frames;
interpolate_motion_frame(&frames[cur_frame], &frames[next_frame], t, out);
}
static void animate(struct RE_instance *inst, int elapsed_ms)
{
float delta_frame = inst->fps * elapsed_ms / 1000.0;
update_motion(inst->motion, delta_frame);
update_motion(inst->next_motion, delta_frame);
if (inst->type != RE_ITYPE_SKINNED || !inst->motion)
return;
mat4 parent_transforms[MAX_BONES];
for (int i = 0; i < inst->model->nr_bones; i++) {
struct mot_frame mf;
calc_motion_frame(inst->motion, i, &mf);
if (inst->motion_blend && inst->next_motion) {
struct mot_frame next_mf;
calc_motion_frame(inst->next_motion, i, &next_mf);
interpolate_motion_frame(&mf, &next_mf, inst->motion_blend_rate, &mf);
}
mat4 bone_transform;
glm_translate_make(bone_transform, mf.pos);
glm_quat_rotate(bone_transform, mf.rotq, bone_transform);
if (inst->model->bones[i].parent >= 0) {
assert(inst->model->bones[i].parent < i);
glm_mat4_mul(parent_transforms[inst->model->bones[i].parent], bone_transform, bone_transform);
}
glm_mat4_copy(bone_transform, parent_transforms[i]);
glm_mat4_mul(bone_transform, inst->model->bones[i].inverse_bind_matrix, inst->bone_transforms[i]);
}
}
struct RE_plugin *RE_plugin_new(void)
{
char *aar_path = gamedir_path("Data/ReignData.red");
@@ -148,6 +217,20 @@ bool RE_plugin_unbind(struct RE_plugin *plugin)
return true;
}
bool RE_build_model(struct RE_plugin *plugin, int elapsed_ms)
{
if (!plugin)
return false;
if (elapsed_ms <= 0)
return true;
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
if (plugin->instances[i])
animate(plugin->instances[i], elapsed_ms);
}
return true;
}
bool RE_set_projection(struct RE_plugin *plugin, float width, float height, float near, float far, float deg)
{
if (!plugin)
+6 -87
View File
@@ -14,7 +14,6 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <assert.h>
#include <cglm/cglm.h>
#include "system4.h"
@@ -25,7 +24,6 @@
#include "asset_manager.h"
#include "reign.h"
#include "sact.h"
#include "vm.h"
enum {
COLOR_TEXTURE_UNIT,
@@ -116,7 +114,6 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
init_billboard_mesh(r);
r->billboard_textures = ht_create(256);
r->last_frame_timestamp = SDL_GetTicks();
return r;
}
@@ -200,73 +197,6 @@ static void update_local_transform(struct RE_instance *inst)
inst->local_transform_needs_update = false;
}
static void interpolate_motion_frame(struct mot_frame *m1, struct mot_frame *m2, float t, struct mot_frame *out)
{
glm_vec3_lerp(m1->pos, m2->pos, t, out->pos);
glm_quat_nlerp(m1->rotq, m2->rotq, t, out->rotq);
}
static void update_motion(struct motion *m, float delta_frame)
{
if (!m || m->state == RE_MOTION_STATE_STOP)
return;
m->current_frame += delta_frame;
switch (m->state) {
case RE_MOTION_STATE_NOLOOP:
if (m->current_frame > m->frame_end) {
m->current_frame = m->frame_end;
m->state = RE_MOTION_STATE_STOP;
}
break;
case RE_MOTION_STATE_LOOP:
if (m->current_frame > m->loop_frame_end)
m->current_frame = m->loop_frame_begin + fmodf(m->current_frame - m->loop_frame_begin, m->loop_frame_end - m->loop_frame_begin);
break;
default:
VM_ERROR("Invalid motion state %d", m->state);
}
}
static void calc_motion_frame(struct motion *m, int bone, struct mot_frame *out)
{
int cur_frame = m->current_frame;
int next_frame = ceilf(m->current_frame);
float t = m->current_frame - cur_frame;
struct mot_frame *frames = m->mot->motions[bone]->frames;
interpolate_motion_frame(&frames[cur_frame], &frames[next_frame], t, out);
}
static void animate(struct RE_instance *inst, struct RE_renderer *r, float delta_time)
{
float delta_frame = delta_time * inst->fps;
update_motion(inst->motion, delta_frame);
update_motion(inst->next_motion, delta_frame);
if (inst->type == RE_ITYPE_BILLBOARD)
return;
for (int i = 0; i < inst->model->nr_bones; i++) {
struct mot_frame mf;
calc_motion_frame(inst->motion, i, &mf);
if (inst->motion_blend && inst->next_motion) {
struct mot_frame next_mf;
calc_motion_frame(inst->next_motion, i, &next_mf);
interpolate_motion_frame(&mf, &next_mf, inst->motion_blend_rate, &mf);
}
mat4 bone_transform;
glm_translate_make(bone_transform, mf.pos);
glm_quat_rotate(bone_transform, mf.rotq, bone_transform);
if (inst->model->bones[i].parent >= 0) {
assert(inst->model->bones[i].parent < i);
glm_mat4_mul(inst->bone_transforms[inst->model->bones[i].parent], bone_transform, bone_transform);
}
glm_mat4_copy(bone_transform, inst->bone_transforms[i]);
glm_mat4_mul(bone_transform, inst->model->bones[i].inverse_bind_matrix, r->bone_transforms[i]);
}
}
static void render_model(struct RE_instance *inst, struct RE_renderer *r)
{
struct model *model = inst->model;
@@ -341,26 +271,23 @@ static void render_static_model(struct RE_instance *inst, struct RE_renderer *r)
render_model(inst, r);
}
static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r, float delta_time)
static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r)
{
struct model *model = inst->model;
if (!model)
return;
animate(inst, r, delta_time);
if (model->nr_bones > 0) {
glUniform1i(r->has_bones, GL_TRUE);
glUniformMatrix4fv(r->bone_matrices, model->nr_bones, GL_FALSE, r->bone_transforms[0][0]);
glUniformMatrix4fv(r->bone_matrices, model->nr_bones, GL_FALSE, inst->bone_transforms[0][0]);
} else {
glUniform1i(r->has_bones, GL_FALSE);
}
render_model(inst, r);
}
static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat, float delta_time)
static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat)
{
animate(inst, r, delta_time);
int cg_no = inst->motion->current_frame;
struct billboard_texture *bt = ht_get_int(r->billboard_textures, cg_no, NULL);
if (!bt)
@@ -448,19 +375,13 @@ static void setup_lights(struct RE_plugin *plugin)
void RE_render(struct sact_sprite *sp)
{
uint32_t timestamp = SDL_GetTicks();
struct RE_plugin *plugin = (struct RE_plugin *)sp->plugin;
struct RE_renderer *r = plugin->renderer;
if (!r) {
r->last_frame_timestamp = timestamp;
if (!r)
return;
}
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
float delta_time = (timestamp - r->last_frame_timestamp) / 1000.0;
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, texture, 0, 0, texture->w, texture->h);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, r->depth_buffer);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
@@ -507,10 +428,10 @@ void RE_render(struct sact_sprite *sp)
render_static_model(inst, r);
break;
case RE_ITYPE_SKINNED:
render_skinned_model(inst, r, delta_time);
render_skinned_model(inst, r);
break;
case RE_ITYPE_BILLBOARD:
render_billboard(inst, r, view_transform, delta_time);
render_billboard(inst, r, view_transform);
break;
default:
break;
@@ -524,6 +445,4 @@ void RE_render(struct sact_sprite *sp)
glUseProgram(0);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
r->last_frame_timestamp = timestamp;
}
+4 -1
View File
@@ -94,7 +94,10 @@ static bool ReignEngine_UnbindPlugin(int handle)
return RE_plugin_unbind(get_plugin(handle));
}
HLL_QUIET_UNIMPLEMENTED(true, bool, ReignEngine, BuildModel, int plugin, int pass_time);
static bool ReignEngine_BuildModel(int plugin, int pass_time)
{
return RE_build_model(get_plugin(plugin), pass_time);
}
static int ReignEngine_CreateInstance(int plugin)
{