nice logo
[censuslogo] / src / logo.c
diff --git a/src/logo.c b/src/logo.c
new file mode 100644 (file)
index 0000000..b36473d
--- /dev/null
@@ -0,0 +1,140 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <cgmath/cgmath.h>
+#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);
+}