shithub: riscv

Download patch

ref: a8644d01c34febd6e709c8968fbb926c9115e6c1
parent: 416aed9b662ad9e7ffa9a0bd608b29a878676a7f
author: qwx <devnull@localhost>
date: Wed Jul 25 01:02:46 EDT 2018

add games/dpic and games/todpic

--- /dev/null
+++ b/sys/man/1/dpic
@@ -1,0 +1,118 @@
+.TH DPIC 1
+.SH NAME
+dpic, todpic \- Doom picture decoder and encoder
+.SH SYNOPSIS
+.B dpic
+[
+.B -f
+] [
+.B -p
+.I palette
+] [
+.I pic
+]
+.PP
+.B todpic
+[
+.B -fw
+] [
+.B -b
+.I bgcol
+] [
+.B -p
+.I palette
+] [
+.I image
+]
+.SH DESCRIPTION
+.I Dpic
+reads a doom picture formatted image (default standard input),
+converts it to a Plan 9
+.IR image (6)
+and writes it to standard out.
+.I Todpic
+does the opposite transformation.
+.PP
+A color palette is needed for the process;
+its location is set to
+.B /mnt/wad/playpal
+by default.
+This may be overridden with the
+.B -p
+command line option.
+Both programs also accept an
+.B -f
+flag to indicate processing a doom 64x64 flat picture.
+.PP
+When encoding a doom picture,
+x and y offsets are set to the input's top left corner coordinates.
+The
+.B -w
+flag sets the offsets so as to center the picture when drawn by the doom engine,
+which is useful for wall patches.
+The
+.B -b
+option sets the RGB24 color to signal transparent pixels,
+.L 0x00FFFF
+by default.
+.SH EXAMPLES
+Create a patch
+.I WAD
+(see
+.BR wadfs (4))
+replacing a sky texture.
+First, create a 256x128 image, mirror it, and convert it for use with
+.BR tweak (1).
+.IP
+.EX
+% png -9t tuttleglenda.png \\
+	| resample -x 128 -y 128 \\
+	| crop -r 0 0 256 128 \\
+	| rotate -l \\
+	| iconv -c m8 > tuttlesky
+.EE
+.PP
+Next, use
+.BR tweak (1)
+to tile the 128x128 picture.
+Then, mount an
+.I IWAD
+containing the base color palette, convert to a doom picture,
+create a patch
+.IR WAD ,
+then launch doom using it.
+.IP
+.EX
+% games/wadfs /sys/games/lib/doom/doom2.wad
+createfile SW18_7: file already exists
+% games/wadfs -m /mnt/new
+% games/todpic tuttlesky > /mnt/new/rsky1
+% cp /mnt/new/WAD tuttle.wad
+% games/doom -file tuttle.wad
+.EE
+.PP
+Create a crude catclock weapon sprite.
+.IP
+.EX
+% games/wadfs /sys/games/lib/doom/doom2.wad
+createfile SW18_7: file already exists
+% mkdir /mnt/new/s
+adding end marker S_END
+% cp /mnt/wad/s/* /mnt/new/s/
+% crop -r 0 0 114 120 -t -120 -60 catclock.bit \\
+	| games/todpic -b 0xffffff > /mnt/new/s/punga0
+% games/doom -file /mnt/new/WAD
+.EE
+.SH SOURCE
+.B /sys/src/games/dpic.c
+.br
+.B /sys/src/games/todpic.c
+.SH "SEE ALSO"
+.IR games (1),
+.IR tweak (1),
+.IR wadfs (4)
+.SH HISTORY
+.I Dpic
+and
+.I todpic
+first appeared in 9front (July, 2018).
--- /dev/null
+++ b/sys/src/games/dpic.c
@@ -1,0 +1,132 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <bio.h>
+
+int dx = 64, dy = 64;
+Biobuf *bi, *bo;
+u32int pal[256];
+
+u8int
+get8(void)
+{
+	uchar v;
+
+	if(Bread(bi, &v, 1) != 1)
+		sysfatal("get8: short read");
+	return v;
+}
+
+u16int
+get16(void)
+{
+	u8int v;
+
+	v = get8();
+	return get8() << 8 | v;
+}
+
+u32int
+get32(void)
+{
+	u16int v;
+
+	v = get16();
+	return get16() << 16 | v;
+}
+
+u32int*
+unpic(void)
+{
+	int n, h;
+	u32int *p, *d, *cols, *buf;
+
+	dx = get16();
+	dy = get16();
+	cols = mallocz(dx * sizeof *cols, 1);
+	buf = mallocz(dx * dy * sizeof *buf, 1);
+	if(cols == nil || buf == nil)
+		sysfatal("mallocz: %r");
+	get32();
+	for(p=cols; p<cols+dx; p++)
+		*p = get32();
+	for(p=cols; p<cols+dx; p++){
+		Bseek(bi, *p, 0);
+		for(;;){
+			if((h = get8()) == 0xff)
+				break;
+			n = get8();
+			get8();
+			for(d=buf+(p-cols)+h*dx; n-->0; d+=dx)
+				*d = pal[get8()];
+			get8();
+		}
+	}
+	free(cols);
+	return buf;
+}
+
+u32int*
+unflat(void)
+{
+	u32int *p;
+	static u32int buf[4096];
+
+	for(p=buf; p<buf+nelem(buf); p++)
+		*p = pal[get8()];
+	return buf;
+}
+
+void
+getpal(char *f)
+{
+	uchar u[3];
+	u32int *p;
+	Biobuf *bp;
+
+	if((bp = Bopen(f, OREAD)) == nil)
+		sysfatal("getpal: %r");
+	for(p=pal; p<pal+nelem(pal); p++){
+		if(Bread(bp, u, 3) != 3)
+			sysfatal("getpal: short read: %r");
+		*p = u[2]<<16 | u[1]<<8 | u[0];
+	}
+	Bterm(bp);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-f] [-p palette] pic\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int fd, flat;
+	char *p, c[9];
+	u32int *buf;
+
+	flat = 0;
+	p = "/mnt/wad/playpal";
+	ARGBEGIN{
+	case 'f': flat = 1; break;
+	case 'p': p = EARGF(usage()); break;
+	default: usage();
+	}ARGEND
+	if(*argv == nil)
+		usage();
+	if((fd = open(*argv, OREAD)) < 0)
+		sysfatal("open: %r");
+	getpal(p);
+	bi = Bfdopen(fd, OREAD);
+	bo = Bfdopen(1, OWRITE);
+	if(bi == nil || bo == nil)
+		sysfatal("Bfdopen: %r");
+	buf = flat ? unflat() : unpic();
+	Bprint(bo, "%11s %11d %11d %11d %11d ",
+		chantostr(c, XBGR32), 0, 0, dx, dy);
+	Bwrite(bo, buf, dx * dy * sizeof *buf);
+	exits(nil);
+}
--- a/sys/src/games/mkfile
+++ b/sys/src/games/mkfile
@@ -17,6 +17,8 @@
 	midi\
 	wadfs\
 	dmid\
+	dpic\
+	todpic\
 
 OFILES=
 HFILES=
--- /dev/null
+++ b/sys/src/games/todpic.c
@@ -1,0 +1,190 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <bio.h>
+
+int wofs;
+u32int pal[256], bg = 0x00ffff;
+Biobuf *bp;
+
+#define abs(x) ((x) < 0 ? -(x) : (x))
+
+void
+put8(u8int v)
+{
+	if(Bwrite(bp, &v, sizeof v) != sizeof v)
+		sysfatal("put8: short write");
+}
+
+void
+put16(u16int v)
+{
+	put8(v);
+	put8(v >> 8);
+}
+
+void
+put32(u32int v)
+{
+	put16(v);
+	put16(v >> 16);
+}
+
+int
+pali(u32int v)
+{
+	int i, Δ, Δ´;
+	u32int *p;
+
+	i = 0;
+	Δ = abs((char)v - (char)*pal)
+		+ abs((char)(v >> 8) - (char)(*pal >> 8))
+		+ abs((char)(v >> 16) - (char)(*pal >> 16));
+	for(p=pal; p<pal+nelem(pal); p++){
+		Δ´ = abs((char)v - (char)*p)
+			+ abs((char)(v >> 8) - (char)(*p >> 8))
+			+ abs((char)(v >> 16) - (char)(*p >> 16));
+		if(Δ´ < Δ){
+			Δ = Δ´;
+			i = p - pal;
+			if(Δ == 0)
+				break;
+		}
+	}
+	return i;
+}
+
+void
+topic(Memimage *i)
+{
+	int w, h, dx, dy;
+	uchar *np, *b, *buf, *p, *pp;
+	u32int v;
+
+	p = i->data->bdata;
+	dx = Dx(i->r);
+	dy = Dy(i->r);
+	if(dy > 254)
+		sysfatal("topic: invalid pic height");
+	put16(dx);
+	put16(dy);
+	put16(wofs ? dx / 2 - 1 : i->r.min.x);
+	put16(wofs ? dy - 5 : i->r.min.y);
+	if(i->r.min.x != 0)
+		dx = i->width;
+	buf = mallocz((5 * dy / 2 + 5) * dx, 1);
+	if(buf == nil)
+		sysfatal("mallocz: %r");
+	for(w=dx, b=buf; w>0; w--, p+=3){
+		put32(b - buf + 8 + dx * 4);
+		for(h=0, np=b+1, pp=p; h<dy; h++, pp+=dx*3){
+			v = pp[2] << 16 | pp[1] << 8 | pp[0];
+			if(v == bg){
+				if(b - np - 2 > 0){
+					*np = b - np - 2;
+					*b++ = 0;
+					np = b + 1;
+				}
+				continue;
+			}
+			if(b - np - 2 < 0){
+				*b++ = h;
+				b++;
+				*b++ = 0;
+			}
+			*b++ = pali(v);
+		}
+		if(b - np - 2 >= 0){
+			*np = b - np - 2;
+			*b++ = 0;
+		}
+		*b++ = 0xff;
+	}
+	Bwrite(bp, buf, b - buf);
+	free(buf);
+}
+
+void
+toflat(Memimage *i)
+{
+	int n;
+	uchar *p;
+
+	if(Dx(i->r) != 64 || Dy(i->r) != 64)
+		sysfatal("toflat: invalid flatpic dimensions");
+	p = i->data->bdata;
+	n = 64*64;
+	while(n-- > 0){
+		put8(pali(p[2] << 16 | p[1] << 8 | p[0]));
+		p += 4;
+	}
+}
+
+static Memimage*
+iconv(Memimage *i)
+{
+	Memimage *ni;
+
+	if(i->chan == RGB24)
+		return i;
+	if((ni = allocmemimage(i->r, RGB24)) == nil)
+		sysfatal("allocmemimage: %r");
+	memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
+	freememimage(i);
+	return ni;
+}
+
+void
+getpal(char *f)
+{
+	uchar u[3];
+	u32int *p;
+	Biobuf *bp;
+
+	if((bp = Bopen(f, OREAD)) == nil)
+		sysfatal("getpal: %r");
+	for(p=pal; p<pal+nelem(pal); p++){
+		if(Bread(bp, u, 3) != 3)
+			sysfatal("getpal: short read: %r");
+		*p = u[0]<<16 | u[1]<<8 | u[2];
+	}
+	Bterm(bp);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-fw] [-b bgcol] [-p palette] [image]\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int fd, flat;
+	char *p;
+	Memimage *i;
+
+	fd = 0;
+	flat = 0;
+	p = "/mnt/wad/playpal";
+	ARGBEGIN{
+	case 'b': bg = strtoul(EARGF(usage()), nil, 0); break;
+	case 'f': flat = 1; break;
+	case 'p': p = EARGF(usage()); break;
+	case 'w': wofs = 1; break;
+	default: usage();
+	}ARGEND
+	if(*argv != nil)
+		if((fd = open(*argv, OREAD)) < 0)
+			sysfatal("open: %r");
+	getpal(p);
+	if((bp = Bfdopen(1, OWRITE)) == nil)
+		sysfatal("Bfdopen: %r");
+	memimageinit();
+	if((i = readmemimage(fd)) == nil)
+		sysfatal("readmemimage: %r");
+	(flat ? toflat : topic)(iconv(i));
+	exits(nil);
+}