shithub: blie

Download patch

ref: da5ef81858616aa4cd9bd350b2de30a8553330a3
parent: a376bcda599c8533bce9ed6128a0d42eaea18ba4
author: sirjofri <[email protected]>
date: Thu Aug 8 11:56:28 EDT 2024

adds zoom support, images should be r8g8b8(a8), masks can be k8 or r8g8b8

--- a/blie.c
+++ b/blie.c
@@ -22,8 +22,14 @@
 Vdata vdata = {
 	.layerwinwidth = 150,
 	.keyoffset = 10,
+	.keyzoom = 0.2,
 };
 
+Vstate vstate = {
+	.zoom = 1.0,
+	.offset = { 0, 0 },
+};
+
 static void
 initvdata(void)
 {
@@ -44,7 +50,6 @@
 
 typedef struct Dstate Dstate;
 struct Dstate {
-	Point offset;
 	Cursor *cursor;
 	Image *cursimg;
 	Image *cursorblit;
@@ -131,28 +136,18 @@
 redrawdrawing(void)
 {
 	Memimage *img[2]; /* swapchain */
-	Memimage *ti; /* intermediate image */
 	int i;
-	int nw;
 	
 	img[0] = nil;
 	img[1] = nil;
 	i = (foreachlayer(docomp, img) + 1) % 2;
+
+	sampleview(panels.drawing, img[i]);
 	
-	ti = allocmemimage(panels.drawing->r, panels.drawing->chan);
-	memfillcolor(ti, DBlack);
-	memimagedraw(ti, ti->r, img[i], dstate.offset, nil, ZP, S);
-	
-	nw = ti->width * Dy(ti->r) * sizeof(ulong);
-	draw(panels.drawing, panels.drawing->r, display->black, nil, ZP);
-	loadimage(panels.drawing, panels.drawing->r, ti->data->bdata, nw);
-	
-	freememimage(ti);
-	
 	if (!(estate.ed && estate.ed->overlay))
 		return;
 	
-	estate.ed->overlay(estate.l, panels.drawing, dstate.offset);
+	estate.ed->overlay(estate.l, panels.drawing);
 }
 
 static void
@@ -320,16 +315,22 @@
 {
 	switch (kbdc) {
 	case Kup:
-		dstate.offset.y += vdata.keyoffset;
+		vstate.offset.y += vdata.keyoffset;
 		goto Redraw;
 	case Kdown:
-		dstate.offset.y -= vdata.keyoffset;
+		vstate.offset.y -= vdata.keyoffset;
 		goto Redraw;
 	case Kleft:
-		dstate.offset.x += vdata.keyoffset;
+		vstate.offset.x += vdata.keyoffset;
 		goto Redraw;
 	case Kright:
-		dstate.offset.x -= vdata.keyoffset;
+		vstate.offset.x -= vdata.keyoffset;
+		goto Redraw;
+	case '.':
+		vstate.zoom += vdata.keyzoom;
+		goto Redraw;
+	case ',':
+		vstate.zoom -= vdata.keyzoom;
 		goto Redraw;
 	}
 	return 0;
--- a/blie.h
+++ b/blie.h
@@ -1,8 +1,10 @@
 typedef struct Layer Layer;
 typedef struct Editor Editor;
 typedef struct Vdata Vdata;
+typedef struct Vstate Vstate;
 
 extern Vdata vdata;
+extern Vstate vstate;
 extern int bliedebug;
 
 struct Layer {
@@ -28,15 +30,24 @@
 	int layerwinwidth; /* width of layers window */
 	int fontheight; /* height of font */
 	int keyoffset; /* offset on key input */
+	float keyzoom; /* zoom change */
 	Image *gray;
 };
 
+struct Vstate {	
+	Point offset;
+	float zoom;
+};
+
+/* writes memimage to drawing image, considering pan and zoom */
+void sampleview(Image*, Memimage*);
+
 struct Editor {
 	char *name;
 	Memimage *(*composite)(Layer*, Memimage*);
 	Memimage *(*raw)(Layer*);
 	Memimage *(*mask)(Layer*);
-	void (*overlay)(Layer*, Image*, Point);
+	void (*overlay)(Layer*, Image*);
 	Rectangle (*toolrect)(Layer*);
 	void (*drawtools)(Layer*, Image*);
 	int (*drawinput)(Layer*, int, Event);
@@ -50,7 +61,11 @@
 int addeditor(Editor*);
 Editor *geteditor(char*);
 
+/* generic composite of layer (using raw) and the composited image
+ * from the previous layer
+ */
 Memimage* ecomposite(Layer*, Memimage*);
+
 Memimage* gencomposite(Memimage*, Memimage*, Memimage*, Drawop);
 Memimage* gencanvas(Memimage*);
 Memimage* dupmemimage(Memimage*);
--- a/mkfile
+++ b/mkfile
@@ -6,6 +6,7 @@
 	blie.$O\
 	editor.$O\
 	layer.$O\
+	sample.$O\
 	util.$O\
 	p9image.$O\
 
--- a/p9image.c
+++ b/p9image.c
@@ -123,13 +123,10 @@
 }
 
 static void
-p9overlay(Layer *l, Image *i, Point offset)
+p9overlay(Layer *l, Image *i)
 {
 	Data *data;
-	Memimage *mi, *tmi;
-	Image *tii;
-	int nw;
-	Rectangle r;
+	Memimage *mi;
 	
 	p9init(l);
 	data = (Data*)l->data;
@@ -155,20 +152,8 @@
 	changecursor(&ccircle, tstate.circle, Pt(-20, -20));
 	if (!mi)
 		return;
-	r.min.x = r.min.y = 0;
-	r.max.x = Dx(i->r);
-	r.max.y = Dy(i->r);
-	tmi = allocmemimage(r, i->chan);
-	memfillcolor(tmi, DBlack);
-	memimagedraw(tmi, rectsubpt(mi->r, offset), mi, ZP, nil, ZP, SoverD);
 	
-	tii = allocimage(display, r, i->chan, 0, DTransparent);
-	nw = tmi->width * Dy(tmi->r) * sizeof(ulong);
-	loadimage(tii, tii->r, tmi->data->bdata, nw);
-	draw(i, i->r, tii, nil, ZP);
-	
-	freeimage(tii);
-	freememimage(tmi);
+	sampleview(i, mi);
 }
 
 static Rectangle
@@ -180,7 +165,6 @@
 static void
 p9drawtools(Layer *l, Image *i)
 {
-	
 	draw(i, insetrect(i->r, 5), display->white, nil, ZP);
 }
 
--- /dev/null
+++ b/sample.c
@@ -1,0 +1,137 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <event.h>
+#include "blie.h"
+
+/* direct copy from /sys/src/cmd/iconv.c:/^writeuncompressed */
+static void
+writeuncompressed(int fd, Memimage *m)
+{
+	char chanstr[32];
+	int bpl, y, j;
+	uchar *buf;
+
+	if(chantostr(chanstr, m->chan) == nil)
+		sysfatal("can't convert channel descriptor: %r");
+	fprint(fd, "%11s %11d %11d %11d %11d ",
+		chanstr, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y);
+
+	bpl = bytesperline(m->r, m->depth);
+	buf = malloc(bpl);
+	if(buf == nil)
+		sysfatal("malloc failed: %r");
+	for(y=m->r.min.y; y<m->r.max.y; y++){
+		j = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), buf, bpl);
+		if(j != bpl)
+			sysfatal("image unload failed: %r");
+		if(write(fd, buf, bpl) != bpl)
+			sysfatal("write failed: %r");
+	}
+	free(buf);
+}
+
+/*
+ * uses external program for resampling in a pipe.
+ * I can see several improvements for performance:
+ *
+ * 1. only scaling what's needed, which means calculating
+ *    the rectangle we want, extracting that to a
+ *    separate image for resampling.
+ * 2. integrate resample functionality in this program
+ * 3. only resample if zoom level or data changes.
+ *    at the moment, it resamples when panning.
+ */
+static Memimage*
+resample(Memimage *src, int nx, int ny)
+{
+	int pin[2];
+	int pout[2];
+	int re, ro;
+	char x[11], y[11];
+	Memimage *tm;
+	Dir *dir;
+	
+	snprint(x, sizeof(x), "%d", nx);
+	snprint(y, sizeof(y), "%d", ny);
+	
+	if (pipe(pout) < 0) {
+		close(pout[0]);
+		close(pout[1]);
+		goto Err;
+	}
+	if (pipe(pin) < 0) {
+		close(pout[0]);
+		close(pout[1]);
+		close(pin[0]);
+		close(pin[1]);
+		goto Err;
+	}
+	
+	dir = dirfstat(pin[0]);
+	if (!dir) {
+		free(dir);
+		goto Err;
+	}
+	dir->length = src->width * Dy(src->r) * sizeof(ulong) + 12 * 5;
+	if (!dirfwstat(pin[0], dir)) {
+		free(dir);
+		goto Err;
+	}
+	free(dir);
+	
+	switch (fork()) {
+	case -1: /* error */
+		goto Err;
+	case 0: /* child */
+		dup(pin[1], 0);
+		dup(pout[1], 1);
+		close(pin[0]);
+		close(pout[0]);
+		execl("/bin/resample", "resample", "-x", x, "-y", y, nil);
+		sysfatal("cannot exec: %r");
+	default: /* parent */
+		close(pout[1]);
+		close(pin[1]);
+		re = pout[0];
+		ro = pin[0];
+	}
+	
+	writeuncompressed(ro, src);
+	tm = readmemimage(re);
+	if (!tm)
+		goto Err;
+	close(re);
+	return tm;
+Err:
+	fprint(2, "resample: %r\n");
+	return nil;
+}
+
+void
+sampleview(Image *img, Memimage *src)
+{
+	Memimage *tmi;
+	Memimage *tsi;
+	Rectangle r;
+	int nw;
+	
+	r.min = ZP;
+	r.max = Pt(Dx(img->r), Dy(img->r));
+	
+	tsi = resample(src, Dx(src->r)*vstate.zoom, Dy(src->r)*vstate.zoom);
+	if (!tsi)
+		return;
+	
+	tmi = allocmemimage(r, img->chan);
+	memfillcolor(tmi, DBlack);
+	memimagedraw(tmi, tmi->r, tsi, 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);
+	loadimage(img, img->r, tmi->data->bdata, nw);
+	
+	freememimage(tsi);
+	freememimage(tmi);
+}
binary files a/test/img/layerA/img b/test/img/layerA/img differ
binary files a/test/img/layerA/mask b/test/img/layerA/mask differ
binary files a/test/img/layerB/img b/test/img/layerB/img differ
binary files a/test/img/layerB/mask b/test/img/layerB/mask differ
--- a/words
+++ b/words
@@ -75,6 +75,7 @@
 Drawing controls:
 
 - Up, Left, Down, Right: pan image
+- , and .: zoom image
 
 Layer controls: