diff --git a/flam3-genome.c b/flam3-genome.c index 3b6ea41..509dbd7 100644 --- a/flam3-genome.c +++ b/flam3-genome.c @@ -39,6 +39,7 @@ void test_cp(flam3_genome *cp) { cp->time = 0.0; cp->interpolation = flam3_interpolation_linear; cp->palette_interpolation = flam3_palette_interpolation_hsv; + cp->hsv_rgb_palette_blend = 0.0; cp->background[0] = 0.0; cp->background[1] = 0.0; cp->background[2] = 0.0; @@ -248,7 +249,8 @@ void spin(int frame, double blend, flam3_genome *parent, flam3_genome *templ) /* Set genome parameters accordingly */ result->time = (double)frame; result->interpolation = flam3_interpolation_linear; - result->palette_interpolation = flam3_palette_interpolation_hsv; + result->palette_interpolation = flam3_palette_interpolation_hsv_circular; + result->hsv_rgb_palette_blend = 0.0; /* Force linear interpolation - unsure if this is still necessary */ /* I believe we put this in so that older clients could render frames */ diff --git a/flam3.c b/flam3.c index c29b579..b1fed28 100644 --- a/flam3.c +++ b/flam3.c @@ -785,7 +785,8 @@ void flam3_interpolate(flam3_genome cps[], int ncps, result->time = time; result->interpolation = flam3_interpolation_linear; result->interpolation_type = cpi[0].interpolation_type; - result->palette_interpolation = flam3_palette_interpolation_hsv; + result->palette_interpolation = flam3_palette_interpolation_hsv_circular; + result->hsv_rgb_palette_blend = 0.0; if (!smoothflag) { flam3_interpolate_n(result, 2, cpi, c, stagger); @@ -1282,6 +1283,7 @@ void clear_cp(flam3_genome *cp, int default_flag) { cp->pixels_per_unit = 50; cp->interpolation = flam3_interpolation_linear; cp->palette_interpolation = flam3_palette_interpolation_hsv_circular; + cp->hsv_rgb_palette_blend = 0.0; cp->genome_index = 0; memset(cp->parent_fname,0,flam3_parent_fn_len); @@ -1618,6 +1620,8 @@ void flam3_apply_template(flam3_genome *cp, flam3_genome *templ) { cp->palette_mode = templ->palette_mode; if (templ->palette_interpolation >= 0) cp->palette_interpolation = templ->palette_interpolation; + if (templ->hsv_rgb_palette_blend >= 0) + cp->hsv_rgb_palette_blend = templ->hsv_rgb_palette_blend; } @@ -1787,8 +1791,11 @@ void flam3_print(FILE *f, flam3_genome *cp, char *extra_attributes, int print_ed fprintf(f, " palette_interpolation=\"rgb\""); else if (flam3_palette_interpolation_hsv == cp->palette_interpolation) fprintf(f, " palette_interpolation=\"hsv\""); - else if (flam3_palette_interpolation_hsv_circular == cp->palette_interpolation) + else if (flam3_palette_interpolation_hsv_circular == cp->palette_interpolation) { fprintf(f, " palette_interpolation=\"hsv_circular\""); + if (cp->hsv_rgb_palette_blend > 0.0) + fprintf(f, " hsv_rgb_palette_blend=\"%g\"", cp->hsv_rgb_palette_blend); + } if (extra_attributes) fprintf(f, " %s", extra_attributes); @@ -3089,7 +3096,8 @@ void flam3_random(flam3_genome *cp, int *ivars, int ivars_n, int sym, int spec_x fprintf(stderr,"error getting palette from xml file, setting to all white\n"); cp->time = 0.0; cp->interpolation = flam3_interpolation_linear; - cp->palette_interpolation = flam3_palette_interpolation_hsv; + cp->palette_interpolation = flam3_palette_interpolation_hsv_circular; + cp->hsv_rgb_palette_blend = 0.0; /* Choose the number of xforms */ if (spec_xforms>0) { diff --git a/flam3.h b/flam3.h index ebfcc04..2039f88 100644 --- a/flam3.h +++ b/flam3.h @@ -453,6 +453,7 @@ typedef struct { int interpolation; int interpolation_type; int palette_interpolation; + double hsv_rgb_palette_blend; int num_xforms; int final_xform_index; int final_xform_enable; diff --git a/interpolation.c b/interpolation.c index c143401..4390337 100644 --- a/interpolation.c +++ b/interpolation.c @@ -372,83 +372,75 @@ double get_stagger_coef(double t, double stagger_prc, int num_xforms, int this_x and have final xform in the same slot) */ void flam3_interpolate_n(flam3_genome *result, int ncp, flam3_genome *cpi, double *c, double stagger) { - int i, j, k, numstd; - -// fprintf(stderr, "xxx pi=%d\n", cpi[0].palette_interpolation); + int i, j, k, l, numstd; if (flam3_palette_interpolation_sweep != cpi[0].palette_interpolation) { - + + /* rgb, hsv or hsv_circular modes. */ + double rgb_fraction = 0.0; /* Assume that we are in plain hsv mode */ + if (flam3_palette_interpolation_rgb == cpi[0].palette_interpolation) + rgb_fraction = 1.0; /* All RGB output */ + else if (flam3_palette_interpolation_hsv_circular == cpi[0].palette_interpolation) + rgb_fraction = cpi[0].hsv_rgb_palette_blend; + for (i = 0; i < 256; i++) { - double t[3], s[5]; + double col_rgb[3], col_hsv[3]; + double new_rgb[3] = {0, 0, 0}; + double new_hsv[3] = {0, 0, 0}; + double new_count = 0, new_index = 0; int alpha1 = 1; - - s[0] = s[1] = s[2] = s[3] = s[4] = 0.0; - + + /* Loop over each control point's color at this index */ for (k = 0; k < ncp; k++) { - if (i == 0) { -// fprintf(stderr, "ncp=%d, k=%d\n", ncp, k); -// fprintf(stderr, "rgb=%g %g %g\n", cpi[k].palette[i].color[0], cpi[k].palette[i].color[1], cpi[k].palette[i].color[2]); + + /* Convert to hsv */ + rgb2hsv(cpi[k].palette[i].color, col_hsv); + + /* Store the rgb */ + for (l = 0; l < 3; l++) + col_rgb[l] = cpi[k].palette[i].color[l]; + + if (2 == ncp && k == 0 && cpi[0].palette_interpolation == flam3_palette_interpolation_hsv_circular) { + /* only adjust the first coordinate based on the other control point's hue */ + double second_color[3]; + rgb2hsv(cpi[1].palette[i].color, second_color); + + /* Adjust the hue so that we go the shorter direction around the circle */ + if ((second_color[0] - col_hsv[0]) > 3.0) { + col_hsv[0] += 6.0; + } else if ((second_color[0] - col_hsv[0]) < -3.0) { + col_hsv[0] -= 6.0; + } } - if (flam3_palette_interpolation_rgb != cpi[0].palette_interpolation) - rgb2hsv(cpi[k].palette[i].color, t); - else { - int l; - for (l = 0; l < 3; l++) - t[l] = cpi[k].palette[i].color[l]; + + for (j = 0; j < 3; j++) { + new_rgb[j] += c[k] * col_rgb[j]; + new_hsv[j] += c[k] * col_hsv[j]; } -// if (i == 0) { -// fprintf(stderr, "hsv=%g %g %g\n", t[0], t[1], t[2]); -// } - - if (2 == ncp && k == 0 &&cpi[0].palette_interpolation == flam3_palette_interpolation_hsv_circular) { - /* should also support blending between rgb and hsv, - and change the color of the cut, so we can keep - a dominant color but control what it is. */ - - /* only adjust the first coordinate based on the other control point's hue */ - double second_color[3]; - rgb2hsv(cpi[1].palette[i].color, second_color); - - /* Adjust the hue so that we go the shorter direction around the circle */ - if ((second_color[0] - t[0]) > 3.0) { - t[0] += 6.0; - } else if ((second_color[0] - t[0]) < -3.0) { - t[0] -= 6.0; - } - } - - for (j = 0; j < 3; j++) - s[j] += c[k] * t[j]; - - s[3] += c[k] * cpi[k].palette[i].color[3]; + + /* Compute the other two components of the color (count and index) */ + new_count += c[k] * cpi[k].palette[i].color[3]; if (cpi[k].palette[i].color[3] != 1.0) alpha1 = 0; - s[4] += c[k] * cpi[k].palette[i].index; + new_index += c[k] * cpi[k].palette[i].index; } if (alpha1 == 1) - s[3] = 1.0; + new_count = 1.0; -// if (i == 0) -// fprintf(stderr, "s0=%g\n", s[0]); - - if (flam3_palette_interpolation_rgb != cpi[0].palette_interpolation) - hsv2rgb(s, result->palette[i].color); - else { - int l; - for (l = 0; l < 3; l++) - result->palette[i].color[l] = s[l]; - } - result->palette[i].color[3] = s[3]; - result->palette[i].index = s[4]; + /* Convert the new hsv coord to back rgb */ + double new_hsv_rgb[3]; + hsv2rgb(new_hsv, new_hsv_rgb); -// if (i == 0) -// fprintf(stderr, "result rgb=%g %g %g\n", -// result->palette[0].color[0], -// result->palette[0].color[1], -// result->palette[0].color[2]); - + /* Store the interpolated color in the new palette */ + for (l = 0; l < 3; l++) + result->palette[i].color[l] = rgb_fraction * new_rgb[l] + (1.0-rgb_fraction) * new_hsv_rgb[l]; + + result->palette[i].color[3] = new_count; + result->palette[i].index = new_index; + + /* Clip the new color appropriately */ for (j = 0; j < 4; j++) { if (result->palette[i].color[j] < 0.0) result->palette[i].color[j] = 0.0; @@ -477,6 +469,7 @@ void flam3_interpolate_n(flam3_genome *result, int ncp, result->interpolation_type = cpi[0].interpolation_type; result->palette_interpolation = cpi[0].palette_interpolation; + result->hsv_rgb_palette_blend = cpi[0].hsv_rgb_palette_blend; INTERP(brightness); INTERP(contrast); INTERP(highlight_power); diff --git a/parser.c b/parser.c index 035363d..b51cd7f 100644 --- a/parser.c +++ b/parser.c @@ -332,6 +332,8 @@ int parse_flame_element(xmlNode *flame_node, flam3_genome *loc_current_cp) { /* Compare attribute names */ if (!xmlStrcmp(cur_att->name, (const xmlChar *)"time")) { cp->time = flam3_atof(att_str); + } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"hsv_rgb_palette_blend")) { + cp->hsv_rgb_palette_blend = flam3_atof(att_str); } else if (!xmlStrcmp(cur_att->name, (const xmlChar *)"interpolation")) { if (!strcmp("linear", att_str)) { cp->interpolation = flam3_interpolation_linear;