shithub: etoys

ref: a5d30a2794ddba047e4dad0eda129d704322aead
dir: /chain.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <geometry.h>

enum {
	MAXMAGNITUDE = 40
};

enum {
	Cbg,
	Cfg,
	NCOLOR
};

typedef struct Strut Strut;

struct Strut
{
	Point2 v;
	Strut *next;
};

RFrame worldrf;
Image *pal[NCOLOR];
Strut *struts;
Point2 origin;

Strut*
newstrut(Point2 v)
{
	Strut *s;

	s = malloc(sizeof(Strut));
	if(s == nil)
		sysfatal("malloc: %r");
	setmalloctag(s, getcallerpc(&v));
	s->v = v;
	s->next = nil;
	return s;
}

Point
toscreen(Point2 p)
{
	p = invrframexform(p, worldrf);
	return Pt(p.x,p.y);
}

Point2
fromscreen(Point p)
{
	return rframexform(Pt2(p.x,p.y,1), worldrf);
}

void
initpalette(void)
{
	pal[Cbg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000ff);
	pal[Cfg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xffffffff);
}

void
redraw(void)
{
	Strut *s;
	Point2 p0, p1;

	p0 = origin;

	lockdisplay(display);
	draw(screen, screen->r, pal[Cbg], nil, ZP);
	for(s = struts; s != nil; s = s->next){
		p1 = addpt2(p0, s->v);
		line(screen, toscreen(p0), toscreen(p1), Endsquare, Endarrow, 0, pal[Cfg], ZP);
		p0 = p1;
	}
	flushimage(display, 1);
	unlockdisplay(display);
}

void
resized(void)
{
	lockdisplay(display);
	if(getwindow(display, Refnone) < 0)
		sysfatal("resize failed");
	unlockdisplay(display);
	worldrf.p = Pt2(screen->r.min.x,screen->r.max.y,1);
	origin = Pt2(Dx(screen->r)/2,Dy(screen->r)/2,1);
	redraw();
}

void
mouse(Mouse m)
{
	Strut *s;
	Point2 mpos, v;
	double θ;

	if((m.buttons & 1) != 0){
		mpos = subpt2(fromscreen(m.xy), origin);
		θ = atan2(mpos.y, mpos.x);
		//v = Vec2(cos(frand() * 2*PI),sin(frand() * 2*PI));
		v = Vec2(cos(θ),sin(θ));
		v = mulpt2(v, frand()*MAXMAGNITUDE);
		s = newstrut(v);
		if(struts == nil)
			struts = s;
		else{
			s->next = struts;
			struts = s;
		}
	}
}

void
key(Rune r)
{
	switch(r){
	case Kdel:
	case 'q':
		threadexitsall(nil);
	}
}

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

void
threadmain(int argc, char *argv[])
{
	Mousectl *mc;
	Keyboardctl *kc;
	Rune r;

	ARGBEGIN{
	default: usage();
	}ARGEND;
	if(argc > 0)
		usage();

	if(initdraw(nil, nil, nil) < 0)
		sysfatal("initdraw: %r");
	if((mc = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if((kc = initkeyboard(nil)) == nil)
		sysfatal("initkeyboard: %r");
	initpalette();
	worldrf.p = Pt2(screen->r.min.x,screen->r.max.y,1);
	worldrf.bx = Vec2(1, 0);
	worldrf.by = Vec2(0,-1);
	origin = Pt2(Dx(screen->r)/2,Dy(screen->r)/2,1);

	display->locking = 1;
	unlockdisplay(display);
	redraw();

	for(;;){
		enum { MOUSE, RESIZE, KEYBOARD };
		Alt a[] = {
			{mc->c, &mc->Mouse, CHANRCV},
			{mc->resizec, nil, CHANRCV},
			{kc->c, &r, CHANRCV},
			{nil, nil, CHANEND}
		};

		switch(alt(a)){
		case MOUSE:
			mouse(mc->Mouse);
			break;
		case RESIZE:
			resized();
			break;
		case KEYBOARD:
			key(r);
			break;
		}

		redraw();
	}
}