[Commit] cairo-demo/X11 Makefile, NONE, 1.1 cairo-demo.c, NONE,
1.1 cairo-freq.c, NONE, 1.1 cairo-knockout.c, NONE,
1.1 cairo-spline.c, NONE, 1.1
Carl Worth
commit at keithp.com
Mon Aug 18 12:11:40 PDT 2003
- Previous message: [Commit] cairo-demo README, NONE, 1.1 Makefile, 1.4, 1.5 xrfreq.c,
1.3, NONE xrknockout.c, 1.10, NONE xrspline.c, 1.10,
NONE xrtest.c, 1.9, NONE
- Next message: [Commit] cairo-demo/png .cvsignore, NONE, 1.1 Makefile, NONE,
1.1 caps_joins.c, NONE, 1.1 hering.c, NONE, 1.1 outline.c,
NONE, 1.1 spiral.c, NONE, 1.1 splines_tolerance.c, NONE,
1.1 stars.c, NONE, 1.1 write_png.c, NONE, 1.1 write_png.h, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Committed by: cworth
Update of /local/src/CVS/cairo-demo/X11
In directory home.keithp.com:/tmp/cvs-serv20528/X11
Added Files:
Makefile cairo-demo.c cairo-freq.c cairo-knockout.c
cairo-spline.c
Log Message:
Added demos from OLS paper.
--- NEW FILE: Makefile ---
CFLAGS=-g -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls `pkg-config --cflags cairo`
LDFLAGS=`pkg-config --libs cairo`
PROGS=cairo-demo cairo-spline cairo-knockout cairo-freq
all: $(PROGS)
clean:
rm -f $(PROGS) *.o
--- NEW FILE: cairo-demo.c ---
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cairo.h>
typedef struct win {
Display *dpy;
int scr;
Window win;
GC gc;
int width, height;
KeyCode quit_code;
} win_t;
static void triangle(cairo_t *ct);
static void square(cairo_t *ct);
static void bowtie(cairo_t *ct);
static void win_init(win_t *win, Display *dpy);
static void win_deinit(win_t *win);
static void win_draw(win_t *win);
static void win_select_events(win_t *win);
static void win_handle_events(win_t *win);
int
main(int argc, char *argv[])
{
win_t win;
Display *dpy = XOpenDisplay(0);
XSynchronize (dpy, 1);
if (dpy == NULL) {
fprintf(stderr, "Failed to open display: %s\n", XDisplayName(0));
return 1;
}
win_init(&win, dpy);
win_draw(&win);
win_handle_events(&win);
win_deinit(&win);
XCloseDisplay(dpy);
return 0;
}
#define SIZE 40
static void
triangle(cairo_t *ct)
{
cairo_move_to(ct, SIZE, 0);
cairo_rel_line_to(ct, SIZE, 2*SIZE);
cairo_rel_line_to(ct, -2*SIZE, 0);
cairo_close_path(ct);
}
static void
square(cairo_t *ct)
{
cairo_move_to(ct, 0, 0);
cairo_rel_line_to(ct, 2*SIZE, 0);
cairo_rel_line_to(ct, 0, 2*SIZE);
cairo_rel_line_to(ct, -2*SIZE, 0);
cairo_close_path(ct);
}
static void
bowtie(cairo_t *ct)
{
cairo_move_to(ct, 0, 0);
cairo_rel_line_to(ct, 2*SIZE, 2*SIZE);
cairo_rel_line_to(ct, -2*SIZE, 0);
cairo_rel_line_to(ct, 2*SIZE, -2*SIZE);
cairo_close_path(ct);
}
static void
inf(cairo_t *ct)
{
cairo_move_to(ct, 0, SIZE);
cairo_rel_curve_to(ct,
0, SIZE,
SIZE, SIZE,
2*SIZE, 0);
cairo_rel_curve_to(ct,
SIZE, -SIZE,
2*SIZE, -SIZE,
2*SIZE, 0);
cairo_rel_curve_to(ct,
0, SIZE,
-SIZE, SIZE,
-2*SIZE, 0);
cairo_rel_curve_to(ct,
-SIZE, -SIZE,
-2*SIZE, -SIZE,
-2*SIZE, 0);
cairo_close_path(ct);
}
static void
draw_shapes(cairo_t *ct, int x, int y, int fill)
{
cairo_save(ct);
cairo_new_path(ct);
cairo_translate(ct, x+SIZE, y+SIZE);
bowtie(ct);
if (fill)
cairo_fill(ct);
else
cairo_stroke(ct);
cairo_new_path(ct);
cairo_translate(ct, 4*SIZE, 0);
square(ct);
if (fill)
cairo_fill(ct);
else
cairo_stroke(ct);
cairo_new_path(ct);
cairo_translate(ct, 4*SIZE, 0);
triangle(ct);
if (fill)
cairo_fill(ct);
else
cairo_stroke(ct);
cairo_new_path(ct);
cairo_translate(ct, 4*SIZE, 0);
inf(ct);
if (fill)
cairo_fill(ct);
else
cairo_stroke(ct);
cairo_restore(ct);
}
static void
fill_shapes(cairo_t *ct, int x, int y)
{
draw_shapes(ct, x, y, 1);
}
static void
stroke_shapes(cairo_t *ct, int x, int y)
{
draw_shapes(ct, x, y, 0);
}
/*
static void
draw_broken_shapes(cairo_t *ct)
{
cairo_save(ct);
cairo_set_line_width(ct, 1);
cairo_set_line_join(ct, CAIRO_LINE_JOIN_BEVEL);
cairo_set_rgb_color(ct, 1, 1, 1);
cairo_move_to(ct, 19.153717041015625, 144.93951416015625);
cairo_line_to(ct, 412.987396240234375, 99.407318115234375);
cairo_line_to(ct, 412.99383544921875, 99.4071807861328125);
cairo_line_to(ct, 413.15008544921875, 99.5634307861328125);
cairo_line_to(ct, 413.082489013671875, 99.6920928955078125);
cairo_line_to(ct, 413.000274658203125, 99.71954345703125);
cairo_line_to(ct, 273.852630615234375, 138.1925201416015625);
cairo_line_to(ct, 273.934844970703125, 138.165069580078125);
cairo_line_to(ct, 16.463653564453125, 274.753662109375);
cairo_line_to(ct, 16.286346435546875, 274.496337890625);
cairo_line_to(ct, 273.757537841796875, 137.907745361328125);
cairo_line_to(ct, 273.839752197265625, 137.8802947998046875);
cairo_line_to(ct, 412.987396240234375, 99.407318115234375);
cairo_line_to(ct, 412.99383544921875, 99.4071807861328125);
cairo_line_to(ct, 413.15008544921875, 99.5634307861328125);
cairo_line_to(ct, 413.082489013671875, 99.6920928955078125);
cairo_line_to(ct, 413.000274658203125, 99.71954345703125);
cairo_line_to(ct, 19.166595458984375, 145.251739501953125);
cairo_fill(ct);
cairo_restore(ct);
}
*/
static void
win_draw(win_t *win)
{
#define NUM_DASH 2
static double dash[NUM_DASH] = {SIZE/4.0, SIZE/4.0};
Display *dpy = win->dpy;
cairo_t *ct;
Drawable drawable = win->win;
XClearWindow(dpy, win->win);
ct = cairo_create();
cairo_set_target_drawable (ct, dpy, drawable);
cairo_set_rgb_color(ct, 1, 1, 1);
/*
cairo_scale(ct, 5, 5);
inf(ct);
cairo_translate(ct, 0, 2 * SIZE);
inf(ct);
cairo_translate(ct, 0, - 2 * SIZE);
cairo_clip(ct);
cairo_scale(ct, 1/5.0, 1/5.0);
*/
/* This is handy for examining problems more closely */
/* cairo_scale(ct, 8, 8); */
#if XXX_JOINS_ARE_BROKEN_AFTER_SOME_TRANSFORMS
cairo_scale(ct, 2, -2);
cairo_translate(ct, 0, -200);
#endif
cairo_set_line_width(ct, SIZE / 4);
cairo_set_tolerance(ct, .1);
cairo_set_line_join(ct, CAIRO_LINE_JOIN_ROUND);
cairo_set_dash(ct, dash, NUM_DASH, 0);
stroke_shapes(ct, 0, 0);
cairo_set_dash(ct, NULL, 0, 0);
stroke_shapes(ct, 0, 4*SIZE);
cairo_set_line_join(ct, CAIRO_LINE_JOIN_BEVEL);
stroke_shapes(ct, 0, 8*SIZE);
cairo_set_line_join(ct, CAIRO_LINE_JOIN_MITER);
stroke_shapes(ct, 0, 12*SIZE);
fill_shapes(ct, 0, 16*SIZE);
cairo_set_line_join(ct, CAIRO_LINE_JOIN_BEVEL);
fill_shapes(ct, 0, 20*SIZE);
cairo_set_rgb_color(ct, 1, 0, 0);
stroke_shapes(ct, 0, 20*SIZE);
/*
draw_broken_shapes(ct);
*/
cairo_destroy(ct);
}
static void
win_init(win_t *win, Display *dpy)
{
Window root;
win->dpy = dpy;
win->width = 400;
win->height = 400;
root = DefaultRootWindow(dpy);
win->scr = DefaultScreen(dpy);
win->win = XCreateSimpleWindow(dpy, root, 0, 0,
win->width, win->height, 0,
BlackPixel(dpy, win->scr), BlackPixel(dpy, win->scr));
win->quit_code = XKeysymToKeycode(dpy, XStringToKeysym("Q"));
win_select_events(win);
XMapWindow(dpy, win->win);
}
static void
win_deinit(win_t *win)
{
XDestroyWindow(win->dpy, win->win);
}
static void
win_select_events(win_t *win)
{
XSelectInput(win->dpy, win->win,
KeyPressMask
|StructureNotifyMask
|ExposureMask);
}
static void
win_handle_events(win_t *win)
{
XEvent xev;
while (1) {
XNextEvent(win->dpy, &xev);
switch(xev.type) {
case KeyPress:
{
XKeyEvent *kev = &xev.xkey;
if (kev->keycode == win->quit_code) {
return;
}
}
break;
case ConfigureNotify:
{
XConfigureEvent *cev = &xev.xconfigure;
win->width = cev->width;
win->height = cev->height;
}
break;
case Expose:
{
XExposeEvent *eev = &xev.xexpose;
if (eev->count == 0)
win_draw(win);
}
break;
}
}
}
--- NEW FILE: cairo-freq.c ---
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <cairo.h>
#define EPSILON (1.0 / (2<<16))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
typedef struct win {
Display *dpy;
int scr;
Window win;
GC gc;
Pixmap pix;
int width, height;
long event_mask;
int needs_refresh;
double tolerance;
double zoom;
} win_t;
typedef struct callback_doc {
void *callback;
char *doc;
} callback_doc_t;
typedef int (*key_callback_t)(win_t *win);
typedef struct key_binding
{
char *key;
int is_alias;
KeyCode keycode;
key_callback_t callback;
} key_binding_t;
static void win_init(win_t *win, Display *dpy);
static void win_deinit(win_t *win);
static void win_refresh(win_t *win);
static void win_select_events(win_t *win);
static void win_handle_events(win_t *win);
static void win_print_help(win_t *win);
static int quit_cb(win_t *win);
static int flatten_cb(win_t *win);
static int smooth_cb(win_t *win);
static const double DEFAULT_TOLERANCE = .1;
static const callback_doc_t callback_doc[] = {
{ quit_cb, "Exit the program" },
{ flatten_cb, "Decrease rendering accuracy, (tolerance *= 10)" },
{ smooth_cb, "Increase rendering accuracy, (tolerance /= 10)" },
};
static key_binding_t key_binding[] = {
/* Keysym, Alias, Keycode, callback */
{ "Q", 0, 0, quit_cb },
{ "greater",0, 0, smooth_cb },
{ "period", 1, 0, smooth_cb },
{ "less", 0, 0, flatten_cb },
{ "comma", 1, 0, flatten_cb },
};
int
main(int argc, char *argv[])
{
win_t win;
Display *dpy = XOpenDisplay(0);
if (dpy == NULL) {
fprintf(stderr, "Failed to open display: %s\n", XDisplayName(0));
return 1;
}
win_init(&win, dpy);
win_print_help(&win);
win_handle_events(&win);
win_deinit(&win);
XCloseDisplay(dpy);
return 0;
}
static void
win_refresh(win_t *win)
{
Display *dpy = win->dpy;
double cx, cy;
double radius, theta, theta_inc;
cairo_t *ct;
Drawable drawable = win->pix;
XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height);
ct = cairo_create();
cairo_set_target_drawable(ct, dpy, drawable);
cairo_set_rgb_color(ct, 1, 1, 1);
cx = win->width / 2.0;
cy = win->height / 2.0;
radius = sqrt(cx*cx+cy*cy);
#define FINS 128.0
#define FIN_WIDTH (.25 * (2 * M_PI / FINS))
theta_inc = 2 * M_PI / FINS;
for (theta=0; theta < 2 * M_PI; theta += theta_inc) {
cairo_move_to(ct, cx, cy);
cairo_line_to(ct, cx + radius * cos(theta), cy + radius * sin(theta));
cairo_line_to(ct, cx + radius * cos(theta + FIN_WIDTH), cy + radius * sin(theta + FIN_WIDTH));
cairo_close_path(ct);
cairo_fill(ct);
}
cairo_destroy(ct);
XCopyArea(win->dpy, win->pix, win->win, win->gc,
0, 0, win->width, win->height,
0, 0);
}
static void
win_init(win_t *win, Display *dpy)
{
int i;
Window root;
XGCValues gcv;
win->dpy = dpy;
win->width = 400;
win->height = 400;
root = DefaultRootWindow(dpy);
win->scr = DefaultScreen(dpy);
win->win = XCreateSimpleWindow(dpy, root, 0, 0,
win->width, win->height, 0,
BlackPixel(dpy, win->scr), BlackPixel(dpy, win->scr));
win->pix = XCreatePixmap(dpy, win->win, win->width, win->height, DefaultDepth(dpy, win->scr));
gcv.foreground = BlackPixel(dpy, win->scr);
win->gc = XCreateGC(dpy, win->pix, GCForeground, &gcv);
XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height);
for (i=0; i < ARRAY_SIZE(key_binding); i++) {
KeySym keysym;
keysym = XStringToKeysym(key_binding[i].key);
if (keysym == NoSymbol)
fprintf(stderr, "ERROR: No keysym for \"%s\"\n", key_binding[i].key);
else
key_binding[i].keycode = XKeysymToKeycode(dpy, keysym);
}
win->tolerance = DEFAULT_TOLERANCE;
win_refresh(win);
win->needs_refresh = 0;
win_select_events(win);
XMapWindow(dpy, win->win);
}
static void
win_deinit(win_t *win)
{
XFreeGC(win->dpy, win->gc);
XFreePixmap(win->dpy, win->pix);
XDestroyWindow(win->dpy, win->win);
}
static void
win_select_events(win_t *win)
{
win->event_mask =
KeyPressMask
| StructureNotifyMask
| ExposureMask;
XSelectInput(win->dpy, win->win, win->event_mask);
}
static char *
get_callback_doc(void *callback)
{
int i;
for (i=0; i < ARRAY_SIZE(callback_doc); i++)
if (callback_doc[i].callback == callback)
return callback_doc[i].doc;
return "<undocumented function>";
}
static void
win_print_help(win_t *win)
{
int i;
printf("Xr spline demonstration\n");
for (i=0; i < ARRAY_SIZE(key_binding); i++)
if (! key_binding[i].is_alias)
printf("%s:\t%s\n",
key_binding[i].key,
get_callback_doc(key_binding[i].callback));
}
static int
win_handle_key_press(win_t *win, XKeyEvent *kev)
{
int i;
for (i=0; i < ARRAY_SIZE(key_binding); i++)
if (key_binding[i].keycode == kev->keycode)
return (key_binding[i].callback)(win);
return 0;
}
static void
win_grow_pixmap(win_t *win)
{
Pixmap new;
new = XCreatePixmap(win->dpy, win->win, win->width, win->height,
DefaultDepth(win->dpy, win->scr));
XFillRectangle(win->dpy, new, win->gc, 0, 0, win->width, win->height);
XCopyArea(win->dpy, win->pix, new, win->gc, 0, 0, win->width, win->height, 0, 0);
XFreePixmap(win->dpy, win->pix);
win->pix = new;
win_refresh(win);
}
static void
win_handle_configure(win_t *win, XConfigureEvent *cev)
{
int has_grown = 0;
if (cev->width > win->width || cev->height > win->height) {
has_grown = 1;
}
win->width = cev->width;
win->height = cev->height;
if (has_grown) {
win_grow_pixmap(win);
} else {
win_refresh(win);
}
}
static void
win_handle_expose(win_t *win, XExposeEvent *eev)
{
XCopyArea(win->dpy, win->pix, win->win, win->gc,
eev->x, eev->y, eev->width, eev->height,
eev->x, eev->y);
}
static void
win_handle_events(win_t *win)
{
int done;
XEvent xev;
while (1) {
if (!XPending(win->dpy) && win->needs_refresh) {
win_refresh(win);
win->needs_refresh = 0;
}
XNextEvent(win->dpy, &xev);
switch(xev.type) {
case KeyPress:
done = win_handle_key_press(win, &xev.xkey);
if (done)
return;
break;
case ConfigureNotify:
win_handle_configure(win, &xev.xconfigure);
break;
case Expose:
win_handle_expose(win, &xev.xexpose);
break;
}
}
}
/* Callbacks */
static int
quit_cb(win_t *win)
{
return 1;
}
static int
flatten_cb(win_t *win)
{
win->tolerance *= 10;
win->needs_refresh = 1;
return 0;
}
static int
smooth_cb(win_t *win)
{
win->tolerance /= 10;
win->needs_refresh = 1;
return 0;
}
--- NEW FILE: cairo-knockout.c ---
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Small example demonstrating emulating knockout-groups as in PDF-1.4
* using cairo_set_operator().
*
* Owen Taylor,
* v0.1 30 November 2002
* v0.2 1 December 2002 - typo fixes from Keith Packard
* v0.3 17 April 2003 - Tracking changes in Xr, (Removal of Xr{Push,Pop}Group)
*/
#include <X11/Xlib.h>
#include <cairo.h>
#include <math.h>
#include <stdio.h>
/* Create a rectangular path
*/
static void
rect_path (cairo_t *r,
double x, double y,
double width, double height)
{
cairo_new_path (r);
cairo_move_to (r, x, y);
cairo_rel_line_to (r, 0, height);
cairo_rel_line_to (r, width, 0);
cairo_rel_line_to (r, 0, -height);
cairo_rel_line_to (r, -width, 0);
cairo_close_path (r);
}
/* Create a path that is roughly a circular oval with
* radii xr, yr at xc, yc. We only use 4 bezier's
* but the deviation is already pretty darn small.
* (max of about 0.02%)
*/
static void
oval_path (cairo_t *r,
double xc, double yc,
double xr, double yr)
{
int i;
cairo_new_path (r);
cairo_move_to (r, xc + xr, yc);
#define TANGENT_MULT (1.65591 / 3.)
for (i = 0; i < 4; i++)
{
double angle1 = ((i + 0) / 2.) * M_PI;
double angle2 = ((i + 1) / 2.) * M_PI;
double x0 = xc + xr * cos (angle1);
double y0 = yc - yr * sin (angle1);
double x1 = x0 - xr * sin (angle1) * TANGENT_MULT;
double y1 = y0 - yr * cos (angle1) * TANGENT_MULT;
double x3 = xc + xr * cos (angle2);
double y3 = yc - yr * sin (angle2);
double x2 = x3 + xr * sin (angle2) * TANGENT_MULT;
double y2 = y3 + yr * cos (angle2) * TANGENT_MULT;
cairo_curve_to (r, x1, y1, x2, y2, x3, y3);
}
cairo_close_path (r);
}
/* Fill the given area with checks in the standard style
* for showing compositing effects.
*/
static void
fill_checks (cairo_t *r,
int x, int y,
int width, int height)
{
cairo_surface_t *check;
cairo_save (r);
#define CHECK_SIZE 32
check = cairo_surface_create_similar (cairo_get_target_surface (r),
CAIRO_FORMAT_RGB24,
2 * CHECK_SIZE, 2 * CHECK_SIZE);
cairo_surface_set_repeat (check, 1);
/* Draw the check */
{
cairo_save (r);
cairo_set_target_surface (r, check);
cairo_set_operator (r, CAIRO_OPERATOR_SRC);
cairo_set_rgb_color (r, 0.4, 0.4, 0.4);
rect_path (r, 0, 0, 2 * CHECK_SIZE, 2 * CHECK_SIZE);
cairo_fill (r);
cairo_set_rgb_color (r, 0.7, 0.7, 0.7);
rect_path (r, x, y, CHECK_SIZE, CHECK_SIZE);
cairo_fill (r);
rect_path (r, x + CHECK_SIZE, y + CHECK_SIZE, CHECK_SIZE, CHECK_SIZE);
cairo_fill (r);
cairo_restore (r);
}
/* Fill the whole surface with the check */
cairo_set_pattern (r, check);
rect_path (r, 0, 0, width, height);
cairo_fill (r);
cairo_surface_destroy (check);
cairo_restore (r);
}
/* Draw a red, green, and blue circle equally spaced inside
* the larger circle of radius r at (xc, yc)
*/
static void
draw_3circles (cairo_t *r,
double xc, double yc,
double radius)
{
double subradius = radius * (2 / 3. - 0.1);
cairo_set_rgb_color (r, 1., 0., 0.);
oval_path (r,
xc + radius / 3. * cos (M_PI * (0.5)),
yc - radius / 3. * sin (M_PI * (0.5)),
subradius, subradius);
cairo_fill (r);
cairo_set_rgb_color (r, 0., 1., 0.);
oval_path (r,
xc + radius / 3. * cos (M_PI * (0.5 + 2/.3)),
yc - radius / 3. * sin (M_PI * (0.5 + 2/.3)),
subradius, subradius);
cairo_fill (r);
cairo_set_rgb_color (r, 0., 0., 1.);
oval_path (r,
xc + radius / 3. * cos (M_PI * (0.5 + 4/.3)),
yc - radius / 3. * sin (M_PI * (0.5 + 4/.3)),
subradius, subradius);
cairo_fill (r);
}
static void
draw (cairo_t *r,
int width,
int height)
{
cairo_surface_t *overlay, *punch, *circles;
/* Fill the background */
double radius = 0.5 * (width < height ? width : height) - 10;
double xc = width / 2.;
double yc = height / 2.;
overlay = cairo_surface_create_similar (cairo_get_target_surface (r),
CAIRO_FORMAT_ARGB32,
width, height);
if (overlay == NULL)
return;
punch = cairo_surface_create_similar (cairo_get_target_surface (r),
CAIRO_FORMAT_A8,
width, height);
if (punch == NULL)
return;
circles = cairo_surface_create_similar (cairo_get_target_surface (r),
CAIRO_FORMAT_ARGB32,
width, height);
if (circles == NULL)
return;
fill_checks (r, 0, 0, width, height);
cairo_save (r);
cairo_set_target_surface (r, overlay);
/* Draw a black circle on the overlay
*/
cairo_set_rgb_color (r, 0., 0., 0.);
oval_path (r, xc, yc, radius, radius);
cairo_fill (r);
cairo_save (r);
cairo_set_target_surface (r, punch);
/* Draw 3 circles to the punch surface, then cut
* that out of the main circle in the overlay
*/
draw_3circles (r, xc, yc, radius);
cairo_restore (r);
cairo_set_operator (r, CAIRO_OPERATOR_OUT_REVERSE);
cairo_show_surface (r, punch, width, height);
/* Now draw the 3 circles in a subgroup again
* at half intensity, and use OperatorAdd to join up
* without seams.
*/
cairo_save (r);
cairo_set_target_surface (r, circles);
cairo_set_alpha (r, 0.5);
cairo_set_operator (r, CAIRO_OPERATOR_OVER);
draw_3circles (r, xc, yc, radius);
cairo_restore (r);
cairo_set_operator (r, CAIRO_OPERATOR_ADD);
cairo_show_surface (r, circles, width, height);
cairo_restore (r);
cairo_show_surface (r, overlay, width, height);
cairo_surface_destroy (overlay);
cairo_surface_destroy (punch);
cairo_surface_destroy (circles);
}
static void
handle_expose (Display *dpy,
int screen,
Window win,
int width,
int height,
Region region)
{
Pixmap p;
cairo_t *r;
XRectangle clip;
GC gc;
/* Create an offscreen pixmap of the size of the
* area we need to repaint, and a cairo_t object
* directed to that pixmap.
*/
XClipBox (region, &clip);
p = XCreatePixmap (dpy, win, clip.width, clip.height, DefaultDepth (dpy, screen));
r = cairo_create ();
cairo_set_target_drawable (r, dpy, p);
/* By adding a translation, we hide the partial
* pixmap from our drawing routine
*/
cairo_translate (r, -clip.x, -clip.y);
/* It would be nice to be able to set 'region' as
* clip for our drawing, then only copy that portion
* of our drawing, but Xr doesn't expose the clipping
* features of Xrender. So, we redraw the entire
* bounding rectangle, even if the area is, e.g., L shaped,
* as frequently happens for exposes.x
*/
/* Draw the contents
*/
draw (r, width, height);
/* Now copy from our offscreen pixmap to the window
*/
gc = XCreateGC (dpy, p, 0, NULL);
XCopyArea (dpy, p, win, gc, 0, 0, clip.width, clip.height, clip.x, clip.y);
XFreeGC (dpy, gc);
XFreePixmap (dpy, p);
cairo_destroy (r);
}
int
main (int argc, char **argv)
{
Display *dpy;
int screen;
Window w;
char *title = "Knockout Groups";
XTextProperty title_prop;
unsigned int quit_keycode;
int width = 400;
int height = 400;
Region update_region = XCreateRegion ();
dpy = XOpenDisplay (NULL);
screen = DefaultScreen (dpy);
w = XCreateSimpleWindow (dpy, RootWindow (dpy, screen),
0, 0, width, height, 0,
BlackPixel (dpy, screen), WhitePixel (dpy, screen));
if (XStringListToTextProperty (&title, 1, &title_prop)) {
XSetWMName (dpy, w, &title_prop);
XFree (title_prop.value);
}
quit_keycode = XKeysymToKeycode(dpy, XStringToKeysym("Q"));
XSelectInput (dpy, w, ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask);
XMapWindow (dpy, w);
while (1) {
XEvent xev;
/* We accumulate the area to repaint until the event
* queue, then repaint. This avoids us getting behind
* on our repaint or painting the same area over and
* over needlessly.
*/
if (!XPending (dpy) && !XEmptyRegion (update_region)) {
handle_expose (dpy, screen, w,
width, height,
update_region);
XDestroyRegion (update_region);
update_region = XCreateRegion ();
}
XNextEvent (dpy, &xev);
switch (xev.xany.type) {
case ButtonPress:
/* A click on the canvas ends the program */
goto DONE;
case KeyPress:
if (xev.xkey.keycode == quit_keycode)
goto DONE;
case ConfigureNotify:
/* Note new size */
width = xev.xconfigure.width;
height = xev.xconfigure.height;
break;
case Expose:
/* Accumulate area that needs redraw */
{
XRectangle r;
r.x = xev.xexpose.x;
r.y = xev.xexpose.y;
r.width = xev.xexpose.width;
r.height = xev.xexpose.height;
XUnionRectWithRegion (&r, update_region, update_region);
}
break;
}
}
DONE:
XDestroyRegion (update_region);
XCloseDisplay (dpy);
return 0;
}
--- NEW FILE: cairo-spline.c ---
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <cairo.h>
#define EPSILON (1.0 / (2<<16))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
typedef struct color {
double red;
double green;
double blue;
} color_t;
typedef struct pt {
double x;
double y;
} pt_t;
typedef struct spline {
pt_t pt[4];
} spline_t;
typedef struct quadr {
pt_t pt[4];
} quadr_t;
typedef struct win {
Display *dpy;
int scr;
Window win;
GC gc;
Pixmap pix;
int width, height;
long event_mask;
int needs_refresh;
double tolerance;
double line_width;
cairo_line_cap_t line_cap;
spline_t spline;
double zoom;
double xtrans;
double ytrans;
int show_path;
int drag;
pt_t drag_pt;
pt_t *active_pt;
int active;
} win_t;
typedef struct callback_doc {
void *callback;
char *doc;
} callback_doc_t;
typedef int (*key_callback_t)(win_t *win);
typedef struct key_binding
{
char *key;
int is_alias;
KeyCode keycode;
key_callback_t callback;
} key_binding_t;
typedef int (*button_callback_t)(win_t *win, int x, int y);
typedef struct button_binding
{
int button;
button_callback_t callback;
} button_binding_t;
static void win_init(win_t *win, Display *dpy);
static void win_deinit(win_t *win);
static void win_refresh(win_t *win);
static void win_select_events(win_t *win);
static void win_handle_events(win_t *win);
static void win_print_help(win_t *win);
static int select_point_cb(win_t *win, int x, int y);
static int snap_point_cb(win_t *win, int x, int y);
static int quit_cb(win_t *win);
static int select_next_cb(win_t *win);
static int left_epsilon_cb(win_t *win);
static int right_epsilon_cb(win_t *win);
static int up_epsilon_cb(win_t *win);
static int down_epsilon_cb(win_t *win);
static int print_spline_cb(win_t *win);
static int zoom_in_cb(win_t *win);
static int zoom_out_cb(win_t *win);
static int trans_left_cb(win_t *win);
static int trans_right_cb(win_t *win);
static int trans_up_cb(win_t *win);
static int trans_down_cb(win_t *win);
static int flatten_cb(win_t *win);
static int smooth_cb(win_t *win);
static int toggle_path(win_t *win);
static int widen_line(win_t *win);
static int narrow_line(win_t *win);
static const double DEFAULT_XTRANS = 0.0;
static const double DEFAULT_YTRANS = 0.0;
static const double DEFAULT_TOLERANCE = .1;
static const double DEFAULT_LINE_WIDTH = 10;
static const cairo_line_cap_t DEFAULT_LINE_CAP = CAIRO_LINE_CAP_ROUND;
/* This was breaking the polygon tessellation code. All fixed now. */
static const spline_t polygon_killer = {
{ { 613.125, 4643.06 }, { 21957.1, 3763.06 }, { 12906, 256 }, { 524, 8788 } }
};
static const spline_t intersection_killer = {
{ { 244.56999999999999318, 268.56999999999993634 }, { 364.56000000000000227, 747.55999999999994543 }, { 34.380000000000002558, 412.56000000000000227 }, { 576.37000000000000455, 203.56999999999999318 } }
};
/*
#define DEFAULT_SPLINE intersection_killer
#define DEFAULT_ZOOM 1.0
*/
/* Showing off the problems with wide butt-capped splines that turn
sharply at the end. */
static const spline_t funky_fangs = {
{ { 69.25, 48.185 }, { 40.225, 43.06 }, { 59.5, 34.5 }, { 59.4998, 35.2514 } }
};
/* Adjust any point by an epsilon to see the fangs appear.
(The fact that they are missing is a bug)
-- Actually, it looks like this one is working now.
*/
static const spline_t touchy_fangs = {
{ { 18.25, 21.875 }, { 18.25, 23.875 }, { 30, 30.375 }, { 30, 27 } }
};
/* Here's another one that starts off buggy, but small adjustments
change it, (here you need to change a control point by a pixel or
two in order to have an effect) */
static const spline_t touchy_shell = {
{ { 8.9375, 6.32812 }, { 8.23434, 10.3594 }, { 8.5625, 4.25 }, { 11.9531, 7.6875 } }
};
/* A simple looping spline. No known problems. */
static const spline_t ribbon = {
{ {110, 20}, {310, 300}, {10, 310}, {210, 20} }
};
static const spline_t simple = {
{ {10, 10}, {70, 10}, {100, 40}, {100, 100} }
};
/* This one's fixed with some proper sorting/duplicate elimination on the pen */
static const spline_t non_uniform_width = {
{ { 18, 12 }, { 18.0001373291015625, 30.26085662841796875 }, { 99.9996185302734375, 48.72466278076171875 }, { 100, 100 } }
};
/* This one shows why my incremental trapexoid generation scheme was flawed */
static const spline_t warts = {
{ { 14.75, 25.25 }, { 30.5001373291015625, 57.76085662841796875 }, { 127.4996185302734375, -17.77533721923828125 }, { 61.75, 33.75 } }
};
/* This one is designed to torture ghostscript */
static const spline_t gstorture = {
{{51.57, 51.57}, {412.56, 412.56}, {34.38, 412.56}, {395.37, 51.57}}
};
/*
#define DEFAULT_SPLINE gstorture
#define DEFAULT_ZOOM 1.0
*/
/*
#define DEFAULT_SPLINE simple
#define DEFAULT_ZOOM 1.0
*/
/* This was causing an infitie loop at one point.
The bug is now fixed, (the while loop no longer exists) */
static const spline_t infinite_loop = {
{ {32 * 4008192 / 65536.0, 32 * 10819706 / 65536.0},
{32 * 44968140 / 65536.0, 32 * 7706746 / 65536.0},
{32 * 26431488 / 65536.0, 32 * 524288 / 65536.0},
{32 * 1073152 / 65536.0, 32 * 17997824 / 65536.0} }
};
/* This one shows a tiny sub-pixel trapezoid that was being rasterized
with a fully-lit pixel. The fix for this has now been applied to
the trap code in the server. */
static const spline_t wart = {
{ { 179, 410 }, { 448, 475 }, { 33, 514 }, { 313, 399 } }
};
/* A new wart, (right on the tip of the spike). I haven't chased this
one down yet. */
static const spline_t another_wart = {
{ { 37.5, 22.125 }, { 40.875, 23.625 }, { 13.375, 57 }, { 34.25, 35.375 } }
};
/* What happens when the spline folds over on itself at the end? */
static const spline_t overlap = {
{ { 3.03125, 5.1875 }, { 12.25, 11.1875 }, { 15.1875, 7.375 }, { 14.25, 7.45312 } }
};
/*
#define DEFAULT_SPLINE funky_fangs
#define DEFAULT_ZOOM 8.0
*/
/*
#define DEFAULT_SPLINE touchy_fangs
#define DEFAULT_ZOOM 8.0
*/
/*
#define DEFAULT_SPLINE touchy_shell
#define DEFAULT_ZOOM 16.0
*/
/*
#define DEFAULT_SPLINE polygon_killer
#define DEFAULT_ZOOM (1 / 32.0)
*/
/*
#define DEFAULT_SPLINE infinite_loop
#define DEFAULT_ZOOM 1 / 32.0
*/
#define DEFAULT_SPLINE ribbon
#define DEFAULT_ZOOM 1.0
/*
#define DEFAULT_SPLINE wart
#define DEFAULT_ZOOM 1.0
*/
/*
#define DEFAULT_SPLINE another_wart
#define DEFAULT_ZOOM 8.0
#define DEFAULT_WIDTH 256
#define DEFAULT_TOLERANCE .001
*/
/*
#define DEFAULT_SPLINE overlap
#define DEFAULT_ZOOM 64
*/
static const callback_doc_t callback_doc[] = {
{ quit_cb, "Exit the program" },
{ select_point_cb, "Activate closest control point" },
{ select_next_cb, "Activate next control point" },
{ snap_point_cb, "Snap active point to closest control point" },
{ left_epsilon_cb, "Move active point left by an epsilon" },
{ right_epsilon_cb, "Move active point right by an epsilon" },
{ up_epsilon_cb, "Move active point up by an epsilon" },
{ down_epsilon_cb, "Move active point down by an epsilon" },
{ print_spline_cb, "Print current spline coordinates on stdout" },
{ zoom_in_cb, "Zoom in (2X)" },
{ zoom_out_cb, "Zoom out (2X)" },
{ trans_left_cb, "Translate left (25%)" },
{ trans_right_cb, "Translate right (25%)" },
{ trans_up_cb, "Translate up (25%)" },
{ trans_down_cb, "Translate down (25%)" },
{ flatten_cb, "Decrease rendering accuracy, (tolerance *= 10)" },
{ smooth_cb, "Increase rendering accuracy, (tolerance /= 10)" },
{ toggle_path, "Toggle thin display of spline path" },
{ widen_line, "Widen line width" },
{ narrow_line, "Narrow line width" },
};
static key_binding_t key_binding[] = {
/* Keysym, Alias, Keycode, callback */
{ "Q", 0, 0, quit_cb },
{ "Left", 0, 0, left_epsilon_cb },
{ "Right", 0, 0, right_epsilon_cb },
{ "Up", 0, 0, up_epsilon_cb },
{ "Down", 0, 0, down_epsilon_cb },
{ "Return", 0, 0, print_spline_cb },
{ "space", 0, 0, select_next_cb },
{ "plus", 0, 0, zoom_in_cb },
{ "equal", 1, 0, zoom_in_cb },
{ "minus", 0, 0, zoom_out_cb },
{ "greater",0, 0, smooth_cb },
{ "period", 1, 0, smooth_cb },
{ "less", 0, 0, flatten_cb },
{ "comma", 1, 0, flatten_cb },
{ "P", 0, 0, toggle_path },
{ "W", 0, 0, widen_line },
{ "N", 0, 0, narrow_line },
};
static const button_binding_t button_binding[] = {
{ 1, select_point_cb },
{ 3, snap_point_cb }
};
int
main(int argc, char *argv[])
{
win_t win;
Display *dpy = XOpenDisplay(0);
if (dpy == NULL) {
fprintf(stderr, "Failed to open display: %s\n", XDisplayName(0));
return 1;
}
win_init(&win, dpy);
win_print_help(&win);
win_handle_events(&win);
win_deinit(&win);
XCloseDisplay(dpy);
return 0;
}
static void
draw_control_line(cairo_t *ct, pt_t *a, pt_t *b, double width)
{
cairo_save(ct);
cairo_set_rgb_color(ct, 0, 0, 1);
cairo_set_line_width(ct, width);
cairo_move_to(ct, a->x, a->y);
cairo_line_to(ct, b->x, b->y);
cairo_stroke(ct);
cairo_restore(ct);
}
static void
draw_handle(cairo_t *ct, pt_t *p, int is_active, double size, double width)
{
cairo_save(ct);
if (is_active)
cairo_set_rgb_color(ct, 0, 1, 0);
else
cairo_set_rgb_color(ct, 1, 0, 0);
cairo_set_line_width(ct, width);
cairo_move_to(ct, p->x - size / 2.0, p->y - size / 2.0);
cairo_rel_line_to(ct, size, 0);
cairo_rel_line_to(ct, 0, size);
cairo_rel_line_to(ct, -size, 0);
cairo_rel_line_to(ct, 0, -size);
cairo_stroke(ct);
cairo_restore(ct);
}
static void
draw_spline(cairo_t *ct, win_t *win)
{
spline_t *spline = &win->spline;
double zoom = win->zoom;
int i;
cairo_save(ct);
cairo_move_to(ct, spline->pt[0].x, spline->pt[0].y);
cairo_curve_to(ct,
spline->pt[1].x, spline->pt[1].y,
spline->pt[2].x, spline->pt[2].y,
spline->pt[3].x, spline->pt[3].y);
cairo_stroke(ct);
if (win->show_path) {
cairo_set_line_width(ct, 1 / zoom);
cairo_set_rgb_color(ct, 1, 1, 1);
cairo_move_to(ct, spline->pt[0].x, spline->pt[0].y);
cairo_curve_to(ct,
spline->pt[1].x, spline->pt[1].y,
spline->pt[2].x, spline->pt[2].y,
spline->pt[3].x, spline->pt[3].y);
cairo_stroke(ct);
}
draw_control_line(ct, &spline->pt[0], &spline->pt[1], 2.0 / zoom);
draw_control_line(ct, &spline->pt[3], &spline->pt[2], 2.0 / zoom);
for (i=0; i < 4; i++) {
draw_handle(ct, &spline->pt[i], i == win->active, 5.0 / zoom, 1.0 / zoom);
}
cairo_restore(ct);
}
static void
win_refresh(win_t *win)
{
Display *dpy = win->dpy;
cairo_t *ct;
cairo_status_t status;
Drawable drawable = win->pix;
XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height);
ct = cairo_create();
/*
if (win->restrict_traps)
cairo_restrict_spline_traps(ct, win->trap_start, win->trap_stop);
*/
cairo_set_target_drawable (ct, dpy, drawable);
cairo_set_rgb_color(ct, 0, 0, 0);
cairo_set_line_width(ct, win->line_width);
cairo_set_line_cap(ct, win->line_cap);
cairo_translate(ct, win->xtrans, win->ytrans);
cairo_scale(ct, win->zoom, win->zoom);
cairo_set_tolerance(ct, win->tolerance);
draw_spline(ct, win);
status = cairo_get_status(ct);
if (status) {
fprintf(stderr, "Xr is unhappy: %s\n", cairo_get_status_string(ct));
}
cairo_destroy(ct);
XCopyArea(win->dpy, win->pix, win->win, win->gc,
0, 0, win->width, win->height,
0, 0);
}
static void
win_init(win_t *win, Display *dpy)
{
int i;
Window root;
XGCValues gcv;
win->dpy = dpy;
win->width = 400;
win->height = 400;
root = DefaultRootWindow(dpy);
win->scr = DefaultScreen(dpy);
win->win = XCreateSimpleWindow(dpy, root, 0, 0,
win->width, win->height, 0,
WhitePixel(dpy, win->scr), WhitePixel(dpy, win->scr));
win->pix = XCreatePixmap(dpy, win->win, win->width, win->height, DefaultDepth (dpy, win->scr));
gcv.foreground = WhitePixel(dpy, win->scr);
win->gc = XCreateGC(dpy, win->pix, GCForeground, &gcv);
XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height);
for (i=0; i < ARRAY_SIZE(key_binding); i++) {
KeySym keysym;
keysym = XStringToKeysym(key_binding[i].key);
if (keysym == NoSymbol)
fprintf(stderr, "ERROR: No keysym for \"%s\"\n", key_binding[i].key);
else
key_binding[i].keycode = XKeysymToKeycode(dpy, keysym);
}
win->active = 0;
win->active_pt = &win->spline.pt[win->active];
win->spline = DEFAULT_SPLINE;
win->tolerance = DEFAULT_TOLERANCE;
win->line_width = DEFAULT_LINE_WIDTH;
win->line_cap = DEFAULT_LINE_CAP;
win->zoom = DEFAULT_ZOOM;
win->show_path = 1;
win->drag = 0;
win_refresh(win);
win->needs_refresh = 0;
win_select_events(win);
XMapWindow(dpy, win->win);
}
static void
win_deinit(win_t *win)
{
XFreeGC(win->dpy, win->gc);
XFreePixmap(win->dpy, win->pix);
XDestroyWindow(win->dpy, win->win);
}
static void
win_select_events(win_t *win)
{
win->event_mask =
ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
| KeyPressMask
| StructureNotifyMask
| ExposureMask;
XSelectInput(win->dpy, win->win, win->event_mask);
}
static char *
get_callback_doc(void *callback)
{
int i;
for (i=0; i < ARRAY_SIZE(callback_doc); i++)
if (callback_doc[i].callback == callback)
return callback_doc[i].doc;
return "<undocumented function>";
}
static void
win_print_help(win_t *win)
{
int i;
printf("Xr spline demonstration\n");
printf("Click and drag to move spline endpoints and control points, or:\n\n");
for (i=0; i < ARRAY_SIZE(button_binding); i++)
printf("Button %d:\t%s\n",
button_binding[i].button,
get_callback_doc(button_binding[i].callback));
printf("\n");
for (i=0; i < ARRAY_SIZE(key_binding); i++)
if (! key_binding[i].is_alias)
printf("%s:\t%s\n",
key_binding[i].key,
get_callback_doc(key_binding[i].callback));
}
static double
distance_sq(pt_t *a, pt_t *b)
{
double dx = b->x - a->x;
double dy = b->y - a->y;
return dx*dx + dy*dy;
}
static int
win_handle_button_press(win_t *win, XButtonEvent *bev)
{
int i;
for (i=0; i < ARRAY_SIZE(button_binding); i++)
if (button_binding[i].button == bev->button)
return (button_binding[i].callback)(win, bev->x, bev->y);
return 0;
}
static void
win_handle_motion(win_t *win, XMotionEvent *mev)
{
if (win->drag) {
win->active_pt->x += (mev->x - win->drag_pt.x) / win->zoom;
win->active_pt->y += (mev->y - win->drag_pt.y) / win->zoom;
win->needs_refresh = 1;
win->drag_pt.x = mev->x;
win->drag_pt.y = mev->y;
}
}
static int
win_handle_key_press(win_t *win, XKeyEvent *kev)
{
int i;
for (i=0; i < ARRAY_SIZE(key_binding); i++)
if (key_binding[i].keycode == kev->keycode)
return (key_binding[i].callback)(win);
return 0;
}
static void
win_grow_pixmap(win_t *win)
{
Pixmap new;
new = XCreatePixmap(win->dpy, win->win, win->width, win->height, DefaultDepth (win->dpy, win->scr));
XFillRectangle(win->dpy, new, win->gc, 0, 0, win->width, win->height);
XCopyArea(win->dpy, win->pix, new, win->gc, 0, 0, win->width, win->height, 0, 0);
XFreePixmap(win->dpy, win->pix);
win->pix = new;
win_refresh(win);
}
static void
win_handle_configure(win_t *win, XConfigureEvent *cev)
{
int has_grown = 0;
if (cev->width > win->width || cev->height > win->height) {
has_grown = 1;
}
win->width = cev->width;
win->height = cev->height;
if (has_grown) {
win_grow_pixmap(win);
}
}
static void
win_handle_expose(win_t *win, XExposeEvent *eev)
{
XCopyArea(win->dpy, win->pix, win->win, win->gc,
eev->x, eev->y, eev->width, eev->height,
eev->x, eev->y);
}
static void
win_handle_events(win_t *win)
{
int done;
XEvent xev;
while (1) {
if (!XPending(win->dpy) && win->needs_refresh) {
win_refresh(win);
win->needs_refresh = 0;
}
XNextEvent(win->dpy, &xev);
switch(xev.type) {
case ButtonPress:
win_handle_button_press(win, &xev.xbutton);
break;
case MotionNotify:
win_handle_motion(win, &xev.xmotion);
break;
case ButtonRelease:
win->drag = 0;
break;
case KeyPress:
done = win_handle_key_press(win, &xev.xkey);
if (done)
return;
break;
case ConfigureNotify:
win_handle_configure(win, &xev.xconfigure);
break;
case Expose:
win_handle_expose(win, &xev.xexpose);
break;
}
}
}
/* Callbacks */
/* nearest control point in spline to given point */
static int
find_nearest(spline_t *spline, double x, double y)
{
int i, nearest;
double dist, min_dist;
pt_t pt;
pt.x = x;
pt.y = y;
for (i=0; i<4; i++) {
dist = distance_sq(&spline->pt[i], &pt);
if (i==0 || dist < min_dist) {
nearest = i;
min_dist = dist;
}
}
return nearest;
}
static int
select_point_cb(win_t *win, int x, int y)
{
win->drag = 1;
win->drag_pt.x = x;
win->drag_pt.y = y;
win->active = find_nearest(&win->spline, x / win->zoom, y / win->zoom);
win->active_pt = &win->spline.pt[win->active];
win->needs_refresh = 1;
return 0;
}
static int
snap_point_cb(win_t *win, int x, int y)
{
*win->active_pt = win->spline.pt[find_nearest(&win->spline, x / win->zoom, y / win->zoom)];
win->needs_refresh = 1;
return 0;
}
static int
quit_cb(win_t *win)
{
return 1;
}
static int
select_next_cb(win_t *win)
{
win->active = (win->active + 1) % 4;
win->active_pt = &win->spline.pt[win->active];
win->needs_refresh = 1;
return 0;
}
static int
left_epsilon_cb(win_t *win)
{
win->active_pt->x -= EPSILON;
win->needs_refresh = 1;
return 0;
}
static int
right_epsilon_cb(win_t *win)
{
win->active_pt->x += EPSILON;
win->needs_refresh = 1;
return 0;
}
static int
up_epsilon_cb(win_t *win)
{
win->active_pt->y -= EPSILON;
win->needs_refresh = 1;
return 0;
}
static int
down_epsilon_cb(win_t *win)
{
win->active_pt->y += EPSILON;
win->needs_refresh = 1;
return 0;
}
static int
print_spline_cb(win_t *win)
{
pt_t *pt = win->spline.pt;
printf("{ { %.20g, %.20g }, { %.20g, %.20g }, { %.20g, %.20g }, { %.20g, %.20g } }\n",
pt[0].x, pt[0].y,
pt[1].x, pt[1].y,
pt[2].x, pt[2].y,
pt[3].x, pt[3].y);
return 0;
}
static int
zoom_in_cb(win_t *win)
{
win->zoom *= 2.0;
win->needs_refresh = 1;
return 0;
}
static int
trans_left_cb(win_t *win)
{
win->xtrans -= win->width / 4.0;
win->needs_refresh = 1;
return 0;
}
static int
trans_right_cb(win_t *win)
{
win->xtrans += win->width / 4.0;
win->needs_refresh = 1;
return 0;
}
static int
trans_up_cb(win_t *win)
{
win->ytrans -= win->height / 4.0;
win->needs_refresh = 1;
return 0;
}
static int
trans_down_cb(win_t *win)
{
win->ytrans += win->height / 4.0;
win->needs_refresh = 1;
return 0;
}
static int
zoom_out_cb(win_t *win)
{
win->zoom /= 2.0;
win->needs_refresh = 1;
return 0;
}
static int
flatten_cb(win_t *win)
{
win->tolerance *= 10;
win->needs_refresh = 1;
return 0;
}
static int
smooth_cb(win_t *win)
{
win->tolerance /= 10;
win->needs_refresh = 1;
return 0;
}
static int
toggle_path(win_t *win)
{
win->show_path = ! win->show_path;
win->needs_refresh = 1;
return 0;
}
static int
widen_line(win_t *win)
{
win->line_width *= 2;
win->needs_refresh = 1;
return 0;
}
static int
narrow_line(win_t *win)
{
win->line_width /= 2;
win->needs_refresh = 1;
return 0;
}
- Previous message: [Commit] cairo-demo README, NONE, 1.1 Makefile, 1.4, 1.5 xrfreq.c,
1.3, NONE xrknockout.c, 1.10, NONE xrspline.c, 1.10,
NONE xrtest.c, 1.9, NONE
- Next message: [Commit] cairo-demo/png .cvsignore, NONE, 1.1 Makefile, NONE,
1.1 caps_joins.c, NONE, 1.1 hering.c, NONE, 1.1 outline.c,
NONE, 1.1 spiral.c, NONE, 1.1 splines_tolerance.c, NONE,
1.1 stars.c, NONE, 1.1 write_png.c, NONE, 1.1 write_png.h, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Commit
mailing list