From a093dd0ee969be5150fdff459db385fbc5613452 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 22 Mar 2015 10:12:05 +0100 Subject: Rewrite flam3_random Disables flam3_mutate. --- flam3.c | 525 ++------------------------------------------------------------- flam3.h | 16 +- genome.c | 299 ++++++++++++++++++++++++++++++++++++ genome.h | 25 +++ main.c | 74 +++++++-- math.h | 15 ++ parser.c | 4 +- parser.h | 2 +- wscript | 2 +- 9 files changed, 418 insertions(+), 544 deletions(-) create mode 100644 genome.c create mode 100644 genome.h diff --git a/flam3.c b/flam3.c index bf0b124..e974b50 100644 --- a/flam3.c +++ b/flam3.c @@ -24,6 +24,7 @@ #include "parser.h" #include "palettes.h" #include "random.h" +#include "math.h" #include #include #include @@ -1025,24 +1026,21 @@ void clear_cp(flam3_genome *cp, int default_flag) { cp->final_xform_index = -1; } -flam3_genome *flam3_parse_xml2(char *xmldata, char *xmlfilename, int default_flag, int *ncps, randctx * const rc) { +flam3_genome *flam3_parse_xml2(const int fd, int default_flag, int *ncps, + randctx * const rc) { xmlDocPtr doc; /* Parsed XML document tree */ xmlNode *rootnode; - char *bn; int i; int loc_all_ncps=0; flam3_genome *loc_all_cp=NULL; char* locale = NULL; char* lorig = setlocale(LC_NUMERIC, NULL); - /* Parse XML string into internal document */ - /* Forbid network access during read */ - doc = xmlReadMemory(xmldata, (int)strlen(xmldata), xmlfilename, NULL, XML_PARSE_NONET); - + doc = xmlReadFd (fd, NULL, NULL, XML_PARSE_NONET); /* Check for errors */ if (doc==NULL) { - fprintf(stderr, "Failed to parse %s\n", xmlfilename); + fprintf(stderr, "Failed to parse \n"); return NULL; } @@ -1062,11 +1060,8 @@ flam3_genome *flam3_parse_xml2(char *xmldata, char *xmlfilename, int default_fla if (setlocale(LC_NUMERIC, "C") == NULL) fprintf(stderr, "error: couldn't set C locale\n"); - /* Scan for nodes, starting with this node */ - bn = basename(xmlfilename); - /* Have to use &loc_all_cp since the memory gets allocated in scan_for_flame_nodes */ - scan_for_flame_nodes(rootnode, bn, default_flag,&loc_all_cp,&loc_all_ncps, rc); + scan_for_flame_nodes(rootnode, default_flag,&loc_all_cp,&loc_all_ncps, rc); // restore locale if (locale != NULL) { @@ -1126,46 +1121,6 @@ flam3_genome *flam3_parse_xml2(char *xmldata, char *xmlfilename, int default_fla return loc_all_cp; } -flam3_genome * flam3_parse_from_file(FILE *f, char *fname, int default_flag, int *ncps, randctx * const rc) { - int i, c, slen = 5000; - char *s, *snew; - flam3_genome *ret; - - /* Incrementally read XML file into a string */ - s = malloc(slen); - i = 0; - do { - c = getc(f); - if (EOF == c) - break; - s[i++] = c; - if (i == slen-1) { - slen *= 2; - snew = realloc(s, slen); - if (snew==NULL) { - fprintf(stderr,"XML file too large to be read. continuing with partial file.\n"); - break; - } else - s = snew; - } - } while (1); - - /* Null-terminate the read XML data */ - s[i] = 0; - - /* Parse the XML string */ - if (fname) - ret = flam3_parse_xml2(s, fname, default_flag, ncps, rc); - else - ret = flam3_parse_xml2(s, "stdin", default_flag, ncps, rc); - - free(s); - - return(ret); - -} - - void flam3_apply_template(flam3_genome *cp, flam3_genome *templ) { /* Check for invalid values - only replace those with valid ones */ @@ -2195,6 +2150,7 @@ void flam3_cross(flam3_genome *cp0, flam3_genome *cp1, flam3_genome *out, int cr } +#if 0 void flam3_mutate(flam3_genome *cp, int mutate_mode, int *ivars, int ivars_n, int sym, double speed, const palette_collection * const pc, randctx *rc) { double randselect; @@ -2228,11 +2184,10 @@ void flam3_mutate(flam3_genome *cp, int mutate_mode, int *ivars, int ivars_n, in if (mutate_mode == MUTATE_ALL_VARIATIONS) { - do { /* Create a random flame, and use the variations */ /* to replace those in the original */ - flam3_random(&mutation, ivars, ivars_n, sym, cp->num_xforms, pc, rc); + flam3_random(&mutation, cp->num_xforms, pc, rc); for (i = 0; i < cp->num_xforms; i++) { for (j = 0; j < flam3_nvariations; j++) { if (cp->xform[i].var[j] != mutation.xform[i].var[j]) { @@ -2404,469 +2359,7 @@ void flam3_mutate(flam3_genome *cp, int mutate_mode, int *ivars, int ivars_n, in clear_cp(&mutation,flam3_defaults_on); } - -void flam3_random(flam3_genome *cp, int *ivars, int ivars_n, int sym, - int spec_xforms, const palette_collection * const pc, - randctx * const rc) { - - int i, nxforms, var, samed, multid, samepost, postid, addfinal=0; - int finum = -1; - int n; - int mvar = flam3_nvariations; - double sum; - - static int xform_distrib[] = { - 2, 2, 2, 2, - 3, 3, 3, 3, - 4, 4, 4, - 5, 5, - 6 - }; - - clear_cp(cp,flam3_defaults_on); - - cp->hue_rotation = rand_mod(rc, 8) ? 0.0 : rand_d01(rc); - const palette * const p = palette_random (pc, rc); - assert (p != NULL); - palette_copy (p, &cp->palette); - palette_rotate_hue (&cp->palette, cp->hue_rotation); - cp->time = 0.0; - cp->interpolation = flam3_interpolation_linear; - cp->palette_interpolation = flam3_palette_interpolation_hsv; - - /* Choose the number of xforms */ - if (spec_xforms>0) { - nxforms = spec_xforms; - flam3_add_xforms(cp,nxforms,0,0); - } else { - nxforms = rand_distrib(rc, xform_distrib); - flam3_add_xforms(cp,nxforms,0,0); - /* Add a final xform 15% of the time */ - addfinal = rand_d01(rc) < 0.15; - if (addfinal) { - flam3_add_xforms(cp,1,0,1); - nxforms = nxforms + addfinal; - finum = nxforms-1; - } - } - - /* If first input variation is 'flam3_variation_random' */ - /* choose one to use or decide to use multiple */ - if (flam3_variation_random == ivars[0]) { - if (rand_bool(rc)) { - var = rand_mod(rc, mvar); - } else { - var = flam3_variation_random; - } - } else { - var = flam3_variation_random_fromspecified; - } - - samed = rand_bool(rc); - multid = rand_bool(rc); - postid = rand_d01(rc) < 0.6; - samepost = rand_bool(rc); - - /* Loop over xforms */ - for (i = 0; i < nxforms; i++) { - int j, k; - cp->xform[i].density = 1.0 / nxforms; - cp->xform[i].color = i&1; - cp->xform[i].color_speed = 0.5; - cp->xform[i].animate = 1.0; - for (j = 0; j < 3; j++) { - for (k = 0; k < 2; k++) { - cp->xform[i].c[j][k] = rand_d11(rc); - cp->xform[i].post[j][k] = (double)(k==j); - } - } - - if ( i != finum ) { - - if (!postid) { - - for (j = 0; j < 3; j++) - for (k = 0; k < 2; k++) { - if (samepost || (i==0)) - cp->xform[i].post[j][k] = rand_d11(rc); - else - cp->xform[i].post[j][k] = cp->xform[0].post[j][k]; - } - } - - /* Clear all variation coefs */ - for (j = 0; j < flam3_nvariations; j++) - cp->xform[i].var[j] = 0.0; - - if (flam3_variation_random != var && - flam3_variation_random_fromspecified != var) { - - /* Use only one variation specified for all xforms */ - cp->xform[i].var[var] = 1.0; - - } else if (multid && flam3_variation_random == var) { - - /* Choose a random var for this xform */ - cp->xform[i].var[rand_mod(rc, mvar)] = 1.0; - - } else { - - if (samed && i > 0) { - - /* Copy the same variations from the previous xform */ - for (j = 0; j < flam3_nvariations; j++) { - cp->xform[i].var[j] = cp->xform[i-1].var[j]; - flam3_copy_params(&(cp->xform[i]),&(cp->xform[i-1]),j); - } - - } else { - - /* Choose a random number of vars to use, at least 2 */ - /* but less than flam3_nvariations.Probability leans */ - /* towards fewer variations. */ - n = 2; - while ((rand_bool(rc)) && (nxform[i].var[rand_mod(rc, mvar)] = rand_d01(rc); - else - cp->xform[i].var[ivars[rand_mod(rc, ivars_n)]] = rand_d01(rc); - } - - /* Normalize weights to 1.0 total. */ - sum = 0.0; - for (j = 0; j < flam3_nvariations; j++) - sum += cp->xform[i].var[j]; - if (sum == 0.0) - cp->xform[i].var[rand_mod(rc, flam3_nvariations)] = 1.0; - else { - for (j = 0; j < flam3_nvariations; j++) - cp->xform[i].var[j] /= sum; - } - } - } - } else { - /* Handle final xform randomness. */ - n = 1; - if (rand_bool(rc)) n++; - - /* Randomly choose n variations, and change their weights. */ - /* A var can be selected more than once, further reducing */ - /* the probability that multiple vars are used. */ - for (j = 0; j < n; j++) { - if (flam3_variation_random_fromspecified != var) - cp->xform[i].var[rand_mod(rc, mvar)] = rand_d01(rc); - else - cp->xform[i].var[ivars[rand_mod(rc, ivars_n)]] = rand_d01(rc); - } - - /* Normalize weights to 1.0 total. */ - sum = 0.0; - for (j = 0; j < flam3_nvariations; j++) - sum += cp->xform[i].var[j]; - if (sum == 0.0) - cp->xform[i].var[rand_mod(rc, flam3_nvariations)] = 1.0; - else { - for (j = 0; j < flam3_nvariations; j++) - cp->xform[i].var[j] /= sum; - } - } - - /* Generate random params for parametric variations, if selected. */ - if (cp->xform[i].var[VAR_BLOB] > 0) { - /* Create random params for blob */ - cp->xform[i].blob_low = 0.2 + 0.5 * rand_d01(rc); - cp->xform[i].blob_high = 0.8 + 0.4 * rand_d01(rc); - cp->xform[i].blob_waves = (int)(2 + 5 * rand_d01(rc)); - } - - if (cp->xform[i].var[VAR_PDJ] > 0) { - /* Create random params for PDJ */ - cp->xform[i].pdj_a = 3.0 * rand_d11(rc); - cp->xform[i].pdj_b = 3.0 * rand_d11(rc); - cp->xform[i].pdj_c = 3.0 * rand_d11(rc); - cp->xform[i].pdj_d = 3.0 * rand_d11(rc); - } - - if (cp->xform[i].var[VAR_FAN2] > 0) { - /* Create random params for fan2 */ - cp->xform[i].fan2_x = rand_d11(rc); - cp->xform[i].fan2_y = rand_d11(rc); - } - - if (cp->xform[i].var[VAR_RINGS2] > 0) { - /* Create random params for rings2 */ - cp->xform[i].rings2_val = 2*rand_d01(rc); - } - - if (cp->xform[i].var[VAR_PERSPECTIVE] > 0) { - - /* Create random params for perspective */ - cp->xform[i].perspective_angle = rand_d01(rc); - cp->xform[i].perspective_dist = 2*rand_d01(rc) + 1.0; - - } - - if (cp->xform[i].var[VAR_JULIAN] > 0) { - - /* Create random params for julian */ - cp->xform[i].julian_power = (int)(5*rand_d01(rc) + 2); - cp->xform[i].julian_dist = 1.0; - - } - - if (cp->xform[i].var[VAR_JULIASCOPE] > 0) { - - /* Create random params for juliaScope */ - cp->xform[i].juliascope_power = (int)(5*rand_d01(rc) + 2); - cp->xform[i].juliascope_dist = 1.0; - - } - - if (cp->xform[i].var[VAR_RADIAL_BLUR] > 0) { - - /* Create random params for radialBlur */ - cp->xform[i].radial_blur_angle = (2 * rand_d01(rc) - 1); - - } - - if (cp->xform[i].var[VAR_PIE] > 0) { - /* Create random params for pie */ - cp->xform[i].pie_slices = (int) 10.0*rand_d01(rc); - cp->xform[i].pie_thickness = rand_d01(rc); - cp->xform[i].pie_rotation = 2.0 * M_PI * rand_d11(rc); - } - - if (cp->xform[i].var[VAR_NGON] > 0) { - /* Create random params for ngon */ - cp->xform[i].ngon_sides = (int) rand_d01(rc)* 10 + 3; - cp->xform[i].ngon_power = 3*rand_d01(rc) + 1; - cp->xform[i].ngon_circle = 3*rand_d01(rc); - cp->xform[i].ngon_corners = 2*rand_d01(rc)*cp->xform[i].ngon_circle; - } - - if (cp->xform[i].var[VAR_CURL] > 0) { - /* Create random params for curl */ - cp->xform[i].curl_c1 = rand_d01(rc); - cp->xform[i].curl_c2 = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_RECTANGLES] > 0) { - /* Create random params for rectangles */ - cp->xform[i].rectangles_x = rand_d01(rc); - cp->xform[i].rectangles_y = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_DISC2] > 0) { - /* Create random params for disc2 */ - cp->xform[i].disc2_rot = 0.5 * rand_d01(rc); - cp->xform[i].disc2_twist = 0.5 * rand_d01(rc); - - } - - if (cp->xform[i].var[VAR_SUPER_SHAPE] > 0) { - /* Create random params for supershape */ - cp->xform[i].super_shape_rnd = rand_d01(rc); - cp->xform[i].super_shape_m = (int) rand_d01(rc)*6; - cp->xform[i].super_shape_n1 = rand_d01(rc)*40; - cp->xform[i].super_shape_n2 = rand_d01(rc)*20; - cp->xform[i].super_shape_n3 = cp->xform[i].super_shape_n2; - cp->xform[i].super_shape_holes = 0.0; - } - - if (cp->xform[i].var[VAR_FLOWER] > 0) { - /* Create random params for flower */ - cp->xform[i].flower_petals = 4 * rand_d01(rc); - cp->xform[i].flower_holes = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_CONIC] > 0) { - /* Create random params for conic */ - cp->xform[i].conic_eccentricity = rand_d01(rc); - cp->xform[i].conic_holes = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_PARABOLA] > 0) { - /* Create random params for parabola */ - cp->xform[i].parabola_height = 0.5 + rand_d01(rc); - cp->xform[i].parabola_width = 0.5 + rand_d01(rc); - } - - if (cp->xform[i].var[VAR_BENT2] > 0) { - /* Create random params for bent2 */ - cp->xform[i].bent2_x = 3*(-0.5 + rand_d01(rc)); - cp->xform[i].bent2_y = 3*(-0.5 + rand_d01(rc)); - } - - if (cp->xform[i].var[VAR_BIPOLAR] > 0) { - /* Create random params for bipolar */ - cp->xform[i].bipolar_shift = 2.0 * rand_d01(rc) - 1; - } - - if (cp->xform[i].var[VAR_CELL] > 0) { - /* Create random params for cell */ - cp->xform[i].cell_size = 2.0 * rand_d01(rc) + 0.5; - } - - if (cp->xform[i].var[VAR_CPOW] > 0) { - /* Create random params for cpow */ - cp->xform[i].cpow_r = 3.0 * rand_d01(rc); - cp->xform[i].cpow_i = rand_d01(rc) - 0.5; - cp->xform[i].cpow_power = (int)(5.0 * rand_d01(rc)); - } - - if (cp->xform[i].var[VAR_CURVE] > 0) { - /* Create random params for curve */ - cp->xform[i].curve_xamp = 5 * (rand_d01(rc)-.5); - cp->xform[i].curve_yamp = 4 * (rand_d01(rc)-.5); - cp->xform[i].curve_xlength = 2 * (rand_d01(rc)+.5); - cp->xform[i].curve_ylength = 2 * (rand_d01(rc)+.5); - } - - if (cp->xform[i].var[VAR_ESCHER] > 0) { - /* Create random params for escher */ - cp->xform[i].escher_beta = M_PI * rand_d11(rc); - } - - if (cp->xform[i].var[VAR_LAZYSUSAN] > 0) { - /* Create random params for lazysusan */ - cp->xform[i].lazysusan_x = 2.0*rand_d11(rc); - cp->xform[i].lazysusan_y = 2.0*rand_d11(rc); - cp->xform[i].lazysusan_spin = M_PI*rand_d11(rc); - cp->xform[i].lazysusan_space = 2.0*rand_d11(rc); - cp->xform[i].lazysusan_twist = 2.0*rand_d11(rc); - } - - if (cp->xform[i].var[VAR_MODULUS] > 0) { - /* Create random params for modulus */ - cp->xform[i].modulus_x = rand_d11(rc); - cp->xform[i].modulus_y = rand_d11(rc); - } - - if (cp->xform[i].var[VAR_OSCILLOSCOPE] > 0) { - /* Create random params for oscope */ - cp->xform[i].oscope_separation = 1.0 + rand_d11(rc); - cp->xform[i].oscope_frequency = M_PI * rand_d11(rc); - cp->xform[i].oscope_amplitude = 1.0 + 2 * rand_d01(rc); - cp->xform[i].oscope_damping = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_POPCORN2] > 0) { - /* Create random params for popcorn2 */ - cp->xform[i].popcorn2_x = 0.2 * rand_d01(rc); - cp->xform[i].popcorn2_y = 0.2 * rand_d01(rc); - cp->xform[i].popcorn2_c = 5 * rand_d01(rc); - } - - if (cp->xform[i].var[VAR_SEPARATION] > 0) { - /* Create random params for separation */ - cp->xform[i].separation_x = 1 + rand_d11(rc); - cp->xform[i].separation_y = 1 + rand_d11(rc); - cp->xform[i].separation_xinside = rand_d11(rc); - cp->xform[i].separation_yinside = rand_d11(rc); - } - - if (cp->xform[i].var[VAR_SPLIT] > 0) { - /* Create random params for split */ - cp->xform[i].split_xsize = rand_d11(rc); - cp->xform[i].split_ysize = rand_d11(rc); - } - - if (cp->xform[i].var[VAR_SPLITS] > 0) { - /* Create random params for splits */ - cp->xform[i].splits_x = rand_d11(rc); - cp->xform[i].splits_y = rand_d11(rc); - } - - if (cp->xform[i].var[VAR_STRIPES] > 0) { - /* Create random params for stripes */ - cp->xform[i].stripes_space = rand_d01(rc); - cp->xform[i].stripes_warp = 5*rand_d01(rc); - } - - if (cp->xform[i].var[VAR_WEDGE] > 0) { - /* Create random params for wedge */ - cp->xform[i].wedge_angle = M_PI*rand_d01(rc); - cp->xform[i].wedge_hole = 0.5*rand_d11(rc); - cp->xform[i].wedge_count = floor(5*rand_d01(rc))+1; - cp->xform[i].wedge_swirl = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_WEDGE_JULIA] > 0) { - - /* Create random params for wedge_julia */ - cp->xform[i].wedge_julia_power = (int)(5*rand_d01(rc) + 2); - cp->xform[i].wedge_julia_dist = 1.0; - cp->xform[i].wedge_julia_count = (int)(3*rand_d01(rc) + 1); - cp->xform[i].wedge_julia_angle = M_PI * rand_d01(rc); - - } - - if (cp->xform[i].var[VAR_WEDGE_SPH] > 0) { - /* Create random params for wedge_sph */ - cp->xform[i].wedge_sph_angle = M_PI*rand_d01(rc); - cp->xform[i].wedge_sph_hole = 0.5*rand_d11(rc); - cp->xform[i].wedge_sph_count = floor(5*rand_d01(rc))+1; - cp->xform[i].wedge_sph_swirl = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_WHORL] > 0) { - /* Create random params for whorl */ - cp->xform[i].whorl_inside = rand_d01(rc); - cp->xform[i].whorl_outside = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_WAVES2] > 0) { - /* Create random params for waves2 */ - cp->xform[i].waves2_scalex = 0.5 + rand_d01(rc); - cp->xform[i].waves2_scaley = 0.5 + rand_d01(rc); - cp->xform[i].waves2_freqx = 4 * rand_d01(rc); - cp->xform[i].waves2_freqy = 4 * rand_d01(rc); - } - - if (cp->xform[i].var[VAR_AUGER] > 0) { - /* Create random params for auger */ - cp->xform[i].auger_sym = 0; - cp->xform[i].auger_weight = 0.5 + rand_d01(rc)/2.0; - cp->xform[i].auger_freq = floor(5*rand_d01(rc))+1; - cp->xform[i].auger_scale = rand_d01(rc); - } - - if (cp->xform[i].var[VAR_FLUX] > 0) { - /* Create random params for flux */ - cp->xform[i].flux_spread = 0.5 + rand_d01(rc)/2.0; - } - - if (cp->xform[i].var[VAR_MOBIUS] > 0) { - /* Create random params for mobius */ - cp->xform[i].mobius_re_a = rand_d11(rc); - cp->xform[i].mobius_im_a = rand_d11(rc); - cp->xform[i].mobius_re_b = rand_d11(rc); - cp->xform[i].mobius_im_b = rand_d11(rc); - cp->xform[i].mobius_re_c = rand_d11(rc); - cp->xform[i].mobius_im_c = rand_d11(rc); - cp->xform[i].mobius_re_d = rand_d11(rc); - cp->xform[i].mobius_im_d = rand_d11(rc); - } - - } - - /* Randomly add symmetry (but not if we've already added a final xform) */ - if (sym || (!rand_mod(rc, 4) && !addfinal)) - flam3_add_symmetry(cp, sym, rc); - else - cp->symmetry = 0; - - //qsort((char *) cp->xform, (cp->num_xforms-addfinal), sizeof(flam3_xform), compare_xforms); - - -} - +#endif static int sort_by_x(const void *av, const void *bv) { double4 a = *((double4 *) av); diff --git a/flam3.h b/flam3.h index 58b6343..8dc4595 100644 --- a/flam3.h +++ b/flam3.h @@ -34,13 +34,9 @@ #include "random.h" -#define flam3_variation_random (-1) -#define flam3_variation_random_fromspecified (-2) - extern char *flam3_variation_names[]; #define flam3_nvariations 99 -#define flam3_nxforms 12 #define flam3_interpolation_linear 0 #define flam3_interpolation_smooth 1 @@ -511,13 +507,8 @@ void flam3_print(FILE *f, flam3_genome *g, char *extra_attributes); void flam3_print_xform(FILE *f, flam3_xform *x, int final_flag, int numstd, double *chaos_row, int motion_flag); char *flam3_print_to_string(flam3_genome *cp); -/* ivars is a list of variations to use, or flam3_variation_random */ -/* ivars_n is the number of values in ivars to select from. */ -/* sym is either a symmetry group or 0 meaning random or no symmetry */ -/* spec_xforms specifies the number of xforms to use, setting to 0 makes the number random. */ -void flam3_random(flam3_genome *cp, int *ivars, int ivars_n, int sym, - int spec_xforms, const palette_collection * const pc, - randctx * const rc); +void flam3_random(flam3_genome *cp, const unsigned int max_xform, + const palette_collection * const pc, randctx * const rc); void add_to_action(char *action, char *addtoaction); @@ -525,8 +516,7 @@ void flam3_mutate(flam3_genome *cp, int mutate_mode, int *ivars, int ivars_n, in void flam3_cross(flam3_genome *cp0, flam3_genome *cp1, flam3_genome *out, int cross_mode, randctx *rc); /* return NULL in case of error */ -flam3_genome *flam3_parse_xml2(char *s, char *fn, int default_flag, int *ncps, randctx * const); -flam3_genome *flam3_parse_from_file(FILE *f, char *fn, int default_flag, int *ncps, randctx * const); +flam3_genome *flam3_parse_xml2(const int, int default_flag, int *ncps, randctx * const); void flam3_add_symmetry(flam3_genome *cp, int sym, randctx * const rc); diff --git a/genome.c b/genome.c new file mode 100644 index 0000000..547a6a8 --- /dev/null +++ b/genome.c @@ -0,0 +1,299 @@ +/* + Copyright (C) 1992-2009 Spotworks LLC + 2015 pucket contributors + + 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 "genome.h" +#include "math.h" +#include "flam3.h" +#include "random.h" + +/* Generate random params for parametric variations */ +static void random_xform_param (flam3_xform * const xform, const unsigned int i, + randctx * const rc) { + switch (i) { + case VAR_BLOB: + xform->blob_low = 0.2 + 0.5 * rand_d01(rc); + xform->blob_high = 0.8 + 0.4 * rand_d01(rc); + xform->blob_waves = (int)(2 + 5 * rand_d01(rc)); + break; + + case VAR_PDJ: + xform->pdj_a = 3.0 * rand_d11(rc); + xform->pdj_b = 3.0 * rand_d11(rc); + xform->pdj_c = 3.0 * rand_d11(rc); + xform->pdj_d = 3.0 * rand_d11(rc); + break; + + case VAR_FAN2: + xform->fan2_x = rand_d11(rc); + xform->fan2_y = rand_d11(rc); + break; + + case VAR_RINGS2: + xform->rings2_val = 2*rand_d01(rc); + break; + + case VAR_PERSPECTIVE: + xform->perspective_angle = rand_d01(rc); + xform->perspective_dist = 2*rand_d01(rc) + 1.0; + break; + + case VAR_JULIAN: + xform->julian_power = (int)(5*rand_d01(rc) + 2); + xform->julian_dist = 1.0; + break; + + case VAR_JULIASCOPE: + xform->juliascope_power = (int)(5*rand_d01(rc) + 2); + xform->juliascope_dist = 1.0; + break; + + case VAR_RADIAL_BLUR: + xform->radial_blur_angle = (2 * rand_d01(rc) - 1); + break; + + case VAR_PIE: + xform->pie_slices = (int) 10.0*rand_d01(rc); + xform->pie_thickness = rand_d01(rc); + xform->pie_rotation = 2.0 * M_PI * rand_d11(rc); + break; + + case VAR_NGON: + xform->ngon_sides = (int) rand_d01(rc)* 10 + 3; + xform->ngon_power = 3*rand_d01(rc) + 1; + xform->ngon_circle = 3*rand_d01(rc); + xform->ngon_corners = 2*rand_d01(rc)*xform->ngon_circle; + break; + + case VAR_CURL: + xform->curl_c1 = rand_d01(rc); + xform->curl_c2 = rand_d01(rc); + break; + + case VAR_RECTANGLES: + xform->rectangles_x = rand_d01(rc); + xform->rectangles_y = rand_d01(rc); + break; + + case VAR_DISC2: + xform->disc2_rot = 0.5 * rand_d01(rc); + xform->disc2_twist = 0.5 * rand_d01(rc); + break; + + case VAR_SUPER_SHAPE: + xform->super_shape_rnd = rand_d01(rc); + xform->super_shape_m = (int) rand_d01(rc)*6; + xform->super_shape_n1 = rand_d01(rc)*40; + xform->super_shape_n2 = rand_d01(rc)*20; + xform->super_shape_n3 = xform->super_shape_n2; + xform->super_shape_holes = 0.0; + break; + + case VAR_FLOWER: + xform->flower_petals = 4 * rand_d01(rc); + xform->flower_holes = rand_d01(rc); + break; + + case VAR_CONIC: + xform->conic_eccentricity = rand_d01(rc); + xform->conic_holes = rand_d01(rc); + break; + + case VAR_PARABOLA: + xform->parabola_height = 0.5 + rand_d01(rc); + xform->parabola_width = 0.5 + rand_d01(rc); + break; + + case VAR_BENT2: + xform->bent2_x = 3*(-0.5 + rand_d01(rc)); + xform->bent2_y = 3*(-0.5 + rand_d01(rc)); + break; + + case VAR_BIPOLAR: + xform->bipolar_shift = 2.0 * rand_d01(rc) - 1; + break; + + case VAR_CELL: + xform->cell_size = 2.0 * rand_d01(rc) + 0.5; + break; + + case VAR_CPOW: + xform->cpow_r = 3.0 * rand_d01(rc); + xform->cpow_i = rand_d01(rc) - 0.5; + xform->cpow_power = (int)(5.0 * rand_d01(rc)); + break; + + case VAR_CURVE: + xform->curve_xamp = 5 * (rand_d01(rc)-.5); + xform->curve_yamp = 4 * (rand_d01(rc)-.5); + xform->curve_xlength = 2 * (rand_d01(rc)+.5); + xform->curve_ylength = 2 * (rand_d01(rc)+.5); + break; + + case VAR_ESCHER: + xform->escher_beta = M_PI * rand_d11(rc); + break; + + case VAR_LAZYSUSAN: + xform->lazysusan_x = 2.0*rand_d11(rc); + xform->lazysusan_y = 2.0*rand_d11(rc); + xform->lazysusan_spin = M_PI*rand_d11(rc); + xform->lazysusan_space = 2.0*rand_d11(rc); + xform->lazysusan_twist = 2.0*rand_d11(rc); + break; + + case VAR_MODULUS: + xform->modulus_x = rand_d11(rc); + xform->modulus_y = rand_d11(rc); + break; + + case VAR_OSCILLOSCOPE: + xform->oscope_separation = 1.0 + rand_d11(rc); + xform->oscope_frequency = M_PI * rand_d11(rc); + xform->oscope_amplitude = 1.0 + 2 * rand_d01(rc); + xform->oscope_damping = rand_d01(rc); + break; + + case VAR_POPCORN2: + xform->popcorn2_x = 0.2 * rand_d01(rc); + xform->popcorn2_y = 0.2 * rand_d01(rc); + xform->popcorn2_c = 5 * rand_d01(rc); + break; + + case VAR_SEPARATION: + xform->separation_x = 1 + rand_d11(rc); + xform->separation_y = 1 + rand_d11(rc); + xform->separation_xinside = rand_d11(rc); + xform->separation_yinside = rand_d11(rc); + break; + + case VAR_SPLIT: + xform->split_xsize = rand_d11(rc); + xform->split_ysize = rand_d11(rc); + break; + + case VAR_SPLITS: + xform->splits_x = rand_d11(rc); + xform->splits_y = rand_d11(rc); + break; + + case VAR_STRIPES: + xform->stripes_space = rand_d01(rc); + xform->stripes_warp = 5*rand_d01(rc); + break; + + case VAR_WEDGE: + xform->wedge_angle = M_PI*rand_d01(rc); + xform->wedge_hole = 0.5*rand_d11(rc); + xform->wedge_count = floor(5*rand_d01(rc))+1; + xform->wedge_swirl = rand_d01(rc); + break; + + case VAR_WEDGE_JULIA: + xform->wedge_julia_power = (int)(5*rand_d01(rc) + 2); + xform->wedge_julia_dist = 1.0; + xform->wedge_julia_count = (int)(3*rand_d01(rc) + 1); + xform->wedge_julia_angle = M_PI * rand_d01(rc); + break; + + case VAR_WEDGE_SPH: + xform->wedge_sph_angle = M_PI*rand_d01(rc); + xform->wedge_sph_hole = 0.5*rand_d11(rc); + xform->wedge_sph_count = floor(5*rand_d01(rc))+1; + xform->wedge_sph_swirl = rand_d01(rc); + break; + + case VAR_WHORL: + xform->whorl_inside = rand_d01(rc); + xform->whorl_outside = rand_d01(rc); + break; + + case VAR_WAVES2: + xform->waves2_scalex = 0.5 + rand_d01(rc); + xform->waves2_scaley = 0.5 + rand_d01(rc); + xform->waves2_freqx = 4 * rand_d01(rc); + xform->waves2_freqy = 4 * rand_d01(rc); + break; + + case VAR_AUGER: + xform->auger_sym = 0; + xform->auger_weight = 0.5 + rand_d01(rc)/2.0; + xform->auger_freq = floor(5*rand_d01(rc))+1; + xform->auger_scale = rand_d01(rc); + break; + + case VAR_FLUX: + xform->flux_spread = 0.5 + rand_d01(rc)/2.0; + break; + + case VAR_MOBIUS: + xform->mobius_re_a = rand_d11(rc); + xform->mobius_im_a = rand_d11(rc); + xform->mobius_re_b = rand_d11(rc); + xform->mobius_im_b = rand_d11(rc); + xform->mobius_re_c = rand_d11(rc); + xform->mobius_im_c = rand_d11(rc); + xform->mobius_re_d = rand_d11(rc); + xform->mobius_im_d = rand_d11(rc); + break; + } +} + +/* Fill xform with random values + */ +void xform_rand (flam3_xform * const xform, const bool add_post, + const unsigned int max_var, randctx * const rc) { + assert (xform != NULL); + assert (rc != NULL); + + /* XXX: the original code alternates between 0/1 for every xform */ + xform->color = rand_bool (rc) ? 1.0 : 0.0; + + for (unsigned int j = 0; j < 3; j++) { + for (unsigned int k = 0; k < 2; k++) { + xform->c[j][k] = rand_d11(rc); + if (add_post) { + xform->post[j][k] = rand_d11(rc); + } else { + xform->post[j][k] = (double)(k==j); + } + } + } + + memset (xform->var, 0, sizeof (*xform->var)); + for (unsigned int i = 0; i < max_var; i++) { + const unsigned int v = rand_mod (rc, flam3_nvariations); + double w; + do { + w = rand_d01 (rc); + } while (w == 0.0); + xform->var[v] += w; + random_xform_param (xform, v, rc); + + /* small number of variations is more likely */ + if (rand_bool (rc)) { + break; + } + } + + /* Normalize weights to 1.0 total. */ + normalize (xform->var, flam3_nvariations); +} + diff --git a/genome.h b/genome.h new file mode 100644 index 0000000..deac97f --- /dev/null +++ b/genome.h @@ -0,0 +1,25 @@ +/* + Copyright (C) 1992-2009 Spotworks LLC + 2015 pucket contributors + + 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 . +*/ + +#pragma once + +#include "flam3.h" + +void xform_rand (flam3_xform * const xform, const bool add_post, + const unsigned int max_var, randctx * const rc); + diff --git a/main.c b/main.c index ecd487a..61ad772 100644 --- a/main.c +++ b/main.c @@ -25,6 +25,8 @@ #include "private.h" #include "img.h" #include "rect.h" +#include "math.h" +#include "genome.h" #define streq(a,b) (strcmp (a, b) == 0) @@ -93,7 +95,7 @@ static void do_render (const render_arguments * const arguments) { rand_seed(&rc); int ncps; - flam3_genome * const cps = flam3_parse_from_file (stdin, NULL, + flam3_genome * const cps = flam3_parse_xml2 (STDIN_FILENO, flam3_defaults_on, &ncps, &rc); if (cps == NULL) { fprintf(stderr,"error reading genomes from file\n"); @@ -141,9 +143,9 @@ static void print_genome (flam3_genome * const genome) { } typedef struct { - int symmetry; const char *palette; - unsigned int width, height; + unsigned int width, height, max_xforms, max_var; + double post_likelihood, final_likelihood, symmetry_likelihood; } random_arguments; static error_t parse_random_opt (int key, char *arg, @@ -170,6 +172,16 @@ static error_t parse_random_opt (int key, char *arg, break; } + case 'x': { + int i = atoi (arg); + if (i <= 0) { + argp_error (state, "Max xforms must be > 0"); + } else { + arguments->max_xforms = i; + } + break; + } + case ARGP_KEY_ARG: if (state->arg_num > 0) { return ARGP_ERR_UNKNOWN; @@ -229,8 +241,41 @@ static void do_random (const random_arguments * const arguments) { assert (bret); flam3_genome genome; - int ivars = flam3_variation_random; - flam3_random (&genome, &ivars, 1, arguments->symmetry, 0, &pc, &rc); + clear_cp (&genome,flam3_defaults_on); + + genome.hue_rotation = rand_mod(&rc, 8) ? 0.0 : rand_d01(&rc); + const palette * const p = palette_random (&pc, &rc); + assert (p != NULL); + palette_copy (p, &genome.palette); + palette_rotate_hue (&genome.palette, genome.hue_rotation); + genome.interpolation = flam3_interpolation_linear; + genome.palette_interpolation = flam3_palette_interpolation_hsv; + genome.rotate = rand_d01 (&rc) * 360.0; + + unsigned int nxforms = rand_mod (&rc, arguments->max_xforms) + 1; + flam3_add_xforms(&genome,nxforms,0,0); + /* Add a final xform 15% of the time */ + const bool add_final = rand_d01(&rc) < arguments->final_likelihood; + if (add_final) { + flam3_add_xforms(&genome,1,0,1); + ++nxforms; + } + + /* Loop over xforms */ + assert (nxforms > 0); + for (unsigned int i = 0; i < nxforms; i++) { + flam3_xform * const xform = &genome.xform[i]; + const bool add_post = rand_d01 (&rc) < arguments->post_likelihood; + xform_rand (xform, add_post, arguments->max_var, &rc); + xform->density = 1.0 / nxforms; + xform->color_speed = 0.5; + xform->animate = 1.0; + } + + /* Randomly add symmetry (but not if we've already added a final xform) */ + if (rand_d01(&rc) < arguments->symmetry_likelihood && !add_final) { + flam3_add_symmetry(&genome, 0, &rc); + } /* random resets genome, adjust before finding appropriate bbox */ genome.width = arguments->width; @@ -295,7 +340,7 @@ static void do_mutate (const mutate_arguments * const arguments) { rand_seed(&rc); int ncps; - flam3_genome * const cps = flam3_parse_from_file (stdin, NULL, + flam3_genome * const cps = flam3_parse_xml2 (STDIN_FILENO, flam3_defaults_on, &ncps, &rc); if (cps == NULL) { fprintf(stderr,"error reading genomes from file\n"); @@ -309,7 +354,7 @@ static void do_mutate (const mutate_arguments * const arguments) { flam3_genome * const genome = &cps[0]; - int ivars = flam3_variation_random; + int ivars = 0; const double speed = 1.0; flam3_mutate (genome, arguments->method, &ivars, 1, arguments->symmetry, speed, &pc, &rc); @@ -362,7 +407,7 @@ static void do_cross (const cross_arguments * const arguments) { rand_seed(&rc); int ncps; - flam3_genome * const cps = flam3_parse_from_file (stdin, NULL, + flam3_genome * const cps = flam3_parse_xml2 (STDIN_FILENO, flam3_defaults_on, &ncps, &rc); if (cps == NULL) { fprintf(stderr,"error reading genomes from file\n"); @@ -449,6 +494,7 @@ int main (int argc, char **argv) { argp_parse (&argp, argc, argv, 0, NULL, &arguments); do_cross (&arguments); +#if 0 } else if (streq (command, "mutate")) { const struct argp_option options[] = { {"method", 'm', "XXX", OPTION_ARG_OPTIONAL, "Mutation method" }, @@ -467,11 +513,13 @@ int main (int argc, char **argv) { argp_parse (&argp, argc, argv, 0, NULL, &arguments); do_mutate (&arguments); +#endif } else if (streq (command, "random")) { /* generate random genome */ const struct argp_option options[] = { - {"height", 'h', "pixels", 0, "Output flame height" }, - {"width", 'w', "pixels", 0, "Output flame width" }, + {"height", 'h', "pixels", 0, "Output flame height (1000)" }, + {"width", 'w', "pixels", 0, "Output flame width (1000)" }, + {"max-xforms", 'x', "number", 0, "Max number of xforms (6)" }, { 0 }, }; const char doc[] = PACKAGE "-random -- a fractal flame generator"; @@ -481,10 +529,14 @@ int main (int argc, char **argv) { }; random_arguments arguments = { - .symmetry = 0, .palette = "flam3-palettes.xml", .width = 1000, .height = 1000, + .max_xforms = 6, + .max_var = flam3_nvariations, + .post_likelihood = 0.4, + .final_likelihood = 0.15, + .symmetry_likelihood = 0.25, }; argp_parse (&argp, argc, argv, 0, NULL, &arguments); diff --git a/math.h b/math.h index dc72d87..fa49d09 100644 --- a/math.h +++ b/math.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include "build/config.h" @@ -79,6 +80,20 @@ inline double sum(const double2 in) { return in[0] + in[1]; } +inline void normalize (double * const a, const size_t n) { + double sum = 0.0; + for (unsigned int j = 0; j < n; j++) { + sum += a[j]; + } + assert (sum > 0.0); + + for (unsigned int j = 0; j < n; j++) { + a[j] /= sum; + } +} + +#define max(a,b) ((a) > (b) ? (a) : (b)) + /* Vector wrapping function, could be replaced by true vector functions later */ diff --git a/parser.c b/parser.c index f28bad8..20eaaa9 100644 --- a/parser.c +++ b/parser.c @@ -216,7 +216,7 @@ int flam3_interp_missing_colors(flam3_genome *cp) { #endif -void scan_for_flame_nodes(xmlNode *cur_node, char *parent_file, int default_flag, flam3_genome **all_cps, int *all_ncps, randctx * const rc) { +void scan_for_flame_nodes(xmlNode *cur_node, int default_flag, flam3_genome **all_cps, int *all_ncps, randctx * const rc) { xmlNode *this_node = NULL; flam3_genome loc_current_cp; @@ -262,7 +262,7 @@ void scan_for_flame_nodes(xmlNode *cur_node, char *parent_file, int default_flag } else { /* Check all of the children of this element */ - scan_for_flame_nodes(this_node->children, parent_file, default_flag, all_cps, all_ncps, rc); + scan_for_flame_nodes(this_node->children, default_flag, all_cps, all_ncps, rc); } } diff --git a/parser.h b/parser.h index e76f812..5fa1923 100644 --- a/parser.h +++ b/parser.h @@ -26,7 +26,7 @@ int var2n(const char *s); int flam3_parse_hexformat_colors(char *colstr, flam3_genome *cp, int numcolors, int chan); #endif -void scan_for_flame_nodes(xmlNode *cur_node, char *parent_file, int default_flag, flam3_genome **all_cp, int *all_ncps, randctx * const); +void scan_for_flame_nodes(xmlNode *cur_node, int default_flag, flam3_genome **all_cp, int *all_ncps, randctx * const); int parse_flame_element(xmlNode *flame_node, flam3_genome *loc_current_cp, randctx * const); int parse_xform_xml(xmlNode *chld_node,flam3_xform *this_xform, int *num_xaos, flam3_chaos_entry **xaos, int numstd, int motionxf); diff --git a/wscript b/wscript index 4841945..3a0b341 100644 --- a/wscript +++ b/wscript @@ -22,5 +22,5 @@ def configure(conf): conf.write_config_header ('config.h') def build(bld): - bld.program (features='c cprogram', source='flam3.c parser.c variations.c interpolation.c palettes.c png.c random.c rect.c main.c', target='pucket', use='xml2 png amdlibm') + bld.program (features='c cprogram', source='flam3.c parser.c variations.c interpolation.c palettes.c png.c random.c rect.c main.c genome.c', target='pucket', use='xml2 png amdlibm') -- cgit v1.2.3