git: 9front

Download patch

ref: e532d0990b63181f0feb569ef782702191db1ea4
parent: a580fff1d14d1dc9e6ca8dccf564fd9ae90cde08
author: rodri <rgl@antares-labs.eu>
date: Sat Dec 27 03:16:06 EST 2025

libmemlayer: implement memlaffinewarp()

--- a/sys/include/memdraw.h
+++ b/sys/include/memdraw.h
@@ -151,6 +151,7 @@
 extern Rectangle	memlinebbox(Point, Point, int, int, int);
 extern int	memlineendsize(int);
 extern void	memaffinewarp(Memimage*, Rectangle, Memimage*, Point, Warp, int);
+extern void	memlaffinewarp(Memimage*, Rectangle, Memimage*, Point, Warp, int);
 extern Memimage*	allocmemimagekernel(double*, int, int, double);
 extern int	memimagecorrelate(Memimage*, Rectangle, Memimage*, Point, Memimage*);
 extern void	_memmkcmap(void);
--- a/sys/man/2/memlayer
+++ b/sys/man/2/memlayer
@@ -81,8 +81,8 @@
 void	memdraw(Memimage *dst, Rectangle r,
 .br
 .B
-		   Memimage *src, Point sp, Memimage *mask, Point mp, Drawop op)
-.fi
+		Memimage *src, Point sp, Memimage *mask, Point mp, Drawop op)
+.PP
 .B
 int	memload(Memimage *i, Rectangle r,
 .br
@@ -95,6 +95,11 @@
 .B
 		uchar *buf, int n)
 .PP
+.B
+void	memlaffinewarp(Memimage *dst, Rectangle r,
+.br
+.B
+		Memimage *src, Point sp, Warp w, int smooth)
 .SH DESCRIPTION
 These functions build upon the
 .IR memdraw (2)
@@ -260,15 +265,17 @@
 .EE
 would be a no-op.
 .PP
-.I Memdraw
-and
+.IR Memdraw ,
 .I memline
+and
+.I memlaffinewarp
 are implemented in the layer library but provide the main entry points for drawing on
 memory-resident windows.
 They have the signatures of
-.I memimagedraw
-and
+.IR memimagedraw ,
 .I memimageline
+and
+.I memaffinewarp
 (see
 .IR memdraw (2))
 but accept
--- a/sys/src/libmemlayer/mkfile
+++ b/sys/src/libmemlayer/mkfile
@@ -4,6 +4,7 @@
 
 OFILES=\
 	draw.$O\
+	warp.$O\
 	lalloc.$O\
 	layerop.$O\
 	ldelete.$O\
--- /dev/null
+++ b/sys/src/libmemlayer/warp.c
@@ -1,0 +1,159 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <memlayer.h>
+
+struct Draw
+{
+	Memlayer	*dstlayer;
+	Memimage	*src;
+	Point		sp;
+	Warp		warp;
+	int		smooth;
+};
+
+static
+void
+ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+	struct Draw *d;
+	Rectangle r;
+
+	d = etc;
+	if(insave && d->dstlayer->save == nil)
+		return;
+
+	if(insave){
+		r = rectsubpt(screenr, d->dstlayer->delta);
+		clipr = rectsubpt(clipr, d->dstlayer->delta);
+	}else
+		r = screenr;
+
+	/* now in logical coordinates */
+
+	/* clipr may have narrowed what we should draw on, so clip if necessary */
+	if(!rectinrect(r, clipr) && rectclip(&r, clipr) == 0)
+		return;
+	memlaffinewarp(dst, r, d->src, d->sp, d->warp, d->smooth);
+}
+
+void
+memlaffinewarp(Memimage *dst, Rectangle r, Memimage *src, Point p0, Warp w, int smooth)
+{
+	struct Draw d;
+	Rectangle srcr, tr;
+	Memlayer *dl, *sl;
+
+    Top:
+	if(dst->layer == nil && src->layer == nil){
+		memaffinewarp(dst, r, src, p0, w, smooth);
+		return;
+	}
+
+	/*
+ 	 * Convert to screen coordinates.
+	 */
+	dl = dst->layer;
+	if(dl != nil){
+		r.min.x += dl->delta.x;
+		r.min.y += dl->delta.y;
+		r.max.x += dl->delta.x;
+		r.max.y += dl->delta.y;
+    Clearlayer:
+		if(dl->clear){
+			if(src == dst){
+				p0.x += dl->delta.x;
+				p0.y += dl->delta.y;
+				src = dl->screen->image;
+			}
+			dst = dl->screen->image;
+			goto Top;
+		}
+	}
+
+	sl = src->layer;
+	if(sl != nil){
+		p0.x += sl->delta.x;
+		p0.y += sl->delta.y;
+		srcr.min.x += sl->delta.x;
+		srcr.min.y += sl->delta.y;
+		srcr.max.x += sl->delta.x;
+		srcr.max.y += sl->delta.y;
+	}
+
+	/*
+	 * Now everything is in screen coordinates.
+	 * mask is an image.  dst and src are images or obscured layers.
+	 */
+
+	/*
+	 * if dst and src are the same layer, just draw in save area and expose.
+	 */
+	if(dl != nil && dst == src){
+		if(dl->save == nil)
+			return;	/* refresh function makes this case unworkable */
+		if(rectXrect(r, srcr)){
+			tr = r;
+			if(srcr.min.x < tr.min.x)
+				tr.min.x = srcr.min.x;
+			if(srcr.min.y < tr.min.y)
+				tr.min.y = srcr.min.y;
+			if(srcr.max.x > tr.max.x)
+				tr.max.x = srcr.max.x;
+			if(srcr.max.y > tr.max.y)
+				tr.max.y = srcr.max.y;
+			memlhide(dst, tr);
+		}else{
+			memlhide(dst, r);
+			memlhide(dst, srcr);
+		}
+		memlaffinewarp(dl->save, rectsubpt(r, dl->delta), dl->save,
+			subpt(srcr.min, src->layer->delta), w, smooth);
+		memlexpose(dst, r);
+		return;
+	}
+
+	if(sl != nil){
+		if(sl->clear){
+			src = sl->screen->image;
+			if(dl != nil){
+				r.min.x -= dl->delta.x;
+				r.min.y -= dl->delta.y;
+				r.max.x -= dl->delta.x;
+				r.max.y -= dl->delta.y;
+			}
+			goto Top;
+		}
+		/* relatively rare case; use save area */
+		if(sl->save == nil)
+			return;	/* refresh function makes this case unworkable */
+		memlhide(src, srcr);
+		/* convert back to logical coordinates */
+		p0.x -= sl->delta.x;
+		p0.y -= sl->delta.y;
+		srcr.min.x -= sl->delta.x;
+		srcr.min.y -= sl->delta.y;
+		srcr.max.x -= sl->delta.x;
+		srcr.max.y -= sl->delta.y;
+		src = src->layer->save;
+	}
+
+	/*
+	 * src is now an image.  dst may be an image or a clear layer
+	 */
+	if(dst->layer == nil)
+		goto Top;
+	if(dst->layer->clear)
+		goto Clearlayer;
+
+	/*
+	 * dst is an obscured layer
+	 */
+	d.dstlayer = dl;
+	d.src = src;
+	d.sp = p0;
+	memmove(d.warp, w, sizeof(Warp));
+	d.smooth = smooth;
+	_memlayerop(ldrawop, dst, r, r, &d);
+}
--