summaryrefslogtreecommitdiff
path: root/flowers-demo.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-09-30 17:37:24 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-09-30 17:38:00 +0100
commitaba8a4c897b97aba9bc798567b2a9a52eac79351 (patch)
tree4621c11eb617174716ac292392c23738cbd5f6a6 /flowers-demo.c
parenta1c3b6e061c298861bcd9ae52d5756aa9258c5b7 (diff)
Add the flowers-demo from ages ago.
Diffstat (limited to 'flowers-demo.c')
-rw-r--r--flowers-demo.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/flowers-demo.c b/flowers-demo.c
new file mode 100644
index 0000000..585805e
--- /dev/null
+++ b/flowers-demo.c
@@ -0,0 +1,462 @@
+/*
+ * Pretty cairo flower hack.
+ *
+ * Removed the redundant clutter.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#include "demo.h"
+
+#define PETAL_MIN 20
+#define PETAL_VAR 40
+#define N_FLOWERS 40
+
+#define ARRAY_LENGTH(A) ((int) sizeof (A) / sizeof (A[0]))
+
+typedef struct _flower {
+ cairo_pattern_t *pattern;
+ int n_groups;
+ int n_petals[4];
+ int color[5];
+ int rotation[4];
+ int pm1[4], pm2[4];
+ int size, petal_size[5];
+ int x, y, v;
+ double rot, rv;
+ double fade, dfade;
+} flower_t;
+
+static flower_t flowers[N_FLOWERS];
+
+/* No science here, just a hack from toying */
+static const struct {
+ double red, green, blue;
+} colors[] = {
+ { 0.71, 0.81, 0.83 },
+ { 1.00, 0.78, 0.57 },
+ { 0.64, 0.30, 0.35 },
+ { 0.73, 0.40, 0.39 },
+ { 0.91, 0.56, 0.64 },
+ { 0.70, 0.47, 0.45 },
+ { 0.92, 0.75, 0.60 },
+ { 0.82, 0.86, 0.85 },
+ { 0.51, 0.56, 0.67 },
+ { 1.00, 0.79, 0.58 },
+};
+
+static void
+make_fast_flower (cairo_surface_t *target, flower_t *f, int w, int h)
+{
+ int petal_size;
+ int n_groups; /* Num groups of petals 1-3 */
+ int n_petals; /* num of petals 4 - 8 */
+ int pm1, pm2;
+ int idx, last_idx = -1;
+ int i, j;
+
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ n_groups = rand () % 3 + 1;
+ petal_size = PETAL_MIN + rand () % PETAL_VAR;
+ f->size = petal_size * 8;
+
+ f->x = (rand() % w - f->size) + f->size/2.;
+ f->y = rand() % h;
+ f->rot = fmod (rand(), 2 * M_PI);
+ f->rv = (fmod (rand(), 5.) + 1) * M_PI * 2. /360.;
+ f->v = rand() % 10 + 2;
+ f->fade = fmod (rand(), 100) / 100.;
+ f->dfade = .01 * fmod (rand(), 100) / 100.;
+
+ surface = cairo_surface_create_similar (target,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ f->size, f->size);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ cairo_translate (cr, f->size/2., f->size/2.);
+
+ for (i = 0; i < n_groups; i++) {
+ n_petals = rand () % 5 + 4;
+ cairo_save (cr);
+
+ cairo_rotate (cr, rand() % 6);
+
+ do {
+ idx = rand () % ARRAY_LENGTH (colors);
+ } while (idx == last_idx);
+
+ cairo_set_source_rgba (cr,
+ colors[idx].red,
+ colors[idx].green,
+ colors[idx].blue,
+ 0.5);
+
+ last_idx = idx;
+
+ /* some bezier randomness */
+ pm1 = rand() % 20;
+ pm2 = rand() % 4;
+
+ for (j = 0; j < n_petals; j++) {
+ /* Petals are made up beziers */
+ cairo_move_to (cr, 0, 0);
+ cairo_rel_curve_to (cr,
+ petal_size, petal_size,
+ (pm2+2)*petal_size, petal_size,
+ 2*petal_size + pm1, 0);
+ cairo_rel_curve_to (cr,
+ 0 + (pm2*petal_size), -petal_size,
+ -petal_size, -petal_size,
+ -(2*petal_size + pm1), 0);
+ cairo_close_path (cr);
+
+ cairo_rotate (cr, 2*M_PI / n_petals);
+ }
+ cairo_fill_preserve (cr);
+
+ cairo_set_line_width (cr, 1.);
+ cairo_set_source_rgb (cr,
+ colors[idx].red,
+ colors[idx].green,
+ colors[idx].blue);
+ cairo_stroke (cr);
+
+ petal_size -= rand () % (f->size/8);
+
+ cairo_restore (cr);
+ }
+
+ /* Finally draw flower center */
+ do {
+ idx = rand() % ARRAY_LENGTH (colors);
+ } while (idx == last_idx);
+
+ cairo_set_source_rgba (cr,
+ colors[idx].red,
+ colors[idx].green,
+ colors[idx].blue,
+ 0.5);
+
+ if (petal_size < 0)
+ petal_size = rand() % 10;
+
+ cairo_arc (cr, 0, 0, petal_size, 0, M_PI * 2);
+ cairo_fill (cr);
+
+ if (petal_size > 4) {
+ cairo_arc (cr, 0, 0, petal_size - 2, 0, M_PI * 2);
+ cairo_set_line_width (cr, 2.);
+ cairo_set_source_rgba (cr,
+ colors[idx].red,
+ colors[idx].green,
+ colors[idx].blue,
+ .75);
+ cairo_stroke (cr);
+ }
+
+ f->pattern = cairo_pattern_create_for_surface (cairo_get_target (cr));
+ cairo_destroy (cr);
+}
+
+static void
+fast_flowers_draw (cairo_t *cr)
+{
+ int i;
+
+ for (i = 0; i< N_FLOWERS; i++) {
+ cairo_matrix_t m;
+ double mid;
+
+ mid = flowers[i].size / 2.;
+ cairo_matrix_init_translate (&m, mid, mid);
+ cairo_matrix_rotate (&m, flowers[i].rot);
+ cairo_matrix_translate (&m, -mid, -mid);
+ cairo_matrix_translate (&m, -flowers[i].x, -flowers[i].y);
+ cairo_pattern_set_matrix (flowers[i].pattern, &m);
+
+ cairo_set_source (cr, flowers[i].pattern);
+ cairo_paint_with_alpha (cr, flowers[i].fade);
+ }
+}
+
+static void
+make_naive_flower (cairo_surface_t *target, flower_t *f, int w, int h)
+{
+ int i, idx, last_idx = -1;
+ int petal_size;
+
+ f->n_groups = rand () % 3 + 1;
+ petal_size = PETAL_MIN + rand () % PETAL_VAR;
+ f->size = petal_size * 8;
+
+ for (i = 0; i < f->n_groups; i++) {
+ f->n_petals[i] = rand () % 5 + 4;
+ do {
+ idx = rand () % ARRAY_LENGTH (colors);
+ } while (idx == last_idx);
+ f->color[i] = idx;
+ f->rotation[i] = rand() % 6;
+ /* some bezier randomness */
+ f->pm1[i] = rand() % 20;
+ f->pm2[i] = rand() % 4;
+ f->petal_size[i] = petal_size;
+
+ petal_size -= rand () % (f->size/8);
+ }
+ if (petal_size < 0)
+ petal_size = rand() % 10;
+ f->petal_size[i] = petal_size;
+ do {
+ idx = rand() % ARRAY_LENGTH (colors);
+ } while (idx == last_idx);
+ f->color[i] = idx;
+
+
+
+ f->x = (rand() % w - f->size) + f->size/2.;
+ f->y = rand() % h;
+ f->rot = fmod (rand(), 2 * M_PI);
+ f->rv = (fmod (rand(), 5.) + 1) * M_PI * 2. /360.;
+ f->v = rand() % 10 + 2;
+ f->fade = fmod (rand(), 100) / 100.;
+ f->dfade = .01 * fmod (rand(), 100) / 100.;
+}
+
+static void
+naive_flowers_draw (cairo_t *cr)
+{
+ int i, j, n;
+
+ for (n = 0; n< N_FLOWERS; n++) {
+ flower_t *f = &flowers[n];
+ cairo_matrix_t m;
+
+ cairo_rectangle (cr, 0, 0, f->size, f->size);
+ cairo_clip (cr);
+ cairo_push_group (cr); {
+ cairo_reset_clip (cr);
+ cairo_translate (cr, f->size/2., f->size/2.);
+ cairo_rotate (cr, f->rot);
+
+ for (i = 0; i < f->n_groups; i++) {
+ int n_petals = f->n_petals[i];
+ cairo_save (cr);
+
+ cairo_rotate (cr, f->rotation[i]);
+ cairo_set_source_rgba (cr,
+ colors[f->color[i]].red,
+ colors[f->color[i]].green,
+ colors[f->color[i]].blue,
+ 0.5);
+
+ for (j = 0; j < n_petals; j++) {
+ /* Petals are made up beziers */
+ cairo_move_to (cr, 0, 0);
+ cairo_rel_curve_to (cr,
+ f->petal_size[i], f->petal_size[i],
+ (f->pm2[i]+2)*f->petal_size[i], f->petal_size[i],
+ 2*f->petal_size[i] + f->pm1[i], 0);
+ cairo_rel_curve_to (cr,
+ 0 + (f->pm2[i]*f->petal_size[i]), -f->petal_size[i],
+ -f->petal_size[i], -f->petal_size[i],
+ -(2*f->petal_size[i] + f->pm1[i]), 0);
+ cairo_close_path (cr);
+
+ cairo_rotate (cr, 2*M_PI / n_petals);
+ }
+ cairo_fill_preserve (cr);
+
+ cairo_set_line_width (cr, 1.);
+ cairo_set_source_rgb (cr,
+ colors[f->color[i]].red,
+ colors[f->color[i]].green,
+ colors[f->color[i]].blue);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+ }
+
+ /* Finally draw flower center */
+ cairo_set_source_rgba (cr,
+ colors[f->color[i]].red,
+ colors[f->color[i]].green,
+ colors[f->color[i]].blue,
+ 0.5);
+
+ cairo_arc (cr, 0, 0, f->petal_size[i], 0, M_PI * 2);
+ cairo_fill (cr);
+
+ if (f->petal_size[i] > 4) {
+ cairo_arc (cr, 0, 0, f->petal_size[i] - 2, 0, M_PI * 2);
+ cairo_set_line_width (cr, 2.);
+ cairo_set_source_rgba (cr,
+ colors[f->color[i]].red,
+ colors[f->color[i]].green,
+ colors[f->color[i]].blue,
+ .75);
+ cairo_stroke (cr);
+ }
+ } cairo_pop_group_to_source(cr);
+ cairo_reset_clip (cr);
+
+ cairo_matrix_init_translate (&m, -f->x, -f->y);
+ cairo_pattern_set_matrix (cairo_get_source(cr), &m);
+ cairo_paint_with_alpha (cr, f->fade);
+ }
+}
+
+static void
+flowers_update (int width, int height)
+{
+ int i;
+
+ for (i = 0; i< N_FLOWERS; i++) {
+ flowers[i].y += flowers[i].v;
+ if (flowers[i].y > height || flowers[i].y + flowers[i].size < 0)
+ flowers[i].v = -flowers[i].v;
+
+ flowers[i].fade += flowers[i].dfade;
+ if (flowers[i].fade < 0. || flowers[i].fade > 1.)
+ flowers[i].dfade = -flowers[i].dfade;
+
+ flowers[i].rot += flowers[i].rv;
+ }
+}
+
+static void
+fps_draw (struct framebuffer *fb, const char *name,
+ const struct timeval *last,
+ const struct timeval *now)
+{
+#define N_FILTER 25
+ static double filter[25];
+ static int filter_pos;
+ cairo_text_extents_t extents;
+ char buf[80];
+ double fps, avg;
+ int n, max;
+ cairo_t *cr;
+
+ fps = now->tv_sec - last->tv_sec;
+ fps += (now->tv_usec - last->tv_usec) / 1000000.;
+
+ max = N_FILTER;
+ avg = fps;
+ if (filter_pos < max)
+ max = filter_pos;
+ for (n = 0; n < max; n++)
+ avg += filter[n];
+ avg /= max + 1;
+ filter[filter_pos++ % N_FILTER] = fps;
+ if (filter_pos < 5)
+ return;
+
+ cr = cairo_create (fb->surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+
+ snprintf (buf, sizeof (buf), "%s: %.1f fps", name, 1. / avg);
+ cairo_set_font_size (cr, 18);
+ cairo_text_extents (cr, buf, &extents);
+
+ cairo_rectangle (cr, 4-1, 4-1, extents.width+2, extents.height+2);
+ cairo_set_source_rgba (cr, .0, .0, .0, .85);
+ cairo_fill (cr);
+
+ cairo_move_to (cr, 4 - extents.x_bearing, 4 - extents.y_bearing);
+ cairo_set_source_rgb (cr, .95, .95, .95);
+ cairo_show_text (cr, buf);
+
+ cairo_destroy (cr);
+}
+
+int main (int argc, char **argv)
+{
+ struct device *device;
+ struct timeval start, last_tty, last_fps, now;
+
+ double delta;
+ int frame = 0;
+ int frames = 0;
+ int benchmark;
+ void (*draw) (cairo_t *);
+ int naive;
+ int i;
+
+ device = device_open(argc, argv);
+ benchmark = device_get_benchmark(argc, argv);
+ if (benchmark == 0)
+ benchmark = 20;
+
+ naive = 0;
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--naive") == 0)
+ naive = 1;
+ }
+
+
+ for (i = 0; i< N_FLOWERS; i++)
+ (naive ? make_naive_flower : make_fast_flower) (device->scanout,
+ &flowers[i],
+ device->width,
+ device->height);
+ draw = naive ? naive_flowers_draw : fast_flowers_draw;
+
+ gettimeofday(&start, 0); now = last_tty = last_fps = start;
+ do {
+ struct framebuffer *fb = device->get_framebuffer (device);
+ cairo_t *cr;
+
+ cr = cairo_create(fb->surface);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ draw(cr);
+
+ cairo_destroy(cr);
+
+ flowers_update(device->width, device->height);
+
+ gettimeofday(&now, NULL);
+ if (benchmark < 0 && last_fps.tv_sec)
+ fps_draw(fb, device->name, &last_fps, &now);
+ last_fps = now;
+
+ fb->show (fb);
+ fb->destroy (fb);
+
+ if (benchmark < 0) {
+ delta = now.tv_sec - last_tty.tv_sec;
+ delta += (now.tv_usec - last_tty.tv_usec)*1e-6;
+ frames++;
+ if (delta > 5) {
+ printf("%.2f fps\n", frames/delta);
+ last_tty = now;
+ frames = 0;
+ }
+ }
+
+ frame++;
+ if (benchmark > 0) {
+ delta = now.tv_sec - start.tv_sec;
+ delta += (now.tv_usec - start.tv_usec)*1e-6;
+ if (delta > benchmark) {
+ printf("%.2f fps\n", frame / delta);
+ break;
+ }
+ }
+ } while (1);
+
+ return 0;
+}