ReignEngine: Implement skeletal animation

This commit is contained in:
kichikuou
2022-06-11 13:28:02 +09:00
parent caec854ed8
commit a2bbe15b20
8 changed files with 668 additions and 57 deletions
+24
View File
@@ -23,6 +23,12 @@
#include "plugin.h"
enum RE_motion_state {
RE_MOTION_STATE_STOP = 0,
RE_MOTION_STATE_NOLOOP = 1,
RE_MOTION_STATE_LOOP = 2,
};
struct RE_options {
int anti_aliasing;
int wait_vsync;
@@ -71,14 +77,22 @@ struct RE_plugin {
struct RE_instance {
struct RE_plugin *plugin;
struct model *model;
struct motion *motion;
struct motion *next_motion;
int type;
vec3 pos;
float pitch, roll, yaw; // in degrees
vec3 vec;
vec3 scale;
bool draw;
float fps;
bool motion_blend;
float motion_blend_rate;
bool local_transform_needs_update;
mat4 local_transform;
mat4 *bone_transforms; // model->nr_bones elements
};
struct RE_plugin *RE_plugin_new(void);
@@ -90,6 +104,16 @@ int RE_create_instance(struct RE_plugin *plugin);
bool RE_release_instance(struct RE_plugin *plugin, int instance);
bool RE_instance_load(struct RE_instance *instance, const char *name);
bool RE_instance_load_motion(struct RE_instance *instance, const char *name);
bool RE_instance_load_next_motion(struct RE_instance *instance, const char *name);
bool RE_instance_free_next_motion(struct RE_instance *instance);
int RE_motion_get_state(struct motion *motion);
bool RE_motion_set_state(struct motion *motion, int state);
float RE_motion_get_frame(struct motion *motion);
bool RE_motion_set_frame(struct motion *motion, float frame);
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);
void RE_render(struct sact_sprite *sp);
void RE_debug_print(struct RE_plugin *p);
+20 -2
View File
@@ -18,12 +18,30 @@ uniform mat4 local_transform;
uniform mat4 view_transform;
uniform mat4 proj_transform;
const int MAX_BONES = 211; // see 3d_internal.h
const int NR_WEIGHTS = 4;
uniform bool has_bones;
uniform mat4 bone_matrices[MAX_BONES];
in vec3 vertex_pos;
in vec3 vertex_normal;
in vec2 vertex_uv;
in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
out vec2 tex_coord;
void main() {
gl_Position = proj_transform * view_transform * local_transform * vec4(vertex_pos, 1.0);
tex_coord = vertex_uv;
mat4 bone_transform = mat4(1.0f);
if (has_bones) {
bone_transform = mat4(0.f);
for (int i = 0; i < NR_WEIGHTS; i++) {
if (vertex_bone_index[i] >= 0) {
bone_transform += bone_matrices[vertex_bone_index[i]] * vertex_bone_weight[i];
}
}
}
gl_Position = proj_transform * view_transform * local_transform * bone_transform * vec4(vertex_pos, 1.0);
tex_coord = vertex_uv;
}
+54 -1
View File
@@ -24,12 +24,17 @@
#include "gfx/gl.h"
#include "gfx/gfx.h"
#define MAX_BONES 211 // Maximum in TT3
struct model {
char *name;
char *path;
int nr_meshes;
struct mesh *meshes;
int nr_materials;
struct material *materials;
int nr_bones;
struct bone *bones;
struct hash_table *bone_map; // bone id in POL/MOT -> struct bone *
};
struct mesh {
@@ -44,6 +49,22 @@ struct material {
bool opaque;
};
struct bone {
char *name;
int index; // index on model->bones
int parent; // index on model->bones, or -1
mat4 inverse_bind_matrix;
};
struct motion {
struct mot *mot;
char *name;
int state;
float current_frame;
float frame_begin, frame_end;
float loop_frame_begin, loop_frame_end;
};
struct RE_renderer {
struct shader shader;
GLuint depth_buffer;
@@ -51,10 +72,17 @@ struct RE_renderer {
// Uniform variable locations
GLint local_transform;
GLint proj_transform;
GLint has_bones;
GLint bone_matrices;
// Attribute variable locations
GLint vertex_normal;
GLint vertex_uv;
GLint vertex_bone_index;
GLint vertex_bone_weight;
mat4 bone_transforms[MAX_BONES];
uint32_t last_frame_timestamp;
};
// model.c
@@ -62,6 +90,9 @@ struct RE_renderer {
struct model *model_load(struct archive *aar, const char *path, struct RE_renderer *renderer);
void model_free(struct model *model);
struct motion *motion_load(const char *name, struct model *model, struct archive *aar);
void motion_free(struct motion *motion);
// renderer.c
struct RE_renderer *RE_renderer_new(struct texture *texture);
@@ -132,7 +163,29 @@ struct pol_bone {
versor rotq;
};
struct mot {
uint32_t nr_frames;
uint32_t nr_bones;
struct mot_bone *motions[];
};
struct mot_frame {
vec3 pos;
versor rotq;
};
struct mot_bone {
char *name;
uint32_t id;
uint32_t parent;
struct mot_frame frames[];
};
struct pol *pol_parse(uint8_t *data, size_t size);
void pol_free(struct pol *pol);
struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id);
struct mot *mot_parse(uint8_t *data, size_t size);
void mot_free(struct mot *mot);
#endif /* SYSTEM4_3D_3D_INTERNAL_H */
+151 -4
View File
@@ -21,14 +21,19 @@
#include "system4.h"
#include "system4/aar.h"
#include "system4/cg.h"
#include "system4/hashtable.h"
#include "3d_internal.h"
#include "reign.h"
#define NR_WEIGHTS 4
struct vertex {
GLfloat pos[3];
GLfloat normal[3];
GLfloat uv[2];
GLint bone_id[NR_WEIGHTS];
GLfloat bone_weight[NR_WEIGHTS];
};
static bool init_material(struct material *material, const struct pol_material *m, struct archive *aar, const char *path)
@@ -75,6 +80,25 @@ static void destroy_material(struct material *material)
glDeleteTextures(1, &material->color_map);
}
static int cmp_by_bone_weight(const void *lhs, const void *rhs)
{
float l = ((struct pol_bone_weight *)lhs)->weight;
float r = ((struct pol_bone_weight *)rhs)->weight;
return (l < r) - (l > r); // descending order.
}
static void sort_and_normalize_bone_weights(struct pol_vertex *v)
{
qsort(v->weights, v->nr_weights, sizeof(struct pol_bone_weight), cmp_by_bone_weight);
float total = 0.0;
for (uint32_t i = 0; i < v->nr_weights && i < NR_WEIGHTS; i++) {
total += v->weights[i].weight;
}
for (uint32_t i = 0; i < v->nr_weights && i < NR_WEIGHTS; i++) {
v->weights[i].weight /= total;
}
}
static void add_mesh(struct model *model, struct pol_mesh *m, int material_index, int material, struct RE_renderer *r)
{
struct vertex *buf = xmalloc(m->nr_triangles * 3 * sizeof(struct vertex));
@@ -84,9 +108,23 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index
if (material_index >= 0 && t->material != (uint32_t)material_index)
continue;
for (int j = 0; j < 3; j++) {
glm_vec3_copy(m->vertices[t->vert_index[j]].pos, buf[v].pos);
struct pol_vertex *vert = &m->vertices[t->vert_index[j]];
glm_vec3_copy(vert->pos, buf[v].pos);
glm_vec3_copy(t->normals[j], buf[v].normal);
glm_vec2_copy(m->uvs[t->uv_index[j]], buf[v].uv);
sort_and_normalize_bone_weights(vert);
for (uint32_t k = 0; k < NR_WEIGHTS; k++) {
if (model->bone_map && k < vert->nr_weights) {
struct bone *bone = ht_get_int(model->bone_map, vert->weights[k].bone, NULL);
if (!bone)
WARNING("%s: invalid bone id in vertex data", model->path);
buf[v].bone_id[k] = bone ? bone->index : -1;
buf[v].bone_weight[k] = vert->weights[k].weight;
} else {
buf[v].bone_id[k] = -1;
buf[v].bone_weight[k] = 0.0;
}
}
v++;
}
}
@@ -107,9 +145,13 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index
glEnableVertexAttribArray(r->shader.vertex);
glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0);
glEnableVertexAttribArray(r->vertex_normal);
glVertexAttribPointer(r->vertex_normal, 3, GL_FLOAT, GL_TRUE, sizeof(struct vertex), (const void *)offsetof(struct vertex, normal));
glVertexAttribPointer(r->vertex_normal, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, normal));
glEnableVertexAttribArray(r->vertex_uv);
glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, uv));
glEnableVertexAttribArray(r->vertex_bone_index);
glVertexAttribIPointer(r->vertex_bone_index, NR_WEIGHTS, GL_INT, sizeof(struct vertex), (const void *)offsetof(struct vertex, bone_id));
glEnableVertexAttribArray(r->vertex_bone_weight);
glVertexAttribPointer(r->vertex_bone_weight, NR_WEIGHTS, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, bone_weight));
glBufferData(GL_ARRAY_BUFFER, mesh->nr_vertices * sizeof(struct vertex), buf, GL_STATIC_DRAW);
glBindVertexArray(0);
@@ -124,6 +166,39 @@ static void destroy_mesh(struct mesh *mesh)
glDeleteBuffers(1, &mesh->attr_buffer);
}
static struct bone *add_bone(struct model *model, struct pol *pol, struct pol_bone *pol_bone)
{
struct bone *bone = ht_get_int(model->bone_map, pol_bone->id, NULL);
if (bone)
return bone; // already added.
struct bone *parent = NULL;
if (pol_bone->parent >= 0) {
// Parent bone must appear before its children in model->bones.
struct pol_bone *pol_parent = pol_find_bone(pol, pol_bone->parent);
if (!pol_parent)
ERROR("Parent bone of \"%s\" is not found", pol_bone->name);
parent = add_bone(model, pol, pol_parent);
}
bone = &model->bones[model->nr_bones];
ht_put_int(model->bone_map, pol_bone->id, bone);
bone->name = strdup(pol_bone->name);
bone->index = model->nr_bones;
bone->parent = parent ? parent->index : -1;
glm_quat_mat4(pol_bone->rotq, bone->inverse_bind_matrix);
glm_translate(bone->inverse_bind_matrix, pol_bone->pos);
model->nr_bones++;
return bone;
}
static void destroy_bone(struct bone *bone)
{
free(bone->name);
}
struct model *model_load(struct archive *aar, const char *path, struct RE_renderer *r)
{
if (path[0] == '\0')
@@ -148,9 +223,23 @@ struct model *model_load(struct archive *aar, const char *path, struct RE_render
free(polname);
return NULL;
}
free(polname);
struct model *model = xcalloc(1, sizeof(struct model));
model->name = polname;
model->path = strdup(path);
// Bones
if (pol->nr_bones > 0) {
if (pol->nr_bones > MAX_BONES)
ERROR("%s: Too many bones (%u)", model->path, pol->nr_bones);
model->bone_map = ht_create(pol->nr_bones * 3 / 2);
model->bones = xcalloc(pol->nr_bones, sizeof(struct bone));
for (uint32_t i = 0; i < pol->nr_bones; i++) {
add_bone(model, pol, &pol->bones[i]);
}
if (model->nr_bones != (int)pol->nr_bones)
ERROR("%s: Broken bone data", model->path);
}
// Materials
int *material_offsets = xmalloc(pol->nr_materials * sizeof(int));
@@ -204,6 +293,64 @@ void model_free(struct model *model)
destroy_material(&model->materials[i]);
free(model->materials);
free(model->name);
for (int i = 0; i < model->nr_bones; i++)
destroy_bone(&model->bones[i]);
free(model->bones);
if (model->bone_map)
ht_free_int(model->bone_map);
free(model->path);
free(model);
}
static int cmp_motions_by_bone_id(const void *lhs, const void *rhs)
{
return (*(struct mot_bone **)lhs)->id - (*(struct mot_bone **)rhs)->id;
}
struct motion *motion_load(const char *name, struct model *model, struct archive *aar)
{
char *motname = xmalloc(strlen(model->path) + strlen(name) + 6);
sprintf(motname, "%s\\%s.MOT", model->path, name);
struct archive_data *dfile = archive_get_by_name(aar, motname);
if (!dfile) {
WARNING("%s: not found", motname);
free(motname);
return NULL;
}
struct mot *mot = mot_parse(dfile->data, dfile->size);
archive_free_data(dfile);
if (!mot) {
WARNING("%s: parse error", motname);
free(motname);
return NULL;
}
free(motname);
if (model->nr_bones != (int)mot->nr_bones)
ERROR("%s: wrong number of bones. Expected %d but got %d", name, model->nr_bones, mot->nr_bones);
// Reorder mot->motions so that motion for model->bones[i] can be
// accessed by mot->motions[i].
for (uint32_t i = 0; i < mot->nr_bones; i++) {
struct bone *bone = ht_get_int(model->bone_map, mot->motions[i]->id, NULL);
if (!bone)
ERROR("%s: invalid bone id %d", name, mot->motions[i]->id);
mot->motions[i]->id = bone->index;
}
qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id);
struct motion *motion = xcalloc(1, sizeof(struct motion));
motion->mot = mot;
motion->name = strdup(name);
return motion;
}
void motion_free(struct motion *motion)
{
mot_free(motion->mot);
free(motion->name);
free(motion);
}
+55
View File
@@ -56,6 +56,7 @@ static void read_quaternion(struct buffer *r, versor q)
float y = -buffer_read_float(r);
float z = buffer_read_float(r);
glm_quat_init(q, x, y, z, w);
glm_quat_normalize(q);
}
static void parse_material(struct buffer *r, struct pol_material *m)
@@ -284,3 +285,57 @@ void pol_free(struct pol *pol)
free(pol->bones);
free(pol);
}
struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id)
{
for (uint32_t i = 0; i < pol->nr_bones; i++) {
if (pol->bones[i].id == id)
return &pol->bones[i];
}
return NULL;
}
struct mot *mot_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (memcmp(buffer_strdata(&r), "MOT\0", 4))
return NULL;
buffer_skip(&r, 4);
uint32_t version = buffer_read_int32(&r);
if (version != 0) {
WARNING("unknown MOT version: %d", version);
return NULL;
}
uint32_t nr_frames = buffer_read_int32(&r);
uint32_t nr_bones = buffer_read_int32(&r);
struct mot *mot = xcalloc(1, sizeof(struct mot) + nr_bones * sizeof(struct mot_bone *));
mot->nr_frames = nr_frames;
mot->nr_bones = nr_bones;
for (uint32_t i = 0; i < nr_bones; i++) {
struct mot_bone *m = xcalloc(1, sizeof(struct mot_bone) + sizeof(struct mot_frame) * nr_frames);
m->name = read_cstring(&r);
m->id = buffer_read_int32(&r);
m->parent = buffer_read_int32(&r);
for (uint32_t j = 0; j < nr_frames; j++) {
read_position(&r, m->frames[j].pos);
read_quaternion(&r, m->frames[j].rotq);
buffer_skip(&r, 16); // another quaternion?
}
mot->motions[i] = m;
}
if (buffer_remaining(&r) != 0) {
WARNING("extra data at end");
}
return mot;
}
void mot_free(struct mot *mot)
{
for (uint32_t i = 0; i < mot->nr_bones; i++) {
free(mot->motions[i]->name);
free(mot->motions[i]);
}
free(mot);
}
+130 -15
View File
@@ -35,14 +35,34 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin)
instance->scale[0] = 1.0;
instance->scale[1] = 1.0;
instance->scale[2] = 1.0;
instance->fps = 30.0;
glm_mat4_identity(instance->local_transform);
return instance;
}
static void unload_instance(struct RE_instance *instance)
{
if (instance->motion) {
motion_free(instance->motion);
instance->motion = NULL;
}
if (instance->next_motion) {
motion_free(instance->next_motion);
instance->next_motion = NULL;
}
if (instance->model) {
model_free(instance->model);
instance->model = NULL;
}
if (instance->bone_transforms) {
free(instance->bone_transforms);
instance->bone_transforms = NULL;
}
}
static void free_instance(struct RE_instance *instance)
{
if (instance->model)
model_free(instance->model);
unload_instance(instance);
free(instance);
}
@@ -138,29 +158,124 @@ bool RE_instance_load(struct RE_instance *instance, const char *name)
{
if (!instance)
return false;
if (instance->model)
model_free(instance->model);
unload_instance(instance);
instance->model = model_load(instance->plugin->aar, name, instance->plugin->renderer);
if (instance->model && instance->model->nr_bones > 0)
instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4));
return !!instance->model;
}
bool RE_instance_load_motion(struct RE_instance *instance, const char *name)
{
if (!instance || !instance->model)
return false;
instance->motion = motion_load(name, instance->model, instance->plugin->aar);
return !!instance->motion;
}
bool RE_instance_load_next_motion(struct RE_instance *instance, const char *name)
{
if (!instance || !instance->model)
return false;
instance->next_motion = motion_load(name, instance->model, instance->plugin->aar);
return !!instance->next_motion;
}
bool RE_instance_free_next_motion(struct RE_instance *instance)
{
if (!instance || !instance->next_motion)
return false;
motion_free(instance->next_motion);
instance->next_motion = NULL;
return true;
}
int RE_motion_get_state(struct motion *motion)
{
return motion ? motion->state : RE_MOTION_STATE_STOP;
}
bool RE_motion_set_state(struct motion *motion, int state)
{
if (!motion)
return false;
motion->state = state;
return true;
}
float RE_motion_get_frame(struct motion *motion)
{
return motion ? motion->current_frame : 0.0;
}
bool RE_motion_set_frame(struct motion *motion, float frame)
{
if (!motion)
return false;
motion->current_frame = frame;
return true;
}
bool RE_motion_set_frame_range(struct motion *motion, float begin, float end)
{
if (!motion)
return false;
motion->frame_begin = begin;
motion->frame_end = end;
return true;
}
bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float end)
{
if (!motion)
return false;
motion->loop_frame_begin = begin;
motion->loop_frame_end = end;
return true;
}
static void print_motion(const char *name, struct motion *m, int indent)
{
const char *state;
switch (m->state) {
case RE_MOTION_STATE_STOP: state = "STOP"; break;
case RE_MOTION_STATE_NOLOOP: state = "NOLOOP"; break;
case RE_MOTION_STATE_LOOP: state = "LOOP"; break;
default: state = "?"; break;
}
indent_printf(indent, "%s = {name=\"%s\", state=%s, frame=%f},\n",
name, m->name, state, m->current_frame);
}
void RE_debug_print(struct RE_plugin *p)
{
printf("camera = { x: %f, y: %f, z: %f, pitch: %f, roll: %f, yaw: %f }",
p->camera.pos[0], p->camera.pos[1], p->camera.pos[2],
p->camera.pitch, p->camera.roll, p->camera.yaw);
int indent = 0;
indent_printf(indent, "camera = {x=%f, y=%f, z=%f, pitch=%f, roll=%f, yaw=%f},\n",
p->camera.pos[0], p->camera.pos[1], p->camera.pos[2],
p->camera.pitch, p->camera.roll, p->camera.yaw);
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
struct RE_instance *inst = p->instances[i];
if (!inst || !inst->model)
continue;
printf("[%d] = {", i);
printf(" name: \"%s\",", inst->model->name);
printf(" type: %d,", inst->type);
printf(" draw: %d,", inst->draw);
printf(" pos: { x: %f, y: %f, z: %f },", inst->pos[0], inst->pos[1], inst->pos[2]);
printf(" vec: { x: %f, y: %f, z: %f },", inst->vec[0], inst->vec[1], inst->vec[2]);
printf(" scale: { x: %f, y: %f, z: %f },", inst->scale[0], inst->scale[1], inst->scale[2]);
printf("}");
indent_printf(indent, "instance[%d] = {\n", i);
indent++;
indent_printf(indent, "path = \"%s\",\n", inst->model->path);
indent_printf(indent, "type = %d,\n", inst->type);
indent_printf(indent, "draw = %d,\n", inst->draw);
indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", inst->pos[0], inst->pos[1], inst->pos[2]);
indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", inst->vec[0], inst->vec[1], inst->vec[2]);
indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", inst->scale[0], inst->scale[1], inst->scale[2]);
if (inst->motion)
print_motion("motion", inst->motion, indent);
if (inst->next_motion)
print_motion("next_motion", inst->next_motion, indent);
indent_printf(indent, "fps = %f,\n", inst->fps);
if (inst->motion_blend)
indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
indent--;
indent_printf(indent, "},\n");
}
}
+91 -3
View File
@@ -14,6 +14,7 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <assert.h>
#include <cglm/cglm.h>
#include "system4.h"
@@ -21,6 +22,7 @@
#include "3d_internal.h"
#include "reign.h"
#include "sact.h"
#include "vm.h"
struct RE_renderer *RE_renderer_new(struct texture *texture)
{
@@ -29,14 +31,19 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
gfx_load_shader(&r->shader, "shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->local_transform = glGetUniformLocation(r->shader.program, "local_transform");
r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform");
r->has_bones = glGetUniformLocation(r->shader.program, "has_bones");
r->bone_matrices = glGetUniformLocation(r->shader.program, "bone_matrices");
r->vertex_normal = glGetAttribLocation(r->shader.program, "vertex_normal");
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
r->vertex_bone_index = glGetAttribLocation(r->shader.program, "vertex_bone_index");
r->vertex_bone_weight = glGetAttribLocation(r->shader.program, "vertex_bone_weight");
glGenRenderbuffers(1, &r->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, r->depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture->w, texture->h);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
r->last_frame_timestamp = SDL_GetTicks();
return r;
}
@@ -79,7 +86,71 @@ static void update_local_transform(struct RE_instance *inst)
inst->local_transform_needs_update = false;
}
static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat4 view_transform, mat4 proj_transform)
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);
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_instance(struct RE_instance *inst, struct RE_renderer *r, mat4 view_transform, mat4 proj_transform, float delta_time)
{
if (!inst->draw || !inst->model)
return;
@@ -87,11 +158,20 @@ static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat
if (inst->local_transform_needs_update)
update_local_transform(inst);
animate(inst, r, delta_time);
glUseProgram(r->shader.program);
glUniformMatrix4fv(r->shader.view_transform, 1, GL_FALSE, view_transform[0]);
glUniformMatrix4fv(r->proj_transform, 1, GL_FALSE, proj_transform[0]);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, inst->local_transform[0]);
if (inst->model->nr_bones > 0) {
glUniform1i(r->has_bones, GL_TRUE);
glUniformMatrix4fv(r->bone_matrices, inst->model->nr_bones, GL_FALSE, r->bone_transforms[0][0]);
} else {
glUniform1i(r->has_bones, GL_FALSE);
}
struct model *model = inst->model;
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
@@ -110,13 +190,19 @@ static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat
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)
if (!r) {
r->last_frame_timestamp = timestamp;
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)
@@ -140,7 +226,7 @@ void RE_render(struct sact_sprite *sp)
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
if (plugin->instances[i])
render_instance(plugin->instances[i], r, view_transform, plugin->proj_transform);
render_instance(plugin->instances[i], r, view_transform, plugin->proj_transform, delta_time);
}
plugin->proj_transform[1][1] *= -1;
@@ -149,4 +235,6 @@ void RE_render(struct sact_sprite *sp)
glDisable(GL_CULL_FACE);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
r->last_frame_timestamp = timestamp;
}
+143 -32
View File
@@ -42,6 +42,18 @@ static struct RE_instance *get_instance(unsigned plugin, unsigned instance)
return instance < RE_MAX_INSTANCES ? rp->instances[instance] : NULL;
}
static struct motion *get_motion(unsigned plugin, unsigned instance)
{
struct RE_instance *inst = get_instance(plugin, instance);
return inst ? inst->motion : NULL;
}
static struct motion *get_next_motion(unsigned plugin, unsigned instance)
{
struct RE_instance *inst = get_instance(plugin, instance);
return inst ? inst->next_motion : NULL;
}
static int ReignEngine_CreatePlugin(void)
{
for (int i = 0; i < RE_MAX_PLUGINS; i++) {
@@ -239,25 +251,110 @@ static bool ReignEngine_GetInstanceDraw(int plugin, int instance)
//bool ReignEngine_GetInstanceDrawBump(int plugin, int instance);
//int ReignEngine_GetInstanceDrawType(int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawType, int plugin, int instance, int draw_type);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, LoadInstanceMotion, int plugin, int instance, struct string *name);
HLL_WARN_UNIMPLEMENTED(0, int, ReignEngine, GetInstanceMotionState, int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(0.0, float, ReignEngine, GetInstanceMotionFrame, int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceMotionState, int plugin, int instance, int state);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceMotionFrame, int plugin, int instance, float frame);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceMotionFrameRange, int plugin, int instance, float begin_frame, float end_frame);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceMotionLoopFrameRange, int plugin, int instance, float begin_frame, float end_frame);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, LoadInstanceNextMotion, int plugin, int instance, struct string *name);
//bool ReignEngine_SetInstanceNextMotionState(int plugin, int instance, int nState);
//bool ReignEngine_SetInstanceNextMotionFrame(int plugin, int instance, float fFrame);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceNextMotionFrameRange, int plugin, int instance, float begin_frame, float end_frame);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceNextMotionLoopFrameRange, int plugin, int instance, float begin_frame, float end_frame);
//bool ReignEngine_SetInstanceMotionBlendRate(int plugin, int instance, float fRate);
//bool ReignEngine_SetInstanceMotionBlend(int plugin, int instance, bool bMotionBlend);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, IsInstanceMotionBlend, int plugin, int instance);
bool ReignEngine_LoadInstanceMotion(int plugin, int instance, struct string *name)
{
return RE_instance_load_motion(get_instance(plugin, instance), name->text);
}
static int ReignEngine_GetInstanceMotionState(int plugin, int instance)
{
return RE_motion_get_state(get_motion(plugin, instance));
}
static float ReignEngine_GetInstanceMotionFrame(int plugin, int instance)
{
return RE_motion_get_frame(get_motion(plugin, instance));
}
static bool ReignEngine_SetInstanceMotionState(int plugin, int instance, int state)
{
return RE_motion_set_state(get_motion(plugin, instance), state);
}
static bool ReignEngine_SetInstanceMotionFrame(int plugin, int instance, float frame)
{
return RE_motion_set_frame(get_motion(plugin, instance), frame);
}
static bool ReignEngine_SetInstanceMotionFrameRange(int plugin, int instance, float begin_frame, float end_frame)
{
return RE_motion_set_frame_range(get_motion(plugin, instance), begin_frame, end_frame);
}
static bool ReignEngine_SetInstanceMotionLoopFrameRange(int plugin, int instance, float begin_frame, float end_frame)
{
return RE_motion_set_loop_frame_range(get_motion(plugin, instance), begin_frame, end_frame);
}
static bool ReignEngine_LoadInstanceNextMotion(int plugin, int instance, struct string *name)
{
return RE_instance_load_next_motion(get_instance(plugin, instance), name->text);
}
static bool ReignEngine_SetInstanceNextMotionState(int plugin, int instance, int state)
{
return RE_motion_set_state(get_next_motion(plugin, instance), state);
}
static bool ReignEngine_SetInstanceNextMotionFrame(int plugin, int instance, float frame)
{
return RE_motion_set_frame(get_next_motion(plugin, instance), frame);
}
static bool ReignEngine_SetInstanceNextMotionFrameRange(int plugin, int instance, float begin_frame, float end_frame)
{
return RE_motion_set_frame_range(get_next_motion(plugin, instance), begin_frame, end_frame);
}
static bool ReignEngine_SetInstanceNextMotionLoopFrameRange(int plugin, int instance, float begin_frame, float end_frame)
{
return RE_motion_set_loop_frame_range(get_next_motion(plugin, instance), begin_frame, end_frame);
}
static bool ReignEngine_SetInstanceMotionBlendRate(int plugin, int instance, float rate)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->motion_blend_rate = rate;
return true;
}
static bool ReignEngine_SetInstanceMotionBlend(int plugin, int instance, bool motion_blend)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->motion_blend = motion_blend;
return true;
}
static bool ReignEngine_IsInstanceMotionBlend(int plugin, int instance)
{
struct RE_instance *ri = get_instance(plugin, instance);
return ri ? ri->motion_blend : false;
}
//bool ReignEngine_GetInstanceMotionBlendPutTime(int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceMotionBlendPutTime, int plugin, int instance, bool flag);
//bool ReignEngine_SwapInstanceMotion(int plugin, int instance);
//bool ReignEngine_FreeInstanceNextMotion(int plugin, int instance);
static bool ReignEngine_SwapInstanceMotion(int plugin, int instance)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
struct motion *tmp = ri->motion;
ri->motion = ri->next_motion;
ri->next_motion = tmp;
return true;
}
static bool ReignEngine_FreeInstanceNextMotion(int plugin, int instance)
{
return RE_instance_free_next_motion(get_instance(plugin, instance));
}
//int ReignEngine_GetInstanceNumofMaterial(int plugin, int instance);
//bool ReignEngine_GetInstanceMaterialName(int plugin, int instance, int num, struct string **pIName);
//float ReignEngine_GetInstanceMaterialParam(int plugin, int instance, int nMaterial, int type);
@@ -281,8 +378,22 @@ HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceColumnAngle, int plu
//bool ReignEngine_SetInstanceDrawColumn(int plugin, int instance, bool bDraw);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceTarget, int plugin, int instance, int index, int target);
//int ReignEngine_GetInstanceTarget(int plugin, int instance, int index);
//float ReignEngine_GetInstanceFPS(int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceFPS, int plugin, int instance, float fps);
static float ReignEngine_GetInstanceFPS(int plugin, int instance)
{
struct RE_instance *ri = get_instance(plugin, instance);
return ri ? ri->fps : 0.0;
}
static bool ReignEngine_SetInstanceFPS(int plugin, int instance, float fps)
{
struct RE_instance *ri = get_instance(plugin, instance);
if (!ri)
return false;
ri->fps = fps;
return true;
}
HLL_WARN_UNIMPLEMENTED(0, int, ReignEngine, GetInstanceBoneIndex, int plugin, int instance, struct string *name);
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, TransInstanceLocalPosToWorldPosByBone, int plugin, int instance, int bone, float offset_x, float offset_y, float offset_z, float *x, float *y, float *z);
//int ReignEngine_GetInstanceNumofPolygon(int plugin, int instance);
@@ -304,7 +415,7 @@ HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, GetEffectFrameRange, int plugin
//float ReignEngine_GetEffectObjectMoveCurve(int plugin, int instance, int nObject);
//void ReignEngine_GetEffectObjectFrame(int plugin, int instance, int nObject, int *pnBeginFrame, int *pnEndFrame);
//int ReignEngine_GetEffectObjectStopFrame(int plugin, int instance, int nObject);
//int ReignEngine_GetEffectNumofObject(int plugin, int instance);
HLL_WARN_UNIMPLEMENTED(0, int, ReignEngine, GetEffectNumofObject, int plugin, int instance);
//void ReignEngine_GetEffectObjectName(int plugin, int instance, int nObject, struct string **pIName);
//int ReignEngine_GetEffectNumofObjectPos(int plugin, int instance, int nObject);
//int ReignEngine_GetEffectNumofObjectPosUnit(int plugin, int instance, int nObject, int nPos);
@@ -417,8 +528,8 @@ HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, GetEffectFrameRange, int plugin
//float ReignEngine_GetEffectObjectOffsetY(int plugin, int instance, int nObject);
//bool ReignEngine_SetEffectObjectOffsetX(int plugin, int instance, int nObject, float fOffsetX);
//bool ReignEngine_SetEffectObjectOffsetY(int plugin, int instance, int nObject, float fOffsetY);
//bool ReignEngine_GetCameraQuakeEffectFlag(int plugin, int instance);
//bool ReignEngine_SetCameraQuakeEffectFlag(int plugin, int instance, bool flag);
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)
{
@@ -928,17 +1039,17 @@ HLL_LIBRARY(ReignEngine,
HLL_EXPORT(SetInstanceMotionFrameRange, ReignEngine_SetInstanceMotionFrameRange),
HLL_EXPORT(SetInstanceMotionLoopFrameRange, ReignEngine_SetInstanceMotionLoopFrameRange),
HLL_EXPORT(LoadInstanceNextMotion, ReignEngine_LoadInstanceNextMotion),
HLL_TODO_EXPORT(SetInstanceNextMotionState, ReignEngine_SetInstanceNextMotionState),
HLL_TODO_EXPORT(SetInstanceNextMotionFrame, ReignEngine_SetInstanceNextMotionFrame),
HLL_EXPORT(SetInstanceNextMotionState, ReignEngine_SetInstanceNextMotionState),
HLL_EXPORT(SetInstanceNextMotionFrame, ReignEngine_SetInstanceNextMotionFrame),
HLL_EXPORT(SetInstanceNextMotionFrameRange, ReignEngine_SetInstanceNextMotionFrameRange),
HLL_EXPORT(SetInstanceNextMotionLoopFrameRange, ReignEngine_SetInstanceNextMotionLoopFrameRange),
HLL_TODO_EXPORT(SetInstanceMotionBlendRate, ReignEngine_SetInstanceMotionBlendRate),
HLL_TODO_EXPORT(SetInstanceMotionBlend, ReignEngine_SetInstanceMotionBlend),
HLL_EXPORT(SetInstanceMotionBlendRate, ReignEngine_SetInstanceMotionBlendRate),
HLL_EXPORT(SetInstanceMotionBlend, ReignEngine_SetInstanceMotionBlend),
HLL_EXPORT(IsInstanceMotionBlend, ReignEngine_IsInstanceMotionBlend),
HLL_TODO_EXPORT(GetInstanceMotionBlendPutTime, ReignEngine_GetInstanceMotionBlendPutTime),
HLL_EXPORT(SetInstanceMotionBlendPutTime, ReignEngine_SetInstanceMotionBlendPutTime),
HLL_TODO_EXPORT(SwapInstanceMotion, ReignEngine_SwapInstanceMotion),
HLL_TODO_EXPORT(FreeInstanceNextMotion, ReignEngine_FreeInstanceNextMotion),
HLL_EXPORT(SwapInstanceMotion, ReignEngine_SwapInstanceMotion),
HLL_EXPORT(FreeInstanceNextMotion, ReignEngine_FreeInstanceNextMotion),
HLL_TODO_EXPORT(GetInstanceNumofMaterial, ReignEngine_GetInstanceNumofMaterial),
HLL_TODO_EXPORT(GetInstanceMaterialName, ReignEngine_GetInstanceMaterialName),
HLL_TODO_EXPORT(GetInstanceMaterialParam, ReignEngine_GetInstanceMaterialParam),
@@ -962,7 +1073,7 @@ HLL_LIBRARY(ReignEngine,
HLL_TODO_EXPORT(SetInstanceDrawColumn, ReignEngine_SetInstanceDrawColumn),
HLL_EXPORT(SetInstanceTarget, ReignEngine_SetInstanceTarget),
HLL_TODO_EXPORT(GetInstanceTarget, ReignEngine_GetInstanceTarget),
HLL_TODO_EXPORT(GetInstanceFPS, ReignEngine_GetInstanceFPS),
HLL_EXPORT(GetInstanceFPS, ReignEngine_GetInstanceFPS),
HLL_EXPORT(SetInstanceFPS, ReignEngine_SetInstanceFPS),
HLL_EXPORT(GetInstanceBoneIndex, ReignEngine_GetInstanceBoneIndex),
HLL_EXPORT(TransInstanceLocalPosToWorldPosByBone, ReignEngine_TransInstanceLocalPosToWorldPosByBone),
@@ -985,7 +1096,7 @@ HLL_LIBRARY(ReignEngine,
HLL_TODO_EXPORT(GetEffectObjectMoveCurve, ReignEngine_GetEffectObjectMoveCurve),
HLL_TODO_EXPORT(GetEffectObjectFrame, ReignEngine_GetEffectObjectFrame),
HLL_TODO_EXPORT(GetEffectObjectStopFrame, ReignEngine_GetEffectObjectStopFrame),
HLL_TODO_EXPORT(GetEffectNumofObject, ReignEngine_GetEffectNumofObject),
HLL_EXPORT(GetEffectNumofObject, ReignEngine_GetEffectNumofObject),
HLL_TODO_EXPORT(GetEffectObjectName, ReignEngine_GetEffectObjectName),
HLL_TODO_EXPORT(GetEffectNumofObjectPos, ReignEngine_GetEffectNumofObjectPos),
HLL_TODO_EXPORT(GetEffectNumofObjectPosUnit, ReignEngine_GetEffectNumofObjectPosUnit),
@@ -1098,8 +1209,8 @@ HLL_LIBRARY(ReignEngine,
HLL_TODO_EXPORT(GetEffectObjectOffsetY, ReignEngine_GetEffectObjectOffsetY),
HLL_TODO_EXPORT(SetEffectObjectOffsetX, ReignEngine_SetEffectObjectOffsetX),
HLL_TODO_EXPORT(SetEffectObjectOffsetY, ReignEngine_SetEffectObjectOffsetY),
HLL_TODO_EXPORT(GetCameraQuakeEffectFlag, ReignEngine_GetCameraQuakeEffectFlag),
HLL_TODO_EXPORT(SetCameraQuakeEffectFlag, ReignEngine_SetCameraQuakeEffectFlag),
HLL_EXPORT(GetCameraQuakeEffectFlag, ReignEngine_GetCameraQuakeEffectFlag),
HLL_EXPORT(SetCameraQuakeEffectFlag, ReignEngine_SetCameraQuakeEffectFlag),
HLL_EXPORT(SetCameraPos, ReignEngine_SetCameraPos),
HLL_EXPORT(SetCameraAngle, ReignEngine_SetCameraAngle),
HLL_EXPORT(SetCameraAngleP, ReignEngine_SetCameraAngleP),