shithub: sce

Download patch

ref: 907f053cc5b9626b62c6087ec5a2a07f1765c546
parent: 373cdd23db1cf6bd2877d6ac41bcd96b336cb4d4
author: qwx <qwx@sciops.net>
date: Sat Mar 14 18:02:07 EDT 2020

add utils/sctile: terrain tile extraction

--- a/utils/mkfile
+++ b/utils/mkfile
@@ -1,6 +1,7 @@
 </$objtype/mkfile
 TARG=\
 	grp\
+	sctile\
 
 HFILES=
 </sys/src/cmd/mkmany
--- /dev/null
+++ b/utils/sctile.c
@@ -1,0 +1,192 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <bio.h>
+
+enum{
+	Subsz = 8,
+	Nmega = 4,
+	Nsub = 4,
+	WPErecord = 4,
+	VR4record = Subsz * Subsz,
+	VX4record = Nsub * Nsub * 2,
+	CV5hdr = 20,
+	CV5record = CV5hdr + Nmega * Nmega * 2,
+	Rgbsz = 3,
+	Tilewidth = Nsub * Subsz,
+	Tileheight = Tilewidth,
+	Tilesz = Tilewidth * Tileheight,
+	Megawidth = Nmega * Tilewidth,
+	Megaheight = Megawidth,
+	Megasz = Megawidth * Megaheight,
+};
+
+uchar *pal, *data, *ref;
+int npal, ndata, nref;
+
+Biobuf *
+bopen(char *pref, char *ext, vlong *size)
+{
+	int fd;
+	char path[64];
+	Dir *d;
+	Biobuf *bf;
+
+	snprint(path, sizeof path, "%s.%s", pref, ext);
+	if((fd = open(path, OREAD)) < 0)
+		sysfatal("open: %r");
+	if((d = dirfstat(fd)) == nil)
+		sysfatal("dirfstat: %r");
+	*size = d->length;
+	free(d);
+	if((bf = Bfdopen(fd, OREAD)) == nil)
+		sysfatal("Bfdopen: %r");
+	return bf;	
+}
+
+void
+readall(char *pref, char *ext, uchar **buf, int *nbuf, int elsize)
+{
+	int n;
+	uchar *p;
+	vlong size;
+	Biobuf *bf;
+
+	bf = bopen(pref, ext, &size);
+	if(size % elsize != 0)
+		sysfatal("readall %s.%s: invalid size", pref, ext);
+	if((*buf = malloc(size)) == nil)
+		sysfatal("malloc: %r");
+	p = *buf;
+	while((n = Bread(bf, p, 128 * elsize)) > 0)
+		p += n;
+	if(n < 0)
+		sysfatal("Bread: %r");
+	if(p - *buf != size)
+		sysfatal("readall %s.%s: phase error (%zd vs %lld)", pref, ext, p-*buf, size);
+	*nbuf = size / elsize;
+	Bterm(bf);
+}
+
+void
+gettile(int n, uchar *buf, int bufwidth)
+{
+	int i, x, tx, flip;
+	uchar *rp, *re, *dp, *de, *pp, *p;
+
+	for(rp=ref+n*VX4record, re=rp+VX4record, p=buf, tx=0; rp<re; rp+=2){
+		i = (rp[1] << 8 | rp[0]) >> 1;
+		if(i >= ndata)
+			sysfatal("writetile: invalid tile index %ud", i);
+		flip = rp[0] & 1;
+		for(dp=data+i*VR4record, de=dp+VR4record; dp<de;){
+			for(x=0; x<Subsz; x++, p+=Rgbsz){
+				pp = pal + (flip ? dp[Subsz-1 - x] : dp[x]) * WPErecord;
+				p[0] = pp[2];
+				p[1] = pp[1];
+				p[2] = pp[0];
+			}
+			dp += Subsz;
+			p += (bufwidth - Subsz) * Rgbsz;
+		}
+		p -= (Subsz * bufwidth - Subsz) * Rgbsz;
+		if(++tx % Nsub == 0)
+			p += ((Subsz - 1) * bufwidth + (bufwidth - Tilewidth)) * Rgbsz;
+	}
+}
+
+void
+writetile(char *pref, int n, char *id, uchar *buf, int nbuf, Memimage *m)
+{
+	int fd;
+	char path[128];
+
+	if(loadmemimage(m, m->r, buf, nbuf) < 0)
+		sysfatal("loadmemimage: %r");
+	snprint(path, sizeof path, "%s.%s%05d.bit", pref, id, n);
+	if((fd = create(path, OWRITE, 0644)) < 0)
+		sysfatal("open: %r");
+	if(writememimage(fd, m) < 0)
+		sysfatal("writememimage: %r");
+	close(fd);
+}
+
+void
+parsecv5(char *pref)
+{
+	int n, nr, x, y;
+	vlong size;
+	uchar u[CV5record], *rp, buf[Megasz * Rgbsz], *p;
+	Biobuf *bf;
+	Memimage *m;
+
+	bf = bopen(pref, "cv5", &size);
+	if(size % CV5record != 0)
+		sysfatal("parsecv5 %s: invalid size", pref);
+	if((m = allocmemimage(Rect(0,0,Megawidth,Megaheight), RGB24)) == nil)
+		sysfatal("allocmemimage: %r");
+	nr = 0;
+	while((n = Bread(bf, u, sizeof u)) > 0){
+		assert(n == sizeof u);
+		for(y=0, rp=u+CV5hdr, p=buf; y<Nmega; y++){
+			for(x=0; x<Nmega; x++, rp+=2){
+				gettile(rp[1] << 8 | rp[0], p, Megawidth);
+				p += Tilewidth * Rgbsz;
+			}
+			p += (Tileheight - 1) * Megawidth * Rgbsz;
+		}
+		writetile(pref, nr++, "g", buf, Megasz * Rgbsz, m);
+	}
+	if(n < 0)
+		sysfatal("Bread: %r");
+	Bterm(bf);
+}
+
+void
+parsetile(char *pref)
+{
+	int n;
+	uchar buf[Tilesz * Rgbsz];
+	Memimage *m;
+
+	if((m = allocmemimage(Rect(0,0,Tilewidth,Tileheight), RGB24)) == nil)
+		sysfatal("allocmemimage: %r");
+	for(n=0; n<nref; n++){
+		gettile(n, buf, Tilewidth);
+		writetile(pref, n, "", buf, Tilesz * Rgbsz, m);
+	}
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-g] tileset\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int group;
+
+	group = 0;
+	ARGBEGIN{
+	case 'g': group = 1; break;
+	default: usage();
+	}ARGEND
+	if(argv[0] == nil)
+		usage();
+	readall(argv[0], "wpe", &pal, &npal, WPErecord);
+	if(npal != 256)
+		sysfatal("invalid pal size %d", npal);
+	readall(argv[0], "vr4", &data, &ndata, VR4record);
+	readall(argv[0], "vx4", &ref, &nref, VX4record);
+	if(memimageinit() < 0)
+		sysfatal("memimageinit: %r");
+	if(group)
+		parsecv5(argv[0]);
+	else
+		parsetile(argv[0]);
+	exits(nil);
+}