]> git.lizzy.rs Git - plan9front.git/commitdiff
add games/dpic and games/todpic
authorqwx <devnull@localhost>
Wed, 25 Jul 2018 03:02:46 +0000 (05:02 +0200)
committerqwx <devnull@localhost>
Wed, 25 Jul 2018 03:02:46 +0000 (05:02 +0200)
sys/man/1/dpic [new file with mode: 0644]
sys/src/games/dpic.c [new file with mode: 0644]
sys/src/games/mkfile
sys/src/games/todpic.c [new file with mode: 0644]

diff --git a/sys/man/1/dpic b/sys/man/1/dpic
new file mode 100644 (file)
index 0000000..dfab9bd
--- /dev/null
@@ -0,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).
diff --git a/sys/src/games/dpic.c b/sys/src/games/dpic.c
new file mode 100644 (file)
index 0000000..98c8170
--- /dev/null
@@ -0,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);
+}
index a42eb89e4b20b568d9aa69c3cbd47c8f25268552..824f422c77831c77dea7699d8128ffb60ea3610b 100644 (file)
@@ -17,6 +17,8 @@ TARG=4s\
        midi\
        wadfs\
        dmid\
+       dpic\
+       todpic\
 
 OFILES=
 HFILES=
diff --git a/sys/src/games/todpic.c b/sys/src/games/todpic.c
new file mode 100644 (file)
index 0000000..89e7aa3
--- /dev/null
@@ -0,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);
+}