home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / unofficial-plug-ins / fuse / fuse.c
Encoding:
C/C++ Source or Header  |  2000-02-14  |  24.2 KB  |  964 lines

  1. /*
  2.    fuse - associative image reconstruction
  3.    Copyright (C) 1997  Scott Draves <spot@cs.cmu.edu>
  4.  
  5.    The GIMP -- an image manipulation program
  6.    Copyright (C) 1995 Spencer Kimball and Peter Mattis
  7.  
  8.    This program is free software; you can redistribute it and/or modify
  9.    it under the terms of the GNU General Public License as published by
  10.    the Free Software Foundation; either version 2 of the License, or
  11.    (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful,
  14.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    GNU General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22.  
  23.  
  24. /*
  25.  
  26.   revision history
  27.  
  28.   Fri Nov 28 1997 - added template image
  29.  
  30.   Sun Nov 16 1997 - listbox to select multiple inputs
  31.  
  32. */
  33.  
  34. #include "config.h"
  35.  
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #ifdef HAVE_UNISTD_H
  39. #include <unistd.h>
  40. #endif
  41. #include <errno.h>
  42. #include <string.h>
  43. #include <time.h>
  44. #include <math.h>
  45. #include <assert.h>
  46.  
  47. #include "gtk/gtk.h"
  48. #include "libgimp/gimp.h"
  49. #include "libgimp/gimpmenu.h"
  50. #include "gck/gck.h"
  51.  
  52. /* //HB: use glib's random */
  53. #define USE_G_RANDOM
  54.  
  55. #ifdef USE_G_RANDOM
  56. GRand* pRandom = NULL;
  57. #define random() g_rand_int(pRandom)
  58. #endif
  59.  
  60. static void query(void);
  61. static void run(char *name,
  62.         int nparams,
  63.         GParam * param,
  64.         int *nreturn_vals,
  65.         GParam ** return_vals);
  66. static gint dialog();
  67.  
  68. static void doit(GDrawable *);
  69.  
  70. typedef unsigned long pixel;
  71.  
  72. typedef struct {
  73.   pixel *pixels;
  74.   int width, height, stride;
  75. } image;
  76.  
  77.  
  78. GPlugInInfo PLUG_IN_INFO =
  79. {
  80.   NULL, /* init_proc */
  81.   NULL, /* quit_proc */
  82.   query, /* query_proc */
  83.   run, /* run_proc */
  84. };
  85.  
  86. int run_flag = 0;
  87.  
  88.  
  89. GtkWidget *dlg;
  90. GckListBox *listbox;
  91.  
  92.  
  93. #define preview_size 150
  94. GtkWidget *preview;
  95.  
  96. GDrawable *drawable;
  97.  
  98. #define max_inputs 100
  99.  
  100. struct {
  101.   int ninputs;
  102.   gint32 input_image_ids[max_inputs];
  103.   int tile_size;
  104.   int overlap;
  105.   int order;
  106.   int acceleration;
  107.   int search_time;
  108.   int use_template;
  109.   double template_weight; /* in [0,10] */
  110. } config = {
  111.   0,
  112.   {0},
  113.   25,
  114.   8,
  115.   0,
  116.   0,
  117.   10,
  118.   0,
  119.   0.5,
  120. };
  121.  
  122.  
  123.  
  124. MAIN();
  125.  
  126. static void query()
  127. {
  128.   static GParamDef args[] =
  129.   {
  130.     {PARAM_INT32, "run_mode", "Interactive, non-interactive"},
  131.     {PARAM_IMAGE, "image", "Input image (unused)"},
  132.     {PARAM_DRAWABLE, "drawable", "Input drawable"},
  133.   };
  134.   static GParamDef *return_vals = NULL;
  135.   static int nargs = sizeof(args) / sizeof(args[0]);
  136.   static int nreturn_vals = 0;
  137.  
  138.   gimp_install_procedure("plug_in_fuse",
  139.              "associative image reconstruction",
  140.              "uhm, image dissociation",
  141.              "Scott Draves",
  142.              "Scott Draves",
  143.              "Nov 1997",
  144.              "<Image>/Filters/Transforms/Fuse",
  145.              "RGB*",
  146.              PROC_PLUG_IN,
  147.              nargs, nreturn_vals,
  148.              args, return_vals);
  149. }
  150.  
  151. static void
  152. run(char *name, int n_params, GParam * param, int *nreturn_vals,
  153.     GParam ** return_vals)
  154. {
  155.   static GParam values[1];
  156.   GRunModeType run_mode;
  157.   GStatusType status = STATUS_SUCCESS;
  158.  
  159.   *nreturn_vals = 1;
  160.   *return_vals = values;
  161.  
  162. #ifdef USE_G_RANDOM
  163.   pRandom = g_rand_new ();
  164. #else
  165.   srandom(time(0));
  166. #endif
  167.  
  168.   run_mode = param[0].data.d_int32;
  169.   
  170.   if (run_mode == RUN_NONINTERACTIVE) {
  171.     status = STATUS_CALLING_ERROR;
  172.   } else {
  173.     gimp_get_data("plug_in_fuse", &config);
  174.  
  175.     drawable = gimp_drawable_get(param[2].data.d_drawable);
  176.  
  177.     if (run_mode == RUN_INTERACTIVE) {      
  178.       if (!dialog()) {
  179.     status = STATUS_EXECUTION_ERROR;
  180.       }
  181.     }
  182.   }
  183.  
  184.  
  185.   if (status == STATUS_SUCCESS) {
  186.  
  187.     if (gimp_drawable_color(drawable->id)) {
  188.       ;
  189.     } else {
  190.       status = STATUS_EXECUTION_ERROR;
  191.     }
  192.     gimp_drawable_detach(drawable);
  193.   }
  194.  
  195.   values[0].type = PARAM_STATUS;
  196.   values[0].data.d_status = status;
  197.  
  198. #ifdef USE_G_RANDOM
  199.   g_rand_free(pRandom);
  200.   pRandom = NULL;
  201. #endif
  202. }
  203.  
  204.  
  205. double
  206. compare(image *in, image *out) {
  207.   int x, y;
  208.   double r = 0.0;
  209.   double t = 0.0;
  210.   for (y = 0; y < in->height; y++) {
  211.     pixel *p = in->pixels + y * in->stride;
  212.     pixel *q = out->pixels + y * out->stride;
  213.     for (x = 0; x < in->width; x++) {
  214.       double rr, z;
  215.       guchar *i = (guchar *) (&p[x]);
  216.       guchar *o = (guchar *) (&q[x]);
  217.       int d;
  218.       if (0 == i[3] || 0 == o[3])
  219.     continue;
  220.       d = i[0] - (int) o[0];
  221.       rr = d * d;
  222.       d = i[1] - (int) o[1];
  223.       rr += d * d;
  224.       d = i[2] - (int) o[2];
  225.       rr += d * d;
  226.       z = i[3] * (double) o[3];
  227.       r += rr * z;
  228.       t += z * z; /* z * 255? */
  229.     }
  230.   }
  231.  
  232.   if (t < 0.5)
  233.     return -1.0;
  234.  
  235.   return r/t;
  236. }
  237.  
  238. /* use bbox of src */
  239. void
  240. blit(image *dst, image *src) {
  241.   int x, y;
  242.   for (y = 0; y < src->height; y++) {
  243.     pixel *p = dst->pixels + y * dst->stride;
  244.     pixel *q = src->pixels + y * src->stride;
  245.     for (x = 0; x < src->width; x++) {
  246.       guchar *o = (guchar *) (&p[x]);
  247.       guchar *i = (guchar *) (&q[x]);
  248.       int s = i[3];
  249.       if (255 == s)
  250.     p[x] = q[x];
  251.       else {
  252.     o[0] = (o[0] * (255 - s) + i[0] * s) >> 8;
  253.     o[1] = (o[1] * (255 - s) + i[1] * s) >> 8;
  254.     o[2] = (o[2] * (255 - s) + i[2] * s) >> 8;
  255.       }
  256.     }
  257.   }
  258. }
  259.  
  260. /* find tile somewhere in IN that matches OUT and TEMPLATE */
  261. void
  262. source_match(image *in, image *out, image *template) {
  263.   int i;
  264.   double best_d = G_MAXDOUBLE;
  265.   image best_tile;
  266.   double w = exp(-0.3 * (10-config.template_weight));
  267.  
  268.   if (0 == out->width || 0 == out->height)
  269.     return;
  270.  
  271.   for (i = 0; i < 1+(config.search_time<<8); i++) {
  272.     image tile;
  273.     double d;
  274.  
  275.     tile.pixels =
  276.       in->pixels + (random() % (in->width - out->width)) +
  277.       in->stride * (random() % (in->height - out->height));
  278.  
  279.     tile.stride = in->stride;
  280.     tile.width = out->width;
  281.     tile.height = out->height;
  282.  
  283.     d = compare(&tile, out);
  284.     if (d < 0.0) {
  285.       /* should really only happen with null overlap */
  286.       best_tile = tile;
  287.       break;
  288.     }
  289.     if (template) {
  290.       double e = compare(&tile, template);
  291.       if (e < 0.0)
  292.     printf("e less than zero\n");
  293.       else
  294.     d = (d * (1.0 - w) + e * w);
  295.     }
  296.       
  297.     if (d < best_d) {
  298.       best_d = d;
  299.       best_tile = tile;
  300.     }
  301.   }
  302.   blit(out, &best_tile);
  303. }
  304.  
  305.  
  306. void
  307. do_fuse(int nin, image *ins, image *out, image *template) {
  308.   int i, parity = 0;
  309.   double r, rad;
  310.   double bo;
  311.   int *prmute;
  312.  
  313.   bo = config.tile_size - config.overlap;
  314.  
  315.   for (i = 0; i < nin; i++)
  316.     if (config.tile_size >= ins[i].width ||
  317.     config.tile_size >= ins[i].height) {
  318.       printf("input smaller than tile - bailing\n");
  319.       return;
  320.     }
  321.  
  322.   rad = sqrt(out->width * out->width +
  323.          out->height * out->height) / 2;
  324.  
  325.   prmute = malloc(sizeof(int) * (1 + rad * 2.0 * G_PI / bo));
  326.       
  327.   for (r = 0; r < rad; r += bo) {
  328.     int n = 1 + r * 2.0 * G_PI / bo;
  329.     for (i = 0; i < n; i++)
  330.       prmute[i] = i;
  331.     for (i = 0; i < 2*n; i++) {
  332.       int i1 = random() % n;
  333.       int i2 = random() % n;
  334.       int t = prmute[i1];
  335.       prmute[i1] = prmute[i2];
  336.       prmute[i2] = t;
  337.     }
  338.     parity++;
  339.     for (i = 0; i < n; i++) {
  340.       image tile, template_tile;
  341.       int x, y, w, h;
  342.       double theta = 2.0 * G_PI * prmute[i] / n;
  343.       if (parity&1)
  344.     theta += G_PI / n;
  345.       w = config.tile_size;
  346.       h = config.tile_size;
  347.       x = (out->width - w) / 2 + r * cos(theta);
  348.       y = (out->height - h) / 2 + r * sin(theta);
  349.  
  350.       /* clip */
  351.       if (x < 0) {w += x; x = 0;}
  352.       if (y < 0) {h += y; y = 0;}
  353.       if (x > out->width - w) w = out->width - x;
  354.       if (y > out->height - h) h = out->height - y;
  355.  
  356.       if (w <= 0 || h <= 0)
  357.     continue;
  358.  
  359.       tile.pixels = out->pixels + y * out->stride + x;
  360.       tile.stride = out->stride;
  361.       tile.width = w;
  362.       tile.height = h;
  363.  
  364.       if (template) {
  365.     template_tile.pixels = template->pixels + y * template->stride + x;
  366.     template_tile.stride = template->stride;
  367.     template_tile.width = w;
  368.     template_tile.height = h;
  369.       }
  370.  
  371.       source_match(ins + (random()%nin), &tile,
  372.            template ? &template_tile : NULL);
  373.       if ((parity < 4) || ((i&7) == 0)) {
  374.     int xx, yy;
  375.     int cx, cy;
  376.     guchar *buf = (guchar *) malloc(3 * preview_size);
  377.     int p2 = preview_size/2;
  378.     if (r < p2) {
  379.       cx = out->width/2;
  380.       cy = out->height/2;
  381.     } else {
  382.       cx = x;
  383.       cy = y;
  384.     }
  385.     for (yy = cy-p2; yy < cy+p2; yy++) {
  386.       for (xx = cx-p2; xx < cx+p2; xx++) {
  387.         guchar *p = &buf[3*(xx-(cx-p2))];
  388.         guchar *q = (guchar *)(out->pixels+yy*out->stride+xx);
  389.         if ((xx < out->width) &&
  390.         (xx >= 0) &&
  391.         (yy < out->height) &&
  392.         (yy >= 0)) {
  393.           p[0] = q[0];
  394.           p[1] = q[1];
  395.           p[2] = q[2];
  396.         } else {
  397.           p[0] = p[1] = p[2] = 0;
  398.         }
  399.       }
  400.       gtk_preview_draw_row(GTK_PREVIEW (preview),
  401.                    buf, 0, (yy-(cy-p2)), preview_size);
  402.     }
  403.     free(buf);
  404.     gtk_widget_draw (preview, NULL);  
  405.       }
  406.       gimp_progress_update((1-i/(double)n) * r * r / (rad * rad) +
  407.                i/(double)n * (r + bo) * (r + bo) / (rad * rad));
  408.     }
  409.   }
  410.   free(prmute);
  411. }
  412.  
  413. static void
  414. doit(GDrawable * target_drawable) {
  415.   image *in, out, template;
  416.   gint bytes;
  417.   GPixelRgn pr;
  418.   GDrawable *input_drawable;
  419.   int i;
  420.  
  421.   if (0 == config.ninputs) {
  422.     printf("fuse needs at least one input\n");
  423.     return;
  424.   }
  425.  
  426.   in = (image *) malloc(sizeof(image) * config.ninputs);
  427.  
  428.   for (i = 0; i < config.ninputs; i++) {
  429.     image *inp = &in[i];
  430.  
  431.     inp->width = gimp_image_width(config.input_image_ids[i]);
  432.     inp->height = gimp_image_height(config.input_image_ids[i]);
  433.     inp->stride = inp->width;
  434.  
  435.     /* allocate and initialize input buffer */
  436.  
  437.     inp->pixels = (pixel *) malloc(inp->width * inp->height * 4);
  438.     if (inp->pixels == NULL) {
  439.       fprintf(stderr, "cannot malloc %d bytes for input.\n", inp->width * inp->height * 4);
  440.       return;
  441.     }
  442.  
  443.     {
  444.       int nlayers;
  445.       gint32 *layer_ids;
  446.       layer_ids = gimp_image_get_layers (config.input_image_ids[i], &nlayers);
  447.       if ((NULL == layer_ids) || (nlayers <= 0)) {
  448.     fprintf(stderr, "fuse: error getting layer IDs\n");
  449.     return;
  450.       }
  451.       input_drawable = gimp_drawable_get(layer_ids[nlayers-1]);
  452.       bytes = input_drawable->bpp;
  453.  
  454.       gimp_pixel_rgn_init(&pr, input_drawable,
  455.               0, 0, inp->width, inp->height, FALSE, FALSE);
  456.       if (4 == bytes) {
  457.     printf("4 channel image, using alpha\n");
  458.     gimp_pixel_rgn_get_rect(&pr, (guchar *)inp->pixels, 0, 0, inp->width, inp->height);
  459.       } else if (3 == bytes) {
  460.     int i;
  461.     guchar *tb = malloc (inp->width * bytes);
  462.     for (i = 0; i < inp->height; i++) {
  463.       int j;
  464.       gimp_pixel_rgn_get_rect(&pr, tb, 0, i, inp->width, 1);
  465.       for (j = 0; j < inp->width; j++) {
  466.         guchar *d = (guchar *) (inp->pixels + (inp->width * i) + j);
  467.         guchar *s = tb + j * bytes;
  468.         d[0] = s[0];
  469.         d[1] = s[1];
  470.         d[2] = s[2];
  471.         d[3] = 255;
  472.       }
  473.     }
  474.     free(tb);
  475.       } else if (1 == bytes) {
  476.     int i;
  477.     guchar *tb = malloc (inp->width * bytes);
  478.     for (i = 0; i < inp->height; i++) {
  479.       int j;
  480.       gimp_pixel_rgn_get_rect(&pr, tb, 0, i, inp->width, 1);
  481.       for (j = 0; j < inp->width; j++) {
  482.         guchar *d = (guchar *) (inp->pixels + (inp->width * i) + j);
  483.         guchar *s = tb + j * bytes;
  484.         d[0] = d[1] = d[2] = s[0];
  485.         d[3] = 255;
  486.       }
  487.     }
  488.     free(tb);
  489.       } else {
  490.     printf("cannot handle image with %d bytes per pixel\n", bytes);
  491.       }
  492.     
  493.  
  494.       if (nlayers > 1) {
  495.     input_drawable = gimp_drawable_get(layer_ids[0]);
  496.     bytes = input_drawable->bpp;
  497.  
  498.     gimp_pixel_rgn_init(&pr, input_drawable,
  499.                 0, 0, inp->width, inp->height, FALSE, FALSE);
  500.     printf("looking for alpha\n");
  501.     if (1 == bytes) {
  502.       int i;
  503.       guchar *tb = malloc (inp->width * bytes);
  504.       printf("got alpha\n");
  505.       for (i = 0; i < inp->height; i++) {
  506.         int j;
  507.         gimp_pixel_rgn_get_rect(&pr, tb, 0, i, inp->width, 1);
  508.         for (j = 0; j < inp->width; j++) {
  509.           guchar *d = (guchar *) (inp->pixels + (inp->width * i) + j);
  510.           guchar *s = tb + j * bytes;
  511.           d[3] = s[0];
  512.         }
  513.       }
  514.       free(tb);
  515.     }
  516.     
  517.       }
  518.     }
  519.   }
  520.  
  521.   {
  522.     out.width = target_drawable->width;
  523.     out.height = target_drawable->height;
  524.     out.stride = out.width;
  525.  
  526.     out.pixels = (pixel *) malloc(out.width * out.height * 4);
  527.     if (out.pixels == NULL) {
  528.       fprintf(stderr, "cannot malloc %d bytes for output.\n",
  529.           out.width * out.height * 4);
  530.       return;
  531.     }
  532.   }
  533.   
  534.   if (config.use_template) {
  535.     template.width = target_drawable->width;
  536.     template.height = target_drawable->height;
  537.     template.stride = template.width;
  538.     template.pixels = (pixel *) malloc(template.width * template.height * 4);
  539.     if (template.pixels == NULL) {
  540.       fprintf(stderr, "cannot malloc %d bytes for output.\n",
  541.           template.width * template.height * 4);
  542.       return;
  543.     }
  544.     
  545.     bytes = target_drawable->bpp;
  546.  
  547.     gimp_pixel_rgn_init(&pr, target_drawable,
  548.             0, 0, template.width, template.height, FALSE, FALSE);
  549.     if (4 == bytes) {
  550.       printf("4 channel image, using alpha\n");
  551.       gimp_pixel_rgn_get_rect(&pr, (guchar *)template.pixels, 0, 0, template.width, template.height);
  552.     } else if (3 == bytes) {
  553.       int i;
  554.       guchar *tb = malloc (template.width * bytes);
  555.       for (i = 0; i < template.height; i++) {
  556.     int j;
  557.     gimp_pixel_rgn_get_rect(&pr, tb, 0, i, template.width, 1);
  558.     for (j = 0; j < template.width; j++) {
  559.       guchar *d = (guchar *) (template.pixels + (template.width * i) + j);
  560.       guchar *s = tb + j * bytes;
  561.       d[0] = s[0];
  562.       d[1] = s[1];
  563.       d[2] = s[2];
  564.       d[3] = 255;
  565.     }
  566.       }
  567.       free(tb);
  568.     }
  569.   }
  570.  
  571.   do_fuse(config.ninputs, in, &out,
  572.       config.use_template ? &template : NULL);
  573.  
  574.   gimp_pixel_rgn_init(&pr, target_drawable,
  575.               0, 0, out.width, out.height, FALSE, FALSE);
  576.  
  577.   bytes = target_drawable->bpp;
  578.  
  579.  
  580.   if (4 == bytes) {
  581.     gimp_pixel_rgn_set_rect(&pr, (guchar *) out.pixels, 0, 0, out.width, out.height);
  582.   } else {
  583.     int i;
  584.     guchar *tb = malloc (out.width * bytes);
  585.     for (i = 0; i < out.height; i++) {
  586.       int j;
  587.       for (j = 0; j < out.width; j++) {
  588.     char *s = (char *) (out.pixels + (out.width * i) + j);
  589.     char *d = tb + j * bytes;
  590.     d[0] = s[0];
  591.     d[1] = s[1];
  592.     d[2] = s[2];
  593.       }
  594.       gimp_pixel_rgn_set_rect(&pr, tb, 0, i, out.width, 1);
  595.     }
  596.     free(tb);
  597.   }
  598.   gimp_drawable_flush(target_drawable);
  599.   /*
  600.   gimp_drawable_merge_shadow(target_drawable->id, TRUE);
  601.   */
  602.   gimp_drawable_update(target_drawable->id, 0, 0,
  603.                target_drawable->width, target_drawable->height);
  604.  
  605.  
  606.  
  607.   for (i = 0; i < config.ninputs; i++)
  608.     free(in[i].pixels);
  609.   free(in);
  610.   
  611.   free(out.pixels);
  612.   if (config.use_template)
  613.     free(template.pixels);
  614. }
  615.  
  616.  
  617. static void close_callback(GtkWidget * widget, gpointer data)
  618. {
  619.   gtk_main_quit();
  620. }
  621.  
  622. static void ok_callback(GtkWidget * widget, gpointer data)
  623. {
  624.   GList *sel;
  625.   int n;
  626.   run_flag = 1;
  627.  
  628.   if (gimp_drawable_color(drawable->id)) {
  629.  
  630.     sel = gck_listbox_get_current_selection(listbox);
  631.  
  632.     n = 0;
  633.     while (sel != NULL && n < max_inputs) {
  634.     
  635.       config.input_image_ids[n] =
  636. #if 0
  637.     ((GckListBoxItem *) sel->data)->user_data;
  638. #else
  639.       /* //HB: don't know if this cast is really ok */
  640.     (int)((GckListBoxItem *) sel->data)->user_data;
  641. #endif
  642.       sel = sel->next;
  643.       n++;
  644.     }
  645.     config.ninputs = n;
  646.  
  647.     gimp_progress_init("Fusing...");
  648.     gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1));
  649.  
  650.     doit(drawable);
  651.  
  652.     gtk_widget_destroy(dlg);
  653.  
  654.     gimp_displays_flush();
  655.     gimp_set_data("plug_in_fuse", &config, sizeof(config));
  656.   }
  657. }
  658.  
  659. static gint
  660. not_indexed_constrain (gint32 image_id, gint32 drawable_id, gpointer data) {
  661.  
  662.   if ((gimp_image_width (image_id) < config.tile_size)
  663.       && (gimp_image_width (image_id) < config.tile_size))
  664.     return 0;
  665.     
  666.   return INDEXED != gimp_image_base_type (image_id);
  667. }
  668.  
  669. static void
  670. overlap_callback (GtkWidget *widget, gpointer   data)
  671. {
  672.   config.overlap = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
  673.   if (config.overlap > config.tile_size)
  674.     config.overlap = config.tile_size;
  675. }
  676.  
  677. static void
  678. tile_size_callback (GtkWidget *widget, gpointer   data)
  679. {
  680.   config.tile_size = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
  681.   if (config.tile_size < 0)
  682.     config.tile_size = 1;
  683. }
  684.  
  685.  
  686. static void
  687. search_time_callback (GtkWidget *widget, gpointer   data)
  688. {
  689.   config.search_time = atoi (gtk_entry_get_text (GTK_ENTRY (widget)));
  690.   if (config.search_time < 0)
  691.     config.search_time = 0;
  692. }
  693.  
  694.  
  695. static void
  696. toggle_callback (GtkWidget *widget, gpointer data)
  697. {
  698.   int *toggle_val;
  699.  
  700.   toggle_val = (int *) data;
  701.  
  702.   if (GTK_TOGGLE_BUTTON (widget)->active)
  703.     *toggle_val = TRUE;
  704.   else
  705.     *toggle_val = FALSE;
  706. }
  707.  
  708. static void
  709. scale_callback (GtkAdjustment *adjustment, gpointer data)
  710. {
  711.   * (double *) data = adjustment->value;
  712. }
  713.  
  714. static char*
  715. gimp_base_name (char *str)
  716. {
  717.   char *t;
  718.  
  719.   t = strrchr (str, '/');
  720.   if (!t)
  721.     return str;
  722.   return t+1;
  723. }
  724.  
  725. static gint dialog() {
  726.   GtkWidget *frame;
  727.   GtkWidget *button;
  728.   GtkWidget *table;
  729.   GtkWidget *box;
  730.   GtkWidget *w;
  731.   gchar **argv;
  732.   gint argc;
  733.   int row;
  734.   guchar *color_cube;
  735.  
  736.   argc = 1;
  737.   argv = g_new(gchar *, 1);
  738.   argv[0] = g_strdup("fuse");
  739.  
  740.   gtk_init(&argc, &argv);
  741.   gtk_rc_parse (gimp_gtkrc ());
  742.  
  743.   gtk_preview_set_gamma (gimp_gamma ());
  744.   gtk_preview_set_install_cmap (gimp_install_cmap ());
  745.   color_cube = gimp_color_cube ();
  746.   gtk_preview_set_color_cube (color_cube[0], color_cube[1],
  747.                   color_cube[2], color_cube[3]);
  748.  
  749.   gtk_widget_set_default_visual (gtk_preview_get_visual ());
  750.   gtk_widget_set_default_colormap (gtk_preview_get_cmap ());
  751.  
  752.   dlg = gtk_dialog_new();
  753.   gtk_window_set_title(GTK_WINDOW(dlg), "Fuse");
  754.   gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
  755.   gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
  756.              (GtkSignalFunc) close_callback, NULL);
  757.  
  758.   button = gtk_button_new_with_label("Ok");
  759.   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  760.   gtk_signal_connect(GTK_OBJECT(button), "clicked",
  761.              (GtkSignalFunc) ok_callback,
  762.              dlg);
  763.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
  764.   gtk_widget_grab_default(button);
  765.   gtk_widget_show(button);
  766.  
  767.   button = gtk_button_new_with_label("Cancel");
  768.   GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  769.   gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
  770.                 (GtkSignalFunc) gtk_widget_destroy,
  771.                 GTK_OBJECT(dlg));
  772.   gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area), button, TRUE, TRUE, 0);
  773.   gtk_widget_show(button);
  774.  
  775.   box = GTK_DIALOG(dlg)->vbox;
  776.  
  777.  
  778.   {
  779.     gint32 *images;
  780.     int i, k, nimages;
  781.     
  782.     frame = gtk_frame_new("Source Images");
  783.     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  784.     gtk_container_border_width(GTK_CONTAINER(frame), 10);
  785.     gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 10);
  786.     gtk_widget_show(frame);
  787.  
  788.     listbox = gck_listbox_new(frame, TRUE, TRUE, 10, 150, 150,
  789.                   GTK_SELECTION_MULTIPLE, NULL,
  790.                   NULL /* event_handler */);
  791.  
  792.     
  793.     images = gimp_query_images (&nimages);
  794.     for (i = 0, k = 0; i < nimages; i++) {
  795.       if (not_indexed_constrain(images[i], 0, 0)) {
  796.     int j;
  797.     GckListBoxItem item;
  798.     char *filename;
  799.     filename = gimp_image_get_filename (images[i]);
  800.     item.label = g_new (char, strlen (filename) + 16);
  801.     sprintf (item.label, "%s-%d", gimp_base_name (filename), images[i]);
  802.     g_free (filename);
  803.  
  804.     item.widget = NULL;
  805.     item.user_data = (gpointer) images[i];
  806.     item.listbox = NULL;
  807.     gck_listbox_insert_item(listbox, &item, k);
  808.     g_free(item.label);
  809.     for (j = 0; j < config.ninputs; j++)
  810.       if (images[i] == config.input_image_ids[j])
  811.         (void) gck_listbox_select_item_by_position(listbox, k);
  812.     k++;
  813.       }
  814.     }
  815.   }
  816.  
  817.   frame = gtk_frame_new("Parameters");
  818.   gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  819.   gtk_container_border_width(GTK_CONTAINER(frame), 10);
  820.   gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 10);
  821.   gtk_widget_show(frame);
  822.  
  823.   box = gtk_vbox_new (FALSE, 5);
  824.   gtk_container_add(GTK_CONTAINER(frame), box);
  825.   gtk_widget_show (box);
  826.  
  827.   {
  828.     GtkWidget *label;
  829.     GtkWidget *entry;
  830.     GtkWidget *hbox;
  831.     char buffer[20];
  832.     hbox = gtk_hbox_new (FALSE, 5);
  833.     gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
  834.  
  835.     label = gtk_label_new ("Tile Size: ");
  836.     gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  837.     gtk_widget_show (label);
  838.  
  839.     entry = gtk_entry_new ();
  840.     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
  841.     sprintf (buffer, "%d", config.tile_size);
  842.     gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  843.     gtk_signal_connect (GTK_OBJECT (entry), "changed",
  844.             (GtkSignalFunc) tile_size_callback,
  845.             NULL);
  846.     gtk_widget_show (entry);
  847.  
  848.     gtk_widget_show (hbox);
  849.   }
  850.  
  851.  
  852.   {
  853.     GtkWidget *label;
  854.     GtkWidget *entry;
  855.     GtkWidget *hbox;
  856.     char buffer[20];
  857.     hbox = gtk_hbox_new (FALSE, 5);
  858.     gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
  859.  
  860.     label = gtk_label_new ("Overlap: ");
  861.     gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  862.     gtk_widget_show (label);
  863.  
  864.     entry = gtk_entry_new ();
  865.     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
  866.     sprintf (buffer, "%d", config.overlap);
  867.     gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  868.     gtk_signal_connect (GTK_OBJECT (entry), "changed",
  869.             (GtkSignalFunc) overlap_callback,
  870.             NULL);
  871.     gtk_widget_show (entry);
  872.  
  873.     gtk_widget_show (hbox);
  874.   }
  875.  
  876.  
  877.   {
  878.     GtkWidget *label;
  879.     GtkWidget *entry;
  880.     GtkWidget *hbox;
  881.     char buffer[20];
  882.     hbox = gtk_hbox_new (FALSE, 5);
  883.     gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
  884.  
  885.     label = gtk_label_new ("Search Time: ");
  886.     gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  887.     gtk_widget_show (label);
  888.  
  889.     entry = gtk_entry_new ();
  890.     gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
  891.     sprintf (buffer, "%d", config.search_time);
  892.     gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  893.     gtk_signal_connect (GTK_OBJECT (entry), "changed",
  894.             (GtkSignalFunc) search_time_callback,
  895.             NULL);
  896.     gtk_widget_show (entry);
  897.  
  898.     gtk_widget_show (hbox);
  899.   }
  900.  
  901.   {
  902.     GtkWidget *toggle;
  903.     toggle = gtk_check_button_new_with_label ("use target as template");
  904.     gtk_box_pack_start(GTK_BOX(box), toggle, FALSE, FALSE, 0);
  905.     gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  906.             (GtkSignalFunc) toggle_callback,
  907.             &config.use_template);
  908.     gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), (config.use_template));
  909.     gtk_widget_show (toggle);
  910.   }
  911.  
  912.   {
  913.     GtkWidget *label;
  914.     GtkWidget *scale;
  915.     GtkObject *scale_data;
  916.     GtkWidget *hbox;
  917.     char buffer[20];
  918.     hbox = gtk_hbox_new (FALSE, 5);
  919.     gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0);
  920.  
  921.     label = gtk_label_new ("Template weight: ");
  922.     gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
  923.     gtk_widget_show (label);
  924.  
  925.     scale_data = gtk_adjustment_new (config.template_weight, 0.0, 10.0,
  926.                      0.01, 0.01, 0.0);
  927.     scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
  928.     gtk_widget_set_usize (scale, 150, 0);
  929.     gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
  930.     gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  931.     gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
  932.     gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
  933.             (GtkSignalFunc) scale_callback,
  934.             &config.template_weight);
  935.     gtk_widget_show (scale);
  936.  
  937.     gtk_widget_show (hbox);
  938.   }
  939.  
  940.   box = GTK_DIALOG(dlg)->vbox;
  941.  
  942.   {
  943.     frame = gtk_frame_new("Preview");
  944.     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
  945.     gtk_container_border_width(GTK_CONTAINER(frame), 10);
  946.     gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 10);
  947.     gtk_widget_show(frame);
  948.  
  949.     
  950.     preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  951.     gtk_preview_size (GTK_PREVIEW (preview), preview_size, preview_size);
  952.     
  953.     gtk_container_add(GTK_CONTAINER(frame), preview);
  954.  
  955.     gtk_widget_show (preview);
  956.   }
  957.  
  958.   gtk_widget_show(dlg);
  959.   gtk_main();
  960.   gdk_flush();
  961.  
  962.   return run_flag;
  963. }
  964.