Initial checkin of Pika from heckimp
This commit is contained in:
83
plug-ins/ifs-compose/README.ifscompose
Normal file
83
plug-ins/ifs-compose/README.ifscompose
Normal file
@ -0,0 +1,83 @@
|
||||
IfsCompose
|
||||
----------
|
||||
|
||||
IfsCompose is a plug-in for PIKA that allows
|
||||
the creation of Iterated Function System fractals by direct
|
||||
manipulation onscreen of the component transforms.
|
||||
|
||||
|
||||
IFS Fractals
|
||||
------------
|
||||
|
||||
You may be familiar with IFS's from the screen
|
||||
hack 'Flame'. They are also the basis of fractal image compression.
|
||||
|
||||
For a brief introduction to IFS's see Foley and van Dam, et
|
||||
al,. _Computer Graphics, Principles and Practice_, 2nd Ed.,
|
||||
(Addison Wesley, 1990).
|
||||
|
||||
The standard references in the field are Michael Barnsley's books (though
|
||||
I haven't looked at them yet):
|
||||
|
||||
M. Barnsley, _Fractals Everywhere_, Academic Press Inc., 1988.
|
||||
M. Barnsley and L. Hurd, _Fractal Image Compression_, Jones and
|
||||
Bartlett.
|
||||
|
||||
Briefly, you take a point and repeatedly apply one of a set of
|
||||
transformations to it, choosing randomly between them, and plot the
|
||||
point at each step. An interesting result (the Collage Theorem) says
|
||||
that if you can find a set of transformations that break up an image
|
||||
into smaller copies of itself, then the resulting fractal exactly
|
||||
reproduces the original image. For example, here is a classic image
|
||||
of a leaf and the same image with the four component transforms
|
||||
colored distinctively.
|
||||
|
||||
But the best way to appreciate this may to install this program and
|
||||
try it out. I've extended the basic concept as found in
|
||||
Foley and van Dam to include transformations in color space as
|
||||
well as in real space.
|
||||
|
||||
Installation
|
||||
------------
|
||||
The included Makefile should work with minor modifications on most
|
||||
systems if you have installed Pika normally. Put the resulting binary
|
||||
in ~/.pika/plug-ins or the system-wide plug-ins directory.
|
||||
|
||||
The included files gtkaspectframe.c/.h implement a modified frame
|
||||
widget that guarantees that the aspect ratio of the child widget
|
||||
remains constant when the parent is resized. It's sort of specialized,
|
||||
but if you think it would be useful for other purposes, let me know
|
||||
and I'll lobby for its inclusion in the standard gtk.
|
||||
|
||||
Use
|
||||
---
|
||||
The interface is somewhat complex and it may take you a little while
|
||||
to get the hang of it. (There are 19 parameters for each
|
||||
transformation in your fractal, after all). The best way to learn is
|
||||
probably to start by making small changes, and seeing what they
|
||||
do. Click on the transformations (represented by polygons) in the
|
||||
design window to manipulate them interactively.
|
||||
|
||||
Button-1: rotate/scale
|
||||
Button-2: distort
|
||||
Button-3: move
|
||||
|
||||
If you hold down shift while clicking, you can select multiple polygons
|
||||
to apply the transformation to.
|
||||
|
||||
Try not to click too near the center of a polygon, as this will
|
||||
amplify your actions.
|
||||
|
||||
Note that if you render onto an image with an alpha channel, the
|
||||
background will be transparent (very useful for compositing several
|
||||
fractals), otherwise the background will be the current background.
|
||||
|
||||
There are tutorials and some example images at:
|
||||
|
||||
http://www.gtk.org/~otaylor/IfsCompose/ifs_tutorial/tutorial.html
|
||||
http://tigert.pika.technology.heckin/ifs-compose/
|
||||
|
||||
|
||||
Have fun!
|
||||
|
||||
Owen Taylor
|
555
plug-ins/ifs-compose/ifs-compose-storage.c
Normal file
555
plug-ins/ifs-compose/ifs-compose-storage.c
Normal file
@ -0,0 +1,555 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 <libpika/pika.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,
|
||||
PikaRGB *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;
|
||||
PikaRGB 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);
|
||||
}
|
1096
plug-ins/ifs-compose/ifs-compose-utils.c
Normal file
1096
plug-ins/ifs-compose/ifs-compose-utils.c
Normal file
File diff suppressed because it is too large
Load Diff
2926
plug-ins/ifs-compose/ifs-compose.c
Normal file
2926
plug-ins/ifs-compose/ifs-compose.c
Normal file
File diff suppressed because it is too large
Load Diff
184
plug-ins/ifs-compose/ifs-compose.h
Normal file
184
plug-ins/ifs-compose/ifs-compose.h
Normal file
@ -0,0 +1,184 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
gdouble a11,a12,a21,a22,b1,b2;
|
||||
} Aff2;
|
||||
|
||||
typedef struct {
|
||||
gdouble vals[3][4];
|
||||
} Aff3;
|
||||
|
||||
typedef struct {
|
||||
GdkPoint *points;
|
||||
gint npoints;
|
||||
} IPolygon;
|
||||
|
||||
typedef struct {
|
||||
gdouble x, y;
|
||||
gdouble theta;
|
||||
gdouble scale;
|
||||
gdouble asym;
|
||||
gdouble shear;
|
||||
gint flip;
|
||||
|
||||
PikaRGB red_color;
|
||||
PikaRGB green_color;
|
||||
PikaRGB blue_color;
|
||||
PikaRGB black_color;
|
||||
|
||||
PikaRGB target_color;
|
||||
gdouble hue_scale;
|
||||
gdouble value_scale;
|
||||
|
||||
gint simple_color;
|
||||
gdouble prob;
|
||||
} AffElementVals;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint num_elements;
|
||||
gint iterations;
|
||||
gint max_memory;
|
||||
gint subdivide;
|
||||
gdouble radius;
|
||||
gdouble aspect_ratio;
|
||||
gdouble center_x;
|
||||
gdouble center_y;
|
||||
} IfsComposeVals;
|
||||
|
||||
typedef struct {
|
||||
AffElementVals v;
|
||||
|
||||
Aff2 trans;
|
||||
Aff3 color_trans;
|
||||
|
||||
gchar *name;
|
||||
|
||||
IPolygon *click_boundary;
|
||||
IPolygon *draw_boundary;
|
||||
} AffElement;
|
||||
|
||||
|
||||
/* manipulation of affine transforms */
|
||||
void aff2_translate (Aff2 *naff,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
void aff2_rotate (Aff2 *naff,
|
||||
gdouble theta);
|
||||
void aff2_scale (Aff2 *naff,
|
||||
gdouble s,
|
||||
gint flip);
|
||||
void aff2_distort (Aff2 *naff,
|
||||
gdouble asym,
|
||||
gdouble shear);
|
||||
void aff2_compute_stretch (Aff2 *naff,
|
||||
gdouble xo,
|
||||
gdouble yo,
|
||||
gdouble xn,
|
||||
gdouble yn);
|
||||
void aff2_compute_distort (Aff2 *naff,
|
||||
gdouble xo,
|
||||
gdouble yo,
|
||||
gdouble xn,
|
||||
gdouble yn);
|
||||
void aff2_compose (Aff2 *naff,
|
||||
Aff2 *aff1,
|
||||
Aff2 *aff2);
|
||||
void aff2_invert (Aff2 *naff,
|
||||
Aff2 *aff);
|
||||
void aff2_apply (Aff2 *aff,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble *xf,
|
||||
gdouble *yf);
|
||||
void aff2_fixed_point (Aff2 *aff,
|
||||
gdouble *xf,
|
||||
gdouble *yf);
|
||||
void aff3_apply (Aff3 *t,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble z,
|
||||
gdouble *xf,
|
||||
gdouble *yf,
|
||||
gdouble *zf);
|
||||
|
||||
|
||||
/* manipulation of polygons */
|
||||
IPolygon *ipolygon_convex_hull (IPolygon *poly);
|
||||
gint ipolygon_contains (IPolygon *poly,
|
||||
gint xt,
|
||||
gint yt);
|
||||
|
||||
|
||||
/* manipulation of composite transforms */
|
||||
AffElement *aff_element_new (gdouble x,
|
||||
gdouble y,
|
||||
PikaRGB *color,
|
||||
gint count);
|
||||
void aff_element_free (AffElement *elem);
|
||||
void aff_element_compute_trans (AffElement *elem,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gdouble center_x,
|
||||
gdouble center_y);
|
||||
void aff_element_compute_color_trans (AffElement *elem);
|
||||
void aff_element_decompose_trans (AffElement *elem,
|
||||
Aff2 *aff,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gdouble center_x,
|
||||
gdouble center_y);
|
||||
void aff_element_compute_boundary (AffElement *elem,
|
||||
gint width,
|
||||
gint height,
|
||||
AffElement **elements,
|
||||
gint num_elements);
|
||||
void aff_element_draw (AffElement *elem,
|
||||
gint selected,
|
||||
gint width,
|
||||
gint height,
|
||||
cairo_t *cr,
|
||||
GdkRGBA *color,
|
||||
PangoLayout *layout);
|
||||
|
||||
|
||||
void ifs_render (AffElement **elements,
|
||||
gint num_elements,
|
||||
gint width,
|
||||
gint height,
|
||||
gint nsteps,
|
||||
IfsComposeVals *vals,
|
||||
gint band_y,
|
||||
gint band_height,
|
||||
guchar *data,
|
||||
guchar *mask,
|
||||
guchar *nhits,
|
||||
gboolean preview);
|
||||
|
||||
gchar * ifsvals_stringify (IfsComposeVals *vals,
|
||||
AffElement **elements);
|
||||
gboolean ifsvals_parse_string (const gchar *str,
|
||||
IfsComposeVals *vals,
|
||||
AffElement ***elements);
|
6
plug-ins/ifs-compose/ifs-menus.gresource.xml
Normal file
6
plug-ins/ifs-compose/ifs-menus.gresource.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/technology.heckin/ifs/">
|
||||
<file preprocess="xml-stripblanks">ifs-menus.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
54
plug-ins/ifs-compose/ifs-menus.ui
Normal file
54
plug-ins/ifs-compose/ifs-menus.ui
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="ifs-compose-menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Move</attribute>
|
||||
<attribute name="action">app.transform</attribute>
|
||||
<attribute name="target">move</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Rotate</attribute>
|
||||
<attribute name="action">app.transform</attribute>
|
||||
<attribute name="target">rotate</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Stretch</attribute>
|
||||
<attribute name="action">app.transform</attribute>
|
||||
<attribute name="target">stretch</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">New</attribute>
|
||||
<attribute name="action">app.new</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Delete</attribute>
|
||||
<attribute name="action">app.delete</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Undo</attribute>
|
||||
<attribute name="action">app.undo</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Redo</attribute>
|
||||
<attribute name="action">app.redo</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Select All</attribute>
|
||||
<attribute name="action">app.select-all</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Recompute Center</attribute>
|
||||
<attribute name="action">app.center</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Render Options</attribute>
|
||||
<attribute name="action">app.options</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
36
plug-ins/ifs-compose/meson.build
Normal file
36
plug-ins/ifs-compose/meson.build
Normal file
@ -0,0 +1,36 @@
|
||||
plugin_name = 'ifs-compose'
|
||||
|
||||
plugin_sources = [
|
||||
'ifs-compose-storage.c',
|
||||
'ifs-compose-utils.c',
|
||||
'ifs-compose.c',
|
||||
]
|
||||
|
||||
plugin_sources += gnome.compile_resources(
|
||||
'ifs-menus',
|
||||
'ifs-menus.gresource.xml',
|
||||
)
|
||||
|
||||
if platform_windows
|
||||
plugin_sources += windows.compile_resources(
|
||||
pika_plugins_rc,
|
||||
args: [
|
||||
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
|
||||
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
|
||||
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
|
||||
],
|
||||
include_directories: [
|
||||
rootInclude, appInclude,
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
executable(plugin_name,
|
||||
plugin_sources,
|
||||
dependencies: [
|
||||
libpikaui_dep,
|
||||
math,
|
||||
],
|
||||
install: true,
|
||||
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
|
||||
)
|
Reference in New Issue
Block a user