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