home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / depthmerge.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  39.6 KB  |  1,262 lines

  1. /* Depth Merge -- Combine two image layers via corresponding depth maps
  2.  * Copyright (C) 1997, 1998 Sean Cier (scier@PostHorizon.com)
  3.  *
  4.  * A plug-in for The GIMP
  5.  * The GIMP is Copyright (C) 1995 Spencer Kimball and Peter Mattis
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  */
  17.  
  18. /* Version 1.0.0: (14 August 1998)
  19.  *   Math optimizations, miscellaneous speedups
  20.  *
  21.  * Version 0.1: (6 July 1997)
  22.  *   Initial Release
  23.  */
  24.  
  25. #include "config.h"
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29.  
  30. #include <gtk/gtk.h>
  31.  
  32. #include <libgimp/gimp.h>
  33. #include <libgimp/gimpui.h>
  34.  
  35. #include "libgimp/stdplugins-intl.h"
  36.  
  37.  
  38. #define DEBUG
  39.  
  40. #ifndef LERP
  41. #define LERP(frac,a,b) ((frac)*(b) + (1-(frac))*(a))
  42. #endif
  43.  
  44. #define MUL255(i) ((i)*256 - (i))
  45. #define DIV255(i) (((i) + (i)/256 + 1) / 256)
  46.  
  47. #define PLUG_IN_NAME    "plug_in_depth_merge"
  48. #define PLUG_IN_VERSION "1.0.0; 14 August 1998"
  49.  
  50. #define PREVIEW_SIZE    256
  51.  
  52. /* ----- DepthMerge ----- */
  53.  
  54. struct _DepthMerge;
  55.  
  56. typedef struct _DepthMergeInterface
  57. {
  58.   gint       active;
  59.  
  60.   GtkWidget *dialog;
  61.  
  62.   GtkWidget *preview;
  63.   gint       previewWidth;
  64.   gint       previewHeight;
  65.  
  66.   guchar    *checkRow0;
  67.   guchar    *checkRow1;
  68.   guchar    *previewSource1;
  69.   guchar    *previewSource2;
  70.   guchar    *previewDepthMap1;
  71.   guchar    *previewDepthMap2;
  72.  
  73.   gint       run;
  74. } DepthMergeInterface;
  75.  
  76. typedef struct _DepthMergeParams
  77. {
  78.   gint32  result;
  79.   gint32  source1;
  80.   gint32  source2;
  81.   gint32  depthMap1;
  82.   gint32  depthMap2;
  83.   gfloat  overlap;
  84.   gfloat  offset;
  85.   gfloat  scale1;
  86.   gfloat  scale2;
  87. } DepthMergeParams;
  88.  
  89. typedef struct _DepthMerge
  90. {
  91.   DepthMergeInterface *interface;
  92.   DepthMergeParams     params;
  93.  
  94.   GimpDrawable           *resultDrawable;
  95.   GimpDrawable           *source1Drawable;
  96.   GimpDrawable           *source2Drawable;
  97.   GimpDrawable           *depthMap1Drawable;
  98.   GimpDrawable           *depthMap2Drawable;
  99.   gint                 selectionX0;
  100.   gint                 selectionY0;
  101.   gint                 selectionX1;
  102.   gint                 selectionY1;
  103.   gint                 selectionWidth;
  104.   gint                 selectionHeight;
  105.   gint                 resultHasAlpha;
  106. } DepthMerge;
  107.  
  108. void   DepthMerge_initParams             (DepthMerge *dm);
  109. void   DepthMerge_construct              (DepthMerge *dm);
  110. void   DepthMerge_destroy                (DepthMerge *dm);
  111. gint32 DepthMerge_execute                (DepthMerge *dm);
  112. void   DepthMerge_executeRegion          (DepthMerge *dm,
  113.                                           guchar *source1Row,
  114.                                           guchar *source2Row,
  115.                                           guchar *depthMap1Row,
  116.                                           guchar *depthMap2Row,
  117.                                           guchar *resultRow,
  118.                       gint length);
  119. gint32 DepthMerge_dialog                 (DepthMerge *dm);
  120. void   DepthMerge_buildPreviewSourceImage(DepthMerge *dm);
  121. void   DepthMerge_updatePreview          (DepthMerge *dm);
  122.  
  123.  
  124. gint constraintResultSizeAndResultColorOrGray(gint32 imageId,
  125.                           gint32 drawableId, gpointer data);
  126. gint constraintResultSizeAndGray(gint32 imageId,
  127.                  gint32 drawableId, gpointer data);
  128.  
  129. void dialogOkCallback               (GtkWidget *widget, gpointer data);
  130. void dialogCancelCallback           (GtkWidget *widget, gpointer data);
  131. void dialogSource1ChangedCallback   (gint32 id, gpointer data);
  132. void dialogSource2ChangedCallback   (gint32 id, gpointer data);
  133. void dialogDepthMap1ChangedCallback (gint32 id, gpointer data);
  134. void dialogDepthMap2ChangedCallback (gint32 id, gpointer data);
  135. void dialogValueScaleUpdateCallback (GtkAdjustment *adjustment, gpointer data);
  136. void dialogValueEntryUpdateCallback (GtkWidget *widget, gpointer data);
  137.  
  138. void util_fillReducedBuffer (guchar *dest, gint destWidth, gint destHeight,
  139.                  gint destBPP, gint destHasAlpha,
  140.                  GimpDrawable *sourceDrawable,
  141.                  gint x0, gint y0,
  142.                  gint sourceWidth, gint sourceHeight);
  143. void util_convertColorspace (guchar *dest,
  144.                  gint destBPP,   gint destHasAlpha,
  145.                  guchar *source,
  146.                  gint sourceBPP, gint sourceHasAlpha,
  147.                  gint length);
  148.  
  149. /* ----- plug-in entry points ----- */
  150.  
  151. static void query (void);
  152. static void run   (gchar   *name,
  153.            gint     nparams,
  154.            GimpParam  *param,
  155.            gint    *nreturn_vals,
  156.            GimpParam **return_vals);
  157.  
  158. GimpPlugInInfo PLUG_IN_INFO =
  159. {
  160.   NULL,  /* init_proc  */
  161.   NULL,  /* quit_proc  */
  162.   query, /* query_proc */
  163.   run    /* run_proc   */
  164. };
  165.  
  166. MAIN ()
  167.  
  168. static void
  169. query (void)
  170. {
  171.   static GimpParamDef args[] =
  172.   {
  173.     { GIMP_PDB_INT32,    "run_mode",  "Interactive, non-interactive" },
  174.     { GIMP_PDB_IMAGE,    "image",     "Input image (unused)" },
  175.     { GIMP_PDB_DRAWABLE, "result",    "Result" },
  176.     { GIMP_PDB_DRAWABLE, "source1",   "Source 1" },
  177.     { GIMP_PDB_DRAWABLE, "source2",   "Source 2" },
  178.     { GIMP_PDB_DRAWABLE, "depthMap1", "Depth map 1" },
  179.     { GIMP_PDB_DRAWABLE, "depthMap2", "Depth map 2" },
  180.     { GIMP_PDB_FLOAT,    "overlap",   "Overlap" },
  181.     { GIMP_PDB_FLOAT,    "offset",    "Depth relative offset" },
  182.     { GIMP_PDB_FLOAT,    "scale1",    "Depth relative scale 1" },
  183.     { GIMP_PDB_FLOAT,    "scale2",    "Depth relative scale 2" }
  184.   };
  185.   static gint numArgs = sizeof (args) / sizeof (GimpParamDef);
  186.  
  187.   gimp_install_procedure (PLUG_IN_NAME,
  188.               "Combine two images using corresponding "
  189.                 "depth maps (z-buffers)",
  190.               "Taking as input two full-color, full-alpha "
  191.                 "images and two corresponding grayscale depth "
  192.                 "maps, this plug-in combines the images based "
  193.                 "on which is closer (has a lower depth map value) "
  194.                 "at each point.",
  195.               "Sean Cier",
  196.               "Sean Cier",
  197.               PLUG_IN_VERSION,
  198.               N_("<Image>/Filters/Combine/Depth Merge..."),
  199.               "RGB*, GRAY*",
  200.               GIMP_PLUGIN,
  201.               numArgs, 0,
  202.               args, NULL);
  203. }
  204.  
  205. static void
  206. run (gchar   *name,
  207.      gint     numParams,
  208.      GimpParam  *param,
  209.      gint    *numReturnVals,
  210.      GimpParam **returnVals)
  211. {
  212.   static GimpParam    values[1];
  213.   GimpRunModeType     runMode;
  214.   GimpPDBStatusType      status;
  215.   DepthMerge       dm;
  216.  
  217.   INIT_I18N_UI();
  218.  
  219.   runMode = (GimpRunModeType) param[0].data.d_int32;
  220.   status = GIMP_PDB_SUCCESS;
  221.   *numReturnVals = 1;
  222.   *returnVals    = values;
  223.  
  224.   switch (runMode)
  225.     {
  226.     case GIMP_RUN_INTERACTIVE:
  227.       DepthMerge_initParams (&dm);
  228.       gimp_get_data (PLUG_IN_NAME, &(dm.params));
  229.       dm.params.result = param[2].data.d_drawable;
  230.       DepthMerge_construct (&dm);
  231.       if (!DepthMerge_dialog (&dm))
  232.     {
  233.       values[0].type = GIMP_PDB_STATUS;
  234.       values[0].data.d_status = GIMP_PDB_SUCCESS;
  235.       return;
  236.     }
  237.       break;
  238.  
  239.     case GIMP_RUN_NONINTERACTIVE:
  240.       DepthMerge_initParams (&dm);
  241.       if (numParams != 11)
  242.     status = GIMP_PDB_CALLING_ERROR;
  243.       else
  244.     {
  245.       dm.params.result    = param[ 2].data.d_drawable;
  246.       dm.params.source1   = param[ 3].data.d_drawable;
  247.       dm.params.source2   = param[ 4].data.d_drawable;
  248.       dm.params.depthMap1 = param[ 5].data.d_drawable;
  249.       dm.params.depthMap2 = param[ 6].data.d_drawable;
  250.       dm.params.overlap   = param[ 7].data.d_float;
  251.       dm.params.offset    = param[ 8].data.d_float;
  252.       dm.params.scale1    = param[ 9].data.d_float;
  253.       dm.params.scale2    = param[10].data.d_float;
  254.     }
  255.       DepthMerge_construct (&dm);
  256.       break;
  257.  
  258.     case GIMP_RUN_WITH_LAST_VALS:
  259.       DepthMerge_initParams (&dm);
  260.       gimp_get_data (PLUG_IN_NAME, &(dm.params));
  261.       DepthMerge_construct (&dm);
  262.       break;
  263.  
  264.     default:
  265.       status = GIMP_PDB_CALLING_ERROR;
  266.     }
  267.  
  268.   if (status == GIMP_PDB_SUCCESS)
  269.     {
  270.       gimp_tile_cache_ntiles ((dm.resultDrawable->width + gimp_tile_width() - 1) /
  271.                   gimp_tile_width());
  272.  
  273.       if (!DepthMerge_execute (&dm))
  274.     status = GIMP_PDB_EXECUTION_ERROR;
  275.       else
  276.     {
  277.       if (runMode != GIMP_RUN_NONINTERACTIVE)
  278.         gimp_displays_flush ();
  279.       if (runMode == GIMP_RUN_INTERACTIVE)
  280.         gimp_set_data (PLUG_IN_NAME,
  281.                &(dm.params), sizeof (DepthMergeParams));
  282.     }
  283.     }
  284.  
  285.   DepthMerge_destroy (&dm);
  286.  
  287.   values[0].data.d_status = status;
  288. }
  289.  
  290. /* ----- DepthMerge ----- */
  291.  
  292. void
  293. DepthMerge_initParams (DepthMerge *dm)
  294. {
  295.   dm->params.result    = -1;
  296.   dm->params.source1   = -1;
  297.   dm->params.source2   = -1;
  298.   dm->params.depthMap1 = -1;
  299.   dm->params.depthMap2 = -1;
  300.   dm->params.overlap   =  0;
  301.   dm->params.offset    =  0;
  302.   dm->params.scale1    =  1;
  303.   dm->params.scale2    =  1;
  304. }
  305.  
  306. void
  307. DepthMerge_construct (DepthMerge *dm)
  308. {
  309.   dm->interface = NULL;
  310.  
  311.   dm->resultDrawable = gimp_drawable_get (dm->params.result);
  312.   gimp_drawable_mask_bounds (dm->resultDrawable->id,
  313.                  &(dm->selectionX0), &(dm->selectionY0),
  314.                  &(dm->selectionX1), &(dm->selectionY1));
  315.   dm->selectionWidth  = dm->selectionX1 - dm->selectionX0;
  316.   dm->selectionHeight = dm->selectionY1 - dm->selectionY0;
  317.   dm->resultHasAlpha = gimp_drawable_has_alpha (dm->resultDrawable->id);
  318.  
  319.   dm->source1Drawable =
  320.     (dm->params.source1 == -1) ? NULL : gimp_drawable_get (dm->params.source1);
  321.  
  322.   dm->source2Drawable =
  323.     (dm->params.source2 == -1) ? NULL : gimp_drawable_get (dm->params.source2);
  324.  
  325.   dm->depthMap1Drawable =
  326.     (dm->params.depthMap1 == -1) ?
  327.     NULL : gimp_drawable_get (dm->params.depthMap1);
  328.  
  329.   dm->depthMap2Drawable =
  330.     (dm->params.depthMap2 == -1) ?
  331.     NULL : gimp_drawable_get (dm->params.depthMap2);
  332.  
  333.   dm->params.overlap = CLAMP (dm->params.overlap, 0, 2);
  334.   dm->params.offset  = CLAMP (dm->params.offset, -1, 1);
  335.   dm->params.scale1  = CLAMP (dm->params.scale1, -1, 1);
  336.   dm->params.scale2  = CLAMP (dm->params.scale2, -1, 1);
  337. }
  338.  
  339. void
  340. DepthMerge_destroy (DepthMerge *dm)
  341. {
  342.   if (dm->interface != NULL)
  343.     {
  344.       g_free (dm->interface->checkRow0);
  345.       g_free (dm->interface->checkRow1);
  346.       g_free (dm->interface->previewSource1);
  347.       g_free (dm->interface->previewSource2);
  348.       g_free (dm->interface->previewDepthMap1);
  349.       g_free (dm->interface->previewDepthMap2);
  350.       g_free (dm->interface);
  351.     }
  352.   if (dm->resultDrawable != NULL)
  353.     gimp_drawable_detach (dm->resultDrawable);
  354.  
  355.   if (dm->source1Drawable != NULL)
  356.     gimp_drawable_detach (dm->source1Drawable);
  357.  
  358.   if (dm->source2Drawable != NULL)
  359.     gimp_drawable_detach (dm->source2Drawable);
  360.  
  361.   if (dm->depthMap1Drawable != NULL)
  362.     gimp_drawable_detach (dm->depthMap1Drawable);
  363.  
  364.   if (dm->depthMap2Drawable != NULL)
  365.     gimp_drawable_detach (dm->depthMap2Drawable);
  366. }
  367.  
  368. gint32
  369. DepthMerge_execute (DepthMerge *dm)
  370. {
  371.   int       x, y;
  372.   GimpPixelRgn source1Rgn, source2Rgn, depthMap1Rgn, depthMap2Rgn,
  373.             resultRgn;
  374.   guchar    *source1Row, *source2Row, *depthMap1Row, *depthMap2Row,
  375.             *resultRow,
  376.             *tempRow;
  377.   gint      source1HasAlpha, source2HasAlpha,
  378.             depthMap1HasAlpha, depthMap2HasAlpha;
  379.  
  380.   /* initialize */
  381.  
  382.   source1HasAlpha = 0;
  383.   source2HasAlpha = 0;
  384.   depthMap1HasAlpha = 0;
  385.   depthMap2HasAlpha = 0;
  386.   
  387.   gimp_progress_init(_("Depth-merging..."));
  388.  
  389.   resultRow    = (guchar *)g_malloc(dm->selectionWidth * 4);
  390.   source1Row   = (guchar *)g_malloc(dm->selectionWidth * 4);
  391.   source2Row   = (guchar *)g_malloc(dm->selectionWidth * 4);
  392.   depthMap1Row = (guchar *)g_malloc(dm->selectionWidth    );
  393.   depthMap2Row = (guchar *)g_malloc(dm->selectionWidth    );
  394.   tempRow      = (guchar *)g_malloc(dm->selectionWidth * 4);
  395.  
  396.   if (dm->source1Drawable != NULL)
  397.     {
  398.       source1HasAlpha = gimp_drawable_has_alpha(dm->source1Drawable->id);
  399.       gimp_pixel_rgn_init(&source1Rgn, dm->source1Drawable,
  400.               dm->selectionX0, dm->selectionY0,
  401.               dm->selectionWidth, dm->selectionHeight,
  402.               FALSE, FALSE);
  403.     }
  404.   else
  405.     for (x = 0; x < dm->selectionWidth; x++)
  406.       {
  407.     source1Row[4*x  ] = 0;
  408.     source1Row[4*x+1] = 0;
  409.     source1Row[4*x+2] = 0;
  410.     source1Row[4*x+3] = 255;
  411.       }
  412.   if (dm->source2Drawable != NULL)
  413.     {
  414.       source2HasAlpha = gimp_drawable_has_alpha(dm->source2Drawable->id);
  415.       gimp_pixel_rgn_init(&source2Rgn, dm->source2Drawable,
  416.               dm->selectionX0, dm->selectionY0,
  417.               dm->selectionWidth, dm->selectionHeight,
  418.               FALSE, FALSE);
  419.     }
  420.   else
  421.     for (x = 0; x < dm->selectionWidth; x++)
  422.       {
  423.     source2Row[4*x  ] = 0;
  424.     source2Row[4*x+1] = 0;
  425.     source2Row[4*x+2] = 0;
  426.     source2Row[4*x+3] = 255;
  427.       }
  428.   if (dm->depthMap1Drawable != NULL)
  429.     {
  430.       depthMap1HasAlpha = gimp_drawable_has_alpha(dm->depthMap1Drawable->id);
  431.       gimp_pixel_rgn_init(&depthMap1Rgn, dm->depthMap1Drawable,
  432.               dm->selectionX0, dm->selectionY0,
  433.               dm->selectionWidth, dm->selectionHeight,
  434.               FALSE, FALSE);
  435.     }
  436.   else
  437.     for (x = 0; x < dm->selectionWidth; x++)
  438.       {
  439.     depthMap1Row[x  ] = 0;
  440.       }
  441.   if (dm->depthMap2Drawable != NULL)
  442.     {
  443.       depthMap2HasAlpha = gimp_drawable_has_alpha(dm->depthMap2Drawable->id);
  444.       gimp_pixel_rgn_init(&depthMap2Rgn, dm->depthMap2Drawable,
  445.               dm->selectionX0, dm->selectionY0,
  446.               dm->selectionWidth, dm->selectionHeight,
  447.               FALSE, FALSE);
  448.     }
  449.   else
  450.     for (x = 0; x < dm->selectionWidth; x++)
  451.       {
  452.     depthMap2Row[x  ] = 0;
  453.       }
  454.   gimp_pixel_rgn_init(&resultRgn, dm->resultDrawable,
  455.                       dm->selectionX0, dm->selectionY0,
  456.                       dm->selectionWidth, dm->selectionHeight,
  457.                       TRUE, TRUE);
  458.  
  459.   for (y = dm->selectionY0; y < dm->selectionY1; y++)
  460.     {
  461.       if (dm->source1Drawable != NULL)
  462.     {
  463.       gimp_pixel_rgn_get_row(&source1Rgn, tempRow,
  464.                  dm->selectionX0, y,
  465.                  dm->selectionWidth);
  466.       util_convertColorspace(source1Row, 4, TRUE,
  467.                  tempRow,
  468.                  dm->source1Drawable->bpp, source1HasAlpha,
  469.                  dm->selectionWidth);
  470.     }
  471.       if (dm->source2Drawable != NULL)
  472.     {
  473.       gimp_pixel_rgn_get_row(&source2Rgn, tempRow,
  474.                  dm->selectionX0, y,
  475.                  dm->selectionWidth);
  476.       util_convertColorspace(source2Row, 4, TRUE,
  477.                  tempRow,
  478.                  dm->source2Drawable->bpp, source2HasAlpha,
  479.                  dm->selectionWidth);
  480.     }
  481.       if (dm->depthMap1Drawable != NULL)
  482.     {
  483.       gimp_pixel_rgn_get_row(&depthMap1Rgn, tempRow,
  484.                  dm->selectionX0, y,
  485.                  dm->selectionWidth);
  486.       util_convertColorspace(depthMap1Row, 1, FALSE,
  487.                  tempRow,
  488.                  dm->depthMap1Drawable->bpp, depthMap1HasAlpha,
  489.                  dm->selectionWidth);
  490.     }
  491.       if (dm->depthMap2Drawable != NULL)
  492.     {
  493.       gimp_pixel_rgn_get_row(&depthMap2Rgn, tempRow,
  494.                  dm->selectionX0, y,
  495.                  dm->selectionWidth);
  496.       util_convertColorspace(depthMap2Row, 1, FALSE,
  497.                  tempRow,
  498.                  dm->depthMap2Drawable->bpp, depthMap2HasAlpha,
  499.                  dm->selectionWidth);
  500.     }
  501.  
  502.       DepthMerge_executeRegion(dm,
  503.                    source1Row, source2Row, depthMap1Row, depthMap2Row,
  504.                    resultRow,
  505.                    dm->selectionWidth);
  506.       util_convertColorspace(tempRow, dm->resultDrawable->bpp, dm->resultHasAlpha,
  507.                  resultRow, 4, TRUE,
  508.                  dm->selectionWidth);
  509.  
  510.       gimp_pixel_rgn_set_row(&resultRgn, tempRow,
  511.                  dm->selectionX0, y,
  512.                  dm->selectionWidth);
  513.  
  514.       gimp_progress_update((double)(y-dm->selectionY0) / (double)(dm->selectionHeight-1));
  515.     }
  516.  
  517.   g_free (resultRow);
  518.   g_free (source1Row);
  519.   g_free (source2Row);
  520.   g_free (depthMap1Row);
  521.   g_free (depthMap2Row);
  522.   g_free (tempRow);
  523.  
  524.   gimp_drawable_flush (dm->resultDrawable);
  525.   gimp_drawable_merge_shadow (dm->resultDrawable->id, TRUE);
  526.   gimp_drawable_update (dm->resultDrawable->id,
  527.             dm->selectionX0, dm->selectionY0,
  528.             dm->selectionWidth, dm->selectionHeight);
  529.   return TRUE;
  530. }
  531.  
  532. void
  533. DepthMerge_executeRegion (DepthMerge *dm,
  534.               guchar     *source1Row,
  535.               guchar     *source2Row,
  536.               guchar     *depthMap1Row,
  537.               guchar     *depthMap2Row,
  538.               guchar     *resultRow,
  539.               gint        length)
  540. {
  541.   float          scale1, scale2, offset255, invOverlap255;
  542.   float          frac, depth1, depth2;
  543.   unsigned short c1[4], c2[4], cR1[4], cR2[4], cR[4], temp;
  544.   int            i, tempInt;
  545.  
  546.   invOverlap255 = 1.0 / (MAX (dm->params.overlap, 0.001) * 255);
  547.   offset255     = dm->params.offset * 255;
  548.   scale1        = dm->params.scale1;
  549.   scale2        = dm->params.scale2;
  550.  
  551.   for (i = 0; i < length; i++)
  552.     {
  553.       depth1 = (float)depthMap1Row[i];
  554.       depth2 = (float)depthMap2Row[i];
  555.  
  556.       frac = (depth2*scale2 - (depth1*scale1 + offset255)) * invOverlap255;
  557.       frac = 0.5 * (frac+1.0);
  558.       frac = CLAMP(frac, 0.0, 1.0);
  559.  
  560.       /* c1 -> color corresponding to source1 */
  561.       c1[0] = source1Row[4*i  ];
  562.       c1[1] = source1Row[4*i+1];
  563.       c1[2] = source1Row[4*i+2];
  564.       c1[3] = source1Row[4*i+3];
  565.  
  566.       /* c2 -> color corresponding to source2 */
  567.       c2[0] = source2Row[4*i  ];
  568.       c2[1] = source2Row[4*i+1];
  569.       c2[2] = source2Row[4*i+2];
  570.       c2[3] = source2Row[4*i+3];
  571.  
  572.       if (frac != 0)
  573.     {
  574.       /* cR1 -> result if c1 is completely on top */
  575.       cR1[0] = c1[3]*c1[0]   + (255-c1[3])*c2[0];
  576.       cR1[1] = c1[3]*c1[1]   + (255-c1[3])*c2[1];
  577.       cR1[2] = c1[3]*c1[2]   + (255-c1[3])*c2[2];
  578.       cR1[3] = MUL255(c1[3]) + (255-c1[3])*c2[3];
  579.     }
  580.  
  581.       if (frac != 1)
  582.     {
  583.       /* cR2 -> result if c2 is completely on top */
  584.       cR2[0] = c2[3]*c2[0]   + (255-c2[3])*c1[0];
  585.       cR2[1] = c2[3]*c2[1]   + (255-c2[3])*c1[1];
  586.       cR2[2] = c2[3]*c2[2]   + (255-c2[3])*c1[2];
  587.       cR2[3] = MUL255(c2[3]) + (255-c2[3])*c1[3];
  588.     }
  589.  
  590.       if (frac == 1)
  591.     {
  592.       cR[0] = cR1[0];
  593.       cR[1] = cR1[1];
  594.       cR[2] = cR1[2];
  595.       cR[3] = cR1[3];
  596.     }
  597.       else if (frac == 0)
  598.     {
  599.       cR[0] = cR2[0];
  600.       cR[1] = cR2[1];
  601.       cR[2] = cR2[2];
  602.       cR[3] = cR2[3];
  603.     }
  604.       else
  605.     {
  606.       tempInt = LERP(frac, cR2[0], cR1[0]); cR[0] = CLAMP(tempInt,0,255*255);
  607.       tempInt = LERP(frac, cR2[1], cR1[1]); cR[1] = CLAMP(tempInt,0,255*255);
  608.       tempInt = LERP(frac, cR2[2], cR1[2]); cR[2] = CLAMP(tempInt,0,255*255);
  609.       tempInt = LERP(frac, cR2[3], cR1[3]); cR[3] = CLAMP(tempInt,0,255*255);
  610.     }
  611.  
  612.       temp = DIV255 (cR[0]); resultRow[4*i  ] = MIN (temp, 255);
  613.       temp = DIV255 (cR[1]); resultRow[4*i+1] = MIN (temp, 255);
  614.       temp = DIV255 (cR[2]); resultRow[4*i+2] = MIN (temp, 255);
  615.       temp = DIV255 (cR[3]); resultRow[4*i+3] = MIN (temp, 255);
  616.     }
  617. }
  618.  
  619. gint32
  620. DepthMerge_dialog (DepthMerge *dm)
  621. {
  622.   GtkWidget *topTable;
  623.   GtkWidget *previewFrame;
  624.   GtkWidget *sourceTable;
  625.   GtkWidget *tempLabel;
  626.   GtkWidget *tempOptionMenu;
  627.   GtkWidget *tempMenu;
  628.   GtkWidget *numericParameterTable;
  629.   GtkObject *adj;
  630.  
  631.   dm->interface = g_new (DepthMergeInterface, 1);
  632.   dm->interface->active = FALSE;
  633.   dm->interface->run    = FALSE;
  634.  
  635.   gimp_ui_init ("depthmerge", TRUE);
  636.  
  637.   dm->interface->dialog =
  638.     gimp_dialog_new (_("Depth Merge"), "depthmerge",
  639.              gimp_standard_help_func, "filters/depthmerge.html",
  640.              GTK_WIN_POS_MOUSE,
  641.              FALSE, TRUE, FALSE,
  642.  
  643.              _("OK"), dialogOkCallback,
  644.              dm, NULL, NULL, TRUE, FALSE,
  645.              _("Cancel"), dialogCancelCallback,
  646.              dm, NULL, NULL, FALSE, TRUE,
  647.  
  648.              NULL);
  649.  
  650.   gtk_signal_connect (GTK_OBJECT (dm->interface->dialog), "destroy",
  651.               GTK_SIGNAL_FUNC (gtk_main_quit),
  652.               NULL);
  653.  
  654.   /* topTable */
  655.   topTable = gtk_table_new (3, 3, FALSE);
  656.   gtk_container_set_border_width (GTK_CONTAINER(topTable), 6);
  657.   gtk_table_set_row_spacings (GTK_TABLE (topTable), 4);
  658.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dm->interface->dialog)->vbox),
  659.               topTable, FALSE, FALSE, 0);
  660.   gtk_widget_show(topTable);
  661.  
  662.   /* Preview */
  663.   previewFrame = gtk_frame_new (NULL);
  664.   gtk_frame_set_shadow_type (GTK_FRAME (previewFrame), GTK_SHADOW_IN);
  665.   gtk_table_attach (GTK_TABLE (topTable), previewFrame, 1, 2, 0, 1, 0, 0, 0, 0);
  666.   gtk_widget_show (previewFrame);
  667.  
  668.   dm->interface->previewWidth  = MIN (dm->selectionWidth,  PREVIEW_SIZE);
  669.   dm->interface->previewHeight = MIN (dm->selectionHeight, PREVIEW_SIZE);
  670.   dm->interface->preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  671.   gtk_preview_size (GTK_PREVIEW (dm->interface->preview),
  672.             dm->interface->previewWidth,
  673.             dm->interface->previewHeight);
  674.   gtk_container_add (GTK_CONTAINER (previewFrame), dm->interface->preview);
  675.   gtk_widget_show (dm->interface->preview);
  676.  
  677.   DepthMerge_buildPreviewSourceImage (dm);
  678.  
  679.   /* Source and Depth Map selection */
  680.   sourceTable = gtk_table_new (2, 4, FALSE);
  681.   gtk_table_set_col_spacings (GTK_TABLE (sourceTable), 4);
  682.   gtk_table_set_col_spacing (GTK_TABLE (sourceTable), 1, 6);
  683.   gtk_table_set_row_spacings (GTK_TABLE (sourceTable), 2);
  684.   gtk_table_attach (GTK_TABLE (topTable), sourceTable, 0, 3, 1, 2,
  685.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  686.   gtk_widget_show (sourceTable);
  687.  
  688.   tempLabel = gtk_label_new (_("Source 1:"));
  689.   gtk_misc_set_alignment (GTK_MISC (tempLabel), 1.0, 0.5);
  690.   gtk_table_attach (GTK_TABLE (sourceTable), tempLabel, 0, 1, 0, 1,
  691.             GTK_FILL, GTK_FILL, 0, 0);
  692.   gtk_widget_show (tempLabel);
  693.  
  694.   tempOptionMenu = gtk_option_menu_new ();
  695.   gtk_table_attach (GTK_TABLE (sourceTable), tempOptionMenu, 1, 2, 0, 1,
  696.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  697.   gtk_widget_show (tempOptionMenu);
  698.   tempMenu = gimp_drawable_menu_new (constraintResultSizeAndResultColorOrGray,
  699.                      dialogSource1ChangedCallback,
  700.                      dm,
  701.                      dm->params.source1);
  702.   gtk_option_menu_set_menu (GTK_OPTION_MENU (tempOptionMenu), tempMenu);
  703.   gtk_widget_show (tempOptionMenu);
  704.  
  705.   tempLabel = gtk_label_new(_("Depth Map:"));
  706.   gtk_misc_set_alignment(GTK_MISC(tempLabel), 1.0, 0.5);
  707.   gtk_table_attach (GTK_TABLE (sourceTable), tempLabel, 2, 3, 0, 1,
  708.             GTK_FILL, GTK_FILL, 0, 0);
  709.   gtk_widget_show (tempLabel);
  710.  
  711.   tempOptionMenu = gtk_option_menu_new ();
  712.   gtk_table_attach (GTK_TABLE (sourceTable), tempOptionMenu, 3, 4, 0, 1,
  713.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  714.   gtk_widget_show (tempOptionMenu);
  715.   tempMenu = gimp_drawable_menu_new (constraintResultSizeAndResultColorOrGray,
  716.                      dialogDepthMap1ChangedCallback,
  717.                      dm,
  718.                      dm->params.depthMap1);
  719.   gtk_option_menu_set_menu (GTK_OPTION_MENU (tempOptionMenu), tempMenu);
  720.   gtk_widget_show (tempOptionMenu);
  721.  
  722.   tempLabel = gtk_label_new (_("Source 2:"));
  723.   gtk_misc_set_alignment (GTK_MISC (tempLabel), 1.0, 0.5);
  724.   gtk_table_attach (GTK_TABLE (sourceTable), tempLabel, 0, 1, 1, 2,
  725.             GTK_FILL, GTK_FILL, 0, 0);
  726.   gtk_widget_show (tempLabel);
  727.  
  728.   tempOptionMenu = gtk_option_menu_new ();
  729.   gtk_table_attach (GTK_TABLE (sourceTable), tempOptionMenu, 1, 2, 1, 2,
  730.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  731.   gtk_widget_show (tempOptionMenu);
  732.   tempMenu = gimp_drawable_menu_new (constraintResultSizeAndResultColorOrGray,
  733.                      dialogSource2ChangedCallback,
  734.                      dm,
  735.                      dm->params.source2);
  736.   gtk_option_menu_set_menu (GTK_OPTION_MENU (tempOptionMenu), tempMenu);
  737.   gtk_widget_show (tempOptionMenu);
  738.  
  739.   tempLabel = gtk_label_new (_("Depth Map:"));
  740.   gtk_misc_set_alignment(GTK_MISC(tempLabel), 1.0, 0.5);
  741.   gtk_table_attach (GTK_TABLE (sourceTable), tempLabel, 2, 3, 1, 2,
  742.             GTK_FILL, GTK_FILL, 0, 0);
  743.   gtk_widget_show (tempLabel);
  744.  
  745.   tempOptionMenu = gtk_option_menu_new ();
  746.   gtk_table_attach (GTK_TABLE (sourceTable), tempOptionMenu, 3, 4, 1, 2,
  747.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  748.   gtk_widget_show (tempOptionMenu);
  749.   tempMenu = gimp_drawable_menu_new (constraintResultSizeAndResultColorOrGray,
  750.                      dialogDepthMap2ChangedCallback,
  751.                      dm,
  752.                      dm->params.depthMap2);
  753.   gtk_option_menu_set_menu (GTK_OPTION_MENU (tempOptionMenu), tempMenu);
  754.   gtk_widget_show (tempOptionMenu);
  755.  
  756.   /* Numeric parameters */
  757.   numericParameterTable = gtk_table_new(4, 3, FALSE);
  758.   gtk_table_set_col_spacings (GTK_TABLE (numericParameterTable), 4);
  759.   gtk_table_set_row_spacings (GTK_TABLE (numericParameterTable), 2);
  760.   gtk_table_attach (GTK_TABLE (topTable), numericParameterTable, 0, 3, 2, 3,
  761.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  762.   gtk_widget_show (numericParameterTable);
  763.  
  764.   adj = gimp_scale_entry_new (GTK_TABLE (numericParameterTable), 0, 0,
  765.                   _("Overlap:"), 0, 0,
  766.                   dm->params.overlap, 0, 2, 0.001, 0.01, 3,
  767.                   TRUE, 0, 0,
  768.                   NULL, NULL);
  769.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  770.               GTK_SIGNAL_FUNC (dialogValueScaleUpdateCallback),
  771.               &(dm->params.overlap));
  772.   gtk_object_set_user_data (GTK_OBJECT (adj), dm);
  773.  
  774.   adj = gimp_scale_entry_new (GTK_TABLE (numericParameterTable), 0, 1,
  775.                   _("Offset:"), 0, 0,
  776.                   dm->params.offset, -1, 1, 0.001, 0.01, 3,
  777.                   TRUE, 0, 0,
  778.                   NULL, NULL);
  779.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  780.               GTK_SIGNAL_FUNC (dialogValueScaleUpdateCallback),
  781.               &(dm->params.offset));
  782.   gtk_object_set_user_data (GTK_OBJECT (adj), dm);
  783.  
  784.   adj = gimp_scale_entry_new (GTK_TABLE (numericParameterTable), 0, 2,
  785.                   _("Scale 1:"), 0, 0,
  786.                   dm->params.scale1, -1, 1, 0.001, 0.01, 3,
  787.                   TRUE, 0, 0,
  788.                   NULL, NULL);
  789.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  790.               GTK_SIGNAL_FUNC (dialogValueScaleUpdateCallback),
  791.               &(dm->params.scale1));
  792.   gtk_object_set_user_data (GTK_OBJECT (adj), dm);
  793.  
  794.   adj = gimp_scale_entry_new (GTK_TABLE (numericParameterTable), 0, 3,
  795.                   _("Scale 2:"), 0, 0,
  796.                   dm->params.scale2, -1, 1, 0.001, 0.01, 3,
  797.                   TRUE, 0, 0,
  798.                   NULL, NULL);
  799.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  800.               GTK_SIGNAL_FUNC (dialogValueScaleUpdateCallback),
  801.               &(dm->params.scale2));
  802.   gtk_object_set_user_data (GTK_OBJECT (adj), dm);
  803.  
  804.   dm->interface->active = TRUE;
  805.  
  806.   gtk_widget_show (dm->interface->dialog);
  807.   DepthMerge_updatePreview (dm);
  808.  
  809.   gtk_main ();
  810.   gdk_flush ();
  811.  
  812.   return dm->interface->run;
  813. }
  814.  
  815. void
  816. DepthMerge_buildPreviewSourceImage (DepthMerge *dm)
  817. {
  818.   int x;
  819.  
  820.   dm->interface->checkRow0 = (guchar *)g_malloc(dm->interface->previewWidth *
  821.                                 sizeof(guchar));
  822.   dm->interface->checkRow1 = (guchar *)g_malloc(dm->interface->previewWidth *
  823.                                 sizeof(guchar));
  824.  
  825.   for (x = 0; x < dm->interface->previewWidth; x++)
  826.     {
  827.       if ((x / GIMP_CHECK_SIZE) & 1)
  828.     {
  829.       dm->interface->checkRow0[x] = GIMP_CHECK_DARK * 255;
  830.       dm->interface->checkRow1[x] = GIMP_CHECK_LIGHT * 255;
  831.     }
  832.       else
  833.     {
  834.       dm->interface->checkRow0[x] = GIMP_CHECK_LIGHT * 255;
  835.       dm->interface->checkRow1[x] = GIMP_CHECK_DARK * 255;
  836.     }
  837.     }
  838.  
  839.   dm->interface->previewSource1   =
  840.     (guchar *)g_malloc(dm->interface->previewWidth *
  841.                    dm->interface->previewHeight * 4);
  842.   util_fillReducedBuffer(dm->interface->previewSource1,
  843.                          dm->interface->previewWidth,
  844.                          dm->interface->previewHeight,
  845.                          4, TRUE,
  846.                          dm->source1Drawable,
  847.                          dm->selectionX0, dm->selectionY0,
  848.                          dm->selectionWidth, dm->selectionHeight);
  849.   dm->interface->previewSource2   =
  850.     (guchar *)g_malloc(dm->interface->previewWidth *
  851.                dm->interface->previewHeight * 4);
  852.   util_fillReducedBuffer(dm->interface->previewSource2,
  853.                          dm->interface->previewWidth,
  854.                          dm->interface->previewHeight,
  855.                          4, TRUE,
  856.                          dm->source2Drawable,
  857.                          dm->selectionX0, dm->selectionY0,
  858.                          dm->selectionWidth, dm->selectionHeight);
  859.   dm->interface->previewDepthMap1 =
  860.     (guchar *)g_malloc(dm->interface->previewWidth *
  861.                dm->interface->previewHeight * 1);
  862.   util_fillReducedBuffer(dm->interface->previewDepthMap1,
  863.                          dm->interface->previewWidth,
  864.                          dm->interface->previewHeight,
  865.                          1, FALSE,
  866.                          dm->depthMap1Drawable,
  867.                          dm->selectionX0, dm->selectionY0,
  868.                          dm->selectionWidth, dm->selectionHeight);
  869.   dm->interface->previewDepthMap2 =
  870.     (guchar *)g_malloc(dm->interface->previewWidth *
  871.                dm->interface->previewHeight * 1);
  872.   util_fillReducedBuffer(dm->interface->previewDepthMap2,
  873.                          dm->interface->previewWidth,
  874.                          dm->interface->previewHeight,
  875.                          1, FALSE,
  876.                          dm->depthMap2Drawable,
  877.                          dm->selectionX0, dm->selectionY0,
  878.                          dm->selectionWidth, dm->selectionHeight);
  879. }
  880.  
  881. void
  882. DepthMerge_updatePreview (DepthMerge *dm)
  883. {
  884.   int    x, y, i;
  885.   guchar *source1Row, *source2Row, *depthMap1Row, *depthMap2Row,
  886.          *resultRowRGBA, *resultRow,
  887.          *checkRow;
  888.  
  889.   if (!dm->interface->active) return;
  890.  
  891.   resultRowRGBA = (guchar *)g_malloc(dm->interface->previewWidth * 4);
  892.   resultRow     = (guchar *)g_malloc(dm->interface->previewWidth * 3);
  893.  
  894.   for (y = 0; y < dm->interface->previewHeight; y++)
  895.     {
  896.       checkRow = ((y/GIMP_CHECK_SIZE)&1) ?
  897.     dm->interface->checkRow1 :
  898.     dm->interface->checkRow0;
  899.  
  900.       source1Row =
  901.     &(dm->interface->previewSource1[  y * dm->interface->previewWidth * 4]);
  902.       source2Row =
  903.     &(dm->interface->previewSource2[  y * dm->interface->previewWidth * 4]);
  904.       depthMap1Row =
  905.     &(dm->interface->previewDepthMap1[y * dm->interface->previewWidth    ]);
  906.       depthMap2Row =
  907.     &(dm->interface->previewDepthMap2[y * dm->interface->previewWidth    ]);
  908.  
  909.       DepthMerge_executeRegion(dm,
  910.                    source1Row, source2Row, depthMap1Row, depthMap2Row,
  911.                    resultRowRGBA,
  912.                    dm->interface->previewWidth);
  913.       for (x = 0; x < dm->interface->previewWidth; x++)
  914.     {
  915.       i = ((int)(      resultRowRGBA[x*4+3])*(int)resultRowRGBA[x*4  ] +
  916.            (int)(255 - resultRowRGBA[x*4+3])*(int)checkRow[x]          );
  917.       resultRow[x*3  ] = DIV255(i);
  918.       i = ((int)(      resultRowRGBA[x*4+3])*(int)resultRowRGBA[x*4+1] +
  919.            (int)(255 - resultRowRGBA[x*4+3])*(int)checkRow[x]          );
  920.       resultRow[x*3+1] = DIV255(i);
  921.       i = ((int)(      resultRowRGBA[x*4+3])*(int)resultRowRGBA[x*4+2] +
  922.            (int)(255 - resultRowRGBA[x*4+3])*(int)checkRow[x]          );
  923.       resultRow[x*3+2] = DIV255(i);
  924.     }
  925.       gtk_preview_draw_row(GTK_PREVIEW(dm->interface->preview), resultRow, 0, y,
  926.                dm->interface->previewWidth);
  927.     }
  928.  
  929.   g_free(resultRowRGBA);
  930.   g_free(resultRow);
  931.  
  932.   gtk_widget_draw(dm->interface->preview, NULL);
  933.   gdk_flush();
  934. }
  935.  
  936. /* ----- Callbacks ----- */
  937.  
  938. gint
  939. constraintResultSizeAndResultColorOrGray (gint32   imageId,
  940.                       gint32   drawableId,
  941.                       gpointer data)
  942. {
  943.   DepthMerge *dm = (DepthMerge *)data;
  944.  
  945.   return((drawableId == -1) ||
  946.          ((gimp_drawable_width (drawableId) ==
  947.        gimp_drawable_width (dm->params.result)) &&
  948.       (gimp_drawable_height (drawableId) ==
  949.        gimp_drawable_height (dm->params.result)) &&
  950.       ((gimp_drawable_is_rgb (drawableId) &&
  951.         (gimp_drawable_is_rgb (dm->params.result))) ||
  952.        gimp_drawable_is_gray (drawableId))));
  953. }
  954.  
  955. gint
  956. constraintResultSizeAndGray (gint32   imageId,
  957.                  gint32   drawableId,
  958.                  gpointer data)
  959. {
  960.   DepthMerge *dm = (DepthMerge *)data;
  961.  
  962.   return((drawableId == -1) ||
  963.          ((gimp_drawable_width (drawableId) ==
  964.        gimp_drawable_width (dm->params.result)) &&
  965.       (gimp_drawable_height (drawableId) ==
  966.        gimp_drawable_height (dm->params.result)) &&
  967.       (gimp_drawable_is_gray (drawableId))));
  968. }
  969.  
  970. void
  971. dialogOkCallback (GtkWidget *widget,
  972.           gpointer   data)
  973. {
  974.   DepthMerge *dm = (DepthMerge *)data;
  975.   dm->interface->run = TRUE;
  976.   gtk_widget_destroy (dm->interface->dialog);
  977. }
  978.  
  979. void
  980. dialogCancelCallback (GtkWidget *widget,
  981.               gpointer   data)
  982. {
  983.   DepthMerge *dm = (DepthMerge *)data;
  984.   dm->interface->run = FALSE;
  985.   gtk_widget_destroy (dm->interface->dialog);
  986. }
  987.  
  988. void
  989. dialogSource1ChangedCallback (gint32   id,
  990.                   gpointer data)
  991. {
  992.   DepthMerge *dm = (DepthMerge *)data;
  993.  
  994.   if (dm->source1Drawable != NULL)
  995.     gimp_drawable_detach (dm->source1Drawable);
  996.   dm->params.source1 = id;
  997.   dm->source1Drawable = (dm->params.source1 == -1) ? NULL :
  998.     gimp_drawable_get (dm->params.source1);
  999.  
  1000.   util_fillReducedBuffer (dm->interface->previewSource1,
  1001.               dm->interface->previewWidth,
  1002.               dm->interface->previewHeight,
  1003.               4, TRUE,
  1004.               dm->source1Drawable,
  1005.               dm->selectionX0, dm->selectionY0,
  1006.               dm->selectionWidth, dm->selectionHeight);
  1007.  
  1008.   DepthMerge_updatePreview (dm);
  1009. }
  1010.  
  1011. void
  1012. dialogSource2ChangedCallback (gint32   id,
  1013.                   gpointer data)
  1014. {
  1015.   DepthMerge *dm = (DepthMerge *)data;
  1016.  
  1017.   if (dm->source2Drawable != NULL)
  1018.     gimp_drawable_detach (dm->source2Drawable);
  1019.   dm->params.source2 = id;
  1020.   dm->source2Drawable = (dm->params.source2   == -1) ? NULL :
  1021.     gimp_drawable_get (dm->params.source2);
  1022.  
  1023.   util_fillReducedBuffer (dm->interface->previewSource2,
  1024.               dm->interface->previewWidth,
  1025.               dm->interface->previewHeight,
  1026.               4, TRUE,
  1027.               dm->source2Drawable,
  1028.               dm->selectionX0, dm->selectionY0,
  1029.               dm->selectionWidth, dm->selectionHeight);
  1030.  
  1031.   DepthMerge_updatePreview (dm);
  1032. }
  1033.  
  1034. void
  1035. dialogDepthMap1ChangedCallback (gint32   id,
  1036.                 gpointer data)
  1037. {
  1038.   DepthMerge *dm = (DepthMerge *)data;
  1039.  
  1040.   if (dm->depthMap1Drawable != NULL)
  1041.     gimp_drawable_detach(dm->depthMap1Drawable);
  1042.   dm->params.depthMap1 = id;
  1043.   dm->depthMap1Drawable = (dm->params.depthMap1 == -1) ? NULL :
  1044.     gimp_drawable_get (dm->params.depthMap1);
  1045.  
  1046.   util_fillReducedBuffer (dm->interface->previewDepthMap1,
  1047.               dm->interface->previewWidth,
  1048.               dm->interface->previewHeight,
  1049.               1, FALSE,
  1050.               dm->depthMap1Drawable,
  1051.               dm->selectionX0, dm->selectionY0,
  1052.               dm->selectionWidth, dm->selectionHeight);
  1053.  
  1054.   DepthMerge_updatePreview (dm);
  1055. }
  1056.  
  1057. void
  1058. dialogDepthMap2ChangedCallback (gint32   id,
  1059.                 gpointer data)
  1060. {
  1061.   DepthMerge *dm = (DepthMerge *)data;
  1062.  
  1063.   if (dm->depthMap2Drawable != NULL)
  1064.     gimp_drawable_detach(dm->depthMap2Drawable);
  1065.   dm->params.depthMap2 = id;
  1066.   dm->depthMap2Drawable = (dm->params.depthMap2 == -1) ? NULL :
  1067.     gimp_drawable_get (dm->params.depthMap2);
  1068.  
  1069.   util_fillReducedBuffer (dm->interface->previewDepthMap2,
  1070.               dm->interface->previewWidth,
  1071.               dm->interface->previewHeight,
  1072.               1, FALSE,
  1073.               dm->depthMap2Drawable,
  1074.               dm->selectionX0, dm->selectionY0,
  1075.               dm->selectionWidth, dm->selectionHeight);
  1076.  
  1077.   DepthMerge_updatePreview (dm);
  1078. }
  1079.  
  1080. void
  1081. dialogValueScaleUpdateCallback (GtkAdjustment *adjustment,
  1082.                 gpointer       data)
  1083. {
  1084.   DepthMerge *dm = gtk_object_get_user_data (GTK_OBJECT (adjustment));
  1085.  
  1086.   gimp_float_adjustment_update (adjustment, data);
  1087.  
  1088.   DepthMerge_updatePreview (dm);
  1089. }
  1090.  
  1091. /* ----- Utility routines ----- */
  1092.  
  1093. void
  1094. util_fillReducedBuffer (guchar    *dest,
  1095.             gint       destWidth,
  1096.             gint       destHeight,
  1097.             gint       destBPP,
  1098.             gint       destHasAlpha,
  1099.             GimpDrawable *sourceDrawable,
  1100.             gint       x0,
  1101.             gint       y0,
  1102.             gint       sourceWidth,
  1103.             gint       sourceHeight)
  1104. {
  1105.   GimpPixelRgn rgn;
  1106.   guchar    *sourceBuffer, *reducedRowBuffer,
  1107.             *sourceBufferRow, *sourceBufferPos, *reducedRowBufferPos;
  1108.   int       x, y, i, yPrime, sourceHasAlpha, sourceBpp;
  1109.   int       *sourceRowOffsetLookup;
  1110.  
  1111.   if ((sourceDrawable == NULL) || (sourceWidth == 0) || (sourceHeight == 0))
  1112.     {
  1113.       for (x = 0; x < destWidth*destHeight*destBPP; x++)
  1114.     dest[x] = 0;
  1115.       return;
  1116.     }
  1117.  
  1118.   sourceBpp = sourceDrawable->bpp;
  1119.  
  1120.   sourceBuffer          = (guchar *)g_malloc(sourceWidth * sourceHeight *
  1121.                                              sourceBpp);
  1122.   reducedRowBuffer      = (guchar *)g_malloc(destWidth   * sourceBpp);
  1123.   sourceRowOffsetLookup = (int    *)g_malloc(destWidth   * sizeof(int));
  1124.   gimp_pixel_rgn_init(&rgn, sourceDrawable, x0, y0, sourceWidth, sourceHeight,
  1125.               FALSE, FALSE);
  1126.   sourceHasAlpha = gimp_drawable_has_alpha(sourceDrawable->id);
  1127.  
  1128.   for (x = 0; x < destWidth; x++)
  1129.     sourceRowOffsetLookup[x] = (x*(sourceWidth-1)/(destWidth-1))*sourceBpp;
  1130.  
  1131.   gimp_pixel_rgn_get_rect(&rgn, sourceBuffer,
  1132.                           x0, y0, sourceWidth, sourceHeight);
  1133.  
  1134.   for (y = 0; y < destHeight; y++)
  1135.     {
  1136.       yPrime = y*(sourceHeight-1)/(destHeight-1);
  1137.       sourceBufferRow = &(sourceBuffer[yPrime * sourceWidth * sourceBpp]);
  1138.       sourceBufferPos = sourceBufferRow;
  1139.       reducedRowBufferPos = reducedRowBuffer;
  1140.       for (x = 0; x < destWidth; x++)
  1141.     {
  1142.       sourceBufferPos = sourceBufferRow + sourceRowOffsetLookup[x];
  1143.       for (i = 0; i < sourceBpp; i++) 
  1144.         reducedRowBufferPos[i] = sourceBufferPos[i];
  1145.       reducedRowBufferPos += sourceBpp;
  1146.     }
  1147.       util_convertColorspace(&(dest[y*destWidth*destBPP]), destBPP, destHasAlpha,
  1148.                  reducedRowBuffer, sourceDrawable->bpp, sourceHasAlpha,
  1149.                  destWidth);
  1150.     }
  1151.  
  1152.   g_free (sourceBuffer);
  1153.   g_free (reducedRowBuffer);
  1154.   g_free (sourceRowOffsetLookup);
  1155. }
  1156.  
  1157. /* Utterly pathetic kludge to convert between color spaces;
  1158.    likes gray and rgb best, of course.  Others will be creatively mutilated,
  1159.    and even rgb->gray is pretty bad */
  1160. void
  1161. util_convertColorspace (guchar *dest,
  1162.             gint    destBPP,
  1163.             gint    destHasAlpha,
  1164.             guchar *source,
  1165.             gint    sourceBPP,
  1166.             gint    sourceHasAlpha,
  1167.             gint    length)
  1168. {
  1169.   int i, j, sourcePos, destPos, accum;
  1170.   int sourceColorBPP = sourceHasAlpha ? (sourceBPP-1) : sourceBPP;
  1171.   int destColorBPP   = destHasAlpha   ? (destBPP  -1) : destBPP;
  1172.  
  1173.   if (((sourceColorBPP != 1) && (sourceColorBPP != 3)) ||
  1174.       ((destColorBPP   != 1) && (destColorBPP   != 3)))
  1175.     fprintf(stderr, "Warning: I don't _like_ this color space.  This is a suggestion, not a threat.\n");
  1176.  
  1177.   if ((sourceColorBPP == destColorBPP) &&
  1178.       (sourceBPP      == destBPP     ))
  1179.     {
  1180.       j = length*sourceBPP;
  1181.       for (i = 0; i < j; i++) dest[i] = source[i];
  1182.       return;
  1183.     }
  1184.  
  1185.   if (sourceColorBPP == destColorBPP)
  1186.     {
  1187.       for (i = destPos = sourcePos = 0; i < length;
  1188.        i++, destPos += destBPP, sourcePos += sourceBPP)
  1189.     {
  1190.       for (j = 0; j < destColorBPP; j++)
  1191.         dest[destPos + j] = source[sourcePos + j];
  1192.     }
  1193.     }
  1194.   else if (sourceColorBPP == 1)
  1195.     {
  1196.       /* Duplicate single "gray" source byte across all dest bytes */
  1197.       for (i = destPos = sourcePos = 0; i < length;
  1198.        i++, destPos += destBPP, sourcePos += sourceBPP)
  1199.     {
  1200.       for (j = 0; j < destColorBPP; j++)
  1201.         dest[destPos + j] = source[sourcePos];
  1202.     }
  1203.     }
  1204.   else if (destColorBPP == 1)
  1205.     {
  1206.       /* Average all source bytes into single "gray" dest byte */
  1207.       for (i = destPos = sourcePos = 0; i < length;
  1208.        i++, destPos += destBPP, sourcePos += sourceBPP)
  1209.     {
  1210.       accum = 0;
  1211.       for (j = 0; j < sourceColorBPP; j++)
  1212.         accum += source[sourcePos + j];
  1213.       dest[destPos] = accum/sourceColorBPP;
  1214.     }
  1215.     }
  1216.   else if (destColorBPP < sourceColorBPP)
  1217.     {
  1218.       /* Copy as many corresponding bytes from source to dest as will fit */
  1219.       for (i = destPos = sourcePos = 0; i < length;
  1220.        i++, destPos += destBPP, sourcePos += sourceBPP)
  1221.     {
  1222.       for (j = 0; j < destColorBPP; j++)
  1223.         dest[destPos + j] = source[sourcePos + j];
  1224.     }
  1225.     }
  1226.   else /* destColorBPP > sourceColorBPP */
  1227.     {
  1228.       /* Fill extra dest bytes with zero */
  1229.       for (i = destPos = sourcePos = 0; i < length;
  1230.        i++, destPos += destBPP, sourcePos += sourceBPP)
  1231.     {
  1232.       for (j = 0; j < sourceColorBPP; j++)
  1233.         dest[destPos + j] = source[destPos + j];
  1234.       for (     ; j < destColorBPP; j++)
  1235.         dest[destPos + j] = 0;
  1236.     }
  1237.     }
  1238.  
  1239.   if (destHasAlpha)
  1240.     {
  1241.       if (sourceHasAlpha)
  1242.     {
  1243.       for (i = 0, destPos = destColorBPP, sourcePos = sourceColorBPP;
  1244.            i < length;
  1245.            i++, destPos += destBPP, sourcePos += sourceBPP)
  1246.         {
  1247.           for (i = 0; i < length; i++)
  1248.         dest[destPos] = source[sourcePos];
  1249.         }
  1250.     }
  1251.       else
  1252.     {
  1253.       for (i = 0, destPos = destColorBPP;
  1254.            i < length;
  1255.            i++, destPos += destBPP)
  1256.         {
  1257.           dest[destPos] = 255;
  1258.         }
  1259.     }
  1260.     }
  1261. }
  1262.