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