head 1.11; access; symbols; locks; strict; comment @ * @; 1.11 date 2003.08.18.18.11.37; author cworth; state dead; branches; next 1.10; 1.10 date 2003.07.18.18.35.23; author cworth; state Exp; branches; next 1.9; 1.9 date 2003.04.17.20.41.17; author cworth; state Exp; branches; next 1.8; 1.8 date 2003.01.08.18.48.45; author cworth; state Exp; branches; next 1.7; 1.7 date 2002.11.02.03.47.29; author cworth; state Exp; branches; next 1.6; 1.6 date 2002.09.27.21.24.13; author cworth; state Exp; branches; next 1.5; 1.5 date 2002.09.27.21.23.13; author cworth; state Exp; branches; next 1.4; 1.4 date 2002.09.10.20.33.12; author cworth; state Exp; branches; next 1.3; 1.3 date 2002.09.10.17.26.17; author cworth; state Exp; branches; next 1.2; 1.2 date 2002.09.10.16.51.50; author cworth; state Exp; branches; next 1.1; 1.1 date 2002.09.10.15.02.27; author cworth; state Exp; branches; next ; desc @@ 1.11 log @Added demos from OLS paper. @ text @#include #include #include #include #include #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 dump_traps; 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 int dump_traps(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 = 142; static const cairo_line_cap_t DEFAULT_LINE_CAP = CAIRO_LINE_CAP_BUTT; /* 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 } } }; /* 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 = { { {10, 20}, {300, 400}, {10, 400}, {300, 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" }, { dump_traps, "Dump tesselation of current spline on stderr" }, }; 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 }, { "D", 0, 0, dump_traps }, }; 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 *xrs, pt_t *a, pt_t *b, double width) { cairo_save(xrs); cairo_set_rgb_color(xrs, 0, 0, 1); cairo_set_line_width(xrs, width); cairo_move_to(xrs, a->x, a->y); cairo_line_to(xrs, b->x, b->y); cairo_stroke(xrs); cairo_restore(xrs); } static void draw_handle(cairo_t *xrs, pt_t *p, int is_active, double size, double width) { cairo_save(xrs); if (is_active) cairo_set_rgb_color(xrs, 0, 1, 0); else cairo_set_rgb_color(xrs, 1, 0, 0); cairo_set_line_width(xrs, width); cairo_move_to(xrs, p->x - size / 2.0, p->y - size / 2.0); cairo_rel_line_to(xrs, size, 0); cairo_rel_line_to(xrs, 0, size); cairo_rel_line_to(xrs, -size, 0); cairo_rel_line_to(xrs, 0, -size); cairo_stroke(xrs); cairo_restore(xrs); } static void draw_spline(cairo_t *xrs, win_t *win) { spline_t *spline = &win->spline; double zoom = win->zoom; int i; cairo_save(xrs); cairo_move_to(xrs, spline->pt[0].x, spline->pt[0].y); cairo_curve_to(xrs, spline->pt[1].x, spline->pt[1].y, spline->pt[2].x, spline->pt[2].y, spline->pt[3].x, spline->pt[3].y); if (win->dump_traps) setenv("XRDEBUG_DUMP_TRAPS","",1); else unsetenv("XRDEBUG_DUMP_TRAPS"); cairo_stroke(xrs); win->dump_traps = 0; if (win->show_path) { cairo_set_line_width(xrs, 1 / zoom); cairo_set_rgb_color(xrs, 1, 1, 1); cairo_move_to(xrs, spline->pt[0].x, spline->pt[0].y); cairo_curve_to(xrs, 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(xrs); } draw_control_line(xrs, &spline->pt[0], &spline->pt[1], 2.0 / zoom); draw_control_line(xrs, &spline->pt[3], &spline->pt[2], 2.0 / zoom); for (i=0; i < 4; i++) { draw_handle(xrs, &spline->pt[i], i == win->active, 5.0 / zoom, 1.0 / zoom); } cairo_restore(xrs); } static void win_refresh(win_t *win) { Display *dpy = win->dpy; cairo_t *xrs; cairo_status_t status; Drawable drawable = win->pix; XFillRectangle(dpy, win->pix, win->gc, 0, 0, win->width, win->height); xrs = cairo_create(); /* if (win->restrict_traps) cairo_restrict_spline_traps(xrs, win->trap_start, win->trap_stop); */ cairo_set_target_drawable (xrs, dpy, drawable); cairo_set_rgb_color(xrs, 0, 0, 0); cairo_set_line_width(xrs, win->line_width); cairo_set_line_cap(xrs, win->line_cap); cairo_translate(xrs, win->xtrans, win->ytrans); cairo_scale(xrs, win->zoom, win->zoom); cairo_set_tolerance(xrs, win->tolerance); draw_spline(xrs, win); status = cairo_get_status(xrs); if (status) { fprintf(stderr, "Xr is unhappy: %s\n", cairo_get_status_string(xrs)); } cairo_destroy(xrs); 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->dump_traps = 0; 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 ""; } 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; } static int dump_traps(win_t *win) { win->dump_traps = 1; win->needs_refresh = 1; return 0; } @ 1.10 log @Updated to work with Cairo rather than Xr @ text @@ 1.9 log @Updated to track changes in Xr @ text @d6 1 a6 1 #include d43 1 a43 1 XrLineCap line_cap; d115 1 a115 1 static const XrLineCap DEFAULT_LINE_CAP = XrLineCapButt; d326 1 a326 1 draw_control_line(XrState *xrs, pt_t *a, pt_t *b, double width) d328 1 a328 1 XrSave(xrs); d330 2 a331 2 XrSetRGBColor(xrs, 0, 0, 1); XrSetLineWidth(xrs, width); d333 3 a335 3 XrMoveTo(xrs, a->x, a->y); XrLineTo(xrs, b->x, b->y); XrStroke(xrs); d337 1 a337 1 XrRestore(xrs); d341 1 a341 1 draw_handle(XrState *xrs, pt_t *p, int is_active, double size, double width) d343 1 a343 1 XrSave(xrs); d346 1 a346 1 XrSetRGBColor(xrs, 0, 1, 0); d348 1 a348 1 XrSetRGBColor(xrs, 1, 0, 0); d350 1 a350 1 XrSetLineWidth(xrs, width); d352 6 a357 6 XrMoveTo(xrs, p->x - size / 2.0, p->y - size / 2.0); XrRelLineTo(xrs, size, 0); XrRelLineTo(xrs, 0, size); XrRelLineTo(xrs, -size, 0); XrRelLineTo(xrs, 0, -size); XrStroke(xrs); d359 1 a359 1 XrRestore(xrs); d363 1 a363 1 draw_spline(XrState *xrs, win_t *win) d370 1 a370 1 XrSave(xrs); d372 2 a373 2 XrMoveTo(xrs, spline->pt[0].x, spline->pt[0].y); XrCurveTo(xrs, d381 1 a381 1 XrStroke(xrs); d385 4 a388 4 XrSetLineWidth(xrs, 1 / zoom); XrSetRGBColor(xrs, 1, 1, 1); XrMoveTo(xrs, spline->pt[0].x, spline->pt[0].y); XrCurveTo(xrs, d392 1 a392 1 XrStroke(xrs); d402 1 a402 1 XrRestore(xrs); d410 2 a411 2 XrState *xrs; XrStatus status; d416 1 a416 1 xrs = XrCreate(); d420 1 a420 1 XrRestrictSplineTraps(xrs, win->trap_start, win->trap_stop); d423 1 a423 1 XrSetTargetDrawable (xrs, dpy, drawable); d425 1 a425 1 XrSetRGBColor(xrs, 0, 0, 0); d427 5 a431 5 XrSetLineWidth(xrs, win->line_width); XrSetLineCap(xrs, win->line_cap); XrTranslate(xrs, win->xtrans, win->ytrans); XrScale(xrs, win->zoom, win->zoom); XrSetTolerance(xrs, win->tolerance); d435 1 a435 1 status = XrGetStatus(xrs); d437 1 a437 1 fprintf(stderr, "Xr is unhappy: %s\n", XrGetStatusString(xrs)); d440 1 a440 1 XrDestroy(xrs); @ 1.8 log @Fixed event loop to use XPending instead of usleep. Removed silly text display @ text @d6 1 a6 1 #include d11 6 d26 4 d46 2 d50 2 a55 4 int restrict_traps; int trap_start; int trap_stop; a87 1 d100 4 d109 1 d111 2 a112 12 static int toggle_restrict_traps(win_t *win); static int decrease_trap_start(win_t *win); static int increase_trap_start(win_t *win); static int decrease_trap_stop(win_t *win); static int increase_trap_stop(win_t *win); d114 1 a114 1 static const double DEFAULT_LINE_WIDTH = 10; d129 3 a131 1 (The fact that they are missing is a bug) */ d148 27 d227 1 d230 1 d261 4 d267 1 a267 6 { toggle_path, "Toggle thin yellow display of path" }, { toggle_restrict_traps, "Toggle restricted subset of spline rendering" }, { decrease_trap_start, "Add a trap to start of spline, (see 'R')" }, { increase_trap_start, "Remove a trap from start of spline, (see 'R')" }, { decrease_trap_stop, "Remove a trap from end of spline, (see 'R')" }, { increase_trap_stop, "Add a trap to end of spline, (see 'R')" }, d270 1 a289 5 { "Z", 0, 0, decrease_trap_start }, { "X", 0, 0, increase_trap_start }, { "C", 0, 0, decrease_trap_stop }, { "V", 0, 0, increase_trap_stop }, { "R", 0, 0, toggle_restrict_traps }, d291 2 a292 1 { "N", 0, 0, narrow_line } d363 1 a363 1 draw_spline(XrState *xrs, spline_t *spline, double zoom, int active, int show_path) d365 3 d377 4 d382 1 d384 3 a386 3 if (show_path) { XrSetLineWidth(xrs, 2.0 / zoom); XrSetRGBColor(xrs, 0, 1, 1); d399 1 a399 1 draw_handle(xrs, &spline->pt[i], i == active, 5.0 / zoom, 1.0 / zoom); d416 1 a416 1 xrs = XrCreate(dpy); d423 3 a425 2 XrSetDrawable(xrs, drawable); XrSetVisual(xrs, DefaultVisual(win->dpy, win->scr)); a426 1 XrSetRGBColor(xrs, 1, 1, 1); d429 1 d433 1 a433 1 draw_spline(xrs, &win->spline, win->zoom, win->active, win->show_path); d463 1 a463 1 BlackPixel(dpy, win->scr), BlackPixel(dpy, win->scr)); d465 2 a466 2 win->pix = XCreatePixmap(dpy, win->win, win->width, win->height, DefaultDepth(dpy, win->scr)); gcv.foreground = BlackPixel(dpy, win->scr); d487 1 a487 4 win->restrict_traps = 0; win->trap_start = 0; win->trap_stop = 1; d607 1 a607 2 new = XCreatePixmap(win->dpy, win->win, win->width, win->height, DefaultDepth(win->dpy, win->scr)); d792 1 a792 1 printf("{ { %g, %g }, { %g, %g }, { %g, %g }, { %g, %g } }\n", a796 3 printf("/* start = %d, stop = %d */\n", win->trap_start, win->trap_stop); d812 1 a812 1 zoom_out_cb(win_t *win) d814 1 a814 1 win->zoom /= 2.0; d822 1 a822 1 flatten_cb(win_t *win) d824 1 a824 1 win->tolerance *= 10; d832 1 a832 1 smooth_cb(win_t *win) d834 1 a834 1 win->tolerance /= 10; d842 1 a842 1 toggle_path(win_t *win) d844 1 a844 1 win->show_path = ! win->show_path; d852 1 a852 1 toggle_restrict_traps(win_t *win) d854 1 a854 1 win->restrict_traps = ! win->restrict_traps; d862 1 a862 1 decrease_trap_start(win_t *win) d864 1 a864 2 if (win->trap_start) win->trap_start--; d872 1 a872 1 increase_trap_start(win_t *win) d874 1 a874 1 win->trap_start++; d882 1 a882 1 decrease_trap_stop(win_t *win) d884 1 a884 2 if (win->trap_stop) win->trap_stop--; d892 1 a892 1 increase_trap_stop(win_t *win) d894 1 a894 1 win->trap_stop++; d902 1 a902 1 widen_line(win_t *win) d904 1 a904 1 win->line_width *= 2; d912 1 a912 1 narrow_line(win_t *win) d914 1 a914 1 win->line_width /= 2; @ 1.7 log @Added text message to xrspline @ text @a392 6 XrSelectFont(xrs, "Verdana"); XrScaleFont(xrs, 10); XrSetRGBColor(xrs, 1, 1, 1); XrMoveTo(xrs, 20, 20); XrShowText(xrs, "Hello World"); d612 1 a612 1 if (win->needs_refresh) { a614 3 } else { /* XXX: This is pretty cheesy */ usleep(100000); d617 1 a617 1 while (XCheckMaskEvent(win->dpy, win->event_mask, &xev)) { d619 21 a639 22 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; } @ 1.6 log @Changed path color to cyan @ text @d158 6 d203 7 d372 1 d379 1 d382 1 d393 6 d400 5 @ 1.5 log @Added line width changing @ text @d334 1 a334 1 XrSetRGBColor(xrs, 0, 0, 1); @ 1.4 log @Added some examples showing current bugs. Added 'P' to toggle yellow display of spline path @ text @d42 4 d94 14 d113 1 d116 1 a116 1 }; /* set zoom to (1 / 32.0) for this one */ d118 2 d124 14 d142 21 d168 11 d181 1 d184 4 d190 9 d215 8 a222 1 { toggle_path, "Toggle thin yellow display of path" } d226 1 d237 1 a237 1 { "greater", 0, 0, smooth_cb }, d241 8 a248 1 { "P", 0, 0, toggle_path } d333 2 a334 2 XrSetLineWidth(xrs, 1.0 / zoom); XrSetRGBColor(xrs, 1, 1, 0); d364 4 d419 1 d425 5 a429 1 win->show_path = 0; d744 3 d795 72 @ 1.3 log @Changed default spline to demonstrate a bug I discovered @ text @d36 1 d89 1 d95 1 a95 3 #define DO_NASTY_BUG_TICKLING_SPLINE #ifdef DO_NASTY_BUG_TICKLING_SPLINE static const spline_t DEFAULT_SPLINE = { d97 4 d102 2 a103 4 static const double DEFAULT_ZOOM = 1 / 32.0; #else /* nice, harmless spline */ static const spline_t DEFAULT_SPLINE = { d106 13 a118 2 static const double DEFAULT_ZOOM = 1.0; #endif d133 2 a134 1 { smooth_cb, "Increase rendering accuracy, (tolerance /= 10)" } d151 2 a152 1 { "comma", 1, 0, flatten_cb } d223 1 a223 1 draw_spline(XrState *xrs, spline_t *spline, double zoom, int active) d236 11 d277 1 a277 1 draw_spline(xrs, &win->spline, win->zoom, win->active); d324 1 d677 10 @ 1.2 log @Added bindings for adjusting tolerance @ text @d92 9 d104 2 d297 1 a297 1 win->zoom = 1.0; @ 1.1 log @Added new interactive test xrspline @ text @d31 1 d53 1 d86 2 d89 1 d107 3 a109 1 { zoom_out_cb, "Zoom out (2X)" } d113 14 a126 10 { "Q", 0, quit_cb }, { "Left", 0, left_epsilon_cb }, { "Right", 0, right_epsilon_cb }, { "Up", 0, up_epsilon_cb }, { "Down", 0, down_epsilon_cb }, { "Return", 0, print_spline_cb }, { "space", 0, select_next_cb }, { "plus", 0, zoom_in_cb }, { "equal", 0, zoom_in_cb }, { "minus", 0, zoom_out_cb } d238 1 a238 1 XrSetTolerance(xrs, .1); d283 1 d348 4 a351 3 printf("%s:\t%s\n", key_binding[i].key, get_callback_doc(key_binding[i].callback)); d418 1 a418 1 int has_grown; d619 20 @