From d95e93bf70f3351e6fd489284794ef7909fd94ce Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 4 Oct 2015 15:35:30 -0400 Subject: Make striping optional. --- main.c | 123 ++++++++++++++++++++++++++++++++++---------------------------- options.c | 10 +++++ options.h | 1 + 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/main.c b/main.c index 055c854..109f9f6 100644 --- a/main.c +++ b/main.c @@ -40,6 +40,10 @@ typedef struct { uint32_t *colors; pixel_t *pixels; png_byte **bitmap; + unsigned int iteration; + unsigned int update_interval; + unsigned int frame; + size_t max_boundary; } state_t; static void init_state(state_t *state, const options_t *options); @@ -109,6 +113,10 @@ init_state(state_t *state, const options_t *options) state->colors = generate_colors(options); state->pixels = create_pixels(options); state->bitmap = create_bitmap(options); + state->iteration = 0; + state->update_interval = 1U << (state->options->bit_depth + 1)/2; + state->frame = 0; + state->max_boundary = 0; } static void generate_bitmap(state_t *state); @@ -342,91 +350,96 @@ print_progress(const char *format, ...) } static void -generate_bitmap(state_t *state) +place_color(state_t *state, kd_forest_t *kdf, unsigned int i) { - // Make the forest - kd_forest_t kdf; - kdf_init(&kdf); + if (state->iteration % state->update_interval == 0) { + if (state->options->animate) { + char filename[strlen(state->options->filename) + 10]; + sprintf(filename, "%s/%04u.png", state->options->filename, state->frame); + write_png(state, filename); + ++state->frame; + } - bool animate = state->options->animate; - unsigned int frame = 0; - char filename[strlen(state->options->filename) + 10]; + print_progress("%.2f%%\t| boundary size: %zu\t| max boundary size: %zu", + 100.0*state->iteration/state->options->ncolors, kdf->size, state->max_boundary); + } - size_t max_size = 0; - unsigned int update_interval = 1U << (state->options->bit_depth + 1)/2; + uint32_t color = state->colors[i]; - // Do multiple passes to get rid of artifacts in HUE_SORT mode - unsigned int bit_depth = state->options->bit_depth; - for (unsigned int i = 1, progress = 0; i <= bit_depth + 1; ++i) { - unsigned int stripe = 1 << i; + double target[KD_DIMEN]; + switch (state->options->color_space) { + case COLOR_SPACE_RGB: + color_set_RGB(target, color); + break; + case COLOR_SPACE_LAB: + color_set_Lab(target, color); + break; + case COLOR_SPACE_LUV: + color_set_Luv(target, color); + break; + } - for (unsigned int j = stripe/2 - 1; j < state->options->ncolors; j += stripe, ++progress) { - if (progress % update_interval == 0) { - if (animate) { - sprintf(filename, "%s/%04u.png", state->options->filename, frame); - write_png(state, filename); - ++frame; - } + pixel_t *pixel; + if (state->iteration == 0) { + pixel = get_pixel(state, state->options->x, state->options->y); + } else { + pixel = find_next_pixel(state, kdf, target); + } - print_progress("%.2f%%\t| boundary size: %zu\t| max boundary size: %zu", - 100.0*progress/state->options->ncolors, kdf.size, max_size); - } + memcpy(pixel->value, target, sizeof(target)); + insert_new_pixel(state, kdf, pixel); + if (kdf->size > state->max_boundary) { + state->max_boundary = kdf->size; + } - uint32_t color = state->colors[j]; - - double target[KD_DIMEN]; - switch (state->options->color_space) { - case COLOR_SPACE_RGB: - color_set_RGB(target, color); - break; - case COLOR_SPACE_LAB: - color_set_Lab(target, color); - break; - case COLOR_SPACE_LUV: - color_set_Luv(target, color); - break; - } + png_byte *png_pixel = state->bitmap[pixel->y] + 4*pixel->x; + color_unpack(png_pixel, color); + png_pixel[3] = 0xFF; +} - pixel_t *pixel; - if (j == 0) { - pixel = get_pixel(state, state->options->x, state->options->y); - } else { - pixel = find_next_pixel(state, &kdf, target); - } +static void +generate_bitmap(state_t *state) +{ + // Make the forest + kd_forest_t kdf; + kdf_init(&kdf); - memcpy(pixel->value, target, sizeof(target)); - insert_new_pixel(state, &kdf, pixel); - if (kdf.size > max_size) { - max_size = kdf.size; + if (state->options->stripe) { + for (unsigned int i = 1; i <= state->options->bit_depth + 1; ++i) { + unsigned int stripe = 1 << i; + for (unsigned int j = stripe/2 - 1; j < state->options->ncolors; j += stripe, ++state->iteration) { + place_color(state, &kdf, j); } - - png_byte *png_pixel = state->bitmap[pixel->y] + 4*pixel->x; - color_unpack(png_pixel, color); - png_pixel[3] = 0xFF; + } + } else { + for (unsigned int i = 0; i < state->options->ncolors; ++i, ++state->iteration) { + place_color(state, &kdf, i); } } - if (animate) { + if (state->options->animate) { + char filename[strlen(state->options->filename) + 10]; + #if __unix__ sprintf(filename, "%s/last.png", state->options->filename); write_png(state, filename); for (int i = 0; i < 120; ++i) { - sprintf(filename, "%s/%04u.png", state->options->filename, frame + i); + sprintf(filename, "%s/%04u.png", state->options->filename, state->frame + i); if (symlink("last.png", filename) != 0) { abort(); } } #else for (int i = 0; i < 120; ++i) { - sprintf(filename, "%s/%04u.png", state->options->filename, frame + i); + sprintf(filename, "%s/%04u.png", state->options->filename, state->frame + i); write_png(state, filename); } #endif } print_progress("%.2f%%\t| boundary size: %zu\t| max boundary size: %zu\n", - 100.0, kdf.size, max_size); + 100.0, kdf.size, state->max_boundary); kdf_destroy(&kdf); } diff --git a/options.c b/options.c index 7834c58..e25930a 100644 --- a/options.c +++ b/options.c @@ -226,6 +226,7 @@ print_usage(FILE *file, const char *command, bool verbose) usage("Usage:\n"); usage(" !$! *%s* [-b|--bit-depth @DEPTH@]\n", command); usage(" %s [-s|--hue-sort] [-r|--random] [-M|--morton] [-H|--hilbert]\n", whitespace); + usage(" %s [-t|--stripe] [-T|--no-stripe]\n", whitespace); usage(" %s [-l|--selection @min@|@mean@]\n", whitespace); usage(" %s [-c|--color-space @RGB@|@Lab@|@Luv@]\n", whitespace); usage(" %s [-w|--width @WIDTH@] [-h|--height @HEIGHT@]\n", whitespace); @@ -250,6 +251,10 @@ print_usage(FILE *file, const char *command, bool verbose) usage(" Place colors in Morton order (Z\\-order)\n"); usage(" -H, --hilbert:\n"); usage(" Place colors in Hilbert curve order\n\n"); + usage(" -t, --stripe:\n"); + usage(" -T, --no-stripe:\n"); + usage(" Whether to reduce artifacts by iterating through the colors in\n"); + usage(" multiple stripes (!default!: --stripe)\n\n"); usage(" -l, --selection @min@|@mean@:\n"); usage(" Specify the selection mode (!default!: @min@)\n\n"); usage(" @min@: Pick the pixel with the closest neighboring pixel\n"); @@ -281,6 +286,7 @@ parse_options(options_t *options, int argc, char *argv[]) // Set defaults options->bit_depth = 24; options->mode = MODE_HUE_SORT; + options->stripe = true; options->selection = SELECTION_MIN; options->color_space = COLOR_SPACE_LAB; options->animate = false; @@ -311,6 +317,10 @@ parse_options(options_t *options, int argc, char *argv[]) options->mode = MODE_MORTON; } else if (parse_arg(argc, argv, "-H", "--hilbert", NULL, &i, &error)) { options->mode = MODE_HILBERT; + } else if (parse_arg(argc, argv, "-t", "--stripe", NULL, &i, &error)) { + options->stripe = true; + } else if (parse_arg(argc, argv, "-T", "--no-stripe", NULL, &i, &error)) { + options->stripe = false; } else if (parse_arg(argc, argv, "-l", "--selection", &value, &i, &error)) { if (strcmp(value, "min") == 0) { options->selection = SELECTION_MIN; diff --git a/options.h b/options.h index 62038a4..07ecc45 100644 --- a/options.h +++ b/options.h @@ -40,6 +40,7 @@ typedef enum { typedef struct { unsigned int bit_depth; mode_t mode; + bool stripe; selection_t selection; color_space_t color_space; unsigned int width, height; -- cgit v1.2.3