ref: f48eac8988cf8ce8b18f49a97b26695c7b44ee52
dir: /pill/pill.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#define INTERNAL_HEIGHT 640
#define INTERNAL_WIDTH 640
#define STEPS 3600
#define RADIUS .60
#define MAXSATURATION 1.0
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(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 * VirtualWindow = nil;
Image * HuePicker = nil;
Image * Gradient = nil;
u32int * RawGradient = nil;
u32int RawGradientSize = 0;
int DrawGradient = 1;
int DrawHuePicker = 1;
int WindowMoved = 1;
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;
int resizeimage(Image * d, Image * s)
{
int i;
Point p;
Image * t, * c;
float scale;
Rectangle dr, sr, tr, r;
dr = rectsubpt(d->r, d->r.min);
sr = rectsubpt(s->r, s->r.min);
tr = dr;
if (Dx(dr) < Dx(sr)) {
tr.max.x = tr.min.x + Dx(sr);
}
if (Dy(dr) < Dy(sr)) {
tr.max.y = tr.min.y + Dy(sr);
}
if ((t = allocimage(display, tr, s->chan, 1, DTransparent)) == nil) {
werrstr("allocimage: %r");
return -1;
}
if ((c = allocimage(display, Rect(0, 0, 1, Dy(tr)), s->chan, 1, DNofill)) == nil)
{
werrstr("allocimage: %r");
freeimage(t);
return -1;
}
scale = ((float)Dx(sr))/((float)Dx(tr));
p = ZP;
r.min = tr.min;
r.max.y = s->r.max.y;
i = 0;
while (i < Dx(tr)) {
drawop(c, c->r, s, nil, p, S);
p.x = s->r.min.x + (int)(((float)i)*scale);
r.min.x = i + tr.min.x;
r.max.x = r.min.x + 1;
draw(screen, r, c, nil, ZP);
i+=1;
}
freeimage(c);
if ((c = allocimage(display, Rect(0, 0, Dx(tr), 1), s->chan, 1, DNofill)) == nil)
{
werrstr("allocimage: %r");
freeimage(t);
return -1;
}
scale = ((float)Dy(sr))/((float)Dy(tr));
p = dr.min;
r.min = tr.min;
r.max.x = tr.max.x;
// i = 0;
// while (r.min.y < dr.max.y) {
// draw(c, c->r, t, nil, p);
// p.y = (int)(((float)i)*scale);
//
// // Move the draw rectangle for the temporary image scale
// // rectangles to the right
// r.min.y = i + tr.min.x;
// r.max.y =i + tr.min.x + 1;
// Rectangle fr = rectaddpt(r, d->r.min);
// draw(d, fr, c, nil, ZP);
// i+=1;
// }
draw(d, d->r, t, nil, d->r.min);
freeimage(t);
freeimage(c);
return 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
initgradient(void)
{
if (Gradient != nil) {
freeimage(Gradient);
}
if (RawGradient != nil) {
free(RawGradient);
}
Gradient = allocimage(display, RECTANGLE(INTERNAL_WIDTH, INTERNAL_HEIGHT), RGBA32, 1, DTransparent);
if(Gradient == nil) {
sysfatal("initgradient: %r");
}
RawGradientSize = bytesperline(Gradient->r, Gradient->depth) * Dy(Gradient->r);
RawGradient = calloc(RawGradientSize, 1);
if (RawGradient == nil) {
sysfatal("calloc: out of memory");
}
}
static void
setgradienthue(void)
{
float t, i, l, s, u, ct, st;
Point c, e;
int rc, dx, dy;
dx = Dx(Gradient->r);
dy = Dy(Gradient->r);
c.x = dx/2;
c.y = dy/2;
l = MIN(dx, dy);
l *= RADIUS/2.0;
i = 1/(l*2);
for (t = 0.0; t < CIRCLEDIAMETER; t += i) {
u = t/CIRCLEDIAMETER;
ct = cos(t + CIRCLESHIFT);
st = sin(t + CIRCLESHIFT);
for (s = 0; s < l; s += 0.1) {
e.x = c.x + s * ct;
e.y = c.y + s * st;
RawGradient[dx * e.y + e.x] = hsv2rgb(
HueStart + u,
(SaturationStart)+(s/l)*(MAXSATURATION - SaturationStart),
Value);
}
}
rc = loadimage(Gradient, Gradient->r, (uchar *)RawGradient, RawGradientSize);
if (rc < 0) {
sysfatal("loadimage: %r");
}
}
static void
inithuepicker(void)
{
int rc, dx, dy, h;
u32int * raw, rawSize;
float t, i, s, u, g, st, ct, l;
Point c;
if (HuePicker != nil) {
freeimage(HuePicker);
}
HuePicker = allocimage(display, RECTANGLE(INTERNAL_WIDTH, INTERNAL_HEIGHT), RGBA32, 1, DTransparent);
if(HuePicker == nil) {
sysfatal("inithuepicker: %r");
}
rawSize = bytesperline(HuePicker->r, HuePicker->depth) * Dy(HuePicker->r);
raw = calloc(rawSize, 1);
if (raw == nil) {
sysfatal("calloc: out of memory");
}
dx = Dx(HuePicker->r);
dy = Dy(HuePicker->r);
c.x = dx/2;
c.y = dy/2;
l = MIN(dx, dy);
l *= RADIUS/2.0;
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);
h = hsv2rgb(t, 1.0, 1.0);
for (g = s; g < u; g++) {
raw[dx * (c.y + ((int)(g * st))) + (c.x + ((int)(g * ct)))] = h;
}
}
rc = loadimage(HuePicker, HuePicker->r, (uchar *)raw, rawSize);
if (rc < 0) {
sysfatal("loadimage: %r");
}
if (raw != nil) {
free(raw);
}
}
static void
drawcanvas(void)
{
Rectangle vwr = VirtualWindow->r;
//print("VirtualWindow: %R\n", VirtualWindow->r);
//print("screen: %R\n", screen->r);
VirtualWindow->r.min = screen->r.min;
VirtualWindow->r.max.x = VirtualWindow->r.min.x + Dx(vwr);
VirtualWindow->r.max.y = VirtualWindow->r.min.y + Dy(vwr);
//draw(screen, screen->r, Background, nil, ZP);
//draw(screen, screen->r, VirtualWindow, 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)
{
int rc;
if (VirtualWindow != nil) {
freeimage(VirtualWindow);
}
VirtualWindow = allocimage(display, screen->r, RGBA32, 0, DTransparent);
if (VirtualWindow == nil) {
sysfatal("initcanvas: %r");
}
draw(screen, screen->r, Background, nil, ZP);
rc = resizeimage(VirtualWindow, HuePicker);
if (rc < 0) {
sysfatal("resizeimage: %r");
}
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");
inithuepicker();
initgradient();
setgradienthue();
einit(Emouse | Ekeyboard);
initcanvas();
for (;RunApp;) {
switch(event(&e)) {
case Ekeyboard:
if (e.kbdc == 'q') {
RunApp = 0;
}
break;
}
}
}