summaryrefslogtreecommitdiffstats
path: root/plug-ins/ifs-compose/ifs-compose-storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'plug-ins/ifs-compose/ifs-compose-storage.c')
-rw-r--r--plug-ins/ifs-compose/ifs-compose-storage.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/plug-ins/ifs-compose/ifs-compose-storage.c b/plug-ins/ifs-compose/ifs-compose-storage.c
new file mode 100644
index 0000000..24705be
--- /dev/null
+++ b/plug-ins/ifs-compose/ifs-compose-storage.c
@@ -0,0 +1,551 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * IfsCompose is a interface for creating IFS fractals by
+ * direct manipulation.
+ * Copyright (C) 1997 Owen Taylor
+ *
+ * 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
+ * MERCHANTBILITY 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h> /* strlen */
+
+#include <gdk/gdk.h>
+
+#include <libgimp/gimp.h>
+
+#include "ifs-compose.h"
+
+
+typedef enum {
+ TOKEN_INVALID = G_TOKEN_LAST,
+ TOKEN_ITERATIONS,
+ TOKEN_MAX_MEMORY,
+ TOKEN_SUBDIVIDE,
+ TOKEN_RADIUS,
+ TOKEN_ASPECT_RATIO,
+ TOKEN_CENTER_X,
+ TOKEN_CENTER_Y,
+ TOKEN_ELEMENT,
+ TOKEN_X,
+ TOKEN_Y,
+ TOKEN_THETA,
+ TOKEN_SCALE,
+ TOKEN_ASYM,
+ TOKEN_SHEAR,
+ TOKEN_FLIP,
+ TOKEN_RED_COLOR,
+ TOKEN_GREEN_COLOR,
+ TOKEN_BLUE_COLOR,
+ TOKEN_BLACK_COLOR,
+ TOKEN_TARGET_COLOR,
+ TOKEN_HUE_SCALE,
+ TOKEN_VALUE_SCALE,
+ TOKEN_SIMPLE_COLOR,
+ TOKEN_PROB
+} IfsComposeToken;
+
+static struct
+{
+ const gchar *name;
+ IfsComposeToken token;
+} symbols[] = {
+ { "iterations", TOKEN_ITERATIONS },
+ { "max_memory", TOKEN_MAX_MEMORY },
+ { "subdivide", TOKEN_SUBDIVIDE },
+ { "radius", TOKEN_RADIUS },
+ { "aspect_ratio", TOKEN_ASPECT_RATIO },
+ { "center_x", TOKEN_CENTER_X },
+ { "center_y", TOKEN_CENTER_Y },
+ { "element", TOKEN_ELEMENT },
+ { "x", TOKEN_X },
+ { "y", TOKEN_Y },
+ { "theta", TOKEN_THETA },
+ { "scale", TOKEN_SCALE },
+ { "asym", TOKEN_ASYM },
+ { "shear", TOKEN_SHEAR },
+ { "flip", TOKEN_FLIP },
+ { "red_color", TOKEN_RED_COLOR },
+ { "green_color", TOKEN_GREEN_COLOR },
+ { "blue_color", TOKEN_BLUE_COLOR },
+ { "black_color", TOKEN_BLACK_COLOR },
+ { "target_color", TOKEN_TARGET_COLOR },
+ { "hue_scale", TOKEN_HUE_SCALE },
+ { "value_scale", TOKEN_VALUE_SCALE },
+ { "simple_color", TOKEN_SIMPLE_COLOR },
+ { "prob", TOKEN_PROB }
+};
+
+static GTokenType
+ifsvals_parse_color (GScanner *scanner,
+ GimpRGB *result)
+{
+ GTokenType token;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_LEFT_CURLY)
+ return G_TOKEN_LEFT_CURLY;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_FLOAT)
+ result->r = scanner->value.v_float;
+ else if (token == G_TOKEN_INT)
+ result->r = scanner->value.v_int;
+ else
+ return G_TOKEN_FLOAT;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_COMMA)
+ return G_TOKEN_COMMA;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_FLOAT)
+ result->g = scanner->value.v_float;
+ else if (token == G_TOKEN_INT)
+ result->g = scanner->value.v_int;
+ else
+ return G_TOKEN_FLOAT;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_COMMA)
+ return G_TOKEN_COMMA;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_FLOAT)
+ result->b = scanner->value.v_float;
+ else if (token == G_TOKEN_INT)
+ result->b = scanner->value.v_int;
+ else
+ return G_TOKEN_FLOAT;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_RIGHT_CURLY)
+ return G_TOKEN_RIGHT_CURLY;
+
+ return G_TOKEN_NONE;
+}
+
+/* Parse a float which (unlike G_TOKEN_FLOAT) can be negative
+ */
+static GTokenType
+parse_genuine_float (GScanner *scanner,
+ gdouble *result)
+{
+ gboolean negate = FALSE;
+ GTokenType token;
+
+ token = g_scanner_get_next_token (scanner);
+
+ if (token == '-')
+ {
+ negate = TRUE;
+ token = g_scanner_get_next_token (scanner);
+ }
+
+ if (token == G_TOKEN_FLOAT)
+ {
+ *result = negate ? -scanner->value.v_float : scanner->value.v_float;
+ return G_TOKEN_NONE;
+ }
+ else if (token == G_TOKEN_INT)
+ {
+ *result = negate ? -scanner->value.v_int : scanner->value.v_int;
+ return G_TOKEN_NONE;
+ }
+ else
+ return G_TOKEN_FLOAT;
+}
+
+static GTokenType
+ifsvals_parse_element (GScanner *scanner,
+ AffElementVals *result)
+{
+ GTokenType token;
+ GTokenType expected_token;
+
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_LEFT_CURLY)
+ return G_TOKEN_LEFT_CURLY;
+
+ token = g_scanner_get_next_token (scanner);
+ while (token != G_TOKEN_RIGHT_CURLY)
+ {
+ switch ((IfsComposeToken) token)
+ {
+ case TOKEN_X:
+ expected_token = parse_genuine_float (scanner, &result->x);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_Y:
+ expected_token = parse_genuine_float (scanner, &result->y);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_THETA:
+ expected_token = parse_genuine_float (scanner, &result->theta);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_SCALE:
+ expected_token = parse_genuine_float (scanner, &result->scale);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_ASYM:
+ expected_token = parse_genuine_float (scanner, &result->asym);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_SHEAR:
+ expected_token = parse_genuine_float (scanner, &result->shear);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_FLIP:
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ result->flip = scanner->value.v_int;
+ break;
+
+ case TOKEN_RED_COLOR:
+ token = ifsvals_parse_color (scanner, &result->red_color);
+ if (token != G_TOKEN_NONE)
+ return token;
+ break;
+
+ case TOKEN_GREEN_COLOR:
+ token = ifsvals_parse_color (scanner, &result->green_color);
+ if (token != G_TOKEN_NONE)
+ return token;
+ break;
+
+ case TOKEN_BLUE_COLOR:
+ token = ifsvals_parse_color (scanner, &result->blue_color);
+ if (token != G_TOKEN_NONE)
+ return token;
+ break;
+
+ case TOKEN_BLACK_COLOR:
+ token = ifsvals_parse_color (scanner, &result->black_color);
+ if (token != G_TOKEN_NONE)
+ return token;
+ break;
+
+ case TOKEN_TARGET_COLOR:
+ token = ifsvals_parse_color (scanner, &result->target_color);
+ if (token != G_TOKEN_NONE)
+ return token;
+ break;
+
+ case TOKEN_HUE_SCALE:
+ expected_token = parse_genuine_float (scanner, &result->hue_scale);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_VALUE_SCALE:
+ expected_token = parse_genuine_float (scanner, &result->value_scale);
+ if (expected_token != G_TOKEN_NONE)
+ return expected_token;
+ break;
+
+ case TOKEN_SIMPLE_COLOR:
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_INT)
+ return G_TOKEN_INT;
+
+ result->simple_color = scanner->value.v_int;
+ break;
+
+ case TOKEN_PROB:
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_FLOAT)
+ result->prob = scanner->value.v_float;
+ else if (token == G_TOKEN_INT)
+ result->prob = scanner->value.v_int;
+ else
+ return G_TOKEN_FLOAT;
+
+ break;
+
+ default:
+ return G_TOKEN_SYMBOL;
+ }
+
+ token = g_scanner_get_next_token (scanner);
+ }
+
+ return G_TOKEN_NONE;
+}
+
+/*************************************************************
+ * ifsvals_parse:
+ * Read in ifsvalues from a GScanner
+ * arguments:
+ * scanner:
+ * vals:
+ * elements:
+ *
+ * results:
+ * If parsing succeeded, TRUE; otherwise FALSE, in which
+ * case vals and elements are unchanged
+ *************************************************************/
+
+static gboolean
+ifsvals_parse (GScanner *scanner,
+ IfsComposeVals *vals,
+ AffElement ***elements)
+{
+ GTokenType token, expected_token;
+ AffElement *el;
+ IfsComposeVals new_vals;
+ GimpRGB color;
+
+ GList *el_list = NULL;
+ GList *tmp_list;
+ gint i;
+
+ new_vals = *vals;
+ new_vals.num_elements = 0;
+ i = 0;
+
+ expected_token = G_TOKEN_NONE;
+ while (expected_token == G_TOKEN_NONE)
+ {
+ token = g_scanner_get_next_token (scanner);
+
+ if (g_scanner_eof (scanner))
+ break;
+
+ switch ((IfsComposeToken) token)
+ {
+ case TOKEN_ITERATIONS:
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_INT)
+ new_vals.iterations = scanner->value.v_int;
+ else
+ expected_token = G_TOKEN_INT;
+ break;
+
+ case TOKEN_MAX_MEMORY:
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_INT)
+ new_vals.max_memory = scanner->value.v_int;
+ else
+ expected_token = G_TOKEN_INT;
+ break;
+
+ case TOKEN_SUBDIVIDE:
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_INT)
+ new_vals.subdivide = scanner->value.v_int;
+ else
+ expected_token = G_TOKEN_INT;
+ break;
+
+ case TOKEN_RADIUS:
+ expected_token = parse_genuine_float (scanner, &new_vals.radius);
+ break;
+
+ case TOKEN_ASPECT_RATIO:
+ expected_token = parse_genuine_float (scanner, &new_vals.aspect_ratio);
+ break;
+
+ case TOKEN_CENTER_X:
+ expected_token = parse_genuine_float (scanner, &new_vals.center_x);
+ break;
+
+ case TOKEN_CENTER_Y:
+ expected_token = parse_genuine_float (scanner, &new_vals.center_y);
+ break;
+
+ case TOKEN_ELEMENT:
+ el = aff_element_new (0.0,0.0, &color, ++i);
+ expected_token = ifsvals_parse_element (scanner, &el->v);
+
+ if (expected_token == G_TOKEN_NONE)
+ {
+ el_list = g_list_prepend (el_list, el);
+ new_vals.num_elements++;
+ }
+ else
+ aff_element_free (el);
+
+ break;
+
+ default:
+ expected_token = G_TOKEN_SYMBOL;
+ }
+ }
+
+ if (expected_token != G_TOKEN_NONE)
+ {
+ g_scanner_unexp_token (scanner,
+ expected_token,
+ NULL,
+ NULL,
+ NULL,
+ "using default values...",
+ TRUE);
+ g_list_free_full (el_list, (GDestroyNotify) g_free);
+ return FALSE;
+ }
+
+ *vals = new_vals;
+
+ el_list = g_list_reverse (el_list);
+ *elements = g_new (AffElement *, new_vals.num_elements);
+
+ tmp_list = el_list;
+ for (i=0; i<new_vals.num_elements; i++)
+ {
+ (*elements)[i] = tmp_list->data;
+ tmp_list = tmp_list->next;
+ }
+
+ g_list_free (el_list);
+
+ return TRUE;
+}
+
+gboolean
+ifsvals_parse_string (const gchar *str,
+ IfsComposeVals *vals,
+ AffElement ***elements)
+{
+ GScanner *scanner = g_scanner_new (NULL);
+ gboolean result;
+ gint i;
+
+ scanner->config->symbol_2_token = TRUE;
+ scanner->config->scan_identifier_1char = TRUE;
+ scanner->input_name = "IfsCompose Saved Data";
+
+ for (i = 0; i < G_N_ELEMENTS (symbols); i++)
+ g_scanner_scope_add_symbol (scanner, 0,
+ symbols[i].name,
+ GINT_TO_POINTER (symbols[i].token));
+
+ g_scanner_input_text (scanner, str, strlen (str));
+
+ result = ifsvals_parse (scanner, vals, elements);
+
+ g_scanner_destroy (scanner);
+
+ return result;
+}
+
+/*************************************************************
+ * ifsvals_stringify:
+ * Stringify a set of vals and elements
+ * arguments:
+ * vals:
+ * elements
+ * results:
+ * The stringified result (free with g_free)
+ *************************************************************/
+
+gchar *
+ifsvals_stringify (IfsComposeVals *vals,
+ AffElement **elements)
+{
+ gint i;
+ gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+ gchar cbuf[3][G_ASCII_DTOSTR_BUF_SIZE];
+ GString *result;
+
+ result = g_string_new (NULL);
+
+ g_string_append_printf (result, "iterations %d\n", vals->iterations);
+ g_string_append_printf (result, "max_memory %d\n", vals->max_memory);
+ g_string_append_printf (result, "subdivide %d\n", vals->subdivide);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, vals->radius);
+ g_string_append_printf (result, "radius %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, vals->aspect_ratio);
+ g_string_append_printf (result, "aspect_ratio %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, vals->center_x);
+ g_string_append_printf (result, "center_x %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, vals->center_y);
+ g_string_append_printf (result, "center_y %s\n", buf);
+
+ for (i=0; i<vals->num_elements; i++)
+ {
+ g_string_append (result, "element {\n");
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.x);
+ g_string_append_printf (result, " x %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.y);
+ g_string_append_printf (result, " y %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.theta);
+ g_string_append_printf (result, " theta %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.scale);
+ g_string_append_printf (result, " scale %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.asym);
+ g_string_append_printf (result, " asym %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.shear);
+ g_string_append_printf (result, " shear %s\n", buf);
+ g_string_append_printf (result, " flip %d\n", elements[i]->v.flip);
+
+ g_ascii_dtostr (cbuf[0], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.red_color.r);
+ g_ascii_dtostr (cbuf[1], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.red_color.g);
+ g_ascii_dtostr (cbuf[2], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.red_color.b);
+ g_string_append_printf (result, " red_color { %s,%s,%s }\n",
+ cbuf[0], cbuf[1], cbuf[2]);
+
+ g_ascii_dtostr (cbuf[0], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.green_color.r);
+ g_ascii_dtostr (cbuf[1], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.green_color.g);
+ g_ascii_dtostr (cbuf[2], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.green_color.b);
+ g_string_append_printf (result, " green_color { %s,%s,%s }\n",
+ cbuf[0], cbuf[1], cbuf[2]);
+
+ g_ascii_dtostr (cbuf[0], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.blue_color.r);
+ g_ascii_dtostr (cbuf[1], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.blue_color.g);
+ g_ascii_dtostr (cbuf[2], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.blue_color.b);
+ g_string_append_printf (result, " blue_color { %s,%s,%s }\n",
+ cbuf[0], cbuf[1], cbuf[2]);
+
+ g_ascii_dtostr (cbuf[0], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.black_color.r);
+ g_ascii_dtostr (cbuf[1], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.black_color.g);
+ g_ascii_dtostr (cbuf[2], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.black_color.b);
+ g_string_append_printf (result, " black_color { %s,%s,%s }\n",
+ cbuf[0], cbuf[1], cbuf[2]);
+
+ g_ascii_dtostr (cbuf[0], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.target_color.r);
+ g_ascii_dtostr (cbuf[1], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.target_color.g);
+ g_ascii_dtostr (cbuf[2], G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.target_color.b);
+ g_string_append_printf (result, " target_color { %s,%s,%s }\n",
+ cbuf[0], cbuf[1], cbuf[2]);
+
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.hue_scale);
+ g_string_append_printf (result, " hue_scale %s\n", buf);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.value_scale);
+ g_string_append_printf (result, " value_scale %s\n", buf);
+ g_string_append_printf (result, " simple_color %d\n",
+ elements[i]->v.simple_color);
+ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, elements[i]->v.prob);
+ g_string_append_printf (result, " prob %s\n", buf);
+ g_string_append (result, "}\n");
+ }
+
+ return g_string_free (result, FALSE);
+}