summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--gears.c439
2 files changed, 443 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index d96b6c8..6b84c3d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
CFLAGS += -W -Wall -g -O3
CFLAGS += `pkg-config --cflags sdl cairo`
-TARGETS=test-cairosdl fuzzy-balls sdl-clock
+TARGETS=test-cairosdl fuzzy-balls sdl-clock gears
all: $(TARGETS)
@@ -11,6 +11,9 @@ fuzzy-balls: fuzzy-balls.o cairosdl.o
sdl-clock: sdl-clock.o cairosdl.o
$(CC) -o $@ $+ `pkg-config --libs sdl cairo`
+gears: gears.o cairosdl.o
+ $(CC) -o $@ $+ `pkg-config --libs sdl cairo`
+
test-cairosdl: test-cairosdl.o cairosdl.o
$(CC) -o $@ $+ `pkg-config --libs sdl cairo`
diff --git a/gears.c b/gears.c
new file mode 100644
index 0000000..1bef6d1
--- /dev/null
+++ b/gears.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright © 2004 David Reveman, Peter Nilsson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the names of
+ * David Reveman and Peter Nilsson not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. David Reveman and Peter Nilsson
+ * makes no representations about the suitability of this software for
+ * any purpose. It is provided "as is" without express or implied warranty.
+ *
+ * DAVID REVEMAN AND PETER NILSSON DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DAVID REVEMAN AND
+ * PETER NILSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+ * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: David Reveman <c99drn@cs.umu.se>
+ * Peter Nilsson <c99pnn@cs.umu.se>
+ */
+#include <stdlib.h>
+#include <cairo.h>
+#include <math.h>
+
+#define LINEWIDTH 3.0
+
+#define FILL_R 0.1
+#define FILL_G 0.1
+#define FILL_B 0.75
+#define FILL_OPACITY 0.5
+
+#define STROKE_R 0.1
+#define STROKE_G 0.75
+#define STROKE_B 0.1
+#define STROKE_OPACITY 1.0
+
+#define NUMPTS 6
+
+#define CHEAT_SHADOWS 1 /* 1: use opaque gear shadows,
+ * 0: semitransparent shadows like qgears2 */
+
+static double animpts[NUMPTS * 2];
+static double deltas[NUMPTS * 2];
+
+static int fill_gradient = 0;
+
+static void
+gear (cairo_t *cr,
+ double inner_radius,
+ double outer_radius,
+ int teeth,
+ double tooth_depth)
+{
+ int i;
+ double r0, r1, r2;
+ double angle, da;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / (double) teeth / 4.0;
+
+ cairo_new_path (cr);
+
+ angle = 0.0;
+ cairo_move_to (cr, r1 * cos (angle + 3 * da), r1 * sin (angle + 3 * da));
+
+ for (i = 1; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / (double) teeth;
+
+ cairo_line_to (cr, r1 * cos (angle), r1 * sin (angle));
+ cairo_line_to (cr, r2 * cos (angle + da), r2 * sin (angle + da));
+ cairo_line_to (cr, r2 * cos (angle + 2 * da), r2 * sin (angle + 2 * da));
+
+ if (i < teeth)
+ cairo_line_to (cr, r1 * cos (angle + 3 * da),
+ r1 * sin (angle + 3 * da));
+ }
+
+ cairo_close_path (cr);
+
+ cairo_move_to (cr, r0 * cos (angle + 3 * da), r0 * sin (angle + 3 * da));
+
+ for (i = 1; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / (double) teeth;
+
+ cairo_line_to (cr, r0 * cos (angle), r0 * sin (angle));
+ }
+
+ cairo_close_path (cr);
+}
+
+void
+trap_setup (cairo_surface_t *target, int w, int h)
+{
+ int i;
+
+ (void)target;
+ //cairo_scale (cr, 3.0, 1.0);
+
+ for (i = 0; i < (NUMPTS * 2); i += 2) {
+ animpts[i + 0] = (float) (drand48 () * w);
+ animpts[i + 1] = (float) (drand48 () * h);
+ deltas[i + 0] = (float) (drand48 () * 6.0 + 4.0);
+ deltas[i + 1] = (float) (drand48 () * 6.0 + 4.0);
+ if (animpts[i + 0] > w / 2.0) {
+ deltas[i + 0] = -deltas[i + 0];
+ }
+ if (animpts[i + 1] > h / 2.0) {
+ deltas[i + 1] = -deltas[i + 1];
+ }
+ }
+}
+
+static void
+stroke_and_fill_animate (double *pts,
+ double *deltas,
+ int index,
+ int limit)
+{
+ double newpt = pts[index] + deltas[index];
+
+ if (newpt <= 0) {
+ newpt = -newpt;
+ deltas[index] = (double) (drand48 () * 4.0 + 2.0);
+ } else if (newpt >= (double) limit) {
+ newpt = 2.0 * limit - newpt;
+ deltas[index] = - (double) (drand48 () * 4.0 + 2.0);
+ }
+ pts[index] = newpt;
+}
+
+static void
+stroke_and_fill_step (int w, int h)
+{
+ int i;
+
+ for (i = 0; i < (NUMPTS * 2); i += 2) {
+ stroke_and_fill_animate (animpts, deltas, i + 0, w);
+ stroke_and_fill_animate (animpts, deltas, i + 1, h);
+ }
+}
+
+static double gear1_rotation = 0.35;
+static double gear2_rotation = 0.33;
+static double gear3_rotation = 0.50;
+
+void
+trap_render (cairo_t *cr, int w, int h)
+{
+ double *ctrlpts = animpts;
+ int len = (NUMPTS * 2);
+ double prevx = ctrlpts[len - 2];
+ double prevy = ctrlpts[len - 1];
+ double curx = ctrlpts[0];
+ double cury = ctrlpts[1];
+ double midx = (curx + prevx) / 2.0;
+ double midy = (cury + prevy) / 2.0;
+ int i;
+ int pass;
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle (cr, 0, 0, w, h);
+ cairo_fill (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgba (cr, 0.75, 0.75, 0.75, 1.0);
+ cairo_set_line_width (cr, 1.0);
+
+ cairo_save (cr); {
+ cairo_scale (cr, (double) w / 512.0, (double) h / 512.0);
+
+ cairo_save (cr); {
+ cairo_translate (cr, -10.0, -10.0);
+ cairo_translate (cr, 170.0, 330.0);
+ cairo_rotate (cr, gear1_rotation);
+ gear (cr, 30.0, 120.0, 20, 20.0);
+ cairo_set_source_rgba (cr, 0.70, 0.70, 0.70, 0.70 + CHEAT_SHADOWS);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+ cairo_save (cr); {
+ cairo_translate (cr, -10.0, -10.0);
+ cairo_translate (cr, 369.0, 330.0);
+ cairo_rotate (cr, gear2_rotation);
+ gear (cr, 15.0, 75.0, 12, 20.0);
+ cairo_set_source_rgba (cr, 0.70, 0.70, 0.70, 0.70 + CHEAT_SHADOWS);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+ cairo_save (cr); {
+ cairo_translate (cr, -10.0, -10.0);
+ cairo_translate (cr, 170.0, 116.0);
+ cairo_rotate (cr, gear3_rotation);
+ gear (cr, 20.0, 90.0, 14, 20.0);
+ cairo_set_source_rgba (cr, 0.70, 0.70, 0.70, 0.70 + CHEAT_SHADOWS);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+
+ cairo_save (cr); {
+ cairo_translate (cr, 170.0, 330.0);
+ cairo_rotate (cr, gear1_rotation);
+ gear (cr, 30.0, 120.0, 20, 20.0);
+ cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 0.25, 0.25, 0.25);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+ cairo_save (cr); {
+ cairo_translate (cr, 369.0, 330.0);
+ cairo_rotate (cr, gear2_rotation);
+ gear (cr, 15.0, 75.0, 12, 20.0);
+ cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 0.25, 0.25, 0.25);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+ cairo_save (cr); {
+ cairo_translate (cr, 170.0, 116.0);
+ cairo_rotate (cr, gear3_rotation);
+ gear (cr, 20.0, 90.0, 14, 20.0);
+ cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 0.25, 0.25, 0.25);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+
+ cairo_restore (cr);
+ }
+
+ gear1_rotation += 0.01;
+ gear2_rotation -= (0.01 * (20.0 / 12.0));
+ gear3_rotation -= (0.01 * (20.0 / 14.0));
+
+ stroke_and_fill_step (w, h);
+
+ cairo_translate (cr, -10, -10);
+ for (pass = 1; pass <= 2; pass++) {
+ cairo_new_path (cr);
+ cairo_move_to (cr, midx, midy);
+
+ for (i = 2; i <= (NUMPTS * 2); i += 2) {
+ double x2, x1 = (midx + curx) / 2.0;
+ double y2, y1 = (midy + cury) / 2.0;
+
+ prevx = curx;
+ prevy = cury;
+ if (i < (NUMPTS * 2)) {
+ curx = ctrlpts[i + 0];
+ cury = ctrlpts[i + 1];
+ } else {
+ curx = ctrlpts[0];
+ cury = ctrlpts[1];
+ }
+ midx = (curx + prevx) / 2.0;
+ midy = (cury + prevy) / 2.0;
+ x2 = (prevx + midx) / 2.0;
+ y2 = (prevy + midy) / 2.0;
+ cairo_curve_to (cr, x1, y1, x2, y2, midx, midy);
+ }
+ cairo_close_path (cr);
+
+ if (pass == 1) {
+ cairo_set_source_rgba (cr, 0,0,0,77/255.0);
+ cairo_fill (cr);
+ cairo_translate (cr, 10, 10);
+ }
+ }
+
+ if (fill_gradient) {
+ double x1, y1, x2, y2;
+ cairo_pattern_t *pattern;
+
+ cairo_fill_extents (cr, &x1, &y1, &x2, &y2);
+
+ pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
+ cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 1.0, 0.75);
+ cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1.0, 0.0, 0.0, 1.0);
+ cairo_pattern_set_filter (pattern, CAIRO_FILTER_BILINEAR);
+
+ cairo_move_to (cr, 0, 0);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ } else {
+ cairo_set_source_rgba (cr, FILL_R, FILL_G, FILL_B, FILL_OPACITY);
+ }
+
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgba (cr, STROKE_R, STROKE_G, STROKE_B, STROKE_OPACITY);
+ cairo_set_line_width (cr, LINEWIDTH);
+ cairo_stroke (cr);
+}
+
+
+/* SDL code */
+#include "cairosdl.h"
+
+static Uint32
+print_fps_timer (Uint32 interval, void *param)
+{
+ unsigned *frame_counter = (unsigned *)param;
+ unsigned num_frames = *frame_counter;
+ *frame_counter = 0;
+
+ printf("%u frames in %u ms = %.3f fps\n",
+ num_frames, interval, 1000.0*num_frames / interval);
+
+ return interval;
+}
+
+
+static void
+push_expose ()
+{
+ SDL_Event event[1];
+ event->type = SDL_VIDEOEXPOSE;
+ if (SDL_PushEvent (event) != 0) {
+ fprintf (stderr, "Failed to push an expose event: %s\n",
+ SDL_GetError ());
+ }
+}
+
+static void
+event_loop (unsigned flags, int width, int height)
+{
+ unsigned num_frames_rendered = 0;
+ SDL_Event event[1];
+ event->resize.type = SDL_VIDEORESIZE;
+ event->resize.w = width;
+ event->resize.h = height;
+ SDL_PushEvent (event);
+
+ SDL_AddTimer (5000, print_fps_timer, &num_frames_rendered);
+
+ while (SDL_WaitEvent (event)) {
+ switch (event->type) {
+ case SDL_VIDEORESIZE:
+ if (SDL_SetVideoMode (event->resize.w,
+ event->resize.h,
+ 32, flags) == NULL)
+ {
+ fprintf (stderr, "Failed to set video mode: %s\n",
+ SDL_GetError ());
+ exit (1);
+ }
+ width = event->resize.w;
+ height = event->resize.h;
+ /* fallthrough */
+
+ case SDL_VIDEOEXPOSE: {
+ SDL_Surface *screen = SDL_GetVideoSurface ();
+ cairo_t *cr;
+ cairo_status_t status;
+
+ while (SDL_LockSurface (screen) != 0)
+ SDL_Delay (1);
+
+ cr = cairosdl_create (screen);
+ trap_render (cr, width, height);
+ status = cairo_status (cr);
+ cairosdl_destroy (cr);
+
+ SDL_UnlockSurface (screen);
+ SDL_Flip (screen);
+
+ ++num_frames_rendered;
+
+ if (status != CAIRO_STATUS_SUCCESS) {
+ fprintf (stderr, "Failed to render: %s\n",
+ cairo_status_to_string (status));
+ }
+
+ push_expose (); /* Schedule another expose soon, */
+ break;
+ }
+ case SDL_KEYDOWN:
+ if (event->key.keysym.sym == SDLK_q)
+ return;
+ }
+ }
+ fprintf (stderr, "WaitEvent failed: %s\n", SDL_GetError ());
+}
+
+int
+main (int argc, char **argv)
+{
+ int width = 512;
+ int height = 512;
+ int flags = SDL_SWSURFACE;
+ int init_flags = SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
+ int i;
+
+ if (SDL_Init (init_flags) < 0) {
+ fprintf (stderr, "Failed to initialise SDL: %s\n",
+ SDL_GetError ());
+ exit (1);
+ }
+ atexit (SDL_Quit);
+
+ for (i=1; i<argc; i++) {
+ if (0 == strcmp(argv[i], "-gradient")) {
+ fill_gradient = 1;
+ }
+ else if (0 == strcmp(argv[i], "-fullscreen")) {
+ flags |= SDL_HWSURFACE | SDL_FULLSCREEN;
+ }
+ else if (0 == strcmp(argv[i], "-hwsurface")) {
+ flags |= SDL_HWSURFACE;
+ }
+ else if (0 == strcmp(argv[i], "-swsurface")) {
+ flags |= SDL_SWSURFACE;
+ }
+ else if (0 == strcmp(argv[i], "-doublebuf")) {
+ flags |= SDL_DOUBLEBUF;
+ }
+ else if (0 == strcmp(argv[i], "-resizable")) {
+ flags |= SDL_RESIZABLE;
+ }
+ else {
+ fprintf(stderr, "usage: [-gradient] [-fullscreen] [-resizable]\n");
+ }
+ }
+
+ event_loop (flags, width, height);
+ return 0;
+}