From cab0e4c6c5420e6253bce50127a0c70fb0cd0552 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 15 Feb 2015 15:50:59 +0100 Subject: Improve command line interface Initial arguments-based cli, replacing the three tools -animate, -genome and -render with just one. Still need to get rid of most calls to getenv. --- main.c | 434 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 main.c (limited to 'main.c') diff --git a/main.c b/main.c new file mode 100644 index 0000000..72c147b --- /dev/null +++ b/main.c @@ -0,0 +1,434 @@ +/* + FLAM3 - cosmic recursive fractal flames + Copyright (C) 1992-2009 Spotworks LLC + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include + +#include "random.h" +#include "private.h" +#include "img.h" + +#define streq(a,b) (strcmp (a, b) == 0) + +const char *argp_program_version = + "vlam3-pre"; + +typedef struct { + bool verbose; + unsigned int threads, bpc, quality; + float scale; + bool transparent; +} render_arguments; + +static error_t parse_render_opt (int key, char *arg, + struct argp_state * const state) { + render_arguments * const arguments = state->input; + switch (key) { + case 'b': { + int i = atoi (arg); + if (i == 8 || i == 16) { + arguments->bpc = i; + } else { + argp_error (state, "Bits per channel must be 8 or 16"); + } + break; + } + + case 'q': { + int i = atoi (arg); + if (i < 1) { + argp_error (state, "Quality must be >= 1"); + } else { + arguments->quality = i; + } + break; + } + + case 's': + arguments->scale = atof (arg); + if (arguments->scale <= 0.0) { + argp_error (state, "Scale must be >= 0"); + } + break; + + case 't': { + int i = atoi (arg); + if (i <= 0) { + argp_error (state, "Threads must be >= 0"); + } else { + arguments->threads = i; + } + break; + } + + case ARGP_KEY_ARG: + if (state->arg_num > 0) { + return ARGP_ERR_UNKNOWN; + } + break; + + case ARGP_KEY_END: + break; + + default: + return ARGP_ERR_UNKNOWN; + break; + } + return 0; +} + +static void do_render (const render_arguments * const arguments) { + randctx rc; + + rand_seed(&rc); + + int ncps; + flam3_genome * const cps = flam3_parse_from_file (stdin, NULL, + flam3_defaults_on, &ncps, &rc); + if (cps == NULL) { + fprintf(stderr,"error reading genomes from file\n"); + exit(1); + } + assert (ncps == 1); + + flam3_genome * const genome = &cps[0]; + + /* Force ntemporal_samples to 1 for -render */ + genome->ntemporal_samples = 1; + genome->sample_density = arguments->quality; + genome->height *= arguments->scale; + genome->width *= arguments->scale; + genome->pixels_per_unit *= arguments->scale; + + flam3_frame f; + f.genomes = genome; + f.ngenomes = 1; + f.verbose = arguments->verbose; + f.time = 0.0; + f.pixel_aspect_ratio = 1.0; + f.progress = 0; + f.nthreads = arguments->threads; + f.earlyclip = 0; + f.sub_batch_size = 10000; + f.bytes_per_channel = arguments->bpc / 8; + + const unsigned int channels = 4; + const size_t this_size = channels * genome->width * genome->height * + f.bytes_per_channel; + void *image = (void *) calloc(this_size, sizeof(char)); + + stat_struct stats; + if (flam3_render (&f, image, flam3_field_both, channels, + arguments->transparent, &stats)) { + fprintf(stderr,"error rendering image: aborting.\n"); + exit(1); + } + + flam3_img_comments fpc; + write_png (stdout, image, genome->width, genome->height, &fpc, + f.bytes_per_channel); +} + +typedef struct { + int symmetry; + const char *palette; +} random_arguments; + +static void do_random (const random_arguments * const arguments) { + randctx rc; + rand_seed(&rc); + + flam3_genome genome = { .edits = NULL }; + int ivars = flam3_variation_random; + flam3_random (&genome, &ivars, 1, arguments->symmetry, 0, &rc); + + flam3_print (stdout, &genome, NULL, flam3_dont_print_edits); + fflush(stdout); +} + +typedef struct { + int method; + unsigned int symmetry; +} mutate_arguments; + +static error_t parse_mutate_opt (int key, char *arg, + struct argp_state * const state) { + mutate_arguments * const arguments = state->input; + switch (key) { + case 'm': + if (arg == NULL) { + arguments->method = MUTATE_NOT_SPECIFIED; + } else if (streq (arg, "all-vars")) { + arguments->method = MUTATE_ALL_VARIATIONS; + } else if (streq(arg,"one-xform")) { + arguments->method = MUTATE_ONE_XFORM_COEFS; + } else if (streq(arg,"add-symmetry")) { + arguments->method = MUTATE_ADD_SYMMETRY; + } else if (streq(arg,"post-xforms")) { + arguments->method = MUTATE_POST_XFORMS; + } else if (streq(arg,"color-palette")) { + arguments->method = MUTATE_COLOR_PALETTE; + } else if (streq(arg,"delete-xform")) { + arguments->method = MUTATE_DELETE_XFORM; + } else if (streq(arg,"all-coefs")) { + arguments->method = MUTATE_ALL_COEFS; + } else { + argp_error (state, "Unknown method %s", arg); + } + break; + + case ARGP_KEY_ARG: + if (state->arg_num > 0) { + return ARGP_ERR_UNKNOWN; + } + break; + + case ARGP_KEY_END: + break; + + default: + return ARGP_ERR_UNKNOWN; + break; + } + + return 0; +} + +static void do_mutate (const mutate_arguments * const arguments) { + randctx rc; + + rand_seed(&rc); + + int ncps; + flam3_genome * const cps = flam3_parse_from_file (stdin, NULL, + flam3_defaults_on, &ncps, &rc); + if (cps == NULL) { + fprintf(stderr,"error reading genomes from file\n"); + exit(1); + } + assert (ncps == 1); + + flam3_genome * const genome = &cps[0]; + + int ivars = flam3_variation_random; + const double speed = 1.0; + flam3_mutate (genome, arguments->method, &ivars, 1, arguments->symmetry, + speed, &rc); + + printf("\n", flam3_version()); + flam3_print (stdout, genome, NULL, flam3_dont_print_edits); + printf("\n"); + fflush(stdout); +} + +typedef struct { + int method; +} cross_arguments; + +static error_t parse_cross_opt (int key, char *arg, + struct argp_state * const state) { + mutate_arguments * const arguments = state->input; + switch (key) { + case 'm': + if (arg == NULL) { + arguments->method = CROSS_NOT_SPECIFIED; + } else if (streq(arg,"union")) { + arguments->method = CROSS_UNION; + } else if (streq(arg,"interpolate")) { + arguments->method = CROSS_INTERPOLATE; + } else if (streq(arg,"alternate")) { + arguments->method = CROSS_ALTERNATE; + } else { + argp_error (state, "Unknown method %s", arg); + } + break; + + case ARGP_KEY_ARG: + if (state->arg_num > 0) { + return ARGP_ERR_UNKNOWN; + } + break; + + case ARGP_KEY_END: + break; + + default: + return ARGP_ERR_UNKNOWN; + break; + } + + return 0; +} + +static void do_cross (const cross_arguments * const arguments) { + randctx rc; + + rand_seed(&rc); + + int ncps; + flam3_genome * const cps = flam3_parse_from_file (stdin, NULL, + flam3_defaults_on, &ncps, &rc); + if (cps == NULL) { + fprintf(stderr,"error reading genomes from file\n"); + exit(1); + } + assert (ncps == 2); + + flam3_genome * const genome_a = &cps[0], * const genome_b = &cps[1]; + flam3_genome genome_out; + + flam3_cross (genome_a, genome_b, &genome_out, arguments->method, &rc); + + printf("\n", flam3_version()); + flam3_print (stdout, &genome_out, NULL, flam3_dont_print_edits); + printf("\n"); + fflush(stdout); +} + +#if 0 +static void do_improvecolors () { + flam3_improve_colors(&cp_orig, 100, 0, 10, &rc); +} + +static void do_interpolate () { + for (ftime = first_frame; ftime <= last_frame; ftime += 1) { + iscp=0; + for (i=0;i