#include "cell.h" #include "stb_ds.h" #include "HandmadeMath.h" #include "math.h" #include "time.h" #define CGLTF_IMPLEMENTATION #include "cgltf.h" #include #include #include struct keyframe { double time; double val; }; #define LINEAR 0 #define STEP 1 #define CUBICSPLINE 2 #define SLERP 3 typedef struct sampler { float *times; HMM_Vec4 *data; int type; } sampler; struct anim_channel { HMM_Vec4 *target; int comps; struct sampler *sampler; }; typedef struct animation { double time; struct anim_channel *channels; sampler *samplers; } animation; HMM_Vec4 sample_cubicspline(sampler *sampler, float t, int prev, int next) { HMM_Vec4 ret; HMM_Quat qv = HMM_SLerp(HMM_QV4(sampler->data[prev]), t, HMM_QV4(sampler->data[next])); memcpy(ret.e, qv.e, sizeof(ret.e)); return ret; } HMM_Vec4 sample_sampler(sampler *sampler, float time) { if (arrlen(sampler->data) == 0) return v4zero; if (arrlen(sampler->data) == 1) return sampler->data[0]; int previous_time=0; int next_time=0; for (int i = 1; i < arrlen(sampler->times); i++) { if (time < sampler->times[i]) { previous_time = i-1; next_time = i; break; } } float td = sampler->times[next_time]-sampler->times[previous_time]; float t = (time - sampler->times[previous_time])/td; HMM_Vec4 ret; HMM_Quat qv; switch(sampler->type) { case LINEAR: return HMM_LerpV4(sampler->data[previous_time],time,sampler->data[next_time]); break; case STEP: return sampler->data[previous_time]; break; case CUBICSPLINE: return sample_cubicspline(sampler,t, previous_time, next_time); break; case SLERP: qv = HMM_SLerp(sampler->data[previous_time].quat, time, sampler->data[next_time].quat); memcpy(ret.e,qv.e,sizeof(ret.e)); return ret; break; } return sample_cubicspline(sampler,t, previous_time, next_time); } void animation_run(struct animation *anim, float now) { float elapsed = now - anim->time; elapsed = fmod(elapsed,2); if (!anim->channels) return; for (int i = 0; i < arrlen(anim->channels); i++) { struct anim_channel *ch = anim->channels+i; HMM_Vec4 s = sample_sampler(ch->sampler, elapsed); *(ch->target) = s; } } #define MAT_POS 0 #define MAT_UV 1 #define MAT_NORM 2 #define MAT_BONE 3 #define MAT_WEIGHT 4 #define MAT_COLOR 5 #define MAT_TAN 6 #define MAT_ANGLE 7 #define MAT_WH 8 #define MAT_ST 9 #define MAT_PPOS 10 #define MAT_SCALE 11 #define MAT_INDEX 100 typedef struct md5joint { struct md5joint *parent; HMM_Vec4 pos; HMM_Quat rot; HMM_Vec4 scale; HMM_Mat4 t; } md5joint; typedef struct skin { md5joint *joints; HMM_Mat4 *invbind; HMM_Mat4 binds[50]; /* binds = joint * invbind */ animation *anim; } skin; SDL_GPUBuffer *texcoord_floats(float *f, int n) { return NULL; } SDL_GPUBuffer *float_buffer(float *f, int v) { return NULL; } SDL_GPUBuffer *index_buffer(float *f, int verts) { return NULL; } uint32_t pack_int10_n2(float *norm) { uint32_t ret = 0; for (int i = 0; i < 3; i++) { int n = (norm[i]+1.0)*511; ret |= (n & 0x3ff) << (10*i); } return ret; } // Pack an array of normals into SDL_GPUBuffer *normal_floats(float *f, int n) { return float_buffer(f, n); } SDL_GPUBuffer *ubyten_buffer(float *f, int v) { return NULL; } SDL_GPUBuffer *ubyte_buffer(float *f, int v) { return NULL; } SDL_GPUBuffer *accessor2buffer(cgltf_accessor *a, int type) { return NULL; } void packFloats(float *src, float *dest, int srcLength) { int i, j; for (i = 0, j = 0; i < srcLength; i += 3, j += 4) { dest[j] = src[i]; dest[j + 1] = src[i + 1]; dest[j + 2] = src[i + 2]; dest[j + 3] = 0.0f; } } static md5joint *node2joint(skin *sk, cgltf_node *n, cgltf_skin *skin) { int k = 0; while (skin->joints[k] != n && k < skin->joints_count) k++; return sk->joints+k; } animation *gltf_anim(cgltf_animation *anim, skin *sk, cgltf_skin *skin) { animation *ret = calloc(sizeof(*ret), 1); animation an = *ret; arrsetlen(an.samplers, anim->samplers_count); for (int i = 0; i < anim->samplers_count; i++) { cgltf_animation_sampler s = anim->samplers[i]; sampler samp = (sampler){0}; int n = cgltf_accessor_unpack_floats(s.input, NULL, 0); arrsetlen(samp.times, n); cgltf_accessor_unpack_floats(s.input, samp.times, n); n = cgltf_accessor_unpack_floats(s.output, NULL, 0); int comp = cgltf_num_components(s.output->type); arrsetlen(samp.data, n/comp); if (comp == 4) cgltf_accessor_unpack_floats(s.output, samp.data, n); else { float *out = malloc(sizeof(*out)*n); cgltf_accessor_unpack_floats(s.output, out, n); packFloats(out, samp.data, n); free(out); } samp.type = s.interpolation; if (samp.type == LINEAR && comp == 4) samp.type = SLERP; an.samplers[i] = samp; } for (int i = 0; i < anim->channels_count; i++) { cgltf_animation_channel ch = anim->channels[i]; struct anim_channel ach = (struct anim_channel){0}; md5joint *md = node2joint(sk, ch.target_node, skin); switch(ch.target_path) { case cgltf_animation_path_type_translation: ach.target = &md->pos; break; case cgltf_animation_path_type_rotation: ach.target = &md->rot; break; case cgltf_animation_path_type_scale: ach.target = &md->scale; break; default: break; } ach.sampler = an.samplers+(ch.sampler-anim->samplers); arrput(an.channels, ach); } an.time = 0; *ret = an; return ret; } skin *make_gltf_skin(cgltf_skin *skin, cgltf_data *data) { int n = cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, NULL, 0); struct skin *sk = NULL; sk = calloc(sizeof(*sk),1); arrsetlen(sk->invbind, n/16); cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, sk->invbind, n); arrsetlen(sk->joints, skin->joints_count); for (int i = 0; i < 50; i++) sk->binds[i] = MAT1; for (int i = 0; i < skin->joints_count; i++) { cgltf_node *n = skin->joints[i]; md5joint *j = sk->joints+i; if (n == skin->skeleton) j->parent = NULL; else j->parent = node2joint(sk, n->parent, skin); for (int i = 0; i < 3; i++) { j->pos.e[i] = n->translation[i]; j->scale.e[i] = n->scale[i]; } for (int i = 0; i < 4; i++) j->rot.e[i] = n->rotation[i]; } sk->anim = gltf_anim(data->animations+0, sk, skin); return sk; } void skin_calculate(skin *sk) { // animation_run(sk->anim, apptime()); for (int i = 0; i < arrlen(sk->joints); i++) { md5joint *md = sk->joints+i; md->t = HMM_M4TRS(md->pos.xyz, md->rot, md->scale.xyz); if (md->parent) md->t = HMM_MulM4(md->parent->t, md->t); sk->binds[i] = HMM_MulM4(md->t, sk->invbind[i]); } }