~moody/pokered

ecd2eb2447bf4dee4ec3be35f881c7e7102adb1b — Jacob Moody 1 year, 4 months ago 1b9540c + 4c6a58e front
merge from upstream
6 files changed, 564 insertions(+), 7 deletions(-)

A mkfile
M tools/common.h
A tools/getopt.c
A tools/getopt.h
M tools/gfx.c
A tools/mkfile
A mkfile => mkfile +198 -0
@@ 0,0 1,198 @@

</$cputype/mkfile
TGFX=tools/$O.gfx
TCMP=tools/$O.pkmncompress
TOOLS=$TGFX $TCMP

AS=rgbasm
AFLAGS=-hL -Q8 -P includes.asm -Weverything '-Wnumeric-string=2' '-Wtruncation=1' -D _RED
LD=rgblink
LDFLAGS=-p 0x00 -d -l layout.link
FIX=rgbfix
FIFLAGS=-p 0x00 -jsv -n 0 -k 01 -l 0x33 -m 0x13 -r 03 -t 'POKEMON RED'
O=o

TARG=pokered.gbc

OFILES=\
	audio.$O\
	home.$O\
	main.$O\
	maps.$O\
	ram.$O\
	text.$O\
	gfx/pics.$O\
	gfx/sprites.$O\
	gfx/tilesets.$O\

IFILES=`{for(i in `{walk | grep asm}){ sed -n 's/.*(INCLUDE|INCBIN) "(gfx.*(2bpp|1bpp|pic))".*/\2/gp' $i}}
PICFILES=`{echo $IFILES | grep '\.pic'}
B2FILES=`{echo $IFILES | grep '\.2bpp'}
B1FILES=`{echo $IFILES | grep '\.1bpp'}
JUNK=${PICFILES:%.pic=%.2bpp}

all:V:	$TARG

check:V:	$TARG
	@{
		rfork e;
		RETAIL=`{awk '{ print $1 }' roms.sha1 | sed 1q}
		OURS=`{sha1sum pokered.gbc | awk '{ print $1 }'}
		if(~ $RETAIL $OURS)
			;
	}

$TOOLS:
	@{ cd tools && mk all}

pic:V:	$PICFILES

d1:V:	$B2FILES

d2:V:	$B1FILES

$OFILES:	pic d1 d2

$TARG: $OFILES 
	$LD $LDFLAGS -o $target $OFILES
	$FIX $FIFLAGS $target

%.$O:	%.asm
	$AS $AFLAGS -o $stem.$O $stem.asm

%.2bpp:	%.png $TOOLS
	rgbgfx -o $stem.2bpp $stem.png

%.1bpp:	%.png $TOOLS
	rgbgfx -d1 -o $stem.1bpp $stem.png

%.pic:	%.2bpp $TOOLS
	$TCMP $stem.2bpp $stem.pic

gfx/battle/move_anim_0.2bpp:	gfx/battle/move_anim_0.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/battle/move_anim_1.2bpp:	gfx/battle/move_anim_1.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target

gfx/intro/blue_jigglypuff_1.2bpp: gfx/intro/blue_jigglypuff_1.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX -o $target $target
gfx/intro/blue_jigglypuff_2.2bpp: gfx/intro/blue_jigglypuff_2.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX -o $target $target
gfx/intro/blue_jigglypuff_3.2bpp: gfx/intro/blue_jigglypuff_3.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX -o $target $target
gfx/intro/red_nidorino_1.2bpp: gfx/intro/red_nidorino_1.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX -o $target $target
gfx/intro/red_nidorino_2.2bpp: gfx/intro/red_nidorino_2.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX -o $target $target
gfx/intro/red_nidorino_3.2bpp: gfx/intro/red_nidorino_3.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX -o $target $target

gfx/credits/the_end.2bpp:	gfx/credits/the_end.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --interleave --png $prereq(1) -o $target $target

gfx/slots/red_slots_1.2bpp:	gfx/slots/red_slots_1.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/slots/blue_slots_1.2bpp:	gfx/slots/blue_slots_1.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target

gfx/trade/game_boy.2bpp: gfx/trade/game_boy.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --remove-duplicates -o $target $target

gfx/intro/gengar.2bpp:	gfx/intro/gengar.png $TOOLS
	rgbgfx -h -o $target $prereq(1)
	$TGFX --remove-duplicates '--preserve=0x19,0x76' -o $target $target
gfx/tilesets/flower/flower1.2bpp:	gfx/tilesets/flower/flower1.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/flower/flower2.2bpp:	gfx/tilesets/flower/flower2.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/flower/flower3.2bpp:	gfx/tilesets/flower/flower3.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/cavern.2bpp:	gfx/tilesets/cavern.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/cemetery.2bpp:	gfx/tilesets/cemetery.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/club.2bpp:	gfx/tilesets/club.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/facility.2bpp:	gfx/tilesets/facility.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/forest.2bpp:	gfx/tilesets/forest.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/gate.2bpp:	gfx/tilesets/gate.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/gym.2bpp:	gfx/tilesets/gym.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/house.2bpp:	gfx/tilesets/house.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/interior.2bpp:	gfx/tilesets/interior.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/lab.2bpp:	gfx/tilesets/lab.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/lobby.2bpp:	gfx/tilesets/lobby.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/mansion.2bpp:	gfx/tilesets/mansion.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/overworld.2bpp:	gfx/tilesets/overworld.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/tilesets_rg/flower.2bpp:	gfx/tilesets/tilesets_rg/flower.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/tilesets_rg/forest.2bpp:	gfx/tilesets/tilesets_rg/forest.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/tilesets_rg/overworld.2bpp:	gfx/tilesets/tilesets_rg/overworld.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/plateau.2bpp:	gfx/tilesets/plateau.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/pokecenter.2bpp:	gfx/tilesets/pokecenter.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/reds_house.2bpp:	gfx/tilesets/reds_house.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX '--preserve=0x48' --trim-whitespace -o $target $target
gfx/tilesets/ship.2bpp:	gfx/tilesets/ship.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/ship_port.2bpp:	gfx/tilesets/ship_port.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target
gfx/tilesets/underground.2bpp:	gfx/tilesets/underground.png $TOOLS
	rgbgfx -o $target $prereq(1)
	$TGFX --trim-whitespace -o $target $target

clean:VQ:
	for(i in $IFILES)
		rm -f $i
	for(i in $JUNK)
		rm -f $i
	rm -f *.o $TARG
	@{ cd tools && mk clean }

M tools/common.h => tools/common.h +0 -3
@@ 28,9 28,6 @@ noreturn void usage_exit(int status) {
	exit(status);
}

int getopt_long_index;
#define getopt_long(argc, argv, optstring, longopts) getopt_long(argc, argv, optstring, longopts, &getopt_long_index)

void *xmalloc(size_t size) {
	errno = 0;
	void *m = malloc(size);

A tools/getopt.c => tools/getopt.c +287 -0
@@ 0,0 1,287 @@
/*
 * Copyright © 2005-2020 Rich Felker, et al.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* This implementation was taken from musl and modified for RGBDS */

#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>

#include "getopt.h"

char *optarg;
int optind = 1, musl_opterr = 1, musl_optopt;
int musl_optreset = 0;
static int musl_optpos;

static void musl_getopt_msg(char const *a, char const *b, char const *c, size_t l)
{
	FILE *f = stderr;

	if (fputs(a, f) >= 0 &&
	    fwrite(b, strlen(b), 1, f) &&
	    fwrite(c, 1, l, f) == l)
		putc('\n', f);
}

static int getopt(int argc, char *argv[], char const *optstring)
{
	int i;
	wchar_t c, d;
	int k, l;
	char *optchar;

	if (!optind || musl_optreset) {
		musl_optreset = 0;
		musl_optpos = 0;
		optind = 1;
	}

	if (optind >= argc || !argv[optind])
		return -1;

	if (argv[optind][0] != '-') {
		if (optstring[0] == '-') {
			optarg = argv[optind++];
			return 1;
		}
		return -1;
	}

	if (!argv[optind][1])
		return -1;

	if (argv[optind][1] == '-' && !argv[optind][2])
		return optind++, -1;

	if (!musl_optpos)
		musl_optpos++;
	k = mbtowc(&c, argv[optind] + musl_optpos, MB_LEN_MAX);
	if (k < 0) {
		k = 1;
		c = 0xfffd; /* replacement char */
	}
	optchar = argv[optind] + musl_optpos;
	musl_optpos += k;

	if (!argv[optind][musl_optpos]) {
		optind++;
		musl_optpos = 0;
	}

	if (optstring[0] == '-' || optstring[0] == '+')
		optstring++;

	i = 0;
	d = 0;
	do {
		l = mbtowc(&d, optstring+i, MB_LEN_MAX);
		if (l > 0)
			i += l;
		else
			i++;
	} while (l && d != c);

	if (d != c || c == ':') {
		musl_optopt = c;
		if (optstring[0] != ':' && musl_opterr)
			musl_getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
		return '?';
	}
	if (optstring[i] == ':') {
		optarg = 0;
		if (optstring[i + 1] != ':' || musl_optpos) {
			optarg = argv[optind++] + musl_optpos;
			musl_optpos = 0;
		}
		if (optind > argc) {
			musl_optopt = c;
			if (optstring[0] == ':')
				return ':';
			if (musl_opterr)
				musl_getopt_msg(argv[0], ": option requires an argument: ",
						optchar, k);
			return '?';
		}
	}
	return c;
}

static void permute(char **argv, int dest, int src)
{
	char *tmp = argv[src];
	int i;

	for (i = src; i > dest; i--)
		argv[i] = argv[i-1];
	argv[dest] = tmp;
}

static int getopt_long_core(int argc, char **argv, char const *optstring,
				 const struct option *longopts, int *idx, int longonly);

int getopt_long(int argc, char **argv, char const *optstring,
			    const struct option *longopts, int *idx, int longonly)
{
	int ret, skipped, resumed;

	if (!optind || musl_optreset) {
		musl_optreset = 0;
		musl_optpos = 0;
		optind = 1;
	}

	if (optind >= argc || !argv[optind])
		return -1;

	skipped = optind;
	if (optstring[0] != '+' && optstring[0] != '-') {
		int i;
		for (i = optind; ; i++) {
			if (i >= argc || !argv[i])
				return -1;
			if (argv[i][0] == '-' && argv[i][1])
				break;
		}
		optind = i;
	}
	resumed = optind;
	ret = getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
	if (resumed > skipped) {
		int i, cnt = optind - resumed;

		for (i = 0; i < cnt; i++)
			permute(argv, skipped, optind - 1);
		optind = skipped + cnt;
	}
	return ret;
}

static int getopt_long_core(int argc, char **argv, char const *optstring,
				 const struct option *longopts, int *idx, int longonly)
{
	optarg = 0;
	if (longopts && argv[optind][0] == '-' &&
	    ((longonly && argv[optind][1] && argv[optind][1] != '-') ||
	     (argv[optind][1] == '-' && argv[optind][2]))) {
		int colon = optstring[optstring[0] == '+' || optstring[0] == '-'] == ':';
		int i, cnt, match = 0;
		char *arg = 0, *opt, *start = argv[optind] + 1;

		for (cnt = i = 0; longopts[i].name; i++) {
			char const *name = longopts[i].name;

			opt = start;
			if (*opt == '-')
				opt++;
			while (*opt && *opt != '=' && *opt == *name) {
				name++;
				opt++;
			}
			if (*opt && *opt != '=')
				continue;
			arg = opt;
			match = i;
			if (!*name) {
				cnt = 1;
				break;
			}
			cnt++;
		}
		if (cnt == 1 && longonly && arg - start == mblen(start, MB_LEN_MAX)) {
			int l = arg - start;

			for (i = 0; optstring[i]; i++) {
				int j = 0;

				while (j < l && start[j] == optstring[i + j])
					j++;
				if (j == l) {
					cnt++;
					break;
				}
			}
		}
		if (cnt == 1) {
			i = match;
			opt = arg;
			optind++;
			if (*opt == '=') {
				if (!longopts[i].has_arg) {
					musl_optopt = longopts[i].val;
					if (colon || !musl_opterr)
						return '?';
					musl_getopt_msg(argv[0],
						": option does not take an argument: ",
						longopts[i].name,
						strlen(longopts[i].name));
					return '?';
				}
				optarg = opt + 1;
			} else if (longopts[i].has_arg == required_argument) {
				optarg = argv[optind];
				if (!optarg) {
					musl_optopt = longopts[i].val;
					if (colon)
						return ':';
					if (!musl_opterr)
						return '?';
					musl_getopt_msg(argv[0],
						": option requires an argument: ",
						longopts[i].name,
						strlen(longopts[i].name));
					return '?';
				}
				optind++;
			}
			if (idx)
				*idx = i;
			if (longopts[i].flag) {
				*longopts[i].flag = longopts[i].val;
				return 0;
			}
			return longopts[i].val;
		}
		if (argv[optind][1] == '-') {
			musl_optopt = 0;
			if (!colon && musl_opterr)
				musl_getopt_msg(argv[0], cnt ?
					": option is ambiguous: " :
					": unrecognized option: ",
					argv[optind] + 2,
					strlen(argv[optind] + 2));
			optind++;
			return '?';
		}
	}
	return getopt(argc, argv, optstring);
}

int getopt_long_only(int argc, char **argv, char const *optstring,
			  const struct option *longopts, int *idx)
{
	return getopt_long(argc, argv, optstring, longopts, idx, 1);
}

A tools/getopt.h => tools/getopt.h +57 -0
@@ 0,0 1,57 @@
/*
 * Copyright © 2005-2020 Rich Felker, et al.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* This implementation was taken from musl and modified for RGBDS */

#ifndef RGBDS_EXTERN_GETOPT_H
#define RGBDS_EXTERN_GETOPT_H

#ifdef __cplusplus
extern "C" {
#endif

extern char *optarg;
extern int optind, musl_opterr, musl_optopt, musl_optreset;

struct option {
	char const *name;
	int has_arg;
	int *flag;
	int val;
};

int getopt_long(int argc, char **argv, char const *optstring,
			  const struct option *longopts, int *idx, int longonly);

int getopt_long_only(int argc, char **argv, char const *optstring,
			  const struct option *longopts, int *idx);

#define no_argument        0
#define required_argument  1
#define optional_argument  2

#ifdef __cplusplus
} // extern "C"
#endif

#endif

M tools/gfx.c => tools/gfx.c +7 -4
@@ 36,7 36,7 @@ void parse_args(int argc, char *argv[]) {
		{"help", no_argument, 0, 'h'},
		{0}
	};
	for (int opt; (opt = getopt_long(argc, argv, "d:o:p:h", long_options)) != -1;) {
	for (int opt; (opt = getopt_long(argc, argv, "d:o:p:h", long_options, NULL, 0)) != -1;) {
		switch (opt) {
		case 'R':
			options.remove_whitespace = true;


@@ 207,14 207,17 @@ const uint8_t flipped[256] = {
};

bool flip_exists(const uint8_t *tile, const uint8_t *tiles, int tile_size, int num_tiles, bool xflip, bool yflip) {
	uint8_t flip[tile_size]; // VLA
	memset(flip, 0, tile_size);
	uint8_t *flip;
	bool ret;
	flip = mallocz(tile_size, 1);
	int half_size = tile_size / 2;
	for (int i = 0; i < tile_size; i++) {
		int j = yflip ? (options.interleave && i < half_size ? half_size : tile_size) - 1 - (i ^ 1) : i;
		flip[j] = xflip ? flipped[tile[i]] : tile[i];
	}
	return tile_exists(flip, tiles, tile_size, num_tiles);
	ret = tile_exists(flip, tiles, tile_size, num_tiles);
	free(flip);
	return ret;
}

void remove_flip(struct Graphic *graphic, bool xflip, bool yflip) {

A tools/mkfile => tools/mkfile +15 -0
@@ 0,0 1,15 @@
</$objtype/mkfile

OFILES=\
	getopt.$O\

TARG=\
	gfx\
	pkmncompress\

# ThIs MaKeS It PoRtAbLe
POSIX=-D PRIu32="ud" -DPRId32="d" -DPRIx32="x" -DPRIX32="X" -DPRIo32="o" -DSTDOUT_FILENO=1 -DSTDIN_FILENO=0 -DPRIu8="ud" -DPRIu16="ud" -DPRId16="d" -DPRIx16="x" -DPRIX16="X" -DMB_LEN_MAX=4 -DUINT32_C='(uint32_t)'

CFLAGS=$CFLAGS -I/sys/include/npe -D__plan9__ -D__${objtype}__ $POSIX

</sys/src/cmd/mkmany