git: 9front

Download patch

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