cml-explorer.c 83.6 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * CML_explorer.c
5
 * Time-stamp: <2000-02-13 18:18:37 yasuhiro>
Elliot Lee's avatar
Elliot Lee committed
6
 * Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp>
7
 * Version: 1.0.11
Elliot Lee's avatar
Elliot Lee committed
8 9
 * URL: http://www.inetq.or.jp/~narazaki/TheGIMP/
 *
10
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 3 of the License, or
Elliot Lee's avatar
Elliot Lee committed
13 14 15 16 17 18 19 20
 * (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
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
22 23 24 25 26 27 28
 *
 * Comment:
 *  CML is the abbreviation of Coupled-Map Lattice that is a model of
 *  complex systems, proposed by a physicist[1,2].
 *
 *  Similar models are summaried as follows:
 *
29 30 31 32
 *                      Value    Time     Space
 *  Coupled-Map Lattice cont.    discrete discrete
 *  Celluar Automata    discrete discrete discrete
 *  Diffrential Eq.     cont.    cont.    cont.
Elliot Lee's avatar
Elliot Lee committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
 *
 *  (But this program uses a parameter: hold-rate to avoid very fast changes.
 *  Thus time is rather continuous than discrete.
 *  Yes, this change to model changes the output completely.)
 *
 *  References:
 *  1. Kunihiko Kaneko, Period-doubling of kind-antikink patterns,
 *     quasi-periodicity in antiferro-like structures and spatial
 *     intermittency in coupled map lattices -- Toward a prelude to a
 *     "field theory of chaos", Prog. Theor. Phys. 72 (1984) 480.
 *
 *  2. Kunihiko Kaneko ed., Theory and Applications of Coupled Map
 *     Lattices (Wiley, 1993).
 *
 *  About Parameter File:
 *  I assume that the possible longest line in CMP parameter file is 1023.
 *  Please read CML_save_to_file_callback if you want know details of syntax.
 *
 *  Format version 1.0 starts with:
 *    ; This is a parameter file for CML_explorer
 *    ; File format version: 1.0
 *    ;
55
 *      Hue
Elliot Lee's avatar
Elliot Lee committed
56 57 58
 *
 *  The old format for CML_explorer included in gimp-0.99.[89] is:
 *    ; CML parameter file (version: 1.0)
59
 *    ; Hue
Elliot Lee's avatar
Elliot Lee committed
60 61 62 63 64 65 66 67 68 69 70
 *
 * (This file format is interpreted as format version 0.99 now.)
 *
 * Thanks:
 *  This version contains patches from:
 *    Tim Mooney <mooney@dogbert.cc.ndsu.NoDak.edu>
 *    Sean P Cier <scier@andrew.cmu.edu>
 *    David Mosberger-Tang <davidm@azstarnet.com>
 *    Michael Sweet <mike@easysw.com>
 *
 */
71
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
72 73 74 75 76

#include <errno.h>
#include <stdlib.h>
#include <string.h>

77
#include <glib/gstdio.h>
78

79 80 81
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

82
#include "libgimp/stdplugins-intl.h"
83

84
#define PARAM_FILE_FORMAT_VERSION 1.0
85
#define PLUG_IN_PROC              "plug-in-cml-explorer"
86
#define PLUG_IN_BINARY            "cml-explorer"
87
#define PLUG_IN_ROLE              "gimp-cml-explorer"
88 89 90 91 92 93 94 95 96 97 98
#define VALS                      CML_explorer_vals
#define PROGRESS_UPDATE_NUM        100
#define CML_LINE_SIZE             1024
#define TILE_CACHE_SIZE             32
#define SCALE_WIDTH                130
#define PREVIEW_WIDTH               64
#define PREVIEW_HEIGHT             220

#define CANNONIZE(p, x)      (255*(((p).range_h - (p).range_l)*(x) + (p).range_l))
#define HCANNONIZE(p, x)     (254*(((p).range_h - (p).range_l)*(x) + (p).range_l))
#define POS_IN_TORUS(i,size) ((i < 0) ? size + i : ((size <= i) ? i - size : i))
Elliot Lee's avatar
Elliot Lee committed
99

100 101 102
typedef struct _WidgetEntry WidgetEntry;

struct _WidgetEntry
Elliot Lee's avatar
Elliot Lee committed
103
{
104 105
  GtkWidget  *widget;
  gpointer    value;
106 107
  void      (*updater) (WidgetEntry *);
};
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

enum
{
  CML_KEEP_VALUES,
  CML_KEEP_FIRST,
  CML_FILL,
  CML_LOGIST,
  CML_LOGIST_STEP,
  CML_POWER,
  CML_POWER_STEP,
  CML_REV_POWER,
  CML_REV_POWER_STEP,
  CML_DELTA,
  CML_DELTA_STEP,
  CML_SIN_CURVE,
Sven Neumann's avatar
Sven Neumann committed
123 124
  CML_SIN_CURVE_STEP,
  CML_NUM_VALUES
Elliot Lee's avatar
Elliot Lee committed
125 126
};

Sven Neumann's avatar
Sven Neumann committed
127
static const gchar *function_names[CML_NUM_VALUES] =
128 129 130 131 132 133 134 135 136 137 138 139 140 141
{
  N_("Keep image's values"),
  N_("Keep the first value"),
  N_("Fill with parameter k"),
  N_("k{x(1-x)}^p"),
  N_("k{x(1-x)}^p stepped"),
  N_("kx^p"),
  N_("kx^p stepped"),
  N_("k(1-x^p)"),
  N_("k(1-x^p) stepped"),
  N_("Delta function"),
  N_("Delta function stepped"),
  N_("sin^p-based function"),
  N_("sin^p, stepped")
Elliot Lee's avatar
Elliot Lee committed
142 143
};

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
enum
{
  COMP_NONE,
  COMP_MAX_LINEAR,
  COMP_MAX_LINEAR_P1,
  COMP_MAX_LINEAR_M1,
  COMP_MIN_LINEAR,
  COMP_MIN_LINEAR_P1,
  COMP_MIN_LINEAR_M1,
  COMP_MAX_LINEAR_P1L,
  COMP_MAX_LINEAR_P1U,
  COMP_MAX_LINEAR_M1L,
  COMP_MAX_LINEAR_M1U,
  COMP_MIN_LINEAR_P1L,
  COMP_MIN_LINEAR_P1U,
  COMP_MIN_LINEAR_M1L,
Sven Neumann's avatar
Sven Neumann committed
160 161
  COMP_MIN_LINEAR_M1U,
  COMP_NUM_VALUES
162 163
};

Sven Neumann's avatar
Sven Neumann committed
164
static const gchar *composition_names[COMP_NUM_VALUES] =
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
{
  N_("None"),
  N_("Max (x, -)"),
  N_("Max (x+d, -)"),
  N_("Max (x-d, -)"),
  N_("Min (x, -)"),
  N_("Min (x+d, -)"),
  N_("Min (x-d, -)"),
  N_("Max (x+d, -), (x < 0.5)"),
  N_("Max (x+d, -), (0.5 < x)"),
  N_("Max (x-d, -), (x < 0.5)"),
  N_("Max (x-d, -), (0.5 < x)"),
  N_("Min (x+d, -), (x < 0.5)"),
  N_("Min (x+d, -), (0.5 < x)"),
  N_("Min (x-d, -), (x < 0.5)"),
  N_("Min (x-d, -), (0.5 < x)")
Elliot Lee's avatar
Elliot Lee committed
181 182
};

183 184 185 186 187 188 189 190 191 192 193
enum
{
  STANDARD,
  AVERAGE,
  ANTILOG,
  RAND_POWER0,
  RAND_POWER1,
  RAND_POWER2,
  MULTIPLY_RANDOM0,
  MULTIPLY_RANDOM1,
  MULTIPLY_GRADIENT,
Sven Neumann's avatar
Sven Neumann committed
194 195
  RAND_AND_P,
  ARRANGE_NUM_VALUES
196 197
};

Sven Neumann's avatar
Sven Neumann committed
198
static const gchar *arrange_names[ARRANGE_NUM_VALUES] =
199 200 201 202 203 204 205 206 207 208 209 210 211 212
{
  N_("Standard"),
  N_("Use average value"),
  N_("Use reverse value"),
  N_("With random power (0,10)"),
  N_("With random power (0,1)"),
  N_("With gradient power (0,1)"),
  N_("Multiply rand. value (0,1)"),
  N_("Multiply rand. value (0,2)"),
  N_("Multiply gradient (0,1)"),
  N_("With p and random (0,1)"),
};

enum
Elliot Lee's avatar
Elliot Lee committed
213
{
214 215 216
  CML_INITIAL_RANDOM_INDEPENDENT = 6,
  CML_INITIAL_RANDOM_SHARED,
  CML_INITIAL_RANDOM_FROM_SEED,
Sven Neumann's avatar
Sven Neumann committed
217 218
  CML_INITIAL_RANDOM_FROM_SEED_SHARED,
  CML_INITIAL_NUM_VALUES
219 220
};

Sven Neumann's avatar
Sven Neumann committed
221
static const gchar *initial_value_names[CML_INITIAL_NUM_VALUES] =
222 223 224 225 226 227 228 229 230 231 232 233
{
  N_("All black"),
  N_("All gray"),
  N_("All white"),
  N_("The first row of the image"),
  N_("Continuous gradient"),
  N_("Continuous grad. w/o gap"),
  N_("Random, ch. independent"),
  N_("Random shared"),
  N_("Randoms from seed"),
  N_("Randoms from seed (shared)")
};
Elliot Lee's avatar
Elliot Lee committed
234

235
#define CML_PARAM_NUM   15
236

Elliot Lee's avatar
Elliot Lee committed
237 238
typedef struct
{
239 240 241 242
  gint    function;
  gint    composition;
  gint    arrange;
  gint    cyclic_range;
243 244
  gdouble mod_rate;             /* diff / old-value */
  gdouble env_sensitivity;      /* self-diff : env-diff */
245
  gint    diffusion_dist;
Elliot Lee's avatar
Elliot Lee committed
246
  gdouble ch_sensitivity;
247
  gint    range_num;
Elliot Lee's avatar
Elliot Lee committed
248 249 250 251 252 253 254 255 256 257 258 259 260
  gdouble power;
  gdouble parameter_k;
  gdouble range_l;
  gdouble range_h;
  gdouble mutation_rate;
  gdouble mutation_dist;
} CML_PARAM;

typedef struct
{
  CML_PARAM hue;
  CML_PARAM sat;
  CML_PARAM val;
261 262 263 264 265
  gint      initial_value;
  gint      scale;
  gint      start_offset;
  gint      seed;
  gchar     last_file_name[256];
Elliot Lee's avatar
Elliot Lee committed
266 267 268 269
} ValueType;

static ValueType VALS =
{
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
  /* function      composition  arra
    cyc chng sens  diff cor  n  pow  k    (l,h)   rnd  dist */
  {
    CML_SIN_CURVE, COMP_NONE,   STANDARD,
    1,  0.5, 0.7,  2,   0.0, 1, 1.0, 1.0, 0, 1,   0.0, 0.1
  },
  {
    CML_FILL,      COMP_NONE,    STANDARD,
    0,  0.6, 0.1,  2,   0.0, 1, 1.4, 0.9, 0, 0.9, 0.0, 0.1
  },
  {
    CML_FILL,      COMP_NONE,    STANDARD,
    0,  0.5, 0.2,  2,   0.0, 1, 2.0, 1.0, 0, 0.9, 0.0, 0.1
  },
  6,    /* random value 1 */
  1,    /* scale */
  0,    /* start_offset */
  0,    /* seed */
  ""    /* last filename */
Elliot Lee's avatar
Elliot Lee committed
289 290
};

291
static CML_PARAM *channel_params[] =
Elliot Lee's avatar
Elliot Lee committed
292
{
293 294 295
  &VALS.hue,
  &VALS.sat,
  &VALS.val
Elliot Lee's avatar
Elliot Lee committed
296 297
};

Sven Neumann's avatar
Sven Neumann committed
298
static const gchar *channel_names[] =
Elliot Lee's avatar
Elliot Lee committed
299
{
300 301 302
  N_("Hue"),
  N_("Saturation"),
  N_("Value")
Elliot Lee's avatar
Elliot Lee committed
303 304
};

Sven Neumann's avatar
Sven Neumann committed
305 306 307 308 309 310 311 312
static const gchar *load_channel_names[] =
{
  N_("(None)"),
  N_("Hue"),
  N_("Saturation"),
  N_("Value")
};

313
static void query (void);
314
static void run   (const gchar      *name,
315 316 317 318
                   gint              nparams,
                   const GimpParam  *param,
                   gint             *nreturn_vals,
                   GimpParam       **return_vals);
319

320
static GimpPDBStatusType CML_main_function     (gboolean   preview_p);
321
static void              CML_compute_next_step (gint       size,
322 323 324 325 326 327 328 329 330
                                                gdouble  **h,
                                                gdouble  **s,
                                                gdouble  **v,
                                                gdouble  **hn,
                                                gdouble  **sn,
                                                gdouble  **vn,
                                                gdouble  **haux,
                                                gdouble  **saux,
                                                gdouble  **vaux);
331
static gdouble           CML_next_value        (gdouble   *vec,
332 333 334 335 336 337
                                                gint       pos,
                                                gint       size,
                                                gdouble    c1,
                                                gdouble    c2,
                                                CML_PARAM *param,
                                                gdouble    aux);
338
static gdouble           logistic_function     (CML_PARAM *param,
339 340
                                                gdouble    x,
                                                gdouble    power);
341 342


343
static gint        CML_explorer_dialog           (void);
344
static GtkWidget * CML_dialog_channel_panel_new  (CML_PARAM *param,
345
                                                  gint       channel_id);
346
static GtkWidget * CML_dialog_advanced_panel_new (void);
347 348

static void     CML_explorer_toggle_entry_init   (WidgetEntry *widget_entry,
349 350
                                                  GtkWidget   *widget,
                                                  gpointer     value_ptr);
351 352

static void     CML_explorer_int_entry_init      (WidgetEntry *widget_entry,
353 354
                                                  GtkObject   *object,
                                                  gpointer     value_ptr);
355 356

static void     CML_explorer_double_entry_init   (WidgetEntry *widget_entry,
357 358
                                                  GtkObject   *object,
                                                  gpointer     value_ptr);
359 360

static void     CML_explorer_menu_update         (GtkWidget   *widget,
361
                                                  gpointer     data);
362
static void     CML_initial_value_menu_update    (GtkWidget   *widget,
363
                                                  gpointer     data);
364
static void     CML_explorer_menu_entry_init     (WidgetEntry *widget_entry,
365 366
                                                  GtkWidget   *widget,
                                                  gpointer     value_ptr);
367 368 369

static void    preview_update                      (void);
static void    function_graph_new                  (GtkWidget *widget,
370
                                                    gpointer  *data);
371
static void    CML_set_or_randomize_seed_callback  (GtkWidget *widget,
372
                                                    gpointer   data);
373
static void    CML_copy_parameters_callback        (GtkWidget *widget,
374
                                                    gpointer   data);
375 376
static void    CML_initial_value_sensitives_update (void);

377 378
static void    CML_save_to_file_callback   (GtkWidget        *widget,
                                            gpointer          data);
379
static void    CML_save_to_file_response   (GtkWidget        *dialog,
380 381 382 383
                                            gint              response_id,
                                            gpointer          data);

static void    CML_preview_update_callback (GtkWidget        *widget,
384
                                            gpointer          data);
385
static void    CML_load_from_file_callback (GtkWidget        *widget,
386
                                            gpointer          data);
387
static gboolean CML_load_parameter_file     (const gchar     *filename,
388
                                             gboolean         interactive_mode);
389
static void    CML_load_from_file_response (GtkWidget        *dialog,
390 391 392
                                            gint              response_id,
                                            gpointer          data);
static gint    parse_line_to_gint          (FILE             *file,
393
                                            gboolean         *flag);
394
static gdouble parse_line_to_gdouble       (FILE             *file,
395
                                            gboolean         *flag);
396

Elliot Lee's avatar
Elliot Lee committed
397

398
const GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
399
{
400 401 402 403
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
Elliot Lee's avatar
Elliot Lee committed
404 405
};

406 407 408
static GtkWidget   *preview;
static WidgetEntry  widget_pointers[4][CML_PARAM_NUM];

409 410 411 412
static guchar          *img;
static gint             img_stride;
static cairo_surface_t *buffer;

Elliot Lee's avatar
Elliot Lee committed
413 414
typedef struct
{
415 416
  GtkWidget *widget;
  gint       logic;
Elliot Lee's avatar
Elliot Lee committed
417
} CML_sensitive_widget_table;
418

419
#define RANDOM_SENSITIVES_NUM 5
420
#define GRAPHSIZE 256
421

422
static CML_sensitive_widget_table random_sensitives[RANDOM_SENSITIVES_NUM] =
423 424 425 426 427 428 429 430
{
  { NULL, 0 },
  { NULL, 0 },
  { NULL, 0 },
  { NULL, 0 },
  { NULL, 0 }
};

431 432 433 434 435 436 437 438 439 440 441 442 443 444
static GRand    *gr;
static gint      drawable_id = 0;
static gint      copy_source = 0;
static gint      copy_destination = 0;
static gint      selective_load_source = 0;
static gint      selective_load_destination = 0;
static gboolean  CML_preview_defer = FALSE;

static gdouble  *mem_chank0 = NULL;
static gint      mem_chank0_size = 0;
static guchar   *mem_chank1 = NULL;
static gint      mem_chank1_size = 0;
static guchar   *mem_chank2 = NULL;
static gint      mem_chank2_size = 0;
Elliot Lee's avatar
Elliot Lee committed
445

446
MAIN ()
Elliot Lee's avatar
Elliot Lee committed
447 448

static void
449
query (void)
Elliot Lee's avatar
Elliot Lee committed
450
{
451
  static const GimpParamDef args [] =
Elliot Lee's avatar
Elliot Lee committed
452
  {
453
    { GIMP_PDB_INT32,    "ru-_mode",           "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
454 455 456
    { GIMP_PDB_IMAGE,    "image",              "Input image (not used)" },
    { GIMP_PDB_DRAWABLE, "drawable",           "Input drawable"  },
    { GIMP_PDB_STRING,   "parameter-filename", "The name of parameter file. CML_explorer makes an image with its settings." }
Elliot Lee's avatar
Elliot Lee committed
457 458
  };

459
  gimp_install_procedure (PLUG_IN_PROC,
460
                          N_("Create abstract Coupled-Map Lattice patterns"),
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
                          "Make an image of Coupled-Map Lattice (CML). CML is "
                          "a kind of Cellula Automata on continuous (value) "
                          "domain. In GIMP_RUN_NONINTERACTIVE, the name of a "
                          "prameter file is passed as the 4th arg. You can "
                          "control CML_explorer via parameter file.",
                          /*  Or do you want to call me with over 50 args? */
                          "Shuji Narazaki (narazaki@InetQ.or.jp); "
                          "http://www.inetq.or.jp/~narazaki/TheGIMP/",
                          "Shuji Narazaki",
                          "1997",
                          N_("CML _Explorer..."),
                          "RGB*, GRAY*",
                          GIMP_PLUGIN,
                          G_N_ELEMENTS (args), 0,
                          args, NULL);
476

477
  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Render/Pattern");
Elliot Lee's avatar
Elliot Lee committed
478 479 480
}

static void
481 482 483 484 485
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
486
{
487 488
  static GimpParam  values[1];
  GimpPDBStatusType status = GIMP_PDB_EXECUTION_ERROR;
489
  GimpRunMode       run_mode;
Elliot Lee's avatar
Elliot Lee committed
490

491
  run_mode    = param[0].data.d_int32;
Elliot Lee's avatar
Elliot Lee committed
492 493
  drawable_id = param[2].data.d_drawable;

494 495
  INIT_I18N ();

Elliot Lee's avatar
Elliot Lee committed
496 497 498
  *nreturn_vals = 1;
  *return_vals = values;

Sven Neumann's avatar
Sven Neumann committed
499
  values[0].type = GIMP_PDB_STATUS;
Elliot Lee's avatar
Elliot Lee committed
500 501 502 503
  values[0].data.d_status = status;

  switch (run_mode)
    {
Sven Neumann's avatar
Sven Neumann committed
504
    case GIMP_RUN_INTERACTIVE:
505
      gimp_get_data (PLUG_IN_PROC, &VALS);
506
      if (! CML_explorer_dialog ())
507
        return;
Elliot Lee's avatar
Elliot Lee committed
508
      break;
Sven Neumann's avatar
Sven Neumann committed
509
    case GIMP_RUN_NONINTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
510
      {
511
        gchar *filename = param[3].data.d_string;
Elliot Lee's avatar
Elliot Lee committed
512

513 514 515
        if (! CML_load_parameter_file (filename, FALSE))
          return;
        break;
Elliot Lee's avatar
Elliot Lee committed
516
      }
Sven Neumann's avatar
Sven Neumann committed
517
    case GIMP_RUN_WITH_LAST_VALS:
518
      gimp_get_data (PLUG_IN_PROC, &VALS);
Elliot Lee's avatar
Elliot Lee committed
519 520 521 522
      break;
    }

  gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
523
  status = CML_main_function (FALSE);
Elliot Lee's avatar
Elliot Lee committed
524

Sven Neumann's avatar
Sven Neumann committed
525
  if (run_mode != GIMP_RUN_NONINTERACTIVE)
Elliot Lee's avatar
Elliot Lee committed
526
    gimp_displays_flush();
Sven Neumann's avatar
Sven Neumann committed
527
  if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
528
    gimp_set_data (PLUG_IN_PROC, &VALS, sizeof (ValueType));
Elliot Lee's avatar
Elliot Lee committed
529

530 531 532
  g_free (mem_chank0);
  g_free (mem_chank1);
  g_free (mem_chank2);
Elliot Lee's avatar
Elliot Lee committed
533

Sven Neumann's avatar
Sven Neumann committed
534
  values[0].type = GIMP_PDB_STATUS;
Elliot Lee's avatar
Elliot Lee committed
535 536 537
  values[0].data.d_status = status;
}

Sven Neumann's avatar
Sven Neumann committed
538
static GimpPDBStatusType
539
CML_main_function (gboolean preview_p)
540
{
Sven Neumann's avatar
Sven Neumann committed
541 542
  GimpDrawable *drawable = NULL;
  GimpPixelRgn  dest_rgn, src_rgn;
543
  guchar    *dest_buffer = NULL;
544
  guchar    *src_buffer  = NULL;
545 546
  gint       x1, x2, y1, y2;
  gint       dx, dy;
547 548 549 550
  gboolean   dest_has_alpha = FALSE;
  gboolean   dest_is_gray   = FALSE;
  gboolean   src_has_alpha  = FALSE;
  gboolean   src_is_gray    = FALSE;
551 552 553 554 555 556 557 558 559
  gint       total, processed = 0;
  gint       keep_height = 1;
  gint       cell_num, width_by_pixel, height_by_pixel;
  gint       index;
  gint       src_bpp, src_bpl;
  gint       dest_bpp, dest_bpl;
  gdouble   *hues, *sats, *vals;
  gdouble   *newh, *news, *newv;
  gdouble   *haux, *saux, *vaux;
Elliot Lee's avatar
Elliot Lee committed
560 561 562 563 564

  /* open THE drawable */
  drawable = gimp_drawable_get (drawable_id);
  gimp_drawable_mask_bounds (drawable_id, &x1, &y1, &x2, &y2);
  src_has_alpha = dest_has_alpha = gimp_drawable_has_alpha (drawable_id);
Marc Lehmann's avatar
Marc Lehmann committed
565
  src_is_gray = dest_is_gray = gimp_drawable_is_gray (drawable_id);
Elliot Lee's avatar
Elliot Lee committed
566 567 568 569 570
  src_bpp = dest_bpp = (src_is_gray ? 1 : 3) + (src_has_alpha ? 1 : 0);

  if (preview_p)
    {
      dest_has_alpha = FALSE;
571
      dest_bpp       = 3;
Elliot Lee's avatar
Elliot Lee committed
572

573 574
      if (PREVIEW_WIDTH < x2 - x1)      /* preview < drawable (selection) */
        x2 = x1 + PREVIEW_WIDTH;
575
      if (PREVIEW_HEIGHT < y2 - y1)
576
        y2 = y1 + PREVIEW_HEIGHT;
Elliot Lee's avatar
Elliot Lee committed
577 578 579 580 581 582 583
    }
  width_by_pixel = x2 - x1;
  height_by_pixel = y2 - y1;
  dest_bpl = width_by_pixel * dest_bpp;
  src_bpl = width_by_pixel * src_bpp;
  cell_num = (width_by_pixel - 1)/ VALS.scale + 1;
  total = height_by_pixel * width_by_pixel;
584 585
  if (total < 1)
    return GIMP_PDB_EXECUTION_ERROR;
Elliot Lee's avatar
Elliot Lee committed
586 587 588 589 590
  keep_height = VALS.scale;

  /* configure reusable memories */
  if (mem_chank0_size < 9 * cell_num * sizeof (gdouble))
    {
591
      g_free (mem_chank0);
Elliot Lee's avatar
Elliot Lee committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
      mem_chank0_size = 9 * cell_num * sizeof (gdouble);
      mem_chank0 = (gdouble *) g_malloc (mem_chank0_size);
    }
  hues = mem_chank0;
  sats = mem_chank0 + cell_num;
  vals = mem_chank0 + 2 * cell_num;
  newh = mem_chank0 + 3 * cell_num;
  news = mem_chank0 + 4 * cell_num;
  newv = mem_chank0 + 5 * cell_num;
  haux = mem_chank0 + 6 * cell_num;
  saux = mem_chank0 + 7 * cell_num;
  vaux = mem_chank0 + 8 * cell_num;

  if (mem_chank1_size < src_bpl * keep_height)
    {
607
      g_free (mem_chank1);
Elliot Lee's avatar
Elliot Lee committed
608 609 610 611 612 613 614
      mem_chank1_size = src_bpl * keep_height;
      mem_chank1 = (guchar *) g_malloc (mem_chank1_size);
    }
  src_buffer = mem_chank1;

  if (mem_chank2_size < dest_bpl * keep_height)
    {
615
      g_free (mem_chank2);
Elliot Lee's avatar
Elliot Lee committed
616 617 618 619
      mem_chank2_size = dest_bpl * keep_height;
      mem_chank2 = (guchar *) g_malloc (mem_chank2_size);
    }
  dest_buffer = mem_chank2;
620

Elliot Lee's avatar
Elliot Lee committed
621 622
  if (! preview_p)
    gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1,
623 624
                         width_by_pixel, height_by_pixel,
                         TRUE, TRUE);
625

Elliot Lee's avatar
Elliot Lee committed
626
  gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1,
627 628
                       width_by_pixel, height_by_pixel,
                       FALSE, FALSE);
629

630 631 632
  gr = g_rand_new ();
  if (VALS.initial_value == CML_INITIAL_RANDOM_FROM_SEED)
    g_rand_set_seed (gr, VALS.seed);
Elliot Lee's avatar
Elliot Lee committed
633 634 635 636

  for (index = 0; index < cell_num; index++)
    {
      switch (VALS.hue.arrange)
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
        {
        case RAND_POWER0:
          haux [index] = g_rand_double_range (gr, 0, 10);
          break;
        case RAND_POWER2:
        case MULTIPLY_GRADIENT:
          haux [index] = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
          break;
        case RAND_POWER1:
        case MULTIPLY_RANDOM0:
          haux [index] = g_rand_double (gr);
          break;
        case MULTIPLY_RANDOM1:
          haux [index] = g_rand_double_range (gr, 0, 2);
          break;
        case RAND_AND_P:
          haux [index] = ((index % (2 * VALS.hue.diffusion_dist) == 0) ?
654
                          g_rand_double (gr) : VALS.hue.power);
655 656 657 658 659
          break;
        default:
          haux [index] = VALS.hue.power;
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
660
      switch (VALS.sat.arrange)
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
        {
        case RAND_POWER0:
          saux [index] = g_rand_double_range (gr, 0, 10);
          break;
        case RAND_POWER2:
        case MULTIPLY_GRADIENT:
          saux [index] = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
          break;
        case RAND_POWER1:
        case MULTIPLY_RANDOM0:
          saux [index] = g_rand_double (gr);
          break;
        case MULTIPLY_RANDOM1:
          saux [index] = g_rand_double_range (gr, 0, 2);
          break;
        case RAND_AND_P:
          saux [index] = ((index % (2 * VALS.sat.diffusion_dist) == 0) ?
678
                          g_rand_double (gr) : VALS.sat.power);
679 680 681 682 683
          break;
        default:
          saux [index] = VALS.sat.power;
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
684
      switch (VALS.val.arrange)
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
        {
        case RAND_POWER0:
          vaux [index] = g_rand_double_range (gr, 0, 10);
          break;
        case RAND_POWER2:
        case MULTIPLY_GRADIENT:
          vaux [index] = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
          break;
        case RAND_POWER1:
        case MULTIPLY_RANDOM0:
          vaux [index] = g_rand_double (gr);
          break;
        case MULTIPLY_RANDOM1:
          vaux [index] = g_rand_double_range (gr, 0, 2);
          break;
        case RAND_AND_P:
          vaux [index] = ((index % (2 * VALS.val.diffusion_dist) == 0) ?
702
                          g_rand_double (gr) : VALS.val.power);
703 704 705 706 707
          break;
        default:
          vaux [index] = VALS.val.power;
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
708
      switch (VALS.initial_value)
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
        {
        case 0:
        case 1:
        case 2:
          hues[index] = sats[index] = vals[index] = 0.5 * (VALS.initial_value);
          break;
        case 3:                 /* use the values of the image (drawable) */
          break;                /* copy from the drawable after this loop */
        case 4:                 /* grandient 1 */
          hues[index] = sats[index] = vals[index]
            = (gdouble) (index % 256) / (gdouble) 256;
          break;                /* gradinet 2 */
        case 5:
          hues[index] = sats[index] = vals[index]
            = (gdouble) abs ((index % 511) - 255) / (gdouble) 256;
          break;
        case CML_INITIAL_RANDOM_INDEPENDENT:
        case CML_INITIAL_RANDOM_FROM_SEED:
          hues[index] = g_rand_double (gr);
          sats[index] = g_rand_double (gr);
          vals[index] = g_rand_double (gr);
          break;
        case CML_INITIAL_RANDOM_SHARED:
        case CML_INITIAL_RANDOM_FROM_SEED_SHARED:
          hues[index] = sats[index] = vals[index] = g_rand_double (gr);
          break;
        }
Elliot Lee's avatar
Elliot Lee committed
736 737 738 739
    }

  if (VALS.initial_value == 3)
    {
740
      int       index;
Elliot Lee's avatar
Elliot Lee committed
741

742 743 744
      for (index = 0;
           index < MIN (cell_num, width_by_pixel / VALS.scale);
           index++)
745 746 747 748 749 750 751 752 753 754 755 756 757
        {
          guchar buffer[4];
          int   rgbi[3];
          int   i;

          gimp_pixel_rgn_get_pixel (&src_rgn, buffer,
                                    x1 + (index * VALS.scale), y1);
          for (i = 0; i < 3; i++) rgbi[i] = buffer[i];
          gimp_rgb_to_hsv_int (rgbi, rgbi + 1, rgbi + 2);
          hues[index] = (gdouble) rgbi[0] / (gdouble) 255;
          sats[index] = (gdouble) rgbi[1] / (gdouble) 255;
          vals[index] = (gdouble) rgbi[2] / (gdouble) 255;
        }
Elliot Lee's avatar
Elliot Lee committed
758
    }
759 760

  if (! preview_p)
761
    gimp_progress_init (_("CML Explorer: evoluting"));
Elliot Lee's avatar
Elliot Lee committed
762 763 764 765

  /* rolling start */
  for (index = 0; index < VALS.start_offset; index++)
    CML_compute_next_step (cell_num, &hues, &sats, &vals, &newh, &news, &newv,
766
                           &haux, &saux, &vaux);
Elliot Lee's avatar
Elliot Lee committed
767 768 769 770

  /* rendering */
  for (dy = 0; dy < height_by_pixel; dy += VALS.scale)
    {
771 772
      gint r, g, b, h, s, v;
      gint offset_x, offset_y, dest_offset;
Elliot Lee's avatar
Elliot Lee committed
773 774

      if (height_by_pixel < dy + keep_height)
775
        keep_height = height_by_pixel - dy;
776

Elliot Lee's avatar
Elliot Lee committed
777
      if ((VALS.hue.function == CML_KEEP_VALUES) ||
778 779 780 781
          (VALS.sat.function == CML_KEEP_VALUES) ||
          (VALS.val.function == CML_KEEP_VALUES))
        gimp_pixel_rgn_get_rect (&src_rgn, src_buffer,
                                 x1, y1 + dy, width_by_pixel, keep_height);
Maurits Rijk's avatar
Maurits Rijk committed
782

783 784 785
      CML_compute_next_step (cell_num,
                             &hues, &sats, &vals,
                             &newh, &news, &newv,
786
                             &haux, &saux, &vaux);
Elliot Lee's avatar
Elliot Lee committed
787 788

      for (dx = 0; dx < cell_num; dx++)
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
        {
          h = r = HCANNONIZE (VALS.hue, hues[dx]);
          s = g = CANNONIZE (VALS.sat, sats[dx]);
          v = b = CANNONIZE (VALS.val, vals[dx]);

          if (! dest_is_gray)
            gimp_hsv_to_rgb_int (&r, &g, &b);

          /* render destination */
          for (offset_y = 0;
               (offset_y < VALS.scale) && (dy + offset_y < height_by_pixel);
               offset_y++)
            for (offset_x = 0;
                 (offset_x < VALS.scale) && (dx * VALS.scale + offset_x < width_by_pixel);
                 offset_x++)
              {
                if ((VALS.hue.function == CML_KEEP_VALUES) ||
                    (VALS.sat.function == CML_KEEP_VALUES) ||
                    (VALS.val.function == CML_KEEP_VALUES))
                  {
                    int rgbi[3];
                    int i;

                    for (i = 0; i < src_bpp; i++)
                      rgbi[i] = src_buffer[offset_y * src_bpl
814
                                           + (dx * VALS.scale + offset_x) * src_bpp + i];
815
                    if (src_is_gray && (VALS.val.function == CML_KEEP_VALUES))
816 817 818
                      {
                        b = rgbi[0];
                      }
819 820 821 822 823 824 825 826 827 828 829 830
                    else
                      {
                        gimp_rgb_to_hsv_int (rgbi, rgbi + 1, rgbi + 2);

                        r = (VALS.hue.function == CML_KEEP_VALUES) ? rgbi[0] : h;
                        g = (VALS.sat.function == CML_KEEP_VALUES) ? rgbi[1] : s;
                        b = (VALS.val.function == CML_KEEP_VALUES) ? rgbi[2] : v;
                        gimp_hsv_to_rgb_int (&r, &g, &b);
                      }
                  }

                dest_offset = (offset_y * dest_bpl +
831 832
                               (dx * VALS.scale + offset_x) * dest_bpp);

833
                if (dest_is_gray)
834 835 836 837 838 839 840 841
                  {
                    dest_buffer[dest_offset++] = b;
                    if (preview_p)
                      {
                        dest_buffer[dest_offset++] = b;
                        dest_buffer[dest_offset++] = b;
                      }
                  }
842 843 844 845 846 847 848 849 850 851
                else
                  {
                    dest_buffer[dest_offset++] = r;
                    dest_buffer[dest_offset++] = g;
                    dest_buffer[dest_offset++] = b;
                  }
                if (dest_has_alpha)
                  dest_buffer[dest_offset] = 255;

                if ((!preview_p) &&
852
                    (++processed % (total / PROGRESS_UPDATE_NUM + 1)) == 0)
853 854 855
                  gimp_progress_update ((gdouble) processed / (gdouble) total);
              }
        }
856

Elliot Lee's avatar
Elliot Lee committed
857
      if (preview_p)
858 859 860 861 862 863
        gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
                                0, dy,
                                width_by_pixel, keep_height,
                                GIMP_RGB_IMAGE,
                                dest_buffer,
                                dest_bpl);
Elliot Lee's avatar
Elliot Lee committed
864
      else
865 866
        gimp_pixel_rgn_set_rect (&dest_rgn, dest_buffer, x1, y1 + dy,
                                 width_by_pixel, keep_height);
Elliot Lee's avatar
Elliot Lee committed
867 868 869
    }
  if (preview_p)
    {
870
      gtk_widget_queue_draw (preview);
Elliot Lee's avatar
Elliot Lee committed
871 872 873 874 875
    }
  else
    {
      gimp_progress_update (1.0);
      gimp_drawable_flush (drawable);
876
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
877 878
      gimp_drawable_update (drawable->drawable_id,
                            x1, y1, (x2 - x1), (y2 - y1));
Elliot Lee's avatar
Elliot Lee committed
879 880 881
      gimp_drawable_detach (drawable);
    }

882 883
  g_rand_free (gr);

Sven Neumann's avatar
Sven Neumann committed
884
  return GIMP_PDB_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
885 886 887
}

static void
888
CML_compute_next_step (gint      size,
889 890 891 892 893 894 895 896 897
                       gdouble **h,
                       gdouble **s,
                       gdouble **v,
                       gdouble **hn,
                       gdouble **sn,
                       gdouble **vn,
                       gdouble **haux,
                       gdouble **saux,
                       gdouble **vaux)
898
{
899
  gint  index;
Elliot Lee's avatar
Elliot Lee committed
900 901 902

  for (index = 0; index < size; index++)
    (*hn)[index] = CML_next_value (*h, index, size,
903 904 905 906
                                   (*s)[POS_IN_TORUS (index, size)],
                                   (*v)[POS_IN_TORUS (index, size)],
                                   &VALS.hue,
                                   (*haux)[POS_IN_TORUS (index , size)]);
Elliot Lee's avatar
Elliot Lee committed
907 908
  for (index = 0; index < size; index++)
    (*sn)[index] = CML_next_value (*s, index, size,
909 910 911 912
                                   (*v)[POS_IN_TORUS (index   , size)],
                                   (*h)[POS_IN_TORUS (index   , size)],
                                   &VALS.sat,
                                   (*saux)[POS_IN_TORUS (index , size)]);
Elliot Lee's avatar
Elliot Lee committed
913 914
  for (index = 0; index < size; index++)
    (*vn)[index] = CML_next_value (*v, index, size,
915 916 917 918
                                   (*h)[POS_IN_TORUS (index   , size)],
                                   (*s)[POS_IN_TORUS (index   , size)],
                                   &VALS.val,
                                   (*vaux)[POS_IN_TORUS (index , size)]);
919

920
#define GD_SWAP(x, y)   { gdouble *tmp = *x; *x = *y; *y = tmp; }
Elliot Lee's avatar
Elliot Lee committed
921 922 923
  GD_SWAP (h, hn);
  GD_SWAP (s, sn);
  GD_SWAP (v, vn);
924
#undef  SWAP
Elliot Lee's avatar
Elliot Lee committed
925 926
}

927 928 929
#define LOGISTICS(x)    logistic_function (param, x, power)
#define ENV_FACTOR(x)   (param->env_sensitivity * LOGISTICS (x))
#define CHN_FACTOR(x)   (param->ch_sensitivity * LOGISTICS (x))
Elliot Lee's avatar
Elliot Lee committed
930 931

static gdouble
932
CML_next_value (gdouble   *vec,
933 934 935 936 937 938
                gint       pos,
                gint       size,
                gdouble    c1,
                gdouble    c2,
                CML_PARAM *param,
                gdouble    power)
939 940 941 942 943 944 945 946 947
{
  gdouble val = vec[pos];
  gdouble diff = 0;
  gdouble self_diff = 0;
  gdouble by_env = 0;
  gdouble self_mod_rate = 0;
  gdouble hold_rate = 1 - param->mod_rate;
  gdouble env_factor = 0;
  gint    index;
Elliot Lee's avatar
Elliot Lee committed
948 949 950 951 952 953 954 955

  self_mod_rate = (1 - param->env_sensitivity - param->ch_sensitivity);

  switch (param->arrange)
    {
    case ANTILOG:
      self_diff = self_mod_rate * LOGISTICS (1 - vec[pos]);
      for (index = 1; index <= param->diffusion_dist / 2; index++)
956 957
        env_factor += ENV_FACTOR (1 - vec[POS_IN_TORUS (pos + index, size)])
          + ENV_FACTOR (1 - vec[POS_IN_TORUS (pos - index, size)]);
Elliot Lee's avatar
Elliot Lee committed
958
      if ((param->diffusion_dist % 2) == 1)
959 960
        env_factor += (ENV_FACTOR (1 - vec[POS_IN_TORUS (pos + index, size)])
                       + ENV_FACTOR (1 - vec[POS_IN_TORUS (pos - index, size)])) / 2;
Elliot Lee's avatar
Elliot Lee committed
961 962 963 964 965 966 967 968
      env_factor /= (gdouble) param->diffusion_dist;
      by_env = env_factor + (CHN_FACTOR (1 - c1) + CHN_FACTOR (1 - c2)) / 2;
      diff = param->mod_rate * (self_diff + by_env);
      val = hold_rate * vec[pos] + diff;
      break;
    case AVERAGE:
      self_diff = self_mod_rate * LOGISTICS (vec[pos]);
      for (index = 1; index <= param->diffusion_dist / 2; index++)
969
        env_factor += vec[POS_IN_TORUS (pos + index, size)] + vec[POS_IN_TORUS (pos - index, size)];
Elliot Lee's avatar
Elliot Lee committed
970
      if ((param->diffusion_dist % 2) == 1)
971
        env_factor += (vec[POS_IN_TORUS (pos + index, size)] + vec[POS_IN_TORUS (pos - index, size)]) / 2;
Elliot Lee's avatar
Elliot Lee committed
972 973 974 975 976 977 978 979 980
      env_factor /= (gdouble) param->diffusion_dist;
      by_env = ENV_FACTOR (env_factor) + (CHN_FACTOR (c1) + CHN_FACTOR (c2)) / 2;
      diff = param->mod_rate * (self_diff + by_env);
      val = hold_rate * vec[pos] + diff;
      break;
    case MULTIPLY_RANDOM0:
    case MULTIPLY_RANDOM1:
    case MULTIPLY_GRADIENT:
      {
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
        gdouble tmp;

        tmp = power;
        power = param->power;
        self_diff = self_mod_rate * LOGISTICS (vec[pos]);
        for (index = 1; index <= param->diffusion_dist / 2; index++)
          env_factor += ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
            + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)]);
        if ((param->diffusion_dist % 2) == 1)
          env_factor += (ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
                         + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)])) / 2;
        env_factor /= (gdouble) param->diffusion_dist;
        by_env = (env_factor + CHN_FACTOR (c1) + CHN_FACTOR (c2)) / 2;
        diff = pow (param->mod_rate * (self_diff + by_env), tmp);
        val = hold_rate * vec[pos] + diff;
        break;
Elliot Lee's avatar
Elliot Lee committed
997 998 999 1000 1001 1002 1003 1004 1005 1006
      }
    case STANDARD:
    case RAND_POWER0:
    case RAND_POWER1:
    case RAND_POWER2:
    case RAND_AND_P:
    default:
      self_diff = self_mod_rate * LOGISTICS (vec[pos]);

      for (index = 1; index <= param->diffusion_dist / 2; index++)
1007 1008
        env_factor += ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
          + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)]);
Elliot Lee's avatar
Elliot Lee committed
1009
      if ((param->diffusion_dist % 2) == 1)
1010 1011
        env_factor += (ENV_FACTOR (vec[POS_IN_TORUS (pos + index, size)])
                       + ENV_FACTOR (vec[POS_IN_TORUS (pos - index, size)])) / 2;
Elliot Lee's avatar
Elliot Lee committed
1012 1013 1014 1015 1016 1017 1018
      env_factor /= (gdouble) param->diffusion_dist;
      by_env = env_factor + (CHN_FACTOR (c1) + CHN_FACTOR (c2)) / 2;
      diff = param->mod_rate * (self_diff + by_env);
      val = hold_rate * vec[pos] + diff;
      break;
    }
  /* finalize */
1019
  if (g_rand_double (gr) < param->mutation_rate)
Elliot Lee's avatar
Elliot Lee committed
1020
    {
1021
      val += ((g_rand_double (gr) < 0.5) ? -1.0 : 1.0) * param->mutation_dist * g_rand_double (gr);
Elliot Lee's avatar
Elliot Lee committed
1022 1023 1024 1025
    }
  if (param->cyclic_range)
    {
      if (1.0 < val)
1026
        val = val - (int) val;
Elliot Lee's avatar
Elliot Lee committed
1027
      else if (val < 0.0)
1028
        val = val - floor (val);
Elliot Lee's avatar
Elliot Lee committed
1029 1030 1031 1032 1033
    }
  else
    /* The range of val should be [0,1], not [0,1).
      Cannonization shuold be done in color mapping phase. */
    val = CLAMP (val, 0.0, 1);
1034

Elliot Lee's avatar
Elliot Lee committed
1035 1036 1037 1038 1039
  return val;
}
#undef LOGISTICS
#undef ENV_FACTOR
#undef CHN_FACTOR
1040

Elliot Lee's avatar
Elliot Lee committed
1041 1042

static gdouble
1043
logistic_function (CML_PARAM *param,
1044 1045
                   gdouble    x,
                   gdouble    power)
Elliot Lee's avatar
Elliot Lee committed
1046 1047 1048
{
  gdouble x1 = x;
  gdouble result = 0;
1049 1050
  gint n = param->range_num;
  gint step;
Elliot Lee's avatar
Elliot Lee committed
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094

  step = (int) (x * (gdouble) n);
  x1 = (x - ((gdouble) step / (gdouble) n)) * n;
  switch (param->function)
    {
    case CML_KEEP_VALUES:
    case CML_KEEP_FIRST:
      result = x;
      return result;
      break;
    case CML_FILL:
      result = CLAMP (param->parameter_k, 0.0, 1.0);
      return result;
      break;
    case CML_LOGIST:
      result = param->parameter_k * pow (4 * x1 * (1.0 - x1), power);
      break;
    case CML_LOGIST_STEP:
      result = param->parameter_k * pow (4 * x1 * (1.0 - x1), power);
      result = (result + step) / (gdouble) n;
      break;
    case CML_POWER:
      result = param->parameter_k * pow (x1, power);
      break;
    case CML_POWER_STEP:
      result = param->parameter_k * pow (x1, power);
      result = (result + step) / (gdouble) n;
      break;
    case CML_REV_POWER:
      result = param->parameter_k * (1 - pow (x1, power));
      break;
    case CML_REV_POWER_STEP:
      result = param->parameter_k * (1 - pow (x1, power));
      result = (result + step) / (gdouble) n;
      break;
    case CML_DELTA:
      result = param->parameter_k * 2 * ((x1 < 0.5) ? x1 : (1.0 - x1));
      break;
    case CML_DELTA_STEP:
      result = param->parameter_k * 2 * ((x1 < 0.5) ? x1 : (1.0 - x1));
      result = (result + step) / (gdouble) n;
      break;
    case CML_SIN_CURVE:
      if (1.0 < power)
1095
        result = 0.5 * (sin (G_PI * ABS (x1 - 0.5) / power) / sin (G_PI * 0.5 / power) + 1);
Elliot Lee's avatar
Elliot Lee committed
1096
      else
1097
        result = 0.5 * (pow (sin (G_PI * ABS (x1 - 0.5)), power) + 1);
Elliot Lee's avatar
Elliot Lee committed
1098 1099 1100 1101
      if (x1 < 0.5) result = 1 - result;
      break;
    case CML_SIN_CURVE_STEP:
      if (1.0 < power)
1102
        result = 0.5 * (sin (G_PI * ABS (x1 - 0.5) / power) / sin (G_PI * 0.5 / power) + 1);
Elliot Lee's avatar
Elliot Lee committed
1103
      else
1104
        result = 0.5 * (pow (sin (G_PI * ABS (x1 - 0.5)), power) + 1);
Elliot Lee's avatar
Elliot Lee committed
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
      if (x1 < 0.5) result = 1 - result;
      result = (result + step) / (gdouble) n;
      break;
    }
  switch (param->composition)
    {
    case COMP_NONE:
      break;
    case COMP_MAX_LINEAR:
      result = MAX ((gdouble) x, (gdouble) result);
      break;
    case COMP_MAX_LINEAR_P1:
      result = MAX ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
      break;
    case COMP_MAX_LINEAR_P1L:
      if (x < 0.5)
1121
        result = MAX ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1122 1123 1124
      break;
    case COMP_MAX_LINEAR_P1U:
      if (0.5 < x)
1125
        result = MAX ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1126 1127 1128 1129 1130 1131
      break;
    case COMP_MAX_LINEAR_M1:
      result = MAX ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
      break;
    case COMP_MAX_LINEAR_M1L:
      if (x < 0.5)
1132
        result = MAX ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1133 1134 1135
      break;
    case COMP_MAX_LINEAR_M1U:
      if (0.5 < x)
1136
        result = MAX ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1137 1138 1139 1140 1141 1142 1143 1144 1145
      break;
    case COMP_MIN_LINEAR:
      result = MIN ((gdouble) x, (gdouble) result);
      break;
    case COMP_MIN_LINEAR_P1:
      result = MIN ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
      break;
    case COMP_MIN_LINEAR_P1L:
      if (x < 0.5)
1146
        result = MIN ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1147 1148 1149
      break;
    case COMP_MIN_LINEAR_P1U:
      if (0.5 < x)
1150
        result = MIN ((gdouble) x + (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1151 1152 1153 1154 1155 1156
      break;
    case COMP_MIN_LINEAR_M1:
      result = MIN ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
      break;
    case COMP_MIN_LINEAR_M1L:
      if (x < 0.5)
1157
        result = MIN ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1158 1159 1160
      break;
    case COMP_MIN_LINEAR_M1U:
      if (0.5 < x)
1161
        result = MIN ((gdouble) x - (gdouble) 1 / (gdouble) 256, (gdouble) result);
Elliot Lee's avatar
Elliot Lee committed
1162 1163 1164 1165 1166 1167
      break;
    }
  return result;
}

/* dialog stuff */
1168 1169
static gint
CML_explorer_dialog (void)
Elliot Lee's avatar
Elliot Lee committed
1170
{
1171
  GtkWidget *dialog;
1172 1173 1174 1175
  GtkWidget *hbox;
  GtkWidget *vbox;
  GtkWidget *frame;
  GtkWidget *abox;
1176
  GtkWidget *bbox;
1177
  GtkWidget *button;
1178
  gboolean   run;
1179

1180
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
1181

1182
  dialog = gimp_dialog_new (_("Coupled-Map-Lattice Explorer"), PLUG_IN_ROLE,
1183 1184
                            NULL, 0,
                            gimp_standard_help_func, PLUG_IN_PROC,
1185

1186 1187
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
1188

1189
                            NULL);
1190

1191
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1192 1193 1194
                                           GTK_RESPONSE_OK,
                                           GTK_RESPONSE_CANCEL,
                                           -1);
1195

1196
  gimp_window_set_transient (GTK_WINDOW (dialog));
1197

Elliot Lee's avatar
Elliot Lee committed
1198 1199
  CML_preview_defer = TRUE;

1200
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
1201
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
1202 1203
  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
                      hbox, FALSE, FALSE, 0);
1204
  gtk_widget_show (hbox);
Elliot Lee's avatar
Elliot Lee committed
1205

1206
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1207 1208
  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  gtk_widget_show (vbox);
Elliot Lee's avatar
Elliot Lee committed
1209

1210
  abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1211
  gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
1212 1213
  gtk_widget_show (abox);

1214 1215 1216 1217
  frame = gtk_frame_new (NULL);
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  gtk_container_add (GTK_CONTAINER (abox), frame);
  gtk_widget_show (frame);
1218

1219 1220 1221
  preview = gimp_preview_area_new ();
  gtk_widget_set_size_request (preview,
                               PREVIEW_WIDTH, PREVIEW_HEIGHT);
1222
  gtk_container_add (GTK_CONTAINER (frame), preview);
1223 1224
  gtk_widget_show (preview);

1225 1226 1227 1228
  bbox = gtk_vbutton_box_new ();
  gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
  gtk_widget_show (bbox);

1229
  button = gtk_button_new_with_label (_("New Seed"));
1230
  gtk_container_add (GTK_CONTAINER (bbox), button);
1231 1232
  gtk_widget_show (button);

1233
  g_signal_connect (button, "clicked",
1234
                    G_CALLBACK (CML_preview_update_callback),
1235 1236
                    &VALS);

1237 1238 1239
  random_sensitives[0].widget = button;
  random_sensitives[0].logic  = TRUE;

1240
  button = gtk_button_new_with_label (_("Fix Seed"));
1241
  gtk_container_add (GTK_CONTAINER (bbox), button);
1242 1243
  gtk_widget_show (button);

1244
  g_signal_connect (button, "clicked",
1245
                    G_CALLBACK (CML_set_or_randomize_seed_callback),
1246 1247
                    &VALS);

1248 1249
  random_sensitives[1].widget = button;
  random_sensitives[1].logic  = TRUE;
1250

1251
  button = gtk_button_new_with_label (_("Random Seed"));
1252
  gtk_container_add (GTK_CONTAINER (bbox), button);
1253 1254
  gtk_widget_show (button);

1255
  g_signal_connect (button, "clicked",
1256 1257 1258
                    G_CALLBACK (CML_set_or_randomize_seed_callback),
                    &VALS);

1259 1260 1261
  random_sensitives[2].widget = button;
  random_sensitives[2].logic  = FALSE;

1262 1263 1264 1265 1266 1267
  bbox = gtk_vbutton_box_new ();
  gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
  gtk_widget_show (bbox);

  button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
  gtk_container_add (GTK_CONTAINER (bbox), button);
1268 1269
  gtk_widget_show (button);

1270
  g_signal_connect (button, "clicked",
1271
                    G_CALLBACK (CML_load_from_file_callback),
1272 1273
                    &VALS);

1274 1275
  button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
  gtk_container_add (GTK_CONTAINER (bbox), button);
1276 1277
  gtk_widget_show (button);

1278
  g_signal_connect (button, "clicked",
1279
                    G_CALLBACK (CML_save_to_file_callback),
1280 1281
                    &VALS);

Elliot Lee's avatar
Elliot Lee committed
1282 1283 1284 1285 1286 1287
  {
    GtkWidget *notebook;
    GtkWidget *page;

    notebook = gtk_notebook_new ();
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
1288
    gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0);
Elliot Lee's avatar
Elliot Lee committed
1289 1290
    gtk_widget_show (notebook);

1291
    page = CML_dialog_channel_panel_new (&VALS.hue, 0);
Elliot Lee's avatar
Elliot Lee committed
1292
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1293
                              gtk_label_new_with_mnemonic (_("_Hue")));
Elliot Lee's avatar
Elliot Lee committed
1294

1295
    page = CML_dialog_channel_panel_new (&VALS.sat, 1);
Elliot Lee's avatar
Elliot Lee committed
1296
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1297
                              gtk_label_new_with_mnemonic (_("Sat_uration")));
Elliot Lee's avatar
Elliot Lee committed
1298

1299
    page = CML_dialog_channel_panel_new (&VALS.val, 2);
Elliot Lee's avatar
Elliot Lee committed
1300
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1301
                              gtk_label_new_with_mnemonic (_("_Value")));
Elliot Lee's avatar
Elliot Lee committed
1302

1303
    page = CML_dialog_advanced_panel_new ();
Elliot Lee's avatar
Elliot Lee committed
1304
    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page,
1305
                              gtk_label_new_with_mnemonic (_("_Advanced")));
Elliot Lee's avatar
Elliot Lee committed
1306

1307
    {
1308 1309 1310 1311 1312 1313 1314
      GtkSizeGroup *group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
      GtkWidget    *table;
      GtkWidget    *label;
      GtkWidget    *combo;
      GtkWidget    *frame;
      GtkWidget    *vbox;
      GtkObject    *adj;
1315

1316
      vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1317
      gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1318 1319
      gtk_widget_show (vbox);

1320
      frame = gimp_frame_new (_("Channel Independent Parameters"));
1321 1322
      gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
      gtk_widget_show (frame);
1323 1324

      table = gtk_table_new (3, 3, FALSE);
1325 1326
      gtk_table_set_col_spacings (GTK_TABLE (table), 6);
      gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1327
      gtk_container_add (GTK_CONTAINER (frame), table);
1328 1329
      gtk_widget_show (table);

Sven Neumann's avatar
Sven Neumann committed
1330 1331 1332 1333
      combo = gimp_int_combo_box_new_array (CML_INITIAL_NUM_VALUES,
                                            initial_value_names);
      gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
                                     VALS.initial_value);
1334

Sven Neumann's avatar
Sven Neumann committed
1335 1336 1337
      g_signal_connect (combo, "changed",
                        G_CALLBACK (CML_initial_value_menu_update),
                        &VALS.initial_value);
1338 1339

      CML_explorer_menu_entry_init (&widget_pointers[3][0],
1340
                                    combo, &VALS.initial_value);
1341
      label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
1342
                                         _("Initial value:"), 0.0, 0.5,
1343 1344 1345
                                         combo, 2, FALSE);
      gtk_size_group_add_widget (group, label);
      g_object_unref (group);
1346 1347

      adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
1348 1349 1350 1351
                                  _("Zoom scale:"), SCALE_WIDTH, 3,
                                  VALS.scale, 1, 10, 1, 2, 0,
                                  TRUE, 0, 0,
                                  NULL, NULL);
1352
      gtk_size_group_add_widget (group, GIMP_SCALE_ENTRY_LABEL (adj));
1353
      CML_explorer_int_entry_init (&widget_pointers[3][1],
1354
                                   adj, &VALS.scale);
Michael Natterer's avatar