ref: 3b862725591bc312572a3e35aab3007712c8b9bf
dir: /p9image.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <event.h>
#include <cursor.h>
#include "blie.h"
Cursor ccircle = {
{-7, -7},
{0xFF, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07,
0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07,
0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07,
0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xFF, 0xFF},
{0x00, 0x00, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02,
0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x00, 0x00}
};
Point toolcell;
typedef struct Data Data;
struct Data {
Memimage *img;
Memimage *mask;
Drawop op;
};
typedef enum {
Composite,
Img,
Mask,
} Mode;
enum {
DTimg = 0,
DTmask,
};
typedef struct Tstate Tstate;
struct Tstate {
Mode mode;
int drawtarget;
Image *circle;
Memimage *circlebrush;
Memimage *colorbrush;
int brushrad;
};
Tstate tstate;
static double
distance(Point p, Point q)
{
double n;
p = subpt(q, p);
p.x *= p.x;
p.y *= p.y;
n = sqrt((double)p.x + (double)p.y);
return n;
}
static int
isaturate(int a)
{
return a < 0 ? 0 : (a > 255 ? 255 : a);
}
static void
setcirclebrush(int r, double exp)
{
int x, y, d, n;
double dist;
d = r*2 + 1;
if (tstate.circlebrush)
freememimage(tstate.circlebrush);
tstate.brushrad = r;
tstate.circlebrush = allocmemimage(Rect(0, 0, d, d), GREY8);
tstate.circlebrush->flags |= Fbytes|Falpha;
for (y = 0; y < d; y++)
for (x = 0; x < d; x++) {
dist = distance(Pt(x, y), Pt(r, r))/r;
dist = pow(1. - dist, exp);
n = (int)(dist * 256.);
*byteaddr(tstate.circlebrush, Pt(x, y)) = isaturate(n);
}
}
static void
setcolorbrush(ulong color)
{
if (tstate.colorbrush)
freememimage(tstate.colorbrush);
tstate.colorbrush = allocmemimage(Rect(0, 0, 1, 1), RGB24);
tstate.colorbrush->flags |= Frepl|Fsimple|Fbytes;
memfillcolor(tstate.colorbrush, color);
}
static void
p9initialize()
{
tstate.mode = Composite;
tstate.drawtarget = DTimg;
toolcell = Pt(15, vdata.fontheight + 4);
if (headless)
return;
tstate.circle = allocimage(display, Rect(0, 0, 41, 41), RGBA32, 0, DTransparent);
ellipse(tstate.circle, Pt(20, 20), 19, 19, 0, display->white, ZP);
ellipse(tstate.circle, Pt(20, 20), 20, 20, 0, display->black, ZP);
setcirclebrush(20, 1.);
setcolorbrush(DRed);
}
static void
p9init(Layer *l)
{
int fd;
char *s;
Data *d;
if (l->data)
return;
d = mallocz(sizeof(Data), 1);
l->data = d;
/* image file */
s = smprint("%s/img", l->name);
fd = open(s, OREAD);
if (fd < 0) {
free(s);
return;
}
free(s);
seek(fd, 0, 0);
d->img = creadmemimage(fd);
if (!d->img) {
seek(fd, 0, 0);
d->img = readmemimage(fd);
}
close(fd);
/* mask file */
s = smprint("%s/mask", l->name);
fd = open(s, OREAD);
if (fd < 0) {
free(s);
return;
}
free(s);
seek(fd, 0, 0);
d->mask = creadmemimage(fd);
if (!d->mask) {
seek(fd, 0, 0);
d->mask = readmemimage(fd);
}
close(fd);
}
/* just use ecompose, which uses raw() and mask() */
static Memimage*
p9composite(Layer *l, Memimage *img)
{
Data *d;
p9init(l);
d = (Data*)l->data;
if (!img) {
fprint(2, "%s: return input image: %p\n", l->name, d->img);
return dupmemimage(d->img);
}
fprint(2, "%s: return composite image: %p %p %p\n", l->name,
img, d->img, d->mask);
return gencomposite(img, d->img, d->mask, l->op);
}
static Memimage*
p9raw(Layer *l)
{
Data *d;
p9init(l);
d = (Data*)l->data;
return d->img;
}
static Memimage*
p9mask(Layer *l)
{
Data *d;
p9init(l);
d = (Data*)l->data;
return d->mask;
}
static int
p9overlay(Layer *l, Image *i)
{
Data *data;
Memimage *mi;
p9init(l);
data = (Data*)l->data;
if (!i)
return tstate.mode != Composite;
switch (tstate.mode) {
case Composite:
break;
case Img:
mi = data->img;
goto Mout;
case Mask:
mi = data->mask;
goto Mout;
}
changecursor(nil, nil, ZP);
return 0;
Mout:
changecursor(&ccircle, tstate.circle, Pt(-20, -20));
if (!mi)
return 0;
setdrawingdirty(Dcontent);
sampleview(i, mi, 0);
return 0;
}
static Rectangle
p9toolrect(Layer *l)
{
return Rect(0, 0, 200, 50);
}
static void
drcells(Image *i, Point p, char *s, int hl)
{
Rectangle r;
r.min = p;
r.max = addpt(p, toolcell);
border(i, r, 1, vdata.gray, ZP);
if (hl) {
r = insetrect(r, 2);
draw(i, r, vdata.gray, nil, ZP);
}
string(i, addpt(p, Pt(2, 2)), display->black, ZP, font, s);
}
static void
p9drawtools(Layer *l, Image *i)
{
Point p;
p = i->r.min;
draw(i, i->r, display->white, nil, ZP);
drcells(i, p, "C", tstate.mode == Composite);
p.x += toolcell.x;
drcells(i, p, "S", tstate.mode == Img);
p.x += toolcell.x;
drcells(i, p, "M", tstate.mode == Mask);
}
static int
p9savedata(Layer *l)
{
p9init(l);
return 1;
}
static Redrawwin
drawbrush(Layer *l, int buttons, Point xy)
{
Memimage *tgt;
Data *d;
Rectangle r;
p9init(l);
d = (Data*)l->data;
if (!buttons)
return Rnil;
tgt = nil;
if (tstate.drawtarget == DTimg)
tgt = d->img;
else if (tstate.drawtarget == DTmask)
tgt = d->mask;
if (!tgt)
return Rnil;
r = insetrect(tgt->r, -tstate.brushrad);
if (!ptinrect(xy, r))
return Rnil;
r = rectaddpt(tstate.circlebrush->r,
subpt(
addpt(tgt->r.min, xy),
Pt(tstate.brushrad, tstate.brushrad)
)
);
tstate.colorbrush->clipr = tstate.circlebrush->r;
memimagedraw(tgt, r, tstate.colorbrush, ZP, tstate.circlebrush, ZP, SoverD);
setdrawingdirty(Dcontent);
dirtylayer(l);
return Rdrawing;
}
static Redrawwin
p9drawinput(Layer *l, int e, Event ev)
{
p9init(l);
switch (e) {
case Ekeyboard:
break;
case Emouse:
return drawbrush(l, ev.mouse.buttons, ev.mouse.xy);
break;
}
return Rnil;
}
static Redrawwin
p9toolinput(Layer *l, int e, Event ev)
{
p9init(l);
if (e != Emouse)
return Rnil;
if (!ev.mouse.buttons)
return Rnil;
if (ev.mouse.xy.y / toolcell.y == 0) {
switch (ev.mouse.xy.x / toolcell.x) {
case 0:
tstate.mode = Composite;
tstate.drawtarget = DTimg;
goto Out;
case 1:
tstate.mode = Img;
tstate.drawtarget = DTimg;
goto Out;
case 2:
tstate.mode = Mask;
tstate.drawtarget = DTmask;
goto Out;
}
}
return Rnil;
Out:
setdrawingdirty(Dcontent);
return Rdrawing|Rtools;
}
Editor p9image = {
.name = "p9img",
.init = p9initialize,
.raw = p9raw,
.mask = p9mask,
.overlay = p9overlay,
.toolrect = p9toolrect,
.drawtools = p9drawtools,
.savedata = p9savedata,
.drawinput = p9drawinput,
.toolinput = p9toolinput,
};