mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
add games/dpic and games/todpic
This commit is contained in:
parent
416aed9b66
commit
a8644d01c3
4 changed files with 442 additions and 0 deletions
118
sys/man/1/dpic
Normal file
118
sys/man/1/dpic
Normal file
|
@ -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).
|
132
sys/src/games/dpic.c
Normal file
132
sys/src/games/dpic.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -17,6 +17,8 @@ TARG=4s\
|
|||
midi\
|
||||
wadfs\
|
||||
dmid\
|
||||
dpic\
|
||||
todpic\
|
||||
|
||||
OFILES=
|
||||
HFILES=
|
||||
|
|
190
sys/src/games/todpic.c
Normal file
190
sys/src/games/todpic.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue