shithub: pain

ref: d63e7e5714f4f42a38372fcd57f56e0129fb4c14
dir: /pill/pill.c/

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

#define STEPS 3600
#define RADIUS .60
#define MAXSATURATION 1.0
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define RAD2DEG(r_) ((180.0)/PI * (r_))
#define DEG2RAD(r_) (PI/(180.0) * (r_))
#define BACKGROUNDCOLOR 0x22272EFF
#define CIRCLESLICE (2*PI/5)
#define CIRCLESHIFT (PI/2 + CIRCLESLICE/2)
#define CIRCLEDIAMETER (2*PI - CIRCLESLICE)
#define COLORPICKERPADDING .10
#define COLORPICKERRADIUS .25
#define RECTANGLE(w, h) ((Rectangle){(Point){(0),(0)}, (Point){(w),(h)}})

Image * Circle = nil;
uint CircleBPL = 0;
u32int * RawCircle = nil;
uint RawCircleSize = 0;
Image * Background = nil;
float SaturationStart = .50;
float HueStart = PI*.35;
float Value = 1.0;
int RunApp = 1;
int UpdateCircle = 1;

static unsigned int
hsv2rgb(float h, float s, float v)
{
	// Taken from Computer Graphics: Principle and Practice
	unsigned int rgb;
	float f, p, q, t, r = 0.0, g = 0.0, b = 0.0;
	int i;
	
	h = RAD2DEG(h);
	h /= 60.0;
	i = (int)floor(h);
	f = h - i;
	p = v * (1.0 - s);
	q = v * (1.0 - (s * f));
	t = v * (1.0 - (s * (1.0 - f)));

	switch(i)
	{
		case 0:
			r = v;
			g = t;
			b = p;
			break;
		case 1:
			r = q;
			g = v;
			b = p;
			break;
		case 2:
			r = p;
			g = v;
			b = t;
			break;
		case 3:
			r = p;
			g = q;
			b = v;
			break;
		case 4:
			r = t;
			g = p;
			b = v;
			break;
		case 5:
			r = v;
			g = p;
			b = q;
			break;
		default:
			break;
	}

	rgb = (0xff & (uint)(b*255));
	rgb |= (0xff & (uint)(g*255)) << 8;
	rgb |= (0xff & (uint)(r*255)) << 16;
	return (rgb << 8) | 0xff;
}

static void
updatecircle(void)
{
	float t, i, l, s, u, g, ct, st;
	Point c, e, k;
	int w;
	uint h;

	if (Circle != nil) {
		freeimage(Circle);
	}
	Circle = allocimage(display, RECTANGLE(Dx(screen->r), Dy(screen->r)), RGBA32, 1, BACKGROUNDCOLOR);
	if (Circle == nil)
		sysfatal("initcanvas: %r");
	if (RawCircle != nil) {
		free(RawCircle);
	}
	CircleBPL = bytesperline(Circle->r, Circle->depth);
	RawCircleSize = CircleBPL * Dy(Circle->r);
	RawCircle = malloc(RawCircleSize);
	unloadimage(Circle, Circle->r, (uchar *)RawCircle, RawCircleSize);

	c.x = Dx(Circle->r)/2;
	c.y = Dy(Circle->r)/2;

	l = MIN(Dx(screen->r), Dy(screen->r));
	l *= RADIUS/2.0;
	
	i = 1/(l*2);
	for (t = 0.0; t < CIRCLEDIAMETER; t += i) {
		u = t/CIRCLEDIAMETER;
		for (s = 0; s < l; s += 0.1) {
			e.x = c.x + s * cos(t + CIRCLESHIFT);
			e.y = c.y + s * sin(t + CIRCLESHIFT);
			RawCircle[Dx(Circle->r) * e.y + e.x] = hsv2rgb(
				HueStart + u, 
				(SaturationStart)+(s/l)*(MAXSATURATION - SaturationStart),
				Value);
		}
	}

	s = l * (1+COLORPICKERPADDING);
	u = s + (l*COLORPICKERRADIUS);
	i = 1/(u*2);
	for (t = .0; t < 2*PI; t+=i) {
		ct = cos(t);
		st = sin(t);
		k.x = c.x + s * ct;
		k.y = c.y + s * st;
		e.x = c.x + u * ct;
		e.y = c.y + u * st;

		if (e.x < k.x) {
			w = e.x;
			e.x = k.x;
			k.x = w;
		}
		
		h = hsv2rgb(t, 1.0, 1.0);
		for (g = s; g < u; g++) {
				RawCircle[Dx(Circle->r) * (c.y + ((int)(g * st))) + (c.x + ((int)(g * ct)))] = h;
		}
	}

	loadimage(Circle, Circle->r, (uchar *)RawCircle, RawCircleSize);
}

static void
drawcanvas(void)
{
	if (UpdateCircle) {
		updatecircle();
		UpdateCircle = 0;
	}
	draw(screen, screen->r, Background, nil, ZP);
	draw(screen, screen->r, Circle, nil, ZP);
}

void
setbackground(ulong col)
{	
	if (Background != nil)
		freeimage(Background);

	Background = allocimage(display, RECTANGLE(1, 1), RGBA32, 1, col);
	if (Background == nil)
		sysfatal("setbackground: %r");
}

static void
initcanvas(void)
{
	UpdateCircle = 1;
	setbackground(BACKGROUNDCOLOR);
	drawcanvas();
}

void
eresized(int)
{	
	if(getwindow(display, Refnone) < 0)
		sysfatal("getwindow: %r");
	initcanvas();
}

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

	USED(argc);
	USED(argv);
	
	if (initdraw(nil, nil, "pill") < 0)
		sysfatal("initdraw: %r\n");
	einit(Emouse | Ekeyboard);
	initcanvas();
	for (;RunApp;) {
		switch(event(&e)) {
		case Ekeyboard:
			if (e.kbdc == 'q') {
				RunApp = 0;
			}
			break;
		}
	}
}