diff options
Diffstat (limited to '')
-rw-r--r-- | plug-ins/ifs-compose/ifs-compose-storage.c | 551 |
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); +} |