ref: 26a582e3bf1c9facd5291be6f25eff320dda5472
parent: 1077381027fbb3b04aff7b5310f2fb744a8bf1fe
author: sirjofri <sirjofri@sirjofri.de>
date: Fri Aug 9 12:03:27 EDT 2024
adds first drawing functionality
--- a/blie.c
+++ b/blie.c
@@ -120,6 +120,7 @@
c = ed->composite ? ed->composite : ecomposite;
+ // BUG: doesn't recomposite if previous layer changed!
if (!l->composited)
l->composited = c(l, img[i]);
img[id%2] = l->composited;
--- a/blie.h
+++ b/blie.h
@@ -86,6 +86,8 @@
*/
Memimage* ecomposite(Layer*, Memimage*);
+Point scalepos(Point);
+
Memimage* gencomposite(Memimage*, Memimage*, Memimage*, Drawop);
Memimage* gencanvas(Memimage*);
Memimage* dupmemimage(Memimage*);
--- a/p9image.c
+++ b/p9image.c
@@ -31,24 +31,86 @@
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;
+
if (headless)
return;
- if (!tstate.circle) {
- 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);
- }
+ 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
@@ -189,13 +251,56 @@
}
static Redrawwin
-p9drawinput(Layer *l, int e, Event)
+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;
+
+ xy = scalepos(xy);
+ 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;
@@ -214,12 +319,15 @@
switch (ev.mouse.xy.x / 50) {
case 0:
tstate.mode = Composite;
+ tstate.drawtarget = DTimg;
break;
case 1:
tstate.mode = Img;
+ tstate.drawtarget = DTimg;
break;
case 2:
tstate.mode = Mask;
+ tstate.drawtarget = DTmask;
break;
default:
return Rnil;
--- a/sample.c
+++ b/sample.c
@@ -53,6 +53,9 @@
Memimage *tm;
Dir *dir;
+ if (nx == Dx(src->r) && ny == Dy(src->r))
+ return nil;
+
snprint(x, sizeof(x), "%d", nx);
snprint(y, sizeof(y), "%d", ny);
@@ -125,6 +128,9 @@
if (!vstate.dirty)
return;
+ if (!src)
+ return;
+
r.min = ZP;
r.max = Pt(Dx(img->r), Dy(img->r));
@@ -134,13 +140,13 @@
}
if (!lastsampled) {
lastsampled = resample(src, Dx(src->r)*vstate.zoom, Dy(src->r)*vstate.zoom);
- if (!lastsampled)
- return;
+ if (lastsampled)
+ src = lastsampled;
}
tmi = allocmemimage(r, img->chan);
memfillcolor(tmi, DBlack);
- memimagedraw(tmi, tmi->r, lastsampled, addpt(tmi->r.min, vstate.offset), nil, ZP, S);
+ memimagedraw(tmi, tmi->r, src, addpt(tmi->r.min, vstate.offset), nil, ZP, S);
nw = tmi->width * tmi->r.max.y * sizeof(ulong); // tmi->r.max.y == Dy(tmi->r)
draw(img, img->r, display->black, nil, ZP);
--- a/util.c
+++ b/util.c
@@ -49,3 +49,12 @@
fprint(2, " c: combine images\n");
return gencomposite(img, s, m, l->op);
}
+
+Point
+scalepos(Point xy)
+{
+ xy = subpt(xy, vstate.offset);
+ xy.x = xy.x / vstate.zoom;
+ xy.y = xy.y / vstate.zoom;
+ return xy;
+}