shithub: etoys

ref: d6beda15798a3d1d604a033febca3756456345d1
dir: /bsplines.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <keyboard.h>

typedef struct Point2 Point2;
typedef struct Bspline Bspline;

struct Point2
{
	double x, y, w;
};

struct Bspline
{
	Point2 *pts;
	ulong npt;
};

enum {
	Cbg,
	Cctl,
	Cbez,
	NCOLOR
};

Image *pal[NCOLOR];
Bspline *bsplines;
Point2 *pts;
ulong nbspline, npt;

Point2
Pt2(double x, double y, double w)
{
	return (Point2){x,y,w};
}

Point
toscreen(Point2 p)
{
	return addpt(screen->r.min, Pt(p.x,p.y));
}

Point2
fromscreen(Point p)
{
	p = subpt(p, screen->r.min);
	return Pt2(p.x,p.y,1);
}

void
initpalette(void)
{
	pal[Cbg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000ff);
	pal[Cctl] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x00ff00ff);
	pal[Cbez] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xff0000ff);
}

void
redraw(void)
{
	Point *bpts;
	int i, j;

	draw(screen, screen->r, pal[Cbg], nil, ZP);
	for(i = 0; i < nbspline; i++){
		bpts = malloc(bsplines[i].npt*sizeof(Point));
		for(j = 0; j < bsplines[i].npt; j++)
			bpts[j] = toscreen(bsplines[i].pts[j]);
		bezspline(screen, bpts, bsplines[i].npt, Endsquare, Endsquare, 0, pal[Cbez], ZP);
		free(bpts);
	}
	for(i = 0; i < npt; i++)
		fillellipse(screen, toscreen(pts[i]), 2, 2, pal[Cctl], ZP);
	flushimage(display, 1);
}

void
usage(void)
{
	fprint(2, "usage: %s\n", argv0);
	exits("usage");
}

void
main(int argc, char *argv[])
{
	Event e;
	Bspline b;

	ARGBEGIN{
	default: usage();
	}ARGEND;
	if(argc > 0)
		usage();
	if(initdraw(nil, nil, nil) < 0)
		sysfatal("initdraw: %r");
	initpalette();
	einit(Emouse|Ekeyboard);
	redraw();
	for(;;)
		switch(event(&e)){
		case Emouse:
			if((e.mouse.buttons&1) != 0){
				pts = realloc(pts, ++npt*sizeof(Point2));
				pts[npt-1] = fromscreen(e.mouse.xy);
				redraw();
			}
			if((e.mouse.buttons&4) != 0){
				if(npt > 2){
					b.pts = pts;
					b.npt = npt;
					bsplines = realloc(bsplines, ++nbspline*sizeof(Bspline));
					bsplines[nbspline-1] = b;
					pts = nil;
					npt = 0;
				}
				redraw();
			}
			break;
		case Ekeyboard:
			switch(e.kbdc){
			case 'q':
			case Kdel:
				exits(0);
			}
			break;
		}
}

void
eresized(int)
{
	if(getwindow(display, Refnone) < 0)
		sysfatal("resize failed");
	redraw();
}