done with the basic effect
[censuslogo] / src / logo.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <ctype.h>
6 #include "cgmath/cgmath.h"
7 #include "logo.h"
8 #include "logodata.h"
9
10 struct cpnode {
11         cgm_vec2 p;
12         struct cpnode *next;
13 };
14
15 #define CPLERP(res, a, b, t) \
16         do { \
17                 (res).x = (a).x + ((b).x - (a).x) * (t); \
18                 (res).y = (a).y + ((b).y - (a).y) * (t); \
19         } while(0)
20
21 static cgm_vec2 *cp;
22 static int numcp;
23
24 #ifdef NOLOAD
25 int init_logo(const char *fname)
26 {
27         cp = logocp;
28         numcp = LOGO_NUM_CP;
29         return 0;
30 }
31 #else   /* !def NOLOAD */
32 int init_logo(const char *fname)
33 {
34         FILE *fp;
35         char buf[256];
36         struct cpnode *cpn, *cplist = 0, *cptail = 0;
37         int idx;
38
39         if(!(fp = fopen(fname, "rb"))) {
40                 fprintf(stderr, "failed to load logo curve: %s\n", fname);
41                 return -1;
42         }
43         fgets(buf, sizeof buf, fp);
44         if(memcmp(buf, "GCURVES", 7) != 0) {
45                 fprintf(stderr, "invalid logo file: %s\n", fname);
46                 fclose(fp);
47                 return -1;
48         }
49
50         numcp = 0;
51         while(fgets(buf, sizeof buf, fp)) {
52                 char *ptr;
53                 cgm_vec2 v;
54
55                 ptr = buf;
56                 while(*ptr && isspace(*ptr)) ptr++;
57
58                 if(sscanf(ptr, "cp %f %f", &v.x, &v.y) == 2) {
59                         if(!(cpn = malloc(sizeof *cpn))) {
60                                 continue;
61                         }
62
63                         cpn->p.x = v.x;
64                         cpn->p.y = v.y;
65                         cpn->next = 0;
66
67                         if(cplist) {
68                                 cptail->next = cpn;
69                                 cptail = cpn;
70                         } else {
71                                 cplist = cptail = cpn;
72                         }
73                         numcp++;
74                 }
75         }
76         fclose(fp);
77
78         if(numcp < 4) {
79                 fprintf(stderr, "invalid logo file, found %d control points\n", numcp);
80                 return -1;
81         }
82
83         if(!(cp = malloc(numcp * sizeof *cp))) {
84                 fprintf(stderr, "failed to allocate curve of %d control points\n", numcp);
85                 while(cplist) {
86                         cpn = cplist;
87                         cplist = cplist->next;
88                         free(cpn);
89                 }
90                 return -1;
91         }
92
93         idx = 0;
94         while(cplist) {
95                 cpn = cplist;
96                 cplist = cplist->next;
97                 cp[idx++] = cpn->p;
98                 free(cpn);
99         }
100
101         return 0;
102 }
103 #endif  /* NOLOAD */
104
105 static void eval_seg(float *res, int a, int b, float t)
106 {
107         int prev, next;
108
109         if(numcp == 2) {
110                 res[0] = cp[a].x + (cp[b].x - cp[a].x) * t;
111                 res[1] = cp[a].y + (cp[b].y - cp[a].y) * t;
112                 return;
113         }
114
115         prev = a <= 0 ? a : a - 1;
116         next = b >= numcp - 1 ? b : b + 1;
117
118         res[0] = cgm_bspline(cp[prev].x, cp[a].x, cp[b].x, cp[next].x, t);
119         res[1] = cgm_bspline(cp[prev].y, cp[a].y, cp[b].y, cp[next].y, t);
120 }
121
122 void eval_logo(float *res, float t)
123 {
124         int idx0, idx1;
125         float t0, t1, dt;
126
127         if(!cp || numcp <= 0) {
128                 res[0] = res[1] = 0;
129                 return;
130         }
131         if(numcp == 1) {
132                 res[0] = cp[0].x;
133                 res[1] = cp[0].y;
134                 return;
135         }
136
137         if(t < 0.0f) t = 0.0f;
138         if(t > 1.0f) t = 1.0f;
139
140         idx0 = (int)floor(t * (numcp - 1));
141         if(idx0 > numcp - 2) idx0 = numcp - 2;
142         idx1 = idx0 + 1;
143
144         dt = 1.0f / (float)(numcp - 1);
145         t0 = (float)idx0 * dt;
146         t1 = (float)idx1 * dt;
147         t = (t - t0) / (t1 - t0);
148
149         eval_seg(res, idx0, idx1, t);
150 }