/*
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, oversample, width, height;
float scale;
} 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 'h': {
int i = atoi (arg);
if (i <= 0) {
argp_error (state, "Height must be > 0");
} else {
arguments->height = i;
}
break;
}
case 'o': {
int i = atoi (arg);
if (i < 1) {
argp_error (state, "Oversample must be >= 1");
} else {
arguments->oversample = i;
}
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 'w': {
int i = atoi (arg);
if (i <= 0) {
argp_error (state, "Width must be > 0");
} else {
arguments->width = 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;
if (arguments->height != 0) {
genome->height = arguments->height;
}
if (arguments->width != 0) {
genome->width = arguments->width;
}
genome->height *= arguments->scale;
genome->width *= arguments->scale;
genome->pixels_per_unit *= arguments->scale;
genome->spatial_oversample = arguments->oversample;
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, &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