From cd3d125861d25ab60393e29e991f55f26a3874f4 Mon Sep 17 00:00:00 2001 From: yenatch Date: Sun, 18 Jun 2017 00:09:25 -0400 Subject: [PATCH] Add `gfx` tool for graphics postprocessing --- tools/Makefile | 3 +- tools/common.h | 37 +++++++++++++++ tools/gfx.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 tools/common.h create mode 100644 tools/gfx.c diff --git a/tools/Makefile b/tools/Makefile index 4a04027fc..9e40bcd27 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -6,7 +6,8 @@ all: \ scan_includes \ palette \ pokemon_animation \ - pokemon_animation_graphics + pokemon_animation_graphics \ + gfx @: %: %.c diff --git a/tools/common.h b/tools/common.h new file mode 100644 index 000000000..bc877ccb9 --- /dev/null +++ b/tools/common.h @@ -0,0 +1,37 @@ +#ifndef GUARD_COMMON_H +#define GUARD_COMMON_H + +int __getopt_long_i__; +#define getopt_long(c, v, s, l) getopt_long(c, v, s, l, &__getopt_long_i__) + +FILE *fopen_verbose(char *filename, char *mode) { + FILE *f = fopen(filename, mode); + if (!f) { + fprintf(stderr, "Could not open file: \"%s\"\n", filename); + } + return f; +} + +uint8_t *read_u8(char *filename, int *size) { + FILE *f = fopen_verbose(filename, "rb"); + if (!f) { + exit(1); + } + fseek(f, 0, SEEK_END); + *size = ftell(f); + rewind(f); + uint8_t *data = malloc(*size); + fread(data, 1, *size, f); + fclose(f); + return data; +} + +void write_u8(char *filename, uint8_t *data, int size) { + FILE *f = fopen_verbose(filename, "wb"); + if (f) { + fwrite(data, 1, size, f); + fclose(f); + } +} + +#endif // GUARD_COMMON_H diff --git a/tools/gfx.c b/tools/gfx.c new file mode 100644 index 000000000..85ce44625 --- /dev/null +++ b/tools/gfx.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +#include "common.h" + +static void usage(void) { + fprintf(stderr, "Usage: gfx [--trim-whitespace] [--remove-whitespace] [-d depth] [-h] [-o outfile] infile \n"); +} + +struct Options { + int trim_whitespace; + int remove_whitespace; + int help; + char *outfile; + int depth; +}; + +struct Options Options = { + .depth = 2, +}; + +void get_args(int argc, char *argv[]) { + struct option long_options[] = { + {"remove-whitespace", no_argument, &Options.remove_whitespace, 1}, + {"trim-whitespace", no_argument, &Options.trim_whitespace, 1}, + {"depth", required_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {0} + }; + for (int opt = 0; opt != -1;) { + switch(opt = getopt_long(argc, argv, "ho:d:", long_options)) { + case 'h': + Options.help = true; + break; + case 'o': + Options.outfile = optarg; + break; + case 'd': + Options.depth = strtoul(optarg, NULL, 0); + break; + case 0: + case -1: + break; + default: + printf("ay %d", opt); + usage(); + exit(1); + break; + } + } +} + +bool is_whitespace(uint8_t *tile, int tile_size) { + uint8_t WHITESPACE = 0; + for (int i = 0; i < tile_size; i++) { + if (tile[i] != WHITESPACE) { + return false; + } + } + return true; +} + +void trim_whitespace(char *infile, char *outfile) { + int size; + uint8_t *data = read_u8(infile, &size); + int tile_size = Options.depth * 8; + for (int i = size - tile_size; i > 0; i -= tile_size) { + if (is_whitespace(&data[i], tile_size)) { + size = i; + } else { + break; + } + } + write_u8(outfile, data, size); +} + +void remove_whitespace(char *infile, char *outfile) { + int size; + uint8_t *data = read_u8(infile, &size); + int tile_size = Options.depth * 8; + int i = 0; + for (int j = 0; i < size && j < size; i += tile_size, j += tile_size) { + while (is_whitespace(&data[j], tile_size)) { + j += tile_size; + } + if (j > i) { + memcpy(&data[i], &data[j], tile_size); + } + } + size = i; + write_u8(outfile, data, size); +} + +int main(int argc, char *argv[]) { + get_args(argc, argv); + argc -= optind; + argv += optind; + if (Options.help) { + usage(); + return 0; + } + if (argc < 1) { + usage(); + exit(1); + } + char *infile = argv[0]; + if (Options.remove_whitespace) { + if (Options.outfile) { + remove_whitespace(infile, Options.outfile); + } + } else if (Options.trim_whitespace) { + if (Options.outfile) { + trim_whitespace(infile, Options.outfile); + } + } + return 0; +}