From 2ab468268aa156ae60e0e60a1319552342f692f6 Mon Sep 17 00:00:00 2001 From: yenatch Date: Wed, 24 Aug 2016 21:56:07 -0400 Subject: Add C build tools. --- tools/lzcomp.c | 404 +++++++++++++++++++++++++++++++++++++ tools/palette.c | 89 ++++++++ tools/png_dimensions.c | 53 +++++ tools/pokemon_animation.c | 256 +++++++++++++++++++++++ tools/pokemon_animation_graphics.c | 165 +++++++++++++++ tools/scan_includes.c | 85 ++++++++ 6 files changed, 1052 insertions(+) create mode 100644 tools/lzcomp.c create mode 100644 tools/palette.c create mode 100644 tools/png_dimensions.c create mode 100644 tools/pokemon_animation.c create mode 100644 tools/pokemon_animation_graphics.c create mode 100644 tools/scan_includes.c (limited to 'tools') diff --git a/tools/lzcomp.c b/tools/lzcomp.c new file mode 100644 index 000000000..1b7b32a5d --- /dev/null +++ b/tools/lzcomp.c @@ -0,0 +1,404 @@ +#include +#include +#include +#include + +#define COMPRESSION_METHODS 72 + +struct command { + unsigned command: 3; + unsigned count: 12; + signed value: 17; +}; + +int main(int, char **); +void error_exit(int, const char *, ...); +void bit_flip(const unsigned char *, unsigned short, unsigned char *); +unsigned char * read_file_into_buffer(const char *, unsigned short *); +void write_commands_to_file(const char *, const struct command *, unsigned, const unsigned char *); +void write_command_to_file(FILE *, struct command, const unsigned char *); +struct command * compress(const unsigned char *, unsigned short *); +struct command * try_compress(const unsigned char *, const unsigned char *, unsigned short *, unsigned); +struct command find_best_copy(const unsigned char *, unsigned short, unsigned short, const unsigned char *, unsigned); +unsigned short scan_forwards(const unsigned char *, unsigned short, const unsigned char *, unsigned short, short *); +unsigned short scan_backwards(const unsigned char *, unsigned short, unsigned short, short *); +struct command find_best_repetition(const unsigned char *, unsigned short, unsigned short); +struct command pick_best_command(unsigned, struct command, ...); +int is_better(struct command, struct command); +short command_size(struct command); +void optimize(struct command *, unsigned short); +void repack(struct command **, unsigned short *); +struct command * select_command_sequence(struct command **, const unsigned short *, unsigned, unsigned short *); +struct command * merge_command_sequences(const struct command *, unsigned short, const struct command *, unsigned short, unsigned short *); +unsigned short compressed_length(const struct command *, unsigned short); + +int main (int argc, char ** argv) { + if (argc < 3) { + fprintf(stderr, "usage: %s \n", *argv); + return 3; + } + unsigned short size; + unsigned char * file_buffer = read_file_into_buffer(argv[1], &size); + struct command * compressed = compress(file_buffer, &size); + write_commands_to_file(argv[2], compressed, size, file_buffer); + free(file_buffer); + free(compressed); + return 0; +} + +void error_exit (int error_code, const char * error, ...) { + va_list ap; + va_start(ap, error); + fputs("error: ", stderr); + vfprintf(stderr, error, ap); + fputc('\n', stderr); + exit(error_code); +} + +void bit_flip (const unsigned char * data, unsigned short length, unsigned char * result) { + unsigned char new_value, pos; + while (length --) { + new_value = 0; + for (pos = 0; pos < 8; pos ++) new_value |= ((*data >> pos) & 1) << (7 - pos); + *(result ++) = new_value; + data ++; + } +} + +unsigned char * read_file_into_buffer (const char * file, unsigned short * size) { + FILE * fp = fopen(file, "rb"); + if (!fp) error_exit(1, "could not open file %s for reading", file); + unsigned char * buf = malloc(32769); + int rv = fread(buf, 1, 32769, fp); + fclose(fp); + if (rv < 0) error_exit(1, "could not read from file %s", file); + if (rv > 32768) error_exit(1, "file %s is too big", file); + *size = rv; + return buf; +} + +void write_commands_to_file (const char * file, const struct command * commands, unsigned count, const unsigned char * input_stream) { + FILE * fp = fopen(file, "wb"); + if (!fp) error_exit(1, "could not open file %s for writing", file); + while (count --) write_command_to_file(fp, *(commands ++), input_stream); + unsigned char terminator = -1; + if (fwrite(&terminator, 1, 1, fp) != 1) error_exit(1, "could not write terminator to compressed output"); + fclose(fp); +} + +void write_command_to_file (FILE * fp, struct command command, const unsigned char * input_stream) { + if ((!command.count) || (command.count > 1024)) error_exit(2, "invalid command in output stream"); + unsigned char buf[4]; + unsigned char * pos = buf; + int n; + command.count --; + if (command.count < 32) + *(pos ++) = (command.command << 5) + command.count; + else { + *(pos ++) = 224 + (command.command << 2) + (command.count >> 8); + *(pos ++) = command.count; + } + switch (command.command) { + case 1: case 2: + if ((command.value < 0) || (command.value >= (1 << (command.command << 3)))) error_exit(2, "invalid command in output stream"); + for (n = 0; n < command.command; n ++) *(pos ++) = command.value >> (n << 3); + case 0: case 3: + break; + default: + if ((command.value < -128) || (command.value > 32767)) error_exit(2, "invalid command in output stream"); + if (command.value < 0) + *(pos ++) = command.value ^ 127; + else { + *(pos ++) = command.value >> 8; + *(pos ++) = command.value; + } + } + if (fwrite(buf, 1, pos - buf, fp) != (pos - buf)) error_exit(1, "could not write command to compressed output"); + if (command.command) return; + command.count ++; + if (fwrite(input_stream + command.value, 1, command.count, fp) != command.count) error_exit(1, "could not write data to compressed output"); +} + +struct command * compress (const unsigned char * data, unsigned short * size) { + unsigned char * bitflipped = malloc(*size); + bit_flip(data, *size, bitflipped); + struct command * compressed_sequences[COMPRESSION_METHODS]; + unsigned short lengths[COMPRESSION_METHODS]; + unsigned current; + for (current = 0; current < COMPRESSION_METHODS; current ++) { + lengths[current] = *size; + compressed_sequences[current] = try_compress(data, bitflipped, lengths + current, current); + } + free(bitflipped); + struct command * result = select_command_sequence(compressed_sequences, lengths, COMPRESSION_METHODS, size); + for (current = 0; current < COMPRESSION_METHODS; current ++) free(compressed_sequences[current]); + return result; +} + +struct command * try_compress (const unsigned char * data, const unsigned char * bitflipped, unsigned short * length, unsigned flags) { + struct command * commands = malloc(sizeof(struct command) * *length); + memset(commands, -1, sizeof(struct command) * *length); + struct command * current_command = commands; + unsigned short position = 0, previous_data = 0; + unsigned char lookahead = 0, lookahead_flag = (flags >> 3) % 3; + struct command copy, repetition; + while (position < *length) { + copy = find_best_copy(data, position, *length, bitflipped, flags); + repetition = find_best_repetition(data, position, *length); + if (flags & 1) + *current_command = pick_best_command(2, repetition, copy); + else + *current_command = pick_best_command(2, copy, repetition); + *current_command = pick_best_command(2, (struct command) {.command = 0, .count = 1, .value = position}, *current_command); + if (flags & 2) { + if (previous_data && (previous_data != 32) && (previous_data != 1024) && (command_size(*current_command) == current_command -> count)) + *current_command = (struct command) {.command = 0, .count = 1, .value = position}; + } + if (lookahead_flag) { + if (lookahead >= lookahead_flag) + lookahead = 0; + else if (current_command -> command) { + lookahead ++; + *current_command = (struct command) {.command = 0, .count = 1, .value = position}; + } + } + if (current_command -> command) + previous_data = 0; + else + previous_data += current_command -> count; + position += (current_command ++) -> count; + } + optimize(commands, current_command - commands); + repack(&commands, length); + return commands; +} + +struct command find_best_copy (const unsigned char * data, unsigned short position, unsigned short length, const unsigned char * bitflipped, unsigned flags) { + struct command simple = {.command = 7}; + struct command flipped = simple, backwards = simple; + short count, offset; + if (count = scan_forwards(data + position, length - position, data, position, &offset)) + simple = (struct command) {.command = 4, .count = count, .value = offset}; + if (count = scan_forwards(data + position, length - position, bitflipped, position, &offset)) + flipped = (struct command) {.command = 5, .count = count, .value = offset}; + if (count = scan_backwards(data, length - position, position, &offset)) + backwards = (struct command) {.command = 6, .count = count, .value = offset}; + struct command command; + switch (flags / 24) { + case 0: command = pick_best_command(3, simple, backwards, flipped); break; + case 1: command = pick_best_command(3, backwards, flipped, simple); break; + case 2: command = pick_best_command(3, flipped, backwards, simple); + } + if ((flags & 4) && (command.count > 32)) command.count = 32; + return command; +} + +unsigned short scan_forwards (const unsigned char * target, unsigned short limit, const unsigned char * source, unsigned short real_position, short * offset) { + unsigned short best_match, best_length = 0; + unsigned short current_length; + unsigned short position; + for (position = 0; position < real_position; position ++) { + if (source[position] != *target) continue; + for (current_length = 0; (current_length < limit) && (source[position + current_length] == target[current_length]); current_length ++); + if (current_length > 1024) current_length = 1024; + if (current_length < best_length) continue; + best_match = position; + best_length = current_length; + } + if (!best_length) return 0; + if ((best_match + 128) >= real_position) + *offset = best_match - real_position; + else + *offset = best_match; + return best_length; +} + +unsigned short scan_backwards (const unsigned char * data, unsigned short limit, unsigned short real_position, short * offset) { + if (real_position < limit) limit = real_position; + unsigned short best_match, best_length = 0; + unsigned short current_length; + unsigned short position; + for (position = 0; position < real_position; position ++) { + if (data[position] != data[real_position]) continue; + for (current_length = 0; (current_length < limit) && (data[position - current_length] == data[real_position + current_length]); current_length ++); + if (current_length > 1024) current_length = 1024; + if (current_length < best_length) continue; + best_match = position; + best_length = current_length; + } + if (!best_length) return 0; + if ((best_match + 128) >= real_position) + *offset = best_match - real_position; + else + *offset = best_match; + return best_length; +} + +struct command find_best_repetition (const unsigned char * data, unsigned short position, unsigned short length) { + if ((position + 1) >= length) return data[position] ? ((struct command) {.command = 7}) : ((struct command) {.command = 3, .count = 1}); + unsigned char value[2] = {data[position], data[position + 1]}; + unsigned repcount, limit = length - position; + if (limit > 1024) limit = 1024; + for (repcount = 2; (repcount < limit) && (data[position + repcount] == value[repcount & 1]); repcount ++); + struct command result; + result.count = repcount; + if (*value != value[1]) { + if (!*value && (repcount < 3)) return (struct command) {.command = 3, .count = 1}; + result.command = 2; + result.value = ((unsigned) (*value)) | (((unsigned) (value[1])) << 8); + } else if (*value) { + result.command = 1; + result.value = *value; + } else + result.command = 3; + return result; +} + +struct command pick_best_command (unsigned count, struct command command, ...) { + struct command result = command; + va_list ap; + va_start(ap, command); + while (-- count) { + command = va_arg(ap, struct command); + if (is_better(command, result)) result = command; + } + va_end(ap); + return result; +} + +int is_better (struct command new, struct command old) { + if (new.command == 7) return 0; + if (old.command == 7) return 1; + short new_savings = new.count - command_size(new), old_savings = old.count - command_size(old); + return new_savings > old_savings; +} + +short command_size (struct command command) { + short header_size = 1 + (command.count > 32); + if (command.command & 4) return header_size + 1 + (command.value >= 0); + return header_size + command.command[(short []) {command.count, 1, 2, 0}]; +} + +void optimize (struct command * commands, unsigned short count) { + while (count && (commands -> command == 7)) commands ++, count --; + if (count < 2) return; + struct command * end = commands + count; + struct command * next = commands + 1; + while (next < end) { + if (next -> command == 7) goto skip; + if ( + !(commands -> command) && + (command_size(*next) == next -> count) && + ((commands -> count + next -> count) <= 1024) && + ((commands -> count > 32) || ((commands -> count + next -> count) <= 32)) + ) { + commands -> count += next -> count; + next -> command = 7; + goto skip; + } + if (next -> command != commands -> command) goto accept; + switch (commands -> command) { + case 0: + if ((commands -> value + commands -> count) != next -> value) break; + commands -> count += next -> count; + next -> command = 7; + if (commands -> count <= 1024) goto skip; + next -> command = 0; + next -> value = commands -> value + 1024; + next -> count = commands -> count - 1024; + commands -> count = 1024; + break; + case 1: + if (commands -> value != next -> value) break; + case 3: + if ((commands -> count + next -> count) <= 1024) { + commands -> count += next -> count; + next -> command = 7; + goto skip; + } + next -> count = (commands -> count + next -> count) - 1024; + commands -> count = 1024; + break; + } + accept: + commands = next; + skip: + next ++; + } +} + +void repack (struct command ** commands, unsigned short * length) { + struct command * new_commands = malloc(sizeof(struct command) * *length); + struct command * current = new_commands; + unsigned short p; + for (p = 0; p < *length; p ++) if (p[*commands].command != 7) *(current ++) = p[*commands]; + free(*commands); + *commands = new_commands; + *length = current - new_commands; +} + +struct command * select_command_sequence (struct command ** sequences, const unsigned short * lengths, unsigned count, unsigned short * final_length) { + unsigned short min_sequence = 0, min_length = compressed_length(*sequences, *lengths); + unsigned short seq, len; + for (seq = 1; seq < count; seq ++) { + len = compressed_length(sequences[seq], lengths[seq]); + if (len < min_length) { + min_sequence = seq; + min_length = len; + } + } + *final_length = lengths[min_sequence]; + struct command * current = malloc(*final_length * sizeof(struct command)); + memcpy(current, sequences[min_sequence], *final_length * sizeof(struct command)); + struct command * new; + for (seq = 1; seq < count; seq ++) { + new = merge_command_sequences(current, *final_length, sequences[(seq + min_sequence) % count], lengths[(seq + min_sequence) % count], final_length); + free(current); + current = new; + } + return current; +} + +struct command * merge_command_sequences (const struct command * current, unsigned short current_length, const struct command * new, unsigned short new_length, + unsigned short * result_length) { + struct command * result = malloc(sizeof(struct command) * (current_length + new_length)); + struct command * current_command = result; + const struct command * saved_current; + const struct command * saved_new; + unsigned short current_pos, new_pos; + while (current_length) { + if (current -> count == new -> count) { + *(current_command ++) = pick_best_command(2, *(current ++), *(new ++)); + current_length --; + continue; + } + saved_current = current; + saved_new = new; + current_pos = (current ++) -> count; + new_pos = (new ++) -> count; + current_length --; + while (current_pos != new_pos) + if (current_pos < new_pos) { + current_pos += (current ++) -> count; + current_length --; + } else + new_pos += (new ++) -> count; + current_pos = compressed_length(saved_current, current - saved_current); + new_pos = compressed_length(saved_new, new - saved_new); + if (new_pos < current_pos) { + memcpy(current_command, saved_new, sizeof(struct command) * (new - saved_new)); + current_command += new - saved_new; + } else { + memcpy(current_command, saved_current, sizeof(struct command) * (current - saved_current)); + current_command += current - saved_current; + } + } + *result_length = current_command - result; + return result; +} + +unsigned short compressed_length (const struct command * commands, unsigned short count) { + unsigned short current, total = 0; + for (current = 0; current < count; current ++) if (commands[current].command != 7) total += command_size(commands[current]); + return total; +} diff --git a/tools/palette.c b/tools/palette.c new file mode 100644 index 000000000..c1beb40e4 --- /dev/null +++ b/tools/palette.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +void usage(void) { + printf("Usage: palette palfile\n"); + exit(1); +} + +void print_rgb(uint16_t word) { + int r, g, b; + r = word & 0x1f; + g = (word >> 5) & 0x1f; + b = (word >> 10) & 0x1f; + printf("\tRGB %2d, %2d, %2d\n", r, g, b); +} + +void print_pokemon_palette(char* palette_filename) { + FILE* f; + uint8_t bytes[4]; + + f = fopen(palette_filename, "rb"); + if (f == NULL) { + fprintf(stderr, "failed to open file %s\n", palette_filename); + exit(1); + } + + fseek(f, 2, SEEK_SET); + fread(bytes, 1, 4, f); + fclose(f); + + print_rgb((bytes[1] << 8) | bytes[0]); + print_rgb((bytes[3] << 8) | bytes[2]); +} + +void print_palette(char* palette_filename) { + FILE* f; + uint8_t* bytes; + long size; + int i; + + f = fopen(palette_filename, "rb"); + if (f == NULL) { + fprintf(stderr, "failed to open file %s\n", palette_filename); + exit(1); + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + bytes = malloc(size); + + fseek(f, 0, SEEK_SET); + fread(bytes, 1, size, f); + fclose(f); + + for (i = 0; i + 1 < size; i += 2) { + print_rgb((bytes[i + 1] << 8) | bytes[i]); + } +} + +int main(int argc, char* argv[]) { + int ch; + bool pokemon; + + while ((ch = getopt(argc, argv, "p")) != -1) { + switch (ch) { + case 'p': + pokemon = true; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc < 1) { + usage(); + } + if (pokemon) { + print_pokemon_palette(argv[0]); + } else { + print_palette(argv[0]); + } + return 0; +} diff --git a/tools/png_dimensions.c b/tools/png_dimensions.c new file mode 100644 index 000000000..5bdc12e4c --- /dev/null +++ b/tools/png_dimensions.c @@ -0,0 +1,53 @@ +#include +#include +#include + +void usage(void) { + fprintf(stderr, "Usage: png_dimensions infile, outfile\n"); + exit(1); +} + +void output_dimensions(char* png_filename, char* out_filename) { + FILE* f; + int width, height; + int i; + uint8_t bytes[4]; + uint8_t output; + + f = fopen(png_filename, "rb"); + if (f == NULL) { + fprintf(stderr, "failed to open file %s\n", png_filename); + exit(1); + } + + // width + fseek(f, 16, SEEK_SET); + fread(bytes, 1, 4, f); + fclose(f); + + width = 0; + for (i = 0; i < 4; i++) { + width |= bytes[i] << (8 * (3 - i)); + } + width >>= 3; + height = width; + + output = width & 0xf; + output |= (height & 0xf) << 4; + + f = fopen(out_filename, "wb"); + if (f == NULL) { + fprintf(stderr, "failed to open file %s\n", out_filename); + exit(1); + } + fwrite(&output, 1, 1, f); + fclose(f); +} + +int main(int argc, char* argv[]) { + if (argc < 3) { + usage(); + } + output_dimensions(argv[1], argv[2]); + return 0; +} diff --git a/tools/pokemon_animation.c b/tools/pokemon_animation.c new file mode 100644 index 000000000..67a9194c9 --- /dev/null +++ b/tools/pokemon_animation.c @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include + +struct Frame { + uint8_t* data; + int size; + int bitmask; +}; + +struct Frames { + struct Frame* frames; + int num_frames; + int frame_size; +}; + +struct Bitmask { + uint8_t* data; + int bitlength; +}; + +struct Bitmasks { + struct Bitmask* bitmasks; + int num_bitmasks; +}; + + +void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap_filename, char* dimensions_filename); +int bitmask_exists(struct Bitmask bitmask, struct Bitmasks bitmasks); +void print_frames(); + + +void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap_filename, char* dimensions_filename) { + uint8_t* tilemap; + uint8_t* this_frame; + FILE* f; + long size; + int width; + int height; + uint8_t byte; + struct Frame* frame; + struct Bitmask* bitmask; + int frame_size; + int num_frames; + int i, j; + + f = fopen(tilemap_filename, "rb"); + if (f == NULL) { + fprintf(stderr, "could not open file %s", tilemap_filename); + exit(1); + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + tilemap = malloc(size); + fread(tilemap, 1, size, f); + fclose(f); + + f = fopen(dimensions_filename, "rb"); + if (f == NULL) { + fprintf(stderr, "could not open file %s", dimensions_filename); + exit(1); + } + fread(&byte, 1, 1, f); + fclose(f); + + width = byte & 0xf; + height = byte >> 4; + + frame_size = width * height; + + num_frames = size / frame_size - 1; + //fprintf(stderr, "num_frames: %d\n", num_frames); + + bitmasks->bitmasks = malloc((sizeof (struct Bitmask*)) * num_frames); + bitmasks->num_bitmasks = 0; + + frames->frames = malloc((sizeof (struct Frame*)) * num_frames); + frames->frame_size = frame_size; + frames->num_frames = 0; + + this_frame = tilemap + frame_size; + for (i = 0; i < num_frames; i++) { + frame = (struct Frame*)malloc(sizeof(struct Frame)); + frame->data = malloc(frame_size); + frame->size = 0; + bitmask = (struct Bitmask*)malloc(sizeof(struct Bitmask)); + bitmask->data = malloc((frame_size + 7) / 8); + bitmask->bitlength = 0; + for (j = 0; j < frame_size; j++) { + if (this_frame[j] != tilemap[j]) { + frame->data[frame->size] = this_frame[j]; + frame->size++; + bitmask->data[bitmask->bitlength / 8] |= 1; + } + bitmask->bitlength++; + if (bitmask->bitlength % 8 != 0) { + bitmask->data[bitmask->bitlength / 8] <<= 1; + } + } + frame->bitmask = bitmask_exists(*bitmask, *bitmasks); + if (frame->bitmask == -1) { + frame->bitmask = bitmasks->num_bitmasks; + bitmasks->bitmasks[bitmasks->num_bitmasks] = *bitmask; + bitmasks->num_bitmasks++; + } else { + free(bitmask->data); + free(bitmask); + } + frames->frames[i] = *frame; + frames->num_frames++; + this_frame += frame_size; + } + + //for (i = 0; i < frames->num_frames; i++) { + //free(frames->frames[i].data); + //free(frames->frames[i]); + //} + //free(frames->frames); + + //fprintf(stderr, "num bitmasks: %d", bitmasks->num_bitmasks); + //for (i = 0; i < bitmasks->num_bitmasks; i++) { + // free(bitmasks->bitmasks[i].data); + // fprintf(stderr, "freed bitmask %d\n", i); + //free(bitmasks->bitmasks[i]); + //} + //free(bitmasks->bitmasks); + //fprintf(stderr, "freed bitmasks\n"); + + free(tilemap); +} + +int bitmask_exists(struct Bitmask bitmask, struct Bitmasks bitmasks) { + int i, j; + struct Bitmask existing; + for (i = 0; i < bitmasks.num_bitmasks; i++) { + existing = bitmasks.bitmasks[i]; + if (bitmask.bitlength != existing.bitlength) { + continue; + } + for (j = 0; j < (bitmask.bitlength + 7) / 8; j++) { + if (bitmask.data[j] != existing.data[j]) { + break; + } + } + if (j == (bitmask.bitlength + 7) / 8) { + return i; + } + } + return -1; +} + +void print_frames(struct Frames* frames) { + int i; + int j; + struct Frame frame; + for (i = 0; i < frames->num_frames; i++) { + printf("\tdw .frame%d\n", i + 1); + } + for (i = 0; i < frames->num_frames; i++) { + frame = frames->frames[i]; + printf(".frame%d\n", i + 1); + printf("\tdb %d\n", frame.bitmask); + if (frame.size > 0) { + printf("\tdb %d", frame.data[0]); + for (j = 1; j < frame.size; j++) { + printf(", %d", frame.data[j]); + } + printf("\n"); + } + } +} + +void print_bitmasks(struct Bitmasks* bitmasks) { + int i, j, k; + int length; + struct Bitmask bitmask; + for (i = 0; i < bitmasks->num_bitmasks; i++) { + printf("; %d\n", i); + bitmask = bitmasks->bitmasks[i]; + length = (bitmask.bitlength + 7) / 8; + for (j = 0; j < length; j++) { + printf("\tdb %%"); + for (k = 0; k < 8; k++) { + if ((bitmask.data[j] >> (7 - k)) & 1) { + printf("1"); + } else { + printf("0"); + }; + } + printf("\n"); + } + } +} + +// HOW ARE YOU GENTLEMEN. +char* cats (char* head, char* tail) { + char* string; + string = malloc(strlen(head) + strlen(tail) + 1); + strcpy(string, head); + strcat(string, tail); + return string; +} + +static void usage(void) { + printf("Usage: pokemon_animation [-b] [-f] tilemap_file dimensions_file\n"); + exit(1); +} + +int main(int argc, char* argv[]) { + struct Frames frames = {0}; + struct Bitmasks bitmasks = {0}; + int ch; + bool use_bitmasks, use_frames; + char* tilemap_filename; + char* dimensions_filename; + + while ((ch = getopt(argc, argv, "bf")) != -1) { + switch (ch) { + case 'b': + use_bitmasks = true; + break; + case 'f': + use_frames = true; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc < 2) { + usage(); + } + tilemap_filename = argv[0]; + dimensions_filename = argv[1]; + + //ext = strrchr(argv[3], '.'); + //if (!ext || ext == argv[3]) { + // fprintf(stderr, "need a file extension to determine what to write to %s", argv[3]); + //} + + make_frames(&frames, &bitmasks, tilemap_filename, dimensions_filename); + if (use_frames) { + print_frames(&frames); + } + if (use_bitmasks) { + print_bitmasks(&bitmasks); + } + return 0; +} diff --git a/tools/pokemon_animation_graphics.c b/tools/pokemon_animation_graphics.c new file mode 100644 index 000000000..089928d11 --- /dev/null +++ b/tools/pokemon_animation_graphics.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include + +static void usage(void) { + printf("Usage: pokemon_animation_graphics [-o outfile] [-t mapfile] 2bpp_file dimensions_file\n"); + exit(1); +} + +struct Tilemap { + uint8_t* data; + int size; +}; + +struct Graphic { + uint8_t* data; + int size; +}; + +void transpose_tiles(uint8_t* tiles, int width, int size, int tile_size) { + int i; + int j; + uint8_t* new_tiles; + new_tiles = malloc(size); + for (i = 0; i < size; i++) { + j = i / tile_size * width * tile_size; + j = j % size + tile_size * (j / size) + i % tile_size; + new_tiles[j] = tiles[i]; + } + memcpy(tiles, new_tiles, size); + free(new_tiles); +} + +int get_tile_index(uint8_t* tile, uint8_t* tiles, int num_tiles) { + int i; + int j; + for (i = 0; i < num_tiles; i++) { + for (j = 0; j < 16; j++) { + if (tile[j] != tiles[16 * i + j]) { + break; + } + } + if (j == 16) { + return i; + } + } + return -1; +} + +void create_tilemap(struct Tilemap* tilemap, struct Graphic* graphic, char* graphics_filename, int width, int height) { + long graphics_size; + uint8_t* graphics; + FILE* f; + int tile; + int num_tiles; + int i; + + f = fopen(graphics_filename, "rb"); + fseek(f, 0, SEEK_END); + graphics_size = ftell(f); + rewind(f); + graphics = malloc(graphics_size); + fread(graphics, 1, graphics_size, f); + fclose(f); + + // transpose each frame + for (i = 0; i < graphics_size / (width * height); i++) { + transpose_tiles(graphics + i * (width * height) * 16, width, width * height * 16, 16); + } + + // first frame is naively populated with redundant tiles + num_tiles = width * height; + tilemap->data = malloc(graphics_size / 16); + for (i = 0; i < num_tiles; i++) { + tilemap->data[tilemap->size] = i; + tilemap->size++; + } + for (i = width * height; i < graphics_size / 16; i++) { + tile = get_tile_index(graphics + i * 16, graphics, i); + if (tile == -1) { + tilemap->data[tilemap->size] = num_tiles; + tilemap->size++; + num_tiles++; + } else { + tilemap->data[tilemap->size] = tile; + tilemap->size++; + } + } + + graphic->data = malloc(tilemap->size * 16); + graphic->size = 16 * width * height; + memcpy(graphic->data, graphics, graphic->size); + for (i = width * height; i < tilemap->size; i++) { + tile = get_tile_index(graphics + 16 * i, graphic->data, graphic->size / 16); + if (tile == -1) { + memcpy(graphic->data + graphic->size, graphics + 16 * i, 16); + graphic->size += 16; + } + } + + free(graphics); +} + +int main(int argc, char* argv[]) { + int ch; + char* dimensions_filename; + char* graphics_filename; + char* outfile; + char* mapfile; + FILE* f; + long size; + uint8_t bytes[1]; + int width; + int height; + struct Graphic graphic = {0}; + struct Tilemap tilemap = {0}; + + while ((ch = getopt(argc, argv, "o:t:")) != -1) { + switch (ch) { + case 'o': + outfile = optarg; + break; + case 't': + mapfile = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc < 2) { + usage(); + } + + graphics_filename = argv[0]; + dimensions_filename = argv[1]; + + f = fopen(dimensions_filename, "rb"); + fread(bytes, 1, 1, f); + fclose(f); + width = bytes[0] & 0xf; + height = bytes[0] >> 4; + + create_tilemap(&tilemap, &graphic, graphics_filename, width, height); + + if (outfile != NULL) { + f = fopen(outfile, "wb"); + fwrite(graphic.data, 1, graphic.size, f); + fclose(f); + } + + if (mapfile != NULL) { + f = fopen(mapfile, "wb"); + fwrite(tilemap.data, 1, tilemap.size, f); + fclose(f); + } + + free(graphic.data); + free(tilemap.data); + + return 0; +} diff --git a/tools/scan_includes.c b/tools/scan_includes.c new file mode 100644 index 000000000..cc6eeb1be --- /dev/null +++ b/tools/scan_includes.c @@ -0,0 +1,85 @@ +#include +#include +#include + +void usage(void) { + printf("Usage: scan_includes filename\n"); + exit(1); +} + +void scan_file(char* filename) { + FILE* f; + long size; + char* orig; + char* buffer; + char* include; + int length; + + f = fopen(filename, "r"); + if (f == NULL) { + fprintf(stderr, "Could not open file: '%s'\n", filename); + exit(1); + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + rewind(f); + + //fprintf(stderr, "malloc: %s\n", filename); + buffer = malloc(size + 1); + orig = buffer; + fread(buffer, 1, size, f); + buffer[size] = '\0'; + fclose(f); + //fprintf(stderr, "read: %s\n", filename); + + for (; (buffer != NULL) && (buffer != 0) && (buffer - orig < size); buffer++) { + //fprintf(stderr, "%c", buffer[0]); + if (buffer[0] == ';') { + buffer = strchr(buffer, '\n'); + if (buffer == NULL) { + fprintf(stderr, "%s: no newline at end of file\n", filename); + break; + } + continue; + } + if ( + (strncmp(buffer, "INCBIN", 6) == 0) || + (strncmp(buffer, "incbin", 6) == 0) + ) { + buffer = strchr(buffer, '"') + 1; + if (buffer == NULL) break; + length = strcspn(buffer, "\""); + include = malloc(length + 1); + strncpy(include, buffer, length); + include[length] = '\0'; + printf("%s ", include); + free(include); + } else if ( + (strncmp(buffer, "INCLUDE", 7) == 0) || + (strncmp(buffer, "include", 7) == 0) + ) { + buffer = strchr(buffer, '"') + 1; + if (buffer == NULL) break; + length = strcspn(buffer, "\""); + include = malloc(length + 1); + strncpy(include, buffer, length); + include[length] = '\0'; + printf("%s ", include); + scan_file(include); + free(include); + } + } + + //fprintf(stderr, "free: %s\n", filename); + free(orig); + //fprintf(stderr, "freed: %s\n", filename); +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + usage(); + } + scan_file(argv[1]); + return 0; +} -- cgit v1.2.3 From b78ba89f5f0db937e7cf4e386bd41340634a31c4 Mon Sep 17 00:00:00 2001 From: yenatch Date: Fri, 28 Apr 2017 01:41:06 -0400 Subject: Refactor scan_includes. --- tools/scan_includes.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'tools') diff --git a/tools/scan_includes.c b/tools/scan_includes.c index cc6eeb1be..4aba83eaa 100644 --- a/tools/scan_includes.c +++ b/tools/scan_includes.c @@ -1,6 +1,7 @@ #include #include #include +#include void usage(void) { printf("Usage: scan_includes filename\n"); @@ -25,55 +26,46 @@ void scan_file(char* filename) { size = ftell(f); rewind(f); - //fprintf(stderr, "malloc: %s\n", filename); buffer = malloc(size + 1); orig = buffer; fread(buffer, 1, size, f); buffer[size] = '\0'; fclose(f); - //fprintf(stderr, "read: %s\n", filename); - for (; (buffer != NULL) && (buffer != 0) && (buffer - orig < size); buffer++) { - //fprintf(stderr, "%c", buffer[0]); + for (; buffer && (buffer - orig < size); buffer++) { if (buffer[0] == ';') { buffer = strchr(buffer, '\n'); - if (buffer == NULL) { + if (!buffer) { fprintf(stderr, "%s: no newline at end of file\n", filename); break; } continue; } - if ( - (strncmp(buffer, "INCBIN", 6) == 0) || - (strncmp(buffer, "incbin", 6) == 0) - ) { - buffer = strchr(buffer, '"') + 1; - if (buffer == NULL) break; - length = strcspn(buffer, "\""); - include = malloc(length + 1); - strncpy(include, buffer, length); - include[length] = '\0'; - printf("%s ", include); - free(include); - } else if ( - (strncmp(buffer, "INCLUDE", 7) == 0) || - (strncmp(buffer, "include", 7) == 0) - ) { + bool is_include = false; + bool is_incbin = false; + if ((strncmp(buffer, "INCBIN", 6) == 0) || (strncmp(buffer, "incbin", 6) == 0)) { + is_incbin = true; + } else if ((strncmp(buffer, "INCLUDE", 7) == 0) || (strncmp(buffer, "include", 7) == 0)) { + is_include = true; + } + if (is_incbin || is_include) { buffer = strchr(buffer, '"') + 1; - if (buffer == NULL) break; + if (!buffer) { + break; + } length = strcspn(buffer, "\""); include = malloc(length + 1); strncpy(include, buffer, length); include[length] = '\0'; printf("%s ", include); - scan_file(include); + if (is_include) { + scan_file(include); + } free(include); } } - //fprintf(stderr, "free: %s\n", filename); free(orig); - //fprintf(stderr, "freed: %s\n", filename); } int main(int argc, char* argv[]) { -- cgit v1.2.3 From 27ba16d827a4a50a1786c32691c2093bd05b1a2a Mon Sep 17 00:00:00 2001 From: yenatch Date: Sun, 28 May 2017 01:11:32 -0400 Subject: Fix pokemon_animation_graphics --- tools/pokemon_animation_graphics.c | 69 ++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 22 deletions(-) (limited to 'tools') diff --git a/tools/pokemon_animation_graphics.c b/tools/pokemon_animation_graphics.c index 089928d11..96d5242aa 100644 --- a/tools/pokemon_animation_graphics.c +++ b/tools/pokemon_animation_graphics.c @@ -48,15 +48,25 @@ int get_tile_index(uint8_t* tile, uint8_t* tiles, int num_tiles) { return -1; } +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; +} + void create_tilemap(struct Tilemap* tilemap, struct Graphic* graphic, char* graphics_filename, int width, int height) { long graphics_size; uint8_t* graphics; FILE* f; - int tile; - int num_tiles; int i; + int tile; - f = fopen(graphics_filename, "rb"); + f = fopen_verbose(graphics_filename, "rb"); + if (!f) { + exit(1); + } fseek(f, 0, SEEK_END); graphics_size = ftell(f); rewind(f); @@ -64,20 +74,27 @@ void create_tilemap(struct Tilemap* tilemap, struct Graphic* graphic, char* grap fread(graphics, 1, graphics_size, f); fclose(f); + int num_tiles_per_frame = width * height; + int tile_size = 16; + int num_frames = graphics_size / (tile_size * num_tiles_per_frame); + int frame_size = num_tiles_per_frame * tile_size; + // transpose each frame - for (i = 0; i < graphics_size / (width * height); i++) { - transpose_tiles(graphics + i * (width * height) * 16, width, width * height * 16, 16); + for (i = 0; i < num_frames; i++) { + transpose_tiles(graphics + i * frame_size, width, frame_size, tile_size); } - // first frame is naively populated with redundant tiles - num_tiles = width * height; - tilemap->data = malloc(graphics_size / 16); + // first frame is naively populated with redundant tiles, + // so fill it unconditionally and start from the second frame + int num_tiles = width * height; + int tilemap_size = graphics_size / tile_size; + tilemap->data = malloc(tilemap_size); for (i = 0; i < num_tiles; i++) { tilemap->data[tilemap->size] = i; tilemap->size++; } - for (i = width * height; i < graphics_size / 16; i++) { - tile = get_tile_index(graphics + i * 16, graphics, i); + for (i = num_tiles; i < tilemap_size; i++) { + tile = get_tile_index(graphics + i * tile_size, graphics, i); if (tile == -1) { tilemap->data[tilemap->size] = num_tiles; tilemap->size++; @@ -103,7 +120,7 @@ void create_tilemap(struct Tilemap* tilemap, struct Graphic* graphic, char* grap } int main(int argc, char* argv[]) { - int ch; + int opt; char* dimensions_filename; char* graphics_filename; char* outfile; @@ -116,8 +133,8 @@ int main(int argc, char* argv[]) { struct Graphic graphic = {0}; struct Tilemap tilemap = {0}; - while ((ch = getopt(argc, argv, "o:t:")) != -1) { - switch (ch) { + while ((opt = getopt(argc, argv, "o:t:")) != -1) { + switch (opt) { case 'o': outfile = optarg; break; @@ -126,6 +143,7 @@ int main(int argc, char* argv[]) { break; default: usage(); + break; } } argc -= optind; @@ -138,7 +156,10 @@ int main(int argc, char* argv[]) { graphics_filename = argv[0]; dimensions_filename = argv[1]; - f = fopen(dimensions_filename, "rb"); + f = fopen_verbose(dimensions_filename, "rb"); + if (!f) { + exit(1); + } fread(bytes, 1, 1, f); fclose(f); width = bytes[0] & 0xf; @@ -146,16 +167,20 @@ int main(int argc, char* argv[]) { create_tilemap(&tilemap, &graphic, graphics_filename, width, height); - if (outfile != NULL) { - f = fopen(outfile, "wb"); - fwrite(graphic.data, 1, graphic.size, f); - fclose(f); + if (outfile) { + f = fopen_verbose(outfile, "wb"); + if (f) { + fwrite(graphic.data, 1, graphic.size, f); + fclose(f); + } } - if (mapfile != NULL) { - f = fopen(mapfile, "wb"); - fwrite(tilemap.data, 1, tilemap.size, f); - fclose(f); + if (mapfile) { + f = fopen_verbose(mapfile, "wb"); + if (f) { + fwrite(tilemap.data, 1, tilemap.size, f); + fclose(f); + } } free(graphic.data); -- cgit v1.2.3 From fe38946b0e2717c973839a4f8db647de0f1d9f3a Mon Sep 17 00:00:00 2001 From: yenatch Date: Sun, 28 May 2017 01:12:16 -0400 Subject: scan_includes: add --strict so it doesn't have to be default --- tools/scan_includes.c | 63 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/scan_includes.c b/tools/scan_includes.c index 4aba83eaa..bec42ed75 100644 --- a/tools/scan_includes.c +++ b/tools/scan_includes.c @@ -2,12 +2,24 @@ #include #include #include +#include void usage(void) { - printf("Usage: scan_includes filename\n"); - exit(1); + printf("Usage: scan_includes [-h] [-s] filename\n" + "-h, --help\n" + " Print usage and exit\n" + "-s, --strict\n" + " Fail if a file cannot be read\n"); } +struct Options { + bool help; + bool strict; +}; + +struct Options Options = {0}; + + void scan_file(char* filename) { FILE* f; long size; @@ -17,9 +29,13 @@ void scan_file(char* filename) { int length; f = fopen(filename, "r"); - if (f == NULL) { - fprintf(stderr, "Could not open file: '%s'\n", filename); - exit(1); + if (!f) { + if (Options.strict) { + fprintf(stderr, "Could not open file: '%s'\n", filename); + exit(1); + } else { + return; + } } fseek(f, 0, SEEK_END); @@ -68,10 +84,43 @@ void scan_file(char* filename) { free(orig); } +void get_args(int argc, char *argv[]) { + while (1) { + struct option long_options[] = { + {"strict", no_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {0} + }; + int i = 0; + int opt = getopt_long(argc, argv, "sh", long_options, &i); + + if (opt == -1) { + break; + } + + switch (opt) { + case 's': + Options.strict = true; + break; + case 'h': + Options.help = true; + break; + } + } +} + int main(int argc, char* argv[]) { - if (argc < 2) { + get_args(argc, argv); + argc -= optind; + argv += optind; + if (Options.help) { usage(); + return 0; + } + if (argc < 1) { + usage(); + exit(1); } - scan_file(argv[1]); + scan_file(argv[0]); return 0; } -- cgit v1.2.3 From 6cce67350186d4a0c37766eb5534e76adaad5a48 Mon Sep 17 00:00:00 2001 From: yenatch Date: Sun, 28 May 2017 23:22:10 -0400 Subject: Fix the pokemon animation tools. Fixed a lot of serious bugs. These tools were not functional. Also added a --girafarig flag for a special case. --- tools/pokemon_animation.c | 70 ++++++++++++++---------- tools/pokemon_animation_graphics.c | 106 ++++++++++++++++++++++++++----------- tools/scan_includes.c | 4 ++ 3 files changed, 120 insertions(+), 60 deletions(-) (limited to 'tools') diff --git a/tools/pokemon_animation.c b/tools/pokemon_animation.c index 67a9194c9..835160c24 100644 --- a/tools/pokemon_animation.c +++ b/tools/pokemon_animation.c @@ -29,8 +29,8 @@ struct Bitmasks { void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap_filename, char* dimensions_filename); -int bitmask_exists(struct Bitmask bitmask, struct Bitmasks bitmasks); -void print_frames(); +int bitmask_exists(struct Bitmask *bitmask, struct Bitmasks *bitmasks); +void print_frames(struct Frames* frames); void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap_filename, char* dimensions_filename) { @@ -41,8 +41,6 @@ void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap int width; int height; uint8_t byte; - struct Frame* frame; - struct Bitmask* bitmask; int frame_size; int num_frames; int i, j; @@ -77,33 +75,40 @@ void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap num_frames = size / frame_size - 1; //fprintf(stderr, "num_frames: %d\n", num_frames); - bitmasks->bitmasks = malloc((sizeof (struct Bitmask*)) * num_frames); + bitmasks->bitmasks = malloc((sizeof (struct Bitmask)) * num_frames); bitmasks->num_bitmasks = 0; - frames->frames = malloc((sizeof (struct Frame*)) * num_frames); + frames->frames = malloc((sizeof (struct Frame)) * num_frames); frames->frame_size = frame_size; frames->num_frames = 0; + uint8_t *first_frame = tilemap; this_frame = tilemap + frame_size; for (i = 0; i < num_frames; i++) { - frame = (struct Frame*)malloc(sizeof(struct Frame)); + struct Frame *frame = (struct Frame*)malloc(sizeof(struct Frame)); frame->data = malloc(frame_size); frame->size = 0; - bitmask = (struct Bitmask*)malloc(sizeof(struct Bitmask)); - bitmask->data = malloc((frame_size + 7) / 8); + struct Bitmask *bitmask = (struct Bitmask*)malloc(sizeof(struct Bitmask)); + bitmask->data = calloc((frame_size + 7) / 8, 1); bitmask->bitlength = 0; for (j = 0; j < frame_size; j++) { - if (this_frame[j] != tilemap[j]) { + if (bitmask->bitlength % 8 == 0) { + bitmask->data[bitmask->bitlength / 8] = 0; + } + bitmask->data[bitmask->bitlength / 8] >>= 1; + if (this_frame[j] != first_frame[j]) { frame->data[frame->size] = this_frame[j]; frame->size++; - bitmask->data[bitmask->bitlength / 8] |= 1; + bitmask->data[bitmask->bitlength / 8] |= (1 << 7); } bitmask->bitlength++; - if (bitmask->bitlength % 8 != 0) { - bitmask->data[bitmask->bitlength / 8] <<= 1; - } } - frame->bitmask = bitmask_exists(*bitmask, *bitmasks); + // I don't remember exactly why this works. + // I think it was that the bits are read backwards, but not indexed backwards. + int last = bitmask->bitlength - 1; + bitmask->data[last / 8] >>= (7 - (last % 8)); + + frame->bitmask = bitmask_exists(bitmask, bitmasks); if (frame->bitmask == -1) { frame->bitmask = bitmasks->num_bitmasks; bitmasks->bitmasks[bitmasks->num_bitmasks] = *bitmask; @@ -135,20 +140,22 @@ void make_frames(struct Frames* frames, struct Bitmasks* bitmasks, char* tilemap free(tilemap); } -int bitmask_exists(struct Bitmask bitmask, struct Bitmasks bitmasks) { +int bitmask_exists(struct Bitmask *bitmask, struct Bitmasks *bitmasks) { int i, j; struct Bitmask existing; - for (i = 0; i < bitmasks.num_bitmasks; i++) { - existing = bitmasks.bitmasks[i]; - if (bitmask.bitlength != existing.bitlength) { + for (i = 0; i < bitmasks->num_bitmasks; i++) { + existing = bitmasks->bitmasks[i]; + if (bitmask->bitlength != existing.bitlength) { continue; } - for (j = 0; j < (bitmask.bitlength + 7) / 8; j++) { - if (bitmask.data[j] != existing.data[j]) { + bool match = true; + for (j = 0; j < (bitmask->bitlength + 7) / 8; j++) { + if (bitmask->data[j] != existing.data[j]) { + match = false; break; } } - if (j == (bitmask.bitlength + 7) / 8) { + if (match) { return i; } } @@ -158,18 +165,23 @@ int bitmask_exists(struct Bitmask bitmask, struct Bitmasks bitmasks) { void print_frames(struct Frames* frames) { int i; int j; - struct Frame frame; for (i = 0; i < frames->num_frames; i++) { printf("\tdw .frame%d\n", i + 1); } for (i = 0; i < frames->num_frames; i++) { - frame = frames->frames[i]; + struct Frame *frame = &frames->frames[i]; printf(".frame%d\n", i + 1); - printf("\tdb %d\n", frame.bitmask); - if (frame.size > 0) { - printf("\tdb %d", frame.data[0]); - for (j = 1; j < frame.size; j++) { - printf(", %d", frame.data[j]); + printf("\tdb $%02x ; bitmask\n", frame->bitmask); + if (frame->size > 0) { + for (j = 0; j < frame->size; j++) { + if (j % 12 == 0) { + if (j) { + printf("\n"); + } + printf("\tdb $%02x", frame->data[j]); + } else { + printf(", $%02x", frame->data[j]); + } } printf("\n"); } diff --git a/tools/pokemon_animation_graphics.c b/tools/pokemon_animation_graphics.c index 96d5242aa..3fb065e4b 100644 --- a/tools/pokemon_animation_graphics.c +++ b/tools/pokemon_animation_graphics.c @@ -2,12 +2,21 @@ #include #include #include +#include +#include static void usage(void) { printf("Usage: pokemon_animation_graphics [-o outfile] [-t mapfile] 2bpp_file dimensions_file\n"); exit(1); } +struct Options { + int girafarig; +}; + +struct Options Options = {0}; + + struct Tilemap { uint8_t* data; int size; @@ -32,16 +41,25 @@ void transpose_tiles(uint8_t* tiles, int width, int size, int tile_size) { free(new_tiles); } -int get_tile_index(uint8_t* tile, uint8_t* tiles, int num_tiles) { - int i; - int j; - for (i = 0; i < num_tiles; i++) { - for (j = 0; j < 16; j++) { - if (tile[j] != tiles[16 * i + j]) { - break; - } +bool compare_tile(uint8_t *tile, uint8_t *other) { + for (int j = 0; j < 16; j++) { + if (tile[j] != other[j]) { + return false; + } + } + return true; +} + +int get_tile_index(uint8_t* tile, uint8_t* tiles, int num_tiles, int preferred_tile_id) { + if (preferred_tile_id >= 0 && preferred_tile_id < num_tiles) { + uint8_t *other = &tiles[preferred_tile_id * 16]; + if (compare_tile(tile, other)) { + return preferred_tile_id; } - if (j == 16) { + } + for (int i = 0; i < num_tiles; i++) { + uint8_t *other = &tiles[i * 16]; + if (compare_tile(tile, other)) { return i; } } @@ -88,33 +106,46 @@ void create_tilemap(struct Tilemap* tilemap, struct Graphic* graphic, char* grap // so fill it unconditionally and start from the second frame int num_tiles = width * height; int tilemap_size = graphics_size / tile_size; - tilemap->data = malloc(tilemap_size); + tilemap->data = malloc(tilemap_size * 2); for (i = 0; i < num_tiles; i++) { tilemap->data[tilemap->size] = i; tilemap->size++; } for (i = num_tiles; i < tilemap_size; i++) { - tile = get_tile_index(graphics + i * tile_size, graphics, i); - if (tile == -1) { - tilemap->data[tilemap->size] = num_tiles; - tilemap->size++; - num_tiles++; + int preferred = i % num_tiles_per_frame; + int index = get_tile_index(graphics + i * tile_size, graphics, i, preferred); + if (Options.girafarig && index == 0) { + tile = num_tiles; + } else if (index == -1) { + tile = num_tiles++; } else { - tilemap->data[tilemap->size] = tile; - tilemap->size++; + tile = tilemap->data[index]; } + tilemap->data[tilemap->size] = tile; + tilemap->size++; } - graphic->data = malloc(tilemap->size * 16); + int graphic_size = tilemap->size * 16; + if (Options.girafarig) { + // This is probably not needed, but just in case... + graphic_size += 16; + } + + graphic->data = malloc(graphic_size); graphic->size = 16 * width * height; memcpy(graphic->data, graphics, graphic->size); for (i = width * height; i < tilemap->size; i++) { - tile = get_tile_index(graphics + 16 * i, graphic->data, graphic->size / 16); + tile = get_tile_index(graphics + 16 * i, graphic->data, graphic->size / 16, i % num_tiles_per_frame); if (tile == -1) { memcpy(graphic->data + graphic->size, graphics + 16 * i, 16); graphic->size += 16; } } + if (Options.girafarig) { + // Add a duplicate of tile 0 to the end. + memcpy(graphic->data + graphic->size, graphics, 16); + graphic->size += 16; + } free(graphics); } @@ -123,8 +154,8 @@ int main(int argc, char* argv[]) { int opt; char* dimensions_filename; char* graphics_filename; - char* outfile; - char* mapfile; + char* outfile = NULL; + char* mapfile = NULL; FILE* f; long size; uint8_t bytes[1]; @@ -133,17 +164,30 @@ int main(int argc, char* argv[]) { struct Graphic graphic = {0}; struct Tilemap tilemap = {0}; - while ((opt = getopt(argc, argv, "o:t:")) != -1) { + while (1) { + struct option long_options[] = { + {"girafarig", no_argument, &Options.girafarig, 1}, + {"tilemap", required_argument, 0, 't'}, + {"output", required_argument, 0, 'o'}, + {0} + }; + int long_option_index = 0; + int opt = getopt_long(argc, argv, "o:t:", long_options, &long_option_index); + if (opt == -1) { + break; + } switch (opt) { - case 'o': - outfile = optarg; - break; - case 't': - mapfile = optarg; - break; - default: - usage(); - break; + case 0: + break; + case 'o': + outfile = optarg; + break; + case 't': + mapfile = optarg; + break; + default: + usage(); + break; } } argc -= optind; diff --git a/tools/scan_includes.c b/tools/scan_includes.c index bec42ed75..b6fcca03a 100644 --- a/tools/scan_includes.c +++ b/tools/scan_includes.c @@ -105,6 +105,10 @@ void get_args(int argc, char *argv[]) { case 'h': Options.help = true; break; + default: + usage(); + exit(1); + break; } } } -- cgit v1.2.3 From d9c329eb3cfd64c4731a7f59bd52c7e71c3e6baf Mon Sep 17 00:00:00 2001 From: yenatch Date: Sun, 28 May 2017 23:49:12 -0400 Subject: pokemon_animation_graphics: stdint.h --- tools/pokemon_animation_graphics.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/pokemon_animation_graphics.c b/tools/pokemon_animation_graphics.c index 3fb065e4b..3d79960e4 100644 --- a/tools/pokemon_animation_graphics.c +++ b/tools/pokemon_animation_graphics.c @@ -4,6 +4,7 @@ #include #include #include +#include static void usage(void) { printf("Usage: pokemon_animation_graphics [-o outfile] [-t mapfile] 2bpp_file dimensions_file\n"); -- cgit v1.2.3 From c81a7aa1621326827088142fa5cc484bbcca9535 Mon Sep 17 00:00:00 2001 From: yenatch Date: Sun, 28 May 2017 23:52:23 -0400 Subject: pokemon_animation_graphics: remove declarations from for loops --- tools/pokemon_animation_graphics.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/pokemon_animation_graphics.c b/tools/pokemon_animation_graphics.c index 3d79960e4..f38850fb0 100644 --- a/tools/pokemon_animation_graphics.c +++ b/tools/pokemon_animation_graphics.c @@ -43,7 +43,8 @@ void transpose_tiles(uint8_t* tiles, int width, int size, int tile_size) { } bool compare_tile(uint8_t *tile, uint8_t *other) { - for (int j = 0; j < 16; j++) { + int j; + for (j = 0; j < 16; j++) { if (tile[j] != other[j]) { return false; } @@ -58,7 +59,8 @@ int get_tile_index(uint8_t* tile, uint8_t* tiles, int num_tiles, int preferred_t return preferred_tile_id; } } - for (int i = 0; i < num_tiles; i++) { + int i; + for (i = 0; i < num_tiles; i++) { uint8_t *other = &tiles[i * 16]; if (compare_tile(tile, other)) { return i; -- cgit v1.2.3 From e78034eb8c818036d2cb11c9b87ad8ae366be0cf Mon Sep 17 00:00:00 2001 From: yenatch Date: Mon, 29 May 2017 19:15:34 -0400 Subject: Use a separate makefile for tools - Fix crystal11 - Fix a bug where the dependency checks would run regardless of target Fixes 0bd74cdd7341a4cff5da73e1c32ac0d237ec8e08 --- tools/Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tools/Makefile (limited to 'tools') diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 000000000..4a04027fc --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,13 @@ +.PHONY: all + +all: \ + lzcomp \ + png_dimensions \ + scan_includes \ + palette \ + pokemon_animation \ + pokemon_animation_graphics + @: + +%: %.c + $(CC) -o $@ $< -- cgit v1.2.3