ref: ebc86924d2378b500c47ae1b16664fbc3cbcabe7
parent: 2a33256a51e43b0571cfbbe1ad0259e3a30faee8
author: rodri <rgl@antares-labs.eu>
date: Sun Sep 7 23:19:14 EDT 2025
libdraw, libmemdraw: implement affinewarp(2) and move mkwarp(2) from memdraw to draw
--- a/sys/include/ape/draw.h
+++ b/sys/include/ape/draw.h
@@ -24,6 +24,7 @@
typedef struct RGB RGB;
typedef struct Screen Screen;
typedef struct Subfont Subfont;
+typedef long Warp[3][3];
#pragma varargck type "R" Rectangle
#pragma varargck type "P" Point
@@ -461,6 +462,8 @@
extern void fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
extern void border(Image*, Rectangle, int, Image*, Point);
extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
+extern void mkwarp(Warp, double[3][3]);
+extern void affinewarp(Image*, Rectangle, Image*, Point, Warp, int);
/*
* Font management
--- a/sys/include/draw.h
+++ b/sys/include/draw.h
@@ -14,6 +14,7 @@
typedef struct RGB RGB;
typedef struct Screen Screen;
typedef struct Subfont Subfont;
+typedef long Warp[3][3];
#pragma incomplete Mouse
@@ -455,6 +456,8 @@
extern void fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
extern void border(Image*, Rectangle, int, Image*, Point);
extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
+extern void mkwarp(Warp, double[3][3]);
+extern void affinewarp(Image*, Rectangle, Image*, Point, Warp, int);
/*
* Font management
--- a/sys/include/memdraw.h
+++ b/sys/include/memdraw.h
@@ -7,7 +7,6 @@
typedef struct Memlayer Memlayer;
typedef struct Memcmap Memcmap;
typedef struct Memdrawparam Memdrawparam;
-typedef long Warp[3][3];
#pragma incomplete Memlayer
@@ -152,7 +151,6 @@
extern Rectangle memlinebbox(Point, Point, int, int, int);
extern int memlineendsize(int);
extern int memaffinewarp(Memimage*, Rectangle, Memimage*, Point, Warp, int);
-extern void mkwarp(Warp, double[3][3]);
extern Memimage* allocmemimagekernel(double*, int, int, double);
extern int memimagecorrelate(Memimage*, Rectangle, Memimage*, Point, Memimage*);
extern void _memmkcmap(void);
--- a/sys/man/2/draw
+++ b/sys/man/2/draw
@@ -1,10 +1,11 @@
.TH DRAW 2
.SH NAME
-Image, draw, gendraw, drawreplxy, drawrepl,
-replclipr, line, poly, fillpoly, bezier, bezspline, fillbezier, fillbezspline, ellipse,
-fillellipse, arc, fillarc, icossin, icossin2, border, string, stringn,
-runestring, runestringn, stringbg, stringnbg, runestringbg,
-runestringnbg, _string, ARROW, drawsetdebug \- graphics functions
+Image, draw, gendraw, drawreplxy, drawrepl, replclipr, line, poly,
+fillpoly, bezier, bezspline, fillbezier, fillbezspline, ellipse,
+fillellipse, arc, fillarc, icossin, icossin2, border, mkwarp,
+affinewarp, string, stringn, runestring, runestringn, stringbg,
+stringnbg, runestringbg, runestringnbg, _string, ARROW, drawsetdebug
+\- graphics functions
.de PB
.PP
.ft L
@@ -58,6 +59,8 @@
Ncomp = 12,
} Drawop;
.PB
+typedef long Warp[3][3];
+.PB
.PD 0
.ta +\w'\fL 'u +\w'\fL 'u +6n +4n
void draw(Image *dst, Rectangle r, Image *src,
@@ -157,6 +160,11 @@
.PB
void borderop(Image *dst, Rectangle r, int i, Image *color, Point sp,
Drawop op)
+.PB
+void mkwarp(Warp w, double m[3][3])
+.PB
+void affinewarp(Image *dst, Rectangle r, Image *src, Point p, Warp w,
+ int smooth)
.br
.PB
Point string(Image *dst, Point p, Image *src, Point sp,
@@ -735,6 +743,41 @@
.I sp
corresponds to
.IB r .min .
+.TP
+.BI mkwarp( w\fP,\fP\ m\fP)
+.I Mkwarp
+converts a 3×3 row-major matrix of
+.BR double s
+(usually a
+.IR geometry (2)
+.BR Matrix )
+into the fixed-point representation required by
+.I affinewarp
+in
+.BR w ,
+ignoring the last row which is always set to
+.B "[0 0 1]"
+for affine transformations.
+.TP
+.BI affinewarp( dst\fP,\fP\ r\fP,\fP\ src\fP,\fP\ p\fP,\fP\ w\fP,\fP\ smooth\fP)
+.I Affinewarp
+applies an affine transformation defined by
+.B w
+to the
+.BR src ,
+and stores the result in the
+.BR dst .
+It follows the behavior of
+.I draw
+regarding the use of
+.B clipr
+and the
+.B repl
+bit, but applied to the affine mappings.
+If
+.B smooth
+is set, each sample will be interpolated for better quality, which
+will make the transformation slower.
.TP
.BI string( dst\fP,\fP\ p\fP,\fP\ src\fP,\fP\ sp\fP,\fP\ font\fP,\fP\ s )
.I String
--- a/sys/man/2/memdraw
+++ b/sys/man/2/memdraw
@@ -25,7 +25,6 @@
memimageline,
memimagedraw,
memaffinewarp,
-mkwarp,
allocmemimagekernel,
memimagecorrelate,
drawclip,
@@ -92,8 +91,6 @@
\fI...\fP
} Memdrawparam;
-typedef long Warp[3][3];
-
.ta \w'\fLMemsubfont* 'u
int drawdebug;
.ft
@@ -141,7 +138,6 @@
Point sp, Memimage *mask, Point mp, Drawop op)
int memaffinewarp(Memimage *dst, Rectangle r, Memimage *src,
Point sp, Warp w, int smooth)
-void mkwarp(Warp w, double m[3][3])
Memimage* allocmemimagekernel(double *k, int dx, int dy,
double denom)
int memimagecorrelate(Memimage *dst, Rectangle r, Memimage *src,
@@ -347,6 +343,7 @@
.IR memellipse ,
.IR memfillpoly ,
.IR memimageline ,
+.IR memaffinewarp ,
and
.I memimagedraw
are identical to the
@@ -355,6 +352,7 @@
.IR ellipse ,
.IR fillpoly ,
.IR line ,
+.IR affinewarp ,
and
.IR gendraw ,
routines described in
@@ -390,39 +388,6 @@
.BR Memsubfont s
rather than
.BR Font s.
-.PP
-.I Memaffinewarp
-applies an affine transformation defined by
-.B w
-to the
-.BR src ,
-and stores the result in the
-.BR dst .
-It follows the behavior of
-.IR draw (2)
-regarding the use of
-.B clipr
-and the
-.B repl
-bit, but applied to the affine mappings.
-If
-.B smooth
-is set, each sample will be interpolated for better quality, which
-will make the transformation slower.
-.PP
-.I Mkwarp
-converts a 3×3 row-major matrix of
-.BR double s
-(usually a
-.IR geometry (2)
-.BR Matrix )
-into the fixed-point representation required by
-.I memaffinewarp
-in
-.BR w ,
-ignoring the last row which is always set to
-.B "[0 0 1]"
-for affine transformations.
.PP
.I Allocmemimagekernel
takes
--- a/sys/src/libdraw/mkfile
+++ b/sys/src/libdraw/mkfile
@@ -62,6 +62,8 @@
writecolmap.$O\
writeimage.$O\
writesubfont.$O\
+ warp.$O\
+ mkwarp.$O\
HFILES=\
/sys/include/draw.h\
--- /dev/null
+++ b/sys/src/libdraw/mkwarp.c
@@ -1,0 +1,21 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <geometry.h>
+
+/* 25.7 fixed-point number operations */
+
+#define flt2fix(n) ((long)((n)*(1<<7) + ((n) < 0? -0.5: 0.5)))
+
+void
+mkwarp(Warp w, double m0[3][3])
+{+ Matrix m;
+
+ memmove(m, m0, sizeof(Matrix));
+ invm(m);
+
+ w[0][0] = flt2fix(m[0][0]); w[0][1] = flt2fix(m[0][1]); w[0][2] = flt2fix(m[0][2]);
+ w[1][0] = flt2fix(m[1][0]); w[1][1] = flt2fix(m[1][1]); w[1][2] = flt2fix(m[1][2]);
+ w[2][0] = 0; w[2][1] = 0; w[2][2] = 1<<7;
+}
--- /dev/null
+++ b/sys/src/libdraw/warp.c
@@ -1,0 +1,41 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+static void
+putwarp(uchar *a, Warp w)
+{+ BPLONG(a+0*3*4+0*4, w[0][0]); BPLONG(a+0*3*4+1*4, w[0][1]); BPLONG(a+0*3*4+2*4, w[0][2]);
+ BPLONG(a+1*3*4+0*4, w[1][0]); BPLONG(a+1*3*4+1*4, w[1][1]); BPLONG(a+1*3*4+2*4, w[1][2]);
+ BPLONG(a+2*3*4+0*4, w[2][0]); BPLONG(a+2*3*4+1*4, w[2][1]); BPLONG(a+2*3*4+2*4, w[2][2]);
+}
+
+void
+affinewarp(Image *dst, Rectangle r, Image *src, Point p, Warp w, int smooth)
+{+ uchar *a;
+
+ if(dst == nil || src == nil)
+ return;
+
+ _setdrawop(dst->display, S);
+
+ _lockdisplay(dst->display);
+ a = bufimage(dst->display, 1+4+4*4+4+2*4+3*3*4+1);
+ if(a == nil){+ _unlockdisplay(dst->display);
+ return;
+ }
+ a[0] = 'a';
+ BPLONG(a+1, dst->id);
+ BPLONG(a+5, r.min.x);
+ BPLONG(a+9, r.min.y);
+ BPLONG(a+13, r.max.x);
+ BPLONG(a+17, r.max.y);
+ BPLONG(a+21, src->id);
+ BPLONG(a+25, p.x);
+ BPLONG(a+29, p.y);
+ putwarp(a+33, w);
+ a[33+3*3*4] = smooth;
+ _unlockdisplay(dst->display);
+}
--- /dev/null
+++ b/sys/src/libdraw/warptest.c
@@ -1,0 +1,76 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <geometry.h>
+
+void
+usage(void)
+{+ fprint(2, "usage: %s [-s sx sy] [-t tx ty] [-r θ]\n", argv0);
+ exits("usage");+}
+
+void
+main(int argc, char *argv[])
+{+ Image *dst, *src;
+ Warp w;
+ double sx, sy, tx, ty, θ, c, s;
+ int smooth;
+
+ sx = sy = 1;
+ tx = ty = 0;
+ θ = 0;
+ smooth = 0;
+ ARGBEGIN{+ case 's':
+ sx = strtod(EARGF(usage()), nil);
+ sy = strtod(EARGF(usage()), nil);
+ break;
+ case 't':
+ tx = strtod(EARGF(usage()), nil);
+ ty = strtod(EARGF(usage()), nil);
+ break;
+ case 'r':
+ θ = strtod(EARGF(usage()), nil)*DEG;
+ break;
+ case 'S':
+ smooth++;
+ break;
+ default:
+ usage();
+ }ARGEND;
+ if(argc != 0)
+ usage();
+
+ if(initdraw(nil, nil, "warp test") < 0)
+ sysfatal("initdraw: %r");+
+ c = cos(θ);
+ s = sin(θ);
+ Matrix S = {+ sx, 0, 0,
+ 0, sy, 0,
+ 0, 0, 1,
+ }, T = {+ 1, 0, tx,
+ 0, 1, ty,
+ 0, 0, 1,
+ }, R = {+ c, -s, 0,
+ s, c, 0,
+ 0, 0, 1,
+ };
+
+ mulm(R, S);
+ mulm(T, R);
+
+ mkwarp(w, T);
+
+ src = readimage(display, 0, 0);
+ dst = allocimage(display, src->r, src->chan, 0, DNofill);
+ affinewarp(dst, dst->r, src, src->r.min, w, smooth);
+ writeimage(1, dst, 0);
+
+ exits(nil);
+}
--- a/sys/src/libmemdraw/mkfile
+++ b/sys/src/libmemdraw/mkfile
@@ -22,7 +22,6 @@
unload.$O\
write.$O\
warp.$O\
- mkwarp.$O\
</sys/src/cmd/mksyslib
--- a/sys/src/libmemdraw/mkwarp.c
+++ /dev/null
@@ -1,22 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <geometry.h>
-
-/* 25.7 fixed-point number operations */
-
-#define flt2fix(n) ((long)((n)*(1<<7) + ((n) < 0? -0.5: 0.5)))
-
-void
-mkwarp(Warp w, double m0[3][3])
-{- Matrix m;
-
- memmove(m, m0, sizeof(Matrix));
- invm(m);
-
- w[0][0] = flt2fix(m[0][0]); w[0][1] = flt2fix(m[0][1]); w[0][2] = flt2fix(m[0][2]);
- w[1][0] = flt2fix(m[1][0]); w[1][1] = flt2fix(m[1][1]); w[1][2] = flt2fix(m[1][2]);
- w[2][0] = 0; w[2][1] = 0; w[2][2] = 1<<7;
-}
--
⑨