diff --git a/mtsread.c b/mtsread.c index acdf4d9..7e8fef6 100644 --- a/mtsread.c +++ b/mtsread.c @@ -28,6 +28,11 @@ #define MTSCHEM_FILE_SIGNATURE 0x4d54534d /* 'MTSM' */ #define MTSCHEM_FILE_VERSION 4 +#define BUFSIZE 512 + +#define is_newline(c) ((c) == '\n' || (c) == '\r') +#define is_whitespace(c) (is_newline(c) || (c) == '\t' || (c) == ' ') + typedef struct mts_header { uint32_t signature; uint16_t version; @@ -46,6 +51,13 @@ typedef struct mts { uint8_t *param2; /* param2 (length X*Y*Z, offset 3*X*Y*Z) */ } mts; +typedef struct colour { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t override; +} colour; + #define foreach_node(schematic, x, y, z) \ for (uint16_t x = 0; x < schematic.header.size_x; x++) \ for (uint16_t y = 0; y < schematic.header.size_y; y++) \ @@ -188,6 +200,53 @@ size_t lookup_name_by_id(mts_header *header, uint16_t id, char **name) { return 2; } +void read_colour(char *s, colour *c) { + uint32_t i = strtol(s, NULL, 16); + while (i > 0xffffff) + i = i >> 4; + c->red = (i & 0xff0000) >> 16; + c->green = (i & 0x00ff00) >> 8; + c->blue = i & 0x0000ff; +} + +colour *read_colourmap(FILE *stream, mts_header *header) { + char buf[BUFSIZE] = {0}; + colour *colourmap = calloc_or_fail(header->name_id_count, sizeof(colour)); + while (fgets(buf, BUFSIZE, stream)) { + colour c; + uint16_t id; + size_t name_end = 0; + for (size_t i = 0; i < BUFSIZE; i++) { + if (is_whitespace(buf[i])) { + buf[i] = '\0'; + name_end = i; + break; + } + } + if (!lookup_id_by_name(header, &id, buf)) { + if (strcmp(buf, "?")) { + fprintf(stderr, "Invalid name: %s\n", buf); + continue; + } + c.override = 0; + } else c.override = 1; + for (size_t i = name_end; i < BUFSIZE; i++) { + if (is_newline(buf[i])) { + buf[i] = '\0'; + break; + } + } + read_colour(&buf[name_end + 1], &c); + if (c.override) + colourmap[id] = c; + else + for (id = 0; id < header->name_id_count; id++) + if (!colourmap[id].override) + colourmap[id] = c; + } + return colourmap; +} + void print_node(mts *schematic, uint16_t x, uint16_t y, uint16_t z) { char *name; uint16_t param0 = index_param0(schematic, x, y, z); @@ -208,7 +267,8 @@ void usage(int status) { "\tdump <x> <y> <z>\tDump param0-2 for a single node\n" "\tlist <name>\tList all nodes of a certain type by name\n" "\tcountall\tCount all nodes by name\n" - "\tcount <name>\tCount all nodes of a certain type by name\n"); + "\tcount <name>\tCount all nodes of a certain type by name\n" + "\tmap <depth>\tMake a PBM map of all nodes in a single layer. Takes name->colour map from stdin\n"); exit(status); } @@ -315,6 +375,26 @@ int main(int argc, char *argv[]) { if (index_param0(&schematic, x, y, z) == id) count++; printf("%lu\n", count); + } else if (!strcmp(argv[2], "map") && argc > 3) { + colour *colourmap; + int y = atoi(argv[3]); + if (y < 0 || y >= schematic.header.size_y) { + fprintf(stderr, "Depth must be between 0 and %d\n", schematic.header.size_y - 1); + return 1; + } + read_nodedefs(fd, &schematic); + colourmap = read_colourmap(stdin, &schematic.header); + printf("P3\n%d %d\n255\n", + schematic.header.size_x, + schematic.header.size_z); + for (uint16_t x = 0; x < schematic.header.size_x; x++) { + for (uint16_t z = 0; z < schematic.header.size_z; z++) { + colour c = colourmap[index_param0(&schematic, x, y, z)]; + printf("%hhu %hhu %hhu ", c.red, c.green, c.blue); + } + printf("\n"); + } + free(colourmap); } else usage(1); return 0; }