Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

View 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

View 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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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);

View 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>

View 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>

View 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,
)