X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=censuslogo;a=blobdiff_plain;f=src%2Flogo.c;fp=src%2Flogo.c;h=b36473d2b4ba8803d930d35083f5b436fe8e7d3f;hp=0000000000000000000000000000000000000000;hb=0dd87713321a351d6f14167c35ff6e3afcfe8ac4;hpb=fc0cfd2c7c9f5efddddb21fc94a15cc42685ca1d diff --git a/src/logo.c b/src/logo.c new file mode 100644 index 0000000..b36473d --- /dev/null +++ b/src/logo.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include "logo.h" + +struct cpnode { + cgm_vec2 p; + struct cpnode *next; +}; + +#define CPLERP(res, a, b, t) \ + do { \ + (res).x = (a).x + ((b).x - (a).x) * (t); \ + (res).y = (a).y + ((b).y - (a).y) * (t); \ + } while(0) + +static cgm_vec2 *cp; +static int numcp; + +int init_logo(const char *fname) +{ + FILE *fp; + char buf[256]; + struct cpnode *cpn, *cplist = 0, *cptail = 0; + int idx; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to load logo curve: %s\n", fname); + return -1; + } + fgets(buf, sizeof buf, fp); + if(memcmp(buf, "GCURVES", 7) != 0) { + fprintf(stderr, "invalid logo file: %s\n", fname); + fclose(fp); + return -1; + } + + numcp = 0; + while(fgets(buf, sizeof buf, fp)) { + char *ptr; + cgm_vec2 v; + + ptr = buf; + while(*ptr && isspace(*ptr)) ptr++; + + if(sscanf(ptr, "cp %f %f", &v.x, &v.y) == 2) { + if(!(cpn = malloc(sizeof *cpn))) { + continue; + } + + cpn->p.x = v.x; + cpn->p.y = v.y; + cpn->next = 0; + + if(cplist) { + cptail->next = cpn; + cptail = cpn; + } else { + cplist = cptail = cpn; + } + numcp++; + } + } + fclose(fp); + + if(numcp < 4) { + fprintf(stderr, "invalid logo file, found %d control points\n", numcp); + return -1; + } + + if(!(cp = malloc(numcp * sizeof *cp))) { + fprintf(stderr, "failed to allocate curve of %d control points\n", numcp); + while(cplist) { + cpn = cplist; + cplist = cplist->next; + free(cpn); + } + return -1; + } + + idx = 0; + while(cplist) { + cpn = cplist; + cplist = cplist->next; + cp[idx++] = cpn->p; + free(cpn); + } + + return 0; +} + +static void eval_seg(float *res, int a, int b, float t) +{ + int prev, next; + + if(numcp == 2) { + res[0] = cp[a].x + (cp[b].x - cp[a].x) * t; + res[1] = cp[a].y + (cp[b].y - cp[a].y) * t; + return; + } + + prev = a <= 0 ? a : a - 1; + next = b >= numcp - 1 ? b : b + 1; + + res[0] = cgm_bspline(cp[prev].x, cp[a].x, cp[b].x, cp[next].x, t); + res[1] = cgm_bspline(cp[prev].y, cp[a].y, cp[b].y, cp[next].y, t); +} + +void eval_logo(float *res, float t) +{ + int idx0, idx1; + float t0, t1, dt; + + if(!cp || numcp <= 0) { + res[0] = res[1] = 0; + return; + } + if(numcp == 1) { + res[0] = cp[0].x; + res[1] = cp[0].y; + return; + } + + if(t < 0.0f) t = 0.0f; + if(t > 1.0f) t = 1.0f; + + idx0 = (int)floor(t * (numcp - 1)); + if(idx0 > numcp - 2) idx0 = numcp - 2; + idx1 = idx0 + 1; + + dt = 1.0f / (float)(numcp - 1); + t0 = (float)idx0 * dt; + t1 = (float)idx1 * dt; + t = (t - t0) / (t1 - t0); + + eval_seg(res, idx0, idx1, t); +}