diff options
| author | JP Appel <jeanpierre.appel01@gmail.com> | 2024-04-30 05:02:08 -0400 |
|---|---|---|
| committer | JP Appel <jeanpierre.appel01@gmail.com> | 2024-04-30 05:02:08 -0400 |
| commit | 05ba9a3fc30878dcabbbe02929f24da189008293 (patch) | |
| tree | 54d4e936822458380a0222fa0233006d9170a52f /src | |
| parent | a9760b31a2dfc672c72c4257a4e293fafb08c0b3 (diff) | |
gif support
Diffstat (limited to 'src')
| -rw-r--r-- | src/fractal_render.c | 96 | ||||
| -rw-r--r-- | src/fractal_render.h | 13 | ||||
| -rw-r--r-- | src/grids.c | 3 | ||||
| -rw-r--r-- | src/renderers.c | 98 | ||||
| -rw-r--r-- | src/renderers.h | 9 |
5 files changed, 201 insertions, 18 deletions
diff --git a/src/fractal_render.c b/src/fractal_render.c index b9ffa09..721d3f2 100644 --- a/src/fractal_render.c +++ b/src/fractal_render.c @@ -7,6 +7,9 @@ #include "grids.h" #include "precision.h" #include "fractal_render.h" +#include "renderers.h" + +#define BUFFER_SIZE 32 void print_usage(FILE* file, const char* program_name) { fprintf(file, "Usage: %s -i input.grid [-r renderer] [-o output.ext]\n", program_name); @@ -16,7 +19,8 @@ void print_help(){ printf("Options:\n" " -i, --input <input grid> the grid to be rendered, if the file name is '-' reads from stdin\n" " -r, --renderer <renderer> the renderer to use, defaults to the text renderer\n" - " renderers: txt, png (TODO), gif (TODO, with additional features)\n" + " renderers: txt, png, gif (TODO, with additional features)\n" + " -d, --delay <delay> the delay between animation frames in 1/100 s\n" " -o, --output <output file> the file to output the result of rendering, if not given defaults to output.<EXT>\n" " where <EXT> is the renderer used\n" " -v, --verbose verbose output\n" @@ -49,16 +53,29 @@ void cleanup(FILE* output_file, FILE* input_file, grid_t* grid) { if(grid) free_grid(grid); } +/* + * Wrapper for print_grid to meet renderer type + */ +void render_txt(FILE* output, const renderer_params* params){ + print_grid(output, params->grid); +} + + int main(const int argc, char* argv[]){ + // defaults char* input_filename = "fractal.grid"; char* output_filename = "fractal.txt"; - renderer_func renderer = print_grid; + renderer_func renderer = render_txt; + int anim_delay = 30; + bool multigrid = false; bool verbose = false; + renderer_params* params = malloc(sizeof(renderer_params)); static struct option long_options[] = { {"input", required_argument, NULL, 'i'}, {"renderer", required_argument, NULL, 'r'}, + {"delay", required_argument, NULL, 'd'}, {"output", required_argument, NULL, 'o'}, {"verbose", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, @@ -66,18 +83,37 @@ int main(const int argc, char* argv[]){ }; int opt; - while((opt = getopt_long(argc, argv, "i:r:o:vh", long_options, NULL)) != -1){ + while((opt = getopt_long(argc, argv, "i:r:o:d:vh", long_options, NULL)) != -1){ switch(opt){ case 'i': input_filename = optarg; break; case 'r': - //TODO: update with other renderers - renderer = print_grid; + if(strcmp(optarg, "png") == 0){ + renderer = render_png; + } + else if(strcmp(optarg, "txt") ==0 ){ + renderer = render_txt; + } + else if(strcmp(optarg, "gif") == 0){ + renderer = render_gif; + multigrid = true; + } + else { + fprintf(stderr, "Unrecognized renderer: %s, exitting", optarg); + exit(2); + } break; case 'o': output_filename = optarg; break; + case 'd': + anim_delay = strtol(optarg, NULL, 10); + if(anim_delay < 1){ + fprintf(stderr, "Invalid frame delay: %d", anim_delay); + exit(2); + } + break; case 'v': verbose = true; break; @@ -92,7 +128,8 @@ int main(const int argc, char* argv[]){ } } - //TODO: logic to set output_filename if o flag is not used + //TODO: logic to set output_filename if o flag is not used + FILE* input_file = NULL; FILE* output_file = NULL; @@ -111,24 +148,53 @@ int main(const int argc, char* argv[]){ if (!output_file) { error_exit("Error opening output file", output_filename); } } - if(strcmp(input_filename, "-") == 0){ - grid = read_grid(stdin); - if (!grid) { error_exit("Error reading from stdin", NULL); } + if(!multigrid){ + if(strcmp(input_filename, "-") == 0){ + grid = read_grid(stdin); + if (!grid) { error_exit("Error reading from stdin", NULL); } + } + else { + input_file = fopen(input_filename, "rb"); + if(!input_file) { error_exit("Error opening input file", input_filename); } + grid = read_grid(input_file); + if(!grid) { error_exit("Error reading from file", input_filename); } + } + params->grid = grid; } else { - input_file = fopen(input_filename, "rb"); - if (!input_file) { error_exit("Error opening input file", input_filename); } - grid = read_grid(input_file); - if (!grid) { error_exit("Error reading from file", input_filename); } + grid_t** grids = malloc(BUFFER_SIZE * sizeof(grid_t*)); + char filename[256]; + size_t size = 0; + FILE* file; + if(strcmp(input_filename, "-") == 0){ + file = stdin; + } + else { + file = fopen(input_filename, "r"); + } + while(fgets(filename, sizeof(filename), file) != NULL && size < BUFFER_SIZE){ + //remove trailing newline from fgets + filename[strcspn(filename, "\n")] = 0; + input_file = fopen(filename, "rb"); + if (!input_file) { error_exit("Error opening input file", filename); } + grids[size] = read_grid(input_file); + if (!grids[size]) { error_exit("Error reading from file", filename); } + size++; + } + //TODO: check grids to make sure they are have the same dimensions + params->grid_array.delay = anim_delay; + params->grid_array.size = size; + params->grid_array.grids = grids; } + if(verbose){ print_grid_info(grid); } - renderer(output_file, grid); + renderer(output_file, params); cleanup(output_file, input_file, grid); - + free(params); return 0; } diff --git a/src/fractal_render.h b/src/fractal_render.h index a23acad..e527ce1 100644 --- a/src/fractal_render.h +++ b/src/fractal_render.h @@ -1,6 +1,17 @@ #pragma once #include <stdio.h> +#include <gd.h> + #include "grids.h" -typedef void (*renderer_func)(FILE*, const grid_t*); +typedef union { + grid_t* grid; + struct { + size_t size; + int delay; + grid_t** grids; + } grid_array; +} renderer_params; +typedef void (*renderer_func)(FILE*, const renderer_params*); +typedef gdImagePtr (*grid_image_converter)(grid_t*); diff --git a/src/grids.c b/src/grids.c index 279fdb5..e73feb4 100644 --- a/src/grids.c +++ b/src/grids.c @@ -142,7 +142,6 @@ CBASE complex grid_to_complex(const grid_t* grid_p, const size_t index) { * Resets all grid values to 0 */ void zoom_grid(grid_t* restrict grid, const CBASE magnification){ - //FIXME: not impelemnted correctly set_grid(grid, 0); // const CBASE complex upper_right = grid->upper_right; const complex_t upper_right = grid->upper_right; @@ -153,7 +152,7 @@ void zoom_grid(grid_t* restrict grid, const CBASE magnification){ const CBASE inv_mag = 1 / magnification; const complex_t center = { .re = inv2 * (lower_left.re + upper_right.re), - .im = inv2 * (lower_left.im + lower_left.im) + .im = inv2 * (lower_left.im + upper_right.im) }; const complex_t offset = { .re = inv_mag * (upper_right.re - lower_left.re), diff --git a/src/renderers.c b/src/renderers.c new file mode 100644 index 0000000..2955fb2 --- /dev/null +++ b/src/renderers.c @@ -0,0 +1,98 @@ +#include "renderers.h" +#include <stdio.h> +#include "fractal_render.h" +#include <gd.h> + +static inline byte scale_iterations(const byte max_iterations, const byte iteration){ + return (byte)((double)iteration / max_iterations * 255); +} + +/* + * Convert a grid into a gd image with true color + * NOTE: modifying the size of colors will allow this function to use the + * millions of colors the true colors support + * As of now it is identical to converter, but should be changed + */ +gdImagePtr truecolor_converter(const grid_t* grid){ + const size_t width = grid->x; + const size_t height = grid->y; + const byte* data = grid->data; + const byte max_iterations = grid->max_iterations; + + gdImagePtr img = gdImageCreateTrueColor(width, height); + int colors[256]; + for(size_t i = 0; i < 255; i++){ + colors[i] = gdImageColorAllocate(img, 0, i, i/2); + } + + colors[255] = gdImageColorAllocate(img, 0, 0, 0); + + for(size_t y = 0; y < height; y++){ + for(size_t x = 0; x < width; x++){ + byte iteration = data[y * width + x]; + byte scaled_iteration = scale_iterations(max_iterations, iteration); + int color = colors[scaled_iteration]; + gdImageSetPixel(img, x, y, color); + } + } + + return img; +} + +/* + * Convert a grid into a gd image + */ +gdImagePtr converter(const grid_t* grid){ + const size_t width = grid->x; + const size_t height = grid->y; + const byte* data = grid->data; + const byte max_iterations = grid->max_iterations; + + gdImagePtr img = gdImageCreate(width, height); + int colors[256]; + for(size_t i = 0; i < 255; i++){ + colors[i] = gdImageColorAllocate(img, 0, i, i/2); + } + + colors[255] = gdImageColorAllocate(img, 0, 0, 0); + for(size_t y = 0; y < height; y++){ + for(size_t x = 0; x < width; x++){ + byte iteration = data[y * width + x]; + byte scaled_iteration = scale_iterations(max_iterations, iteration); + int color = colors[scaled_iteration]; + gdImageSetPixel(img, x, y, color); + } + } + + return img; +} + + +void render_png(FILE *output, const renderer_params* params){ + gdImagePtr img = truecolor_converter(params->grid); + gdImagePng(img, output); + gdImageDestroy(img); +} + +void render_gif(FILE* output, const renderer_params* params){ + const size_t size = params->grid_array.size; + grid_t** grids = params->grid_array.grids; + const int delay = params->grid_array.delay; + + gdImagePtr imgs[size]; + + imgs[0] = converter(grids[0]); + gdImageGifAnimBegin(imgs[0], output, 1, -1); + gdImageGifAnimAdd(imgs[0], output, 0, 0, 0, delay, 1, NULL); + + for(size_t i = 1; i < size; i++){ + imgs[i] = converter(grids[i]); + gdImagePaletteCopy(imgs[i], imgs[i-1]); + gdImageGifAnimAdd(imgs[i], output, 0, 0, 0, delay, 1, imgs[i-1]); + } + + gdImageGifAnimEnd(output); + for(size_t i = 0; i < size; i++){ + gdImageDestroy(imgs[i]); + } +} diff --git a/src/renderers.h b/src/renderers.h new file mode 100644 index 0000000..add7594 --- /dev/null +++ b/src/renderers.h @@ -0,0 +1,9 @@ +#pragma once + +#include <gd.h> +#include <stdio.h> +#include "fractal_render.h" +#include "grids.h" + +void render_png(FILE* output, const renderer_params* params); +void render_gif(FILE* output, const renderer_params* params); |
