dungeon_crawler
diff prototype/anim/track.c @ 67:2560a7ab0243
internalized libanim, libimago2, and libpsys
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 07 Oct 2012 02:04:00 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/prototype/anim/track.c Sun Oct 07 02:04:00 2012 +0300 1.3 @@ -0,0 +1,272 @@ 1.4 +#include <stdlib.h> 1.5 +#include <string.h> 1.6 +#include <assert.h> 1.7 +#include "track.h" 1.8 +#include "dynarr.h" 1.9 + 1.10 +static int keycmp(const void *a, const void *b); 1.11 +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm); 1.12 + 1.13 +static float interp_step(float v0, float v1, float v2, float v3, float t); 1.14 +static float interp_linear(float v0, float v1, float v2, float v3, float t); 1.15 +static float interp_cubic(float v0, float v1, float v2, float v3, float t); 1.16 + 1.17 +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end); 1.18 +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end); 1.19 +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end); 1.20 + 1.21 +/* XXX keep this in sync with enum anm_interpolator at track.h */ 1.22 +static float (*interp[])(float, float, float, float, float) = { 1.23 + interp_step, 1.24 + interp_linear, 1.25 + interp_cubic, 1.26 + 0 1.27 +}; 1.28 + 1.29 +/* XXX keep this in sync with enum anm_extrapolator at track.h */ 1.30 +static anm_time_t (*remap_time[])(anm_time_t, anm_time_t, anm_time_t) = { 1.31 + remap_extend, 1.32 + remap_clamp, 1.33 + remap_repeat, 1.34 + 0 1.35 +}; 1.36 + 1.37 +int anm_init_track(struct anm_track *track) 1.38 +{ 1.39 + memset(track, 0, sizeof *track); 1.40 + 1.41 + if(!(track->keys = dynarr_alloc(0, sizeof *track->keys))) { 1.42 + return -1; 1.43 + } 1.44 + track->interp = ANM_INTERP_LINEAR; 1.45 + track->extrap = ANM_EXTRAP_CLAMP; 1.46 + return 0; 1.47 +} 1.48 + 1.49 +void anm_destroy_track(struct anm_track *track) 1.50 +{ 1.51 + dynarr_free(track->keys); 1.52 +} 1.53 + 1.54 +struct anm_track *anm_create_track(void) 1.55 +{ 1.56 + struct anm_track *track; 1.57 + 1.58 + if((track = malloc(sizeof *track))) { 1.59 + if(anm_init_track(track) == -1) { 1.60 + free(track); 1.61 + return 0; 1.62 + } 1.63 + } 1.64 + return track; 1.65 +} 1.66 + 1.67 +void anm_free_track(struct anm_track *track) 1.68 +{ 1.69 + anm_destroy_track(track); 1.70 + free(track); 1.71 +} 1.72 + 1.73 +int anm_set_track_name(struct anm_track *track, const char *name) 1.74 +{ 1.75 + char *tmp; 1.76 + 1.77 + if(!(tmp = malloc(strlen(name) + 1))) { 1.78 + return -1; 1.79 + } 1.80 + free(track->name); 1.81 + track->name = tmp; 1.82 + return 0; 1.83 +} 1.84 + 1.85 +const char *anm_get_track_name(struct anm_track *track) 1.86 +{ 1.87 + return track->name; 1.88 +} 1.89 + 1.90 +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in) 1.91 +{ 1.92 + track->interp = in; 1.93 +} 1.94 + 1.95 +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex) 1.96 +{ 1.97 + track->extrap = ex; 1.98 +} 1.99 + 1.100 +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end) 1.101 +{ 1.102 + return remap_time[track->extrap](tm, start, end); 1.103 +} 1.104 + 1.105 +void anm_set_track_default(struct anm_track *track, float def) 1.106 +{ 1.107 + track->def_val = def; 1.108 +} 1.109 + 1.110 +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key) 1.111 +{ 1.112 + int idx = anm_get_key_interval(track, key->time); 1.113 + 1.114 + /* if we got a valid keyframe index, compare them... */ 1.115 + if(idx >= 0 && idx < track->count && keycmp(key, track->keys + idx) == 0) { 1.116 + /* ... it's the same key, just update the value */ 1.117 + track->keys[idx].val = key->val; 1.118 + } else { 1.119 + /* ... it's a new key, add it and re-sort them */ 1.120 + void *tmp; 1.121 + if(!(tmp = dynarr_push(track->keys, key))) { 1.122 + return -1; 1.123 + } 1.124 + track->keys = tmp; 1.125 + /* TODO lazy qsort */ 1.126 + qsort(track->keys, ++track->count, sizeof *track->keys, keycmp); 1.127 + } 1.128 + return 0; 1.129 +} 1.130 + 1.131 +static int keycmp(const void *a, const void *b) 1.132 +{ 1.133 + return ((struct anm_keyframe*)a)->time - ((struct anm_keyframe*)b)->time; 1.134 +} 1.135 + 1.136 +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx) 1.137 +{ 1.138 + if(idx < 0 || idx >= track->count) { 1.139 + return 0; 1.140 + } 1.141 + return track->keys + idx; 1.142 +} 1.143 + 1.144 +int anm_get_key_interval(struct anm_track *track, anm_time_t tm) 1.145 +{ 1.146 + int last; 1.147 + 1.148 + if(!track->count || tm < track->keys[0].time) { 1.149 + return -1; 1.150 + } 1.151 + 1.152 + last = track->count - 1; 1.153 + if(tm > track->keys[last].time) { 1.154 + return last; 1.155 + } 1.156 + 1.157 + return find_prev_key(track->keys, 0, last, tm); 1.158 +} 1.159 + 1.160 +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm) 1.161 +{ 1.162 + int mid; 1.163 + 1.164 + if(end - start <= 1) { 1.165 + return start; 1.166 + } 1.167 + 1.168 + mid = (start + end) / 2; 1.169 + if(tm < arr[mid].time) { 1.170 + return find_prev_key(arr, start, mid, tm); 1.171 + } 1.172 + if(tm > arr[mid].time) { 1.173 + return find_prev_key(arr, mid, end, tm); 1.174 + } 1.175 + return mid; 1.176 +} 1.177 + 1.178 +int anm_set_value(struct anm_track *track, anm_time_t tm, float val) 1.179 +{ 1.180 + struct anm_keyframe key; 1.181 + key.time = tm; 1.182 + key.val = val; 1.183 + 1.184 + return anm_set_keyframe(track, &key); 1.185 +} 1.186 + 1.187 +float anm_get_value(struct anm_track *track, anm_time_t tm) 1.188 +{ 1.189 + int idx0, idx1, last_idx; 1.190 + anm_time_t tstart, tend; 1.191 + float t, dt; 1.192 + float v0, v1, v2, v3; 1.193 + 1.194 + if(!track->count) { 1.195 + return track->def_val; 1.196 + } 1.197 + 1.198 + last_idx = track->count - 1; 1.199 + 1.200 + tstart = track->keys[0].time; 1.201 + tend = track->keys[last_idx].time; 1.202 + 1.203 + if(tstart == tend) { 1.204 + return track->keys[0].val; 1.205 + } 1.206 + 1.207 + tm = remap_time[track->extrap](tm, tstart, tend); 1.208 + 1.209 + idx0 = anm_get_key_interval(track, tm); 1.210 + assert(idx0 >= 0 && idx0 < track->count); 1.211 + idx1 = idx0 + 1; 1.212 + 1.213 + if(idx0 == last_idx) { 1.214 + return track->keys[idx0].val; 1.215 + } 1.216 + 1.217 + dt = (float)(track->keys[idx1].time - track->keys[idx0].time); 1.218 + t = (float)(tm - track->keys[idx0].time) / dt; 1.219 + 1.220 + v1 = track->keys[idx0].val; 1.221 + v2 = track->keys[idx1].val; 1.222 + 1.223 + /* get the neigboring values to allow for cubic interpolation */ 1.224 + v0 = idx0 > 0 ? track->keys[idx0 - 1].val : v1; 1.225 + v3 = idx1 < last_idx ? track->keys[idx1 + 1].val : v2; 1.226 + 1.227 + return interp[track->interp](v0, v1, v2, v3, t); 1.228 +} 1.229 + 1.230 + 1.231 +static float interp_step(float v0, float v1, float v2, float v3, float t) 1.232 +{ 1.233 + return v1; 1.234 +} 1.235 + 1.236 +static float interp_linear(float v0, float v1, float v2, float v3, float t) 1.237 +{ 1.238 + return v1 + (v2 - v1) * t; 1.239 +} 1.240 + 1.241 +static float interp_cubic(float a, float b, float c, float d, float t) 1.242 +{ 1.243 + float x, y, z, w; 1.244 + float tsq = t * t; 1.245 + 1.246 + x = -a + 3.0 * b - 3.0 * c + d; 1.247 + y = 2.0 * a - 5.0 * b + 4.0 * c - d; 1.248 + z = c - a; 1.249 + w = 2.0 * b; 1.250 + 1.251 + return 0.5 * (x * tsq * t + y * tsq + z * t + w); 1.252 +} 1.253 + 1.254 +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end) 1.255 +{ 1.256 + return remap_repeat(tm, start, end); 1.257 +} 1.258 + 1.259 +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end) 1.260 +{ 1.261 + return tm < start ? start : (tm >= end ? end - 1 : tm); 1.262 +} 1.263 + 1.264 +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end) 1.265 +{ 1.266 + anm_time_t interv = end - start; 1.267 + 1.268 + if(tm < start) { 1.269 + while(tm < start) { 1.270 + tm += interv; 1.271 + } 1.272 + return tm; 1.273 + } 1.274 + return (tm - start) % interv + start; 1.275 +}