shithub: blie

Download patch

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;
+}