--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/gl.h>
+#include "app.h"
+#include "logo.h"
+
+#ifndef GL_MULTISAMPLE
+#define GL_MULTISAMPLE 0x809d
+#endif
+
+int nverts = 256;
+int msaa = 1;
+int fullscr = 0;
+
+
+static void draw_disc(float x, float y, float rad, int sub);
+static void draw_line(float x0, float y0, float x1, float y1, float rad);
+static void print_usage(const char *argv0);
+
+int app_init(void)
+{
+ if(init_logo("data/census.curves") == -1) {
+ return -1;
+ }
+
+#ifdef MSAA
+ if(msaa) {
+ glEnable(GL_MULTISAMPLE);
+ }
+#endif
+
+ return 0;
+}
+
+#define LOOPTIME 1.45f
+
+void app_display(void)
+{
+ int i;
+ float t = (float)msec / 1000.0f;
+ float a[2], b[2], dt;
+ float anim, alpha;
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glLineWidth(5.0);
+
+ anim = fmod(t / 6.0f, LOOPTIME);
+ alpha = 1.0f - ((anim - (LOOPTIME - 0.075)) / 0.06f);
+ if(alpha < 0.0f) alpha = 0.0f;
+ if(alpha > 1.0f) alpha = 1.0f;
+
+ dt = (anim > 1.0f ? 1.0f : anim) / (float)(nverts - 1);
+
+ glColor4f(1, 1, 1, alpha);
+ for(i=0; i<nverts-1; i++) {
+ float t0 = (float)i * dt;
+ float t1 = (float)(i + 1) * dt;
+ eval_logo(a, t0);
+ eval_logo(b, t1);
+ draw_line(a[0], a[1], b[0], b[1], 0.02);
+ }
+
+ if(anim > 0.0f) {
+ eval_logo(a, 0);
+ draw_disc(a[0], a[1], 0.05, 22);
+ }
+ if(anim >= 1.0f) {
+ eval_logo(b, 1);
+ draw_disc(b[0], b[1], 0.05, 22);
+ }
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glColor4f(0.8, 0, 0, 2.0 * (anim - 1.0f) / (LOOPTIME - 1.0f));
+ draw_disc(0, 0, 0.14, 30);
+
+ if(alpha < 1.0f) {
+ glBegin(GL_QUADS);
+ glColor4f(0, 0, 0, 1.0f - alpha);
+ glVertex2f(-1, -1);
+ glVertex2f(1, -1);
+ glVertex2f(1, 1);
+ glVertex2f(-1, 1);
+ glEnd();
+ }
+
+ glDisable(GL_BLEND);
+}
+
+static void draw_disc(float x, float y, float rad, int sub)
+{
+ int i;
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(x, y);
+ for(i=0; i<sub; i++) {
+ float t = (float)i / (float)(sub - 1);
+ float theta = t * M_PI * 2.0;
+ glVertex2f(cos(theta) * rad + x, sin(theta) * rad + y);
+ }
+ glEnd();
+}
+
+static void draw_line(float x0, float y0, float x1, float y1, float rad)
+{
+ float dx, dy, rx, ry, len;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+ len = sqrt(dx * dx + dy * dy);
+
+ rx = rad * dy / len;
+ ry = -rad * dx / len;
+
+ draw_disc(x0, y0, rad, 12);
+ draw_disc(x1, y1, rad, 12);
+
+ glBegin(GL_QUADS);
+ glVertex2f(x0 + rx, y0 + ry);
+ glVertex2f(x1 + rx, y1 + ry);
+ glVertex2f(x1 - rx, y1 - ry);
+ glVertex2f(x0 - rx, y0 - ry);
+ glEnd();
+}
+
+
+void app_reshape(int x, int y)
+{
+ float aspect = (float)x / (float)y;
+ glViewport(0, 0, x, y);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glScalef(1.0f / aspect, 1.0f, 1.0f);
+}
+
+void app_keyboard(int key, int pressed)
+{
+ switch(key) {
+ case 27:
+ app_quit();
+
+ case '-':
+ nverts -= 8;
+ printf("nverts: %d\n", nverts);
+ break;
+
+ case '=':
+ nverts += 8;
+ printf("nverts: %d\n", nverts);
+ break;
+
+ case 'f':
+ fullscr = !fullscr;
+ if(fullscr) {
+ app_fullscreen();
+ } else {
+ app_windowed();
+ }
+ break;
+ }
+}
+
+
+int app_parse_args(int argc, char **argv)
+{
+ int i;
+
+ for(i=1; i<argc; i++) {
+ if(argv[i][0] == '-') {
+ if(strcmp(argv[i], "-fs") == 0) {
+ fullscr = 1;
+ } else if(strcmp(argv[i], "-noaa") == 0) {
+ msaa = 0;
+ } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
+ print_usage(argv[0]);
+ exit(0);
+ } else {
+ fprintf(stderr, "invalid option: %s\n", argv[i]);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "unexpected argument: %s\n", argv[i]);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void print_usage(const char *argv0)
+{
+ printf("Usage: %s [options]\n", argv0);
+ printf("Options:\n");
+ printf(" -fs: fullscreen\n");
+ printf(" -noaa: disable anti-aliasing\n");
+ printf(" -h,-help: print usage and exit\n");
+}