From 28387947e2ac4bb2110b8b5930c00d293b2fbcf9 Mon Sep 17 00:00:00 2001 From: krimtonz <33664508+krimtonz@users.noreply.github.com> Date: Sun, 26 Apr 2020 17:14:41 -0500 Subject: [PATCH] vtx extractor (#94) --- tools/.gitignore | 1 + tools/Makefile | 3 +- tools/vtxdis.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 tools/vtxdis.c diff --git a/tools/.gitignore b/tools/.gitignore index c52361c4a3..2da9fd53e6 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -4,3 +4,4 @@ yaz0 makeromfs elf2rom mkldscript +vtxdis diff --git a/tools/Makefile b/tools/Makefile index dd514d09eb..f8147317c2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,6 +1,6 @@ CC := gcc CFLAGS := -Wall -Wextra -pedantic -std=c99 -g -O2 -PROGRAMS := yaz0 makeromfs elf2rom mkldscript +PROGRAMS := yaz0 makeromfs elf2rom mkldscript vtxdis ZAP2 := ZAP2/ZAP2.out all: $(PROGRAMS) @@ -15,6 +15,7 @@ mkldscript_SOURCES := mkldscript.c util.c elf2rom_SOURCES := elf2rom.c elf32.c n64chksum.c util.c yaz0_SOURCES := yaz0tool.c yaz0.c util.c makeromfs_SOURCES := makeromfs.c n64chksum.c util.c +vtxdis_SOURCES := vtxdis.c #$(ZAP2): # cd ZAP2 && $(MAKE) diff --git a/tools/vtxdis.c b/tools/vtxdis.c new file mode 100644 index 0000000000..6650eec1d5 --- /dev/null +++ b/tools/vtxdis.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define VTXDIS_VER "0.1" + +#define SWAP16(x) (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) + +typedef struct { + int16_t pos[3]; /* 0x00 */ + int16_t flag; /* 0x06 */ + int16_t tpos[2]; /* 0x08 */ + uint8_t cn[4]; /* 0x0C */ +} Vtx; /* 0x10 */ + +static char *filename = NULL; +static char *data = NULL; +static int offset = 0; +static int data_len = 0; +static int count = 0; + +const struct option cmdline_opts[] = { + { "offset", required_argument, NULL, 'o', }, + { "length", required_argument, NULL, 'l', }, + { "file" , required_argument, NULL, 'f', }, + { "version", no_argument, NULL, '~', }, + { "help", no_argument, NULL, '?', }, + { "count", required_argument, NULL, 'c', }, + { 0, 0, 0, 0 }, +}; + +static uint32_t parse_int(const char *num){ + uint32_t ret = 0; + char outnum[20]; + if(strlen(num) > 2 && num[0] == '0' && (num[1] == 'x' || num[1] == 'X')) { + strncpy(outnum, &num[2], 20); + sscanf(outnum, "%"SCNx32, &ret); + } else if(strlen(num) == 0){ + ret = -1; + } else { + strncpy(outnum, num, 20); + sscanf(outnum, "%"SCNu32, &ret); + } + return ret; + +} + +static void print_usage(void) +{ + puts("vtxdis version " VTXDIS_VER "\n" + "Usage:\n" + " vtxdis -f/--file FILE [options]\n" + " vtxdis -?/--help\n" + " vtxdis --version\n" + "Options:\n" + " -f, --file The file path to extract vertex data from.\n" + " -c, --count The number of vertices to extract.\n" + " -l, --length The amount of data to extract vertices from.\n" + " -o, --offset The offset into file to start reading vertex data.\n" + " -?, --help Prints this help message\n" + " --version Prints the current version\n" + ); +} + +static void print_version(void){ + puts("Version: " VTXDIS_VER); +} + +static void print_vtx_data(Vtx *vtx, int vtx_cnt) +{ + printf("{\n"); + for(int i = 0; i < vtx_cnt; i++) + { + Vtx *v = &vtx[i]; + + printf(" VTX(%d, %d, %d, %d, %d, 0x%02X, 0x%02X, 0x%02X, 0x%02X),\n", v->pos[0], v->pos[1], v->pos[2], v->tpos[0], v->tpos[1], v->cn[0], v->cn[1], v->cn[2], v->cn[3]); + } + printf("}\n"); +} + +static void parse_file(void) +{ + int alloc_size = 0; + struct stat sbuffer; + stat(filename, &sbuffer); + if(errno != 0){ + perror("Count not stat file."); + exit(1); + } + + /* sanity checks */ + if(count > 0) + { + alloc_size = sizeof(Vtx) * count; + if((offset > 0 && (offset + alloc_size) > sbuffer.st_size) || alloc_size > sbuffer.st_size) + { + printf("Requested data is beyond file boundaries."); + exit(1); + } + } + else if(data_len > 0) + { + alloc_size = data_len; + + if((offset > 0 && (offset + alloc_size) > sbuffer.st_size) || alloc_size > sbuffer.st_size) + { + printf("Requested data is beyond file boundaries."); + exit(1); + } + } + else + { + if (offset > 0) + { + alloc_size = sbuffer.st_size - offset; + } + else + { + alloc_size = sbuffer.st_size; + } + } + + if(alloc_size % sizeof(Vtx) != 0) + { + printf("Requested data size is not a multiple of sizeof(Vtx). Requested size is %8x", alloc_size); + exit(1); + } + + FILE *file = fopen(filename, "rb"); + if(!file){ + perror("Could not open file"); + exit(1); + } + + if(offset > 0){ + if(fseek(file, offset, SEEK_SET)){ + perror("Could not seek file"); + fclose(file); + exit(1); + } + } + + Vtx *data = NULL; + data = malloc(alloc_size); + if(!data){ + fclose(file); + perror("Could not allocate vtx data"); + exit(1); + } + + if(!fread(data, alloc_size, 1, file)){ + perror("Could not read from file"); + fclose(file); + free(data); + exit(1); + } + + fclose(file); + + int vtx_cnt = alloc_size / sizeof(Vtx); + for(int i = 0; i < vtx_cnt; i++){ + Vtx *v = &data[i]; + + v->pos[0] = SWAP16(v->pos[0]); + v->pos[1] = SWAP16(v->pos[1]); + v->pos[2] = SWAP16(v->pos[2]); + v->flag = SWAP16(v->flag); + v->tpos[0] = SWAP16(v->tpos[0]); + v->tpos[1] = SWAP16(v->tpos[1]); + } + + print_vtx_data(data, vtx_cnt); + free(data); +} + +int main(int argc, char **argv) +{ + int opt; + int argv_idx = 0; + while(1){ + argv_idx++; + opt = getopt_long(argc, argv, "o:l:f:c:v?", cmdline_opts, NULL); + if(opt == -1){ + break; + } + switch(opt){ + case 'd': + data = optarg; + break; + case '~': + print_version(); + return 0; + case '?': + print_usage(); + return 0; + case 'l': + data_len = parse_int(optarg); + break; + case 'o': + offset = parse_int(optarg); + break; + case 'f': + filename = optarg; + break; + case 'c': + count = parse_int(optarg); + break; + } + } + + if (filename == NULL && data == NULL) + { + printf("Must specify -f or -d\n"); + print_usage(); + exit(1); + } + + if(data_len < 0) + { + printf("Invalid -l/--length parameter passed."); + print_usage(); + exit(1); + } + + if(offset < 0) + { + printf("Invalid -o/--offset parameter passed."); + print_usage(); + exit(1); + } + + if(count < 0) + { + printf("Invalid -c/--count parameter passed."); + print_usage(); + exit(1); + } + + if(count > 0 && data_len > 0) + { + printf("Cannot specify both -c/--count and -l/--length."); + print_usage(); + exit(1); + } + + if(filename != NULL) + { + parse_file(); + } + + return 0; +} \ No newline at end of file