From a8644d01c34febd6e709c8968fbb926c9115e6c1 Mon Sep 17 00:00:00 2001 From: qwx Date: Wed, 25 Jul 2018 05:02:46 +0200 Subject: [PATCH] add games/dpic and games/todpic --- sys/man/1/dpic | 118 +++++++++++++++++++++++++ sys/src/games/dpic.c | 132 ++++++++++++++++++++++++++++ sys/src/games/mkfile | 2 + sys/src/games/todpic.c | 190 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 442 insertions(+) create mode 100644 sys/man/1/dpic create mode 100644 sys/src/games/dpic.c create mode 100644 sys/src/games/todpic.c diff --git a/sys/man/1/dpic b/sys/man/1/dpic new file mode 100644 index 000000000..dfab9bd3a --- /dev/null +++ b/sys/man/1/dpic @@ -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 index 000000000..98c8170bc --- /dev/null +++ b/sys/src/games/dpic.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +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; p0; d+=dx) + *d = pal[get8()]; + get8(); + } + } + free(cols); + return buf; +} + +u32int* +unflat(void) +{ + u32int *p; + static u32int buf[4096]; + + for(p=buf; p +#include +#include +#include +#include + +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> 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 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