cgm_vec3 pos, sz;
};
+struct erb_key {
+ long tm;
+ float val;
+};
+
+enum {
+ ERB_TRK_X, ERB_TRK_Y, ERB_TRK_Z, /* position (x,y,z) */
+ ERB_TRK_QX, ERB_TRK_QY, ERB_TRK_QZ, ERB_TRK_QW, /* rotation quat (xi+yj+zk+w) */
+ ERB_TRK_SX, ERB_TRK_SY, ERB_TRK_SZ, /* scaling (x,y,z) */
+ ERB_NUM_TRACKS
+};
+enum erb_interp { ERB_LINEAR, ERB_STEP, ERB_CUBIC };
+enum erb_extrap { ERB_CLAMP, ERB_EXTEND, ERB_REPEAT };
+
+struct erb_track {
+ enum erb_interp interp; /* interpolation mode */
+ enum erb_extrap extrap; /* extrapolation mode */
+ struct erb_key *keys; /* dynamic array of keyframes */
+ int num_keys, max_keys; /* max_keys: allocated size, num_keys: used */
+};
+
struct erb_node {
struct erb_node *par; /* parent node */
struct erb_node *clist; /* child nodes */
struct erb_surf *surflist; /* surfaces in this node */
+ struct erb_track track[ERB_NUM_TRACKS]; /* PRS keyframe tracks */
float xform[16], inv_xform[16]; /* global transformation */
float node_xform[16], inv_node_xform[16]; /* local transformation */
};
int erb_allocframe(struct erb_rend *erb, int width, int height);
float *erb_getframe(struct erb_rend *erb);
+void erb_setfov(struct erb_rend *erb, float vfov_deg);
+
/* clears the framebuffer and sample counters to begin rendering a new frame */
void erb_begin(struct erb_rend *erb);
/* finalizes the frame, averaging samples (optional) */
int erb_node_rmsurf(struct erb_node *n, struct erb_surf *s);
/* sets the transformation matrix and also calculates the inverse */
+void erb_node_pos(struct erb_node *n, long tm, float x, float y, float z);
+void erb_node_rot(struct erb_node *n, long tm, float qx, float qy, float qz, float qw);
+void erb_node_rot_axis(struct erb_node *n, long tm, float angle_deg, float x, float y, float z);
+void erb_node_scale(struct erb_node *n, long tm, float sx, float sy, float sz);
+/* calculates transformation matrices for time tm by keyframe interpolation */
+void erb_node_update(struct erb_node *n, long tm);
+/* sets transformation, ignoring animation keyframes */
void erb_node_setxform(struct erb_node *n, float *mat);
+void erb_node_eval_pos(struct erb_node *n, long tm, cgm_vec3 *pos);
+void erb_node_eval_rot(struct erb_node *n, long tm, cgm_quat *rot);
+void erb_node_eval_scale(struct erb_node *n, long tm, cgm_vec3 *scale);
+
+void erb_node_eval_matrix(struct erb_node *n, long tm, float *mat); /* mat[16] */
+void erb_node_eval_node_matrix(struct erb_node *n, long tm, float *mat); /* mat[16] */
+
/* surfaces */
struct erb_surf *erb_surface(int datasz);
void erb_free_surface(struct erb_surf *surf);
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include "erebus.h"
+
+static struct erb_key *findkey(struct erb_track *trk, long tm);
+static int setkey(struct erb_track *trk, long key, float val);
+static float evalkey(struct erb_track *trk, long key);
+
+void erb_node_pos(struct erb_node *n, long tm, float x, float y, float z)
+{
+ setkey(n->track + ERB_TRK_X, tm, x);
+ setkey(n->track + ERB_TRK_Y, tm, y);
+ setkey(n->track + ERB_TRK_Z, tm, z);
+}
+
+void erb_node_rot(struct erb_node *n, long tm, float qx, float qy, float qz, float qw)
+{
+ setkey(n->track + ERB_TRK_QX, tm, qx);
+ setkey(n->track + ERB_TRK_QY, tm, qy);
+ setkey(n->track + ERB_TRK_QZ, tm, qz);
+ setkey(n->track + ERB_TRK_QW, tm, qw);
+}
+
+void erb_node_rot_axis(struct erb_node *n, long tm, float angle_deg, float x, float y, float z)
+{
+ cgm_quat q;
+ cgm_qrotation(&q, cgm_deg_to_rad(angle_deg), x, y, z);
+ erb_node_rot(n, tm, q.x, q.y, q.z, q.w);
+}
+
+void erb_node_scale(struct erb_node *n, long tm, float sx, float sy, float sz)
+{
+ setkey(n->track + ERB_TRK_SX, tm, sx);
+ setkey(n->track + ERB_TRK_SY, tm, sy);
+ setkey(n->track + ERB_TRK_SZ, tm, sz);
+}
+
+void erb_node_update(struct erb_node *n, long tm)
+{
+ erb_node_eval_node_matrix(n, tm, n->node_xform);
+
+ cgm_mcopy(n->inv_node_xform, n->node_xform);
+ cgm_minverse(n->inv_node_xform);
+
+ cgm_mcopy(n->xform, n->node_xform);
+ cgm_mcopy(n->inv_xform, n->inv_node_xform);
+
+ if(n->par) {
+ cgm_mmul(n->xform, n->par->xform);
+ cgm_mpremul(n->inv_xform, n->par->inv_xform);
+ }
+}
+
+void erb_node_setxform(struct erb_node *n, float *mat)
+{
+ cgm_mcopy(n->node_xform, mat);
+ cgm_mcopy(n->inv_node_xform, mat);
+ cgm_minverse(n->inv_node_xform);
+
+ cgm_mcopy(n->xform, n->node_xform);
+ cgm_mcopy(n->inv_xform, n->inv_node_xform);
+
+ if(n->par) {
+ cgm_mmul(n->xform, n->par->xform);
+ cgm_mpremul(n->inv_xform, n->par->inv_xform);
+ }
+}
+
+void erb_node_eval_pos(struct erb_node *n, long tm, cgm_vec3 *pos)
+{
+ pos->x = evalkey(n->track + ERB_TRK_X, tm);
+ pos->y = evalkey(n->track + ERB_TRK_Y, tm);
+ pos->z = evalkey(n->track + ERB_TRK_Z, tm);
+}
+
+void erb_node_eval_rot(struct erb_node *n, long tm, cgm_quat *rot)
+{
+ rot->x = evalkey(n->track + ERB_TRK_QX, tm);
+ rot->y = evalkey(n->track + ERB_TRK_QY, tm);
+ rot->z = evalkey(n->track + ERB_TRK_QZ, tm);
+ rot->w = evalkey(n->track + ERB_TRK_QW, tm);
+}
+
+void erb_node_eval_scale(struct erb_node *n, long tm, cgm_vec3 *scale)
+{
+ scale->x = evalkey(n->track + ERB_TRK_SX, tm);
+ scale->y = evalkey(n->track + ERB_TRK_SY, tm);
+ scale->z = evalkey(n->track + ERB_TRK_SZ, tm);
+}
+
+void erb_node_eval_matrix(struct erb_node *n, long tm, float *mat)
+{
+ erb_node_eval_node_matrix(n, tm, mat);
+ if(n->par) {
+ cgm_mmul(mat, n->par->xform);
+ }
+}
+
+void erb_node_eval_node_matrix(struct erb_node *n, long tm, float *mat)
+{
+ cgm_vec3 pos, scale;
+ cgm_quat rot;
+
+ erb_node_eval_pos(n, tm, &pos);
+ erb_node_eval_rot(n, tm, &rot);
+ erb_node_eval_scale(n, tm, &scale);
+
+ cgm_midentity(mat);
+ cgm_mtranslate(mat, pos.x, pos.y, pos.z);
+ cgm_mrotate_quat(mat, &rot);
+ cgm_mscale(mat, scale.x, scale.y, scale.z);
+}
+
+static struct erb_key *findkey(struct erb_track *trk, long tm)
+{
+ struct erb_key *beg, *end, *mid;
+
+ /* TODO: if num_keys < something_small, do linear search */
+ if(trk->num_keys <= 0) return 0;
+
+ beg = trk->keys;
+ end = trk->keys + trk->num_keys;
+
+ while(beg < end) {
+ mid = beg + ((end - beg) >> 1);
+
+ if(tm == mid->tm) return mid;
+ if(tm < mid->tm) {
+ end = mid;
+ } else {
+ beg = mid + 1;
+ }
+ }
+ return beg;
+}
+
+
+static int setkey(struct erb_track *trk, long tm, float val)
+{
+ int rest;
+ struct erb_key *key;
+
+ if((key = findkey(trk, tm)) && key->tm == tm) {
+ key->val = val;
+ return 0;
+ }
+
+ if(trk->num_keys >= trk->max_keys) {
+ int newsz = trk->max_keys ? trk->max_keys << 1 : 8;
+ void *ptr;
+
+ if(!(ptr = realloc(trk->keys, newsz * sizeof *key))) {
+ fprintf(stderr, "erebus: failed to add keyframe (realloc track failed)\n");
+ return -1;
+ }
+ trk->keys = ptr;
+ trk->max_keys = newsz;
+ }
+
+ key++;
+ rest = trk->num_keys - (key - trk->keys);
+ if(rest > 0) {
+ memmove(key + 1, key, rest * sizeof *key);
+ }
+ key->tm = tm;
+ key->val = val;
+ trk->num_keys++;
+ return 0;
+}
+
+static float evalkey(struct erb_track *trk, long tm)
+{
+ /* TODO */
+ return 0;
+}