[gimp-normalmap] / trunk / normalmap.c Repository:
ViewVC logotype

View of /trunk/normalmap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 41 - (download) (as text) (annotate)
Fri Apr 11 20:16:52 2008 UTC (19 months, 1 week ago) by cocidius
File size: 65464 byte(s)
* Update INSTALL, README
* Update contact information if file headers
    1 /*
    2    normalmap GIMP plugin
    3 
    4    Copyright (C) 2002-2008 Shawn Kirst <skirst@insightbb.com>
    5 
    6    This program is free software; you can redistribute it and/or
    7    modify it under the terms of the GNU General Public
    8    License as published by the Free Software Foundation; either
    9    version 2 of the License, or (at your option) any later version.
   10 
   11    This program is distributed in the hope that it will be useful,
   12    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14    General Public License for more details.
   15 
   16    You should have received a copy of the GNU General Public License
   17    along with this program; see the file COPYING.  If not, write to
   18    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   19    Boston, MA 02111-1307, USA.
   20 */
   21 
   22 #include <stdlib.h>
   23 #include <stdio.h>
   24 #include <string.h>
   25 
   26 #include <gtk/gtk.h>
   27 
   28 #include <libgimp/gimp.h>
   29 #include <libgimp/gimpui.h>
   30 
   31 #include "scale.h"
   32 #include "preview3d.h"
   33 
   34 #define PREVIEW_SIZE 150
   35 
   36 enum FILTER_TYPE
   37 {
   38    FILTER_NONE = 0, FILTER_SOBEL_3x3, FILTER_SOBEL_5x5, FILTER_PREWITT_3x3,
   39    FILTER_PREWITT_5x5, FILTER_3x3, FILTER_5x5, FILTER_7x7, FILTER_9x9,
   40    MAX_FILTER_TYPE
   41 };
   42 
   43 enum ALPHA_TYPE
   44 {
   45    ALPHA_NONE = 0, ALPHA_HEIGHT, ALPHA_INVERSE_HEIGHT, ALPHA_ZERO, ALPHA_ONE,
   46    ALPHA_INVERT, ALPHA_MAP, MAX_ALPHA_TYPE
   47 };
   48 
   49 enum CONVERSION_TYPE
   50 {
   51    CONVERT_NONE = 0, CONVERT_BIASED_RGB, CONVERT_RED, CONVERT_GREEN,
   52    CONVERT_BLUE, CONVERT_MAX_RGB, CONVERT_MIN_RGB, CONVERT_COLORSPACE,
   53    CONVERT_NORMALIZE_ONLY, CONVERT_DUDV_TO_NORMAL, CONVERT_HEIGHTMAP,
   54    MAX_CONVERSION_TYPE
   55 };
   56 
   57 enum DUDV_TYPE
   58 {
   59    DUDV_NONE, DUDV_8BIT_SIGNED, DUDV_8BIT_UNSIGNED, DUDV_16BIT_SIGNED,
   60    DUDV_16BIT_UNSIGNED,
   61    MAX_DUDV_TYPE
   62 };
   63 
   64 typedef struct
   65 {
   66    gint filter;
   67    gdouble minz;
   68    gdouble scale;
   69    gint wrap;
   70    gint height_source;
   71    gint alpha;
   72    gint conversion;
   73    gint dudv;
   74    gint xinvert;
   75    gint yinvert;
   76    gint swapRGB;
   77    gdouble contrast;
   78    gint32 alphamap_id;
   79 } NormalmapVals;
   80 
   81 static void query(void);
   82 static void run(const gchar *name, gint params, const GimpParam *param,
   83                 gint *nreturn_vals, GimpParam **return_vals);
   84 
   85 static gint32 normalmap(GimpDrawable *drawable, gboolean preview_mode);
   86 
   87 static gint normalmap_dialog(GimpDrawable *drawable);
   88 
   89 GimpPlugInInfo PLUG_IN_INFO =
   90 {
   91    0, 0, query, run
   92 };
   93 
   94 NormalmapVals nmapvals =
   95 {
   96    .filter = 0,
   97    .minz = 0.0,
   98    .scale = 1.0,
   99    .wrap = 0,
  100    .height_source = 0,
  101    .alpha = ALPHA_NONE,
  102    .conversion = CONVERT_NONE,
  103    .dudv = DUDV_NONE,
  104    .xinvert = 0,
  105    .yinvert = 0,
  106    .swapRGB = 0,
  107    .contrast = 0.0,
  108    .alphamap_id = 0
  109 };
  110 
  111 static const float oneover255 = 1.0f / 255.0f;
  112 
  113 gint runme = 0;
  114 
  115 static GtkWidget *dialog;
  116 static GtkWidget *preview;
  117 
  118 MAIN()
  119 
  120 static void query(void)
  121 {
  122    static GimpParamDef args[]=
  123    {
  124       {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  125       {GIMP_PDB_IMAGE, "image", "Input image (unused)"},
  126       {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  127       {GIMP_PDB_INT32, "filter", "Filter type (0 = 4 sample, 1 = sobel 3x3, 2 = sobel 5x5, 3 = prewitt 3x3, 4 = prewitt 5x5, 5-8 = 3x3,5x5,7x7,9x9)"},
  128       {GIMP_PDB_FLOAT, "minz", "Minimun Z (0 to 1)"},
  129       {GIMP_PDB_FLOAT, "scale", "Scale (>0)"},
  130       {GIMP_PDB_INT32, "wrap", "Wrap (0 = no)"},
  131       {GIMP_PDB_INT32, "height_source", "Height source (0 = average RGB, 1 = alpha channel)"},
  132       {GIMP_PDB_INT32, "alpha", "Alpha (0 = unchanged, 1 = set to height, 2 = set to inverse height, 3 = set to 0, 4 = set to 1, 5 = invert, 6 = set to alpha map value)"},
  133       {GIMP_PDB_INT32, "conversion", "Conversion (0 = normalize only, 1 = Biased RGB, 2 = Red, 3 = Green, 4 = Blue, 5 = Max RGB, 6 = Min RGB, 7 = Colorspace, 8 = Normalize only, 9 = Convert to height map)"},
  134       {GIMP_PDB_INT32, "dudv", "DU/DV map (0 = none, 1 = 8-bit, 2 = 8-bit unsigned, 3 = 16-bit, 4 = 16-bit unsigned)"},
  135       {GIMP_PDB_INT32, "xinvert", "Invert X component of normal"},
  136       {GIMP_PDB_INT32, "yinvert", "Invert Y component of normal"},
  137       {GIMP_PDB_INT32, "swapRGB", "Swap RGB components"},
  138       {GIMP_PDB_FLOAT, "contrast", "Height contrast (0 to 1). If converting to a height map, this value is applied to the results"},
  139       {GIMP_PDB_DRAWABLE, "alphamap", "Alpha map drawable"}
  140    };
  141    static gint nargs = sizeof(args) / sizeof(args[0]);
  142 
  143    gimp_install_procedure("plug_in_normalmap",
  144                           "Converts image to an RGB normalmap",
  145                           "foo!",
  146                           "Shawn Kirst",
  147                           "Shawn Kirst",
  148                           "February 2002",
  149                           "<Image>/Filters/Map/Normalmap...",
  150                           "RGB*",
  151                           GIMP_PLUGIN,
  152                           nargs, 0,
  153                           args, NULL);
  154 }
  155 
  156 static void run(const gchar *name, gint nparams, const GimpParam *param,
  157                 gint *nreturn_vals, GimpParam **return_vals)
  158 {
  159    static GimpParam values[1];
  160    GimpDrawable *drawable;
  161    GimpRunMode run_mode;
  162    GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  163 
  164    run_mode = param[0].data.d_int32;
  165 
  166    *nreturn_vals = 1;
  167    *return_vals = values;
  168 
  169    values[0].type = GIMP_PDB_STATUS;
  170    values[0].data.d_status = status;
  171 
  172    drawable = gimp_drawable_get(param[2].data.d_drawable);
  173 
  174    switch(run_mode)
  175    {
  176       case GIMP_RUN_INTERACTIVE:
  177          gimp_ui_init("normalmap", 0);
  178          gimp_get_data("plug_in_normalmap", &nmapvals);
  179          if(!normalmap_dialog(drawable))
  180          {
  181             gimp_drawable_detach(drawable);
  182             return;
  183          }
  184          break;
  185       case GIMP_RUN_NONINTERACTIVE:
  186          if(nparams != 16)
  187             status=GIMP_PDB_CALLING_ERROR;
  188          else
  189          {
  190             nmapvals.filter = param[3].data.d_int32;
  191             nmapvals.minz = param[4].data.d_float;
  192             nmapvals.scale = param[5].data.d_float;
  193             nmapvals.wrap = param[6].data.d_int32;
  194             nmapvals.height_source = param[7].data.d_int32;
  195             nmapvals.alpha = param[8].data.d_int32;
  196             nmapvals.conversion = param[9].data.d_int32;
  197             nmapvals.dudv = param[10].data.d_int32;
  198             nmapvals.xinvert = param[11].data.d_int32;
  199             nmapvals.yinvert = param[12].data.d_int32;
  200             nmapvals.swapRGB = param[13].data.d_int32;
  201             nmapvals.contrast = param[14].data.d_float;
  202             nmapvals.alphamap_id = gimp_drawable_get(param[15].data.d_drawable)->drawable_id;
  203          }
  204          break;
  205       case GIMP_RUN_WITH_LAST_VALS:
  206          gimp_get_data("plug_in_normalmap", &nmapvals);
  207          break;
  208       default:
  209          break;
  210    }
  211 
  212    gimp_progress_init("Creating normalmap...");
  213 
  214    if(normalmap(drawable,FALSE) == -1)
  215       status = GIMP_PDB_EXECUTION_ERROR;
  216 
  217    if(run_mode != GIMP_RUN_NONINTERACTIVE)
  218       gimp_displays_flush();
  219 
  220    if(run_mode == GIMP_RUN_INTERACTIVE)
  221       gimp_set_data("plug_in_normalmap", &nmapvals, sizeof(nmapvals));
  222 
  223    values[0].data.d_status = status;
  224 
  225    gimp_drawable_detach(drawable);
  226 }
  227 
  228 #ifndef min
  229 #define min(a,b)  ((a)<(b) ? (a) : (b))
  230 #endif
  231 #ifndef max
  232 #define max(a,b)  ((a)>(b) ? (a) : (b))
  233 #endif
  234 
  235 #define SQR(x)      ((x) * (x))
  236 #define LERP(a,b,c) ((a) + ((b) - (a)) * (c))
  237 
  238 static inline void NORMALIZE(float *v)
  239 {
  240    float len = sqrtf(SQR(v[0]) + SQR(v[1]) + SQR(v[2]));
  241 
  242    if(len > 1e-04f)
  243    {
  244       len = 1.0f / len;
  245       v[0] *= len;
  246       v[1] *= len;
  247       v[2] *= len;
  248    }
  249    else
  250       v[0] = v[1] = v[2] = 0;
  251 }
  252 
  253 typedef struct
  254 {
  255    int x,y;
  256    float w;
  257 } kernel_element;
  258 
  259 static void make_kernel(kernel_element *k, float *weights, int size)
  260 {
  261    int x, y, idx;
  262 
  263    for(y = 0; y < size; ++y)
  264    {
  265       for(x = 0; x < size; ++x)
  266       {
  267          idx = x + y * size;
  268          k[idx].x = x - (size / 2);
  269          k[idx].y = (size / 2) - y;
  270          k[idx].w = weights[idx];
  271       }
  272    }
  273 }
  274 
  275 static void rotate_array(float *dst, float *src, int size)
  276 {
  277    int x, y, newx, newy;
  278 
  279    for(y = 0; y < size; ++y)
  280    {
  281       for(x = 0; x < size; ++x)
  282       {
  283          newy = size - x - 1;
  284          newx = y;
  285          dst[newx + newy * size] = src[x + y * size];
  286       }
  287    }
  288 }
  289 
  290 static int sample_alpha_map(unsigned char *pixels, int x, int y,
  291                             int w, int h, int sw, int sh)
  292 {
  293    float fx, fy, dx, dy;
  294    float v, r0, r1, r2, r3;
  295    int ix, iy;
  296 
  297    fx = ((float)x / (float)sw) * (float)w;
  298    fy = ((float)y / (float)sh) * (float)h;
  299    ix = (int)floor(fx);
  300    iy = (int)floor(fy);
  301    dx = fx - (float)ix;
  302    dy = fy - (float)iy;
  303 
  304 #define VAL(x, y) \
  305    (float)pixels[((y) < 0 ? 0 : (y) >= h ? h - 1 : (y)) * w + \
  306                  ((x) < 0 ? 0 : (x) >= w ? w - 1 : (x))]
  307 
  308    r0 = cubic_interpolate(VAL(ix - 1, iy - 1),
  309                           VAL(ix,     iy - 1),
  310                           VAL(ix + 1, iy - 1),
  311                           VAL(ix + 2, iy - 1), dx);
  312    r1 = cubic_interpolate(VAL(ix - 1, iy    ),
  313                           VAL(ix,     iy    ),
  314                           VAL(ix + 1, iy    ),
  315                           VAL(ix + 2, iy    ), dx);
  316    r2 = cubic_interpolate(VAL(ix - 1, iy + 1),
  317                           VAL(ix,     iy + 1),
  318                           VAL(ix + 1, iy + 1),
  319                           VAL(ix + 2, iy + 1), dx);
  320    r3 = cubic_interpolate(VAL(ix - 1, iy + 2),
  321                           VAL(ix,     iy + 2),
  322                           VAL(ix + 1, iy + 2),
  323                           VAL(ix + 2, iy + 2), dx);
  324 #undef VAL
  325 
  326    v = cubic_interpolate(r0, r1, r2, r3, dy);
  327 
  328    if(v <   0) v = 0;
  329    if(v > 255) v = 255;
  330 
  331    return((unsigned char)v);
  332 }
  333 
  334 static void make_heightmap(unsigned char *image, int w, int h, int bpp)
  335 {
  336    unsigned int i, num_pixels = w * h;
  337    int x, y;
  338    float v, hmin, hmax;
  339    float *s, *r;
  340 
  341    s = (float*)g_malloc(w * h * 3 * sizeof(float));
  342    if(s == 0)
  343    {
  344       g_message("Memory allocation error!");
  345       return;
  346    }
  347    r = (float*)g_malloc(w * h * 4 * sizeof(float));
  348    if(r == 0)
  349    {
  350       g_free(s);
  351       g_message("Memory allocation error!");
  352       return;
  353    }
  354 
  355    /* scale into 0 to 1 range, make signed -1 to 1 */
  356    for(i = 0; i < num_pixels; ++i)
  357    {
  358       s[3 * i + 0] = (((float)image[bpp * i + 0] / 255.0f) - 0.5) * 2.0f;
  359       s[3 * i + 1] = (((float)image[bpp * i + 1] / 255.0f) - 0.5) * 2.0f;
  360       s[3 * i + 2] = (((float)image[bpp * i + 2] / 255.0f) - 0.5) * 2.0f;
  361    }
  362 
  363    memset(r, 0, w * h * 4 * sizeof(float));
  364 
  365 #define S(x, y, n) s[(y) * (w * 3) + ((x) * 3) + (n)]
  366 #define R(x, y, n) r[(y) * (w * 4) + ((x) * 4) + (n)]
  367 
  368    /* top-left to bottom-right */
  369    for(x = 1; x < w; ++x)
  370       R(x, 0, 0) = R(x - 1, 0, 0) + S(x - 1, 0, 0);
  371    for(y = 1; y < h; ++y)
  372       R(0, y, 0) = R(0, y - 1, 0) + S(0, y - 1, 1);
  373    for(y = 1; y < h; ++y)
  374    {
  375       for(x = 1; x < w; ++x)
  376       {
  377          R(x, y, 0) = (R(x, y - 1, 0) + R(x - 1, y, 0) +
  378                        S(x - 1, y, 0) + S(x, y - 1, 1)) * 0.5f;
  379       }
  380    }
  381 
  382    /* top-right to bottom-left */
  383    for(x = w - 2; x >= 0; --x)
  384       R(x, 0, 1) = R(x + 1, 0, 1) - S(x + 1, 0, 0);
  385    for(y = 1; y < h; ++y)
  386       R(0, y, 1) = R(0, y - 1, 1) + S(0, y - 1, 1);
  387    for(y = 1; y < h; ++y)
  388    {
  389       for(x = w - 2; x >= 0; --x)
  390       {
  391          R(x, y, 1) = (R(x, y - 1, 1) + R(x + 1, y, 1) -
  392                        S(x + 1, y, 0) + S(x, y - 1, 1)) * 0.5f;
  393       }
  394    }
  395 
  396    /* bottom-left to top-right */
  397    for(x = 1; x < w; ++x)
  398       R(x, 0, 2) = R(x - 1, 0, 2) + S(x - 1, 0, 0);
  399    for(y = h - 2; y >= 0; --y)
  400       R(0, y, 2) = R(0, y + 1, 2) - S(0, y + 1, 1);
  401    for(y = h - 2; y >= 0; --y)
  402    {
  403       for(x = 1; x < w; ++x)
  404       {
  405          R(x, y, 2) = (R(x, y + 1, 2) + R(x - 1, y, 2) +
  406                        S(x - 1, y, 0) - S(x, y + 1, 1)) * 0.5f;
  407       }
  408    }
  409 
  410    /* bottom-right to top-left */
  411    for(x = w - 2; x >= 0; --x)
  412       R(x, 0, 3) = R(x + 1, 0, 3) - S(x + 1, 0, 0);
  413    for(y = h - 2; y >= 0; --y)
  414       R(0, y, 3) = R(0, y + 1, 3) - S(0, y + 1, 1);
  415    for(y = h - 2; y >= 0; --y)
  416    {
  417       for(x = w - 2; x >= 0; --x)
  418       {
  419          R(x, y, 3) = (R(x, y + 1, 3) + R(x + 1, y, 3) -
  420                        S(x + 1, y, 0) - S(x, y + 1, 1)) * 0.5f;
  421       }
  422    }
  423 
  424 #undef S
  425 #undef R
  426 
  427    /* accumulate, find min/max */
  428    hmin =  1e10f;
  429    hmax = -1e10f;
  430    for(i = 0; i < num_pixels; ++i)
  431    {
  432       r[4 * i] += r[4 * i + 1] + r[4 * i + 2] + r[4 * i + 3];
  433       if(r[4 * i] < hmin) hmin = r[4 * i];
  434       if(r[4 * i] > hmax) hmax = r[4 * i];
  435    }
  436 
  437    /* scale into 0 - 1 range */
  438    for(i = 0; i < num_pixels; ++i)
  439    {
  440       v = (r[4 * i] - hmin) / (hmax - hmin);
  441       /* adjust contrast */
  442       v = (v - 0.5f) * nmapvals.contrast + v;
  443       if(v < 0) v = 0;
  444       if(v > 1) v = 1;
  445       r[4 * i] = v;
  446    }
  447 
  448    /* write out results */
  449    for(i = 0; i < num_pixels; ++i)
  450    {
  451       v = r[4 * i] * 255.0f;
  452       image[bpp * i + 0] = (unsigned char)v;
  453       image[bpp * i + 1] = (unsigned char)v;
  454       image[bpp * i + 2] = (unsigned char)v;
  455    }
  456 
  457    g_free(s);
  458    g_free(r);
  459 }
  460 
  461 static gint32 normalmap(GimpDrawable *drawable, gboolean preview_mode)
  462 {
  463    gint x, y;
  464    gint width, height, bpp, rowbytes, pw, ph, amap_w = 0, amap_h = 0;
  465    guchar *d, *dst, *s, *src, *tmp, *amap = 0;
  466    float *heights;
  467    float val, du, dv, n[3], weight;
  468    float rgb_bias[3];
  469    int i, num_elements = 0;
  470    kernel_element *kernel_du = 0;
  471    kernel_element *kernel_dv = 0;
  472    GimpPixelRgn src_rgn, dst_rgn, amap_rgn;
  473    GdkCursor *cursor = 0;
  474 
  475    if(nmapvals.filter < 0 || nmapvals.filter >= MAX_FILTER_TYPE)
  476       nmapvals.filter = FILTER_NONE;
  477    if(drawable->bpp != 4) nmapvals.height_source = 0;
  478    if(drawable->bpp != 4 && (nmapvals.dudv == DUDV_16BIT_SIGNED ||
  479                              nmapvals.dudv == DUDV_16BIT_UNSIGNED))
  480       nmapvals.dudv = DUDV_NONE;
  481 
  482    width = drawable->width;
  483    height = drawable->height;
  484    bpp = drawable->bpp;
  485    rowbytes = width * bpp;
  486 
  487    dst = g_malloc(width * height * bpp);
  488    if(dst == 0)
  489    {
  490       g_message("Memory allocation error!");
  491       return(-1);
  492    }
  493 
  494    src = g_malloc(width * height * bpp);
  495    if(src == 0)
  496    {
  497       g_message("Memory allocation error!");
  498       return(-1);
  499    }
  500 
  501    heights = g_new(float, width * height);
  502    if(heights == 0)
  503    {
  504       g_message("Memory allocation error!");
  505       return(-1);
  506    }
  507 
  508    if(!nmapvals.dudv && drawable->bpp == 4 && nmapvals.alpha == ALPHA_MAP &&
  509       nmapvals.alphamap_id != 0)
  510    {
  511       GimpDrawable *alphamap = gimp_drawable_get(nmapvals.alphamap_id);
  512 
  513       amap_w = alphamap->width;
  514       amap_h = alphamap->height;
  515 
  516       amap = g_malloc(amap_w * amap_h);
  517 
  518       gimp_pixel_rgn_init(&amap_rgn, alphamap, 0, 0, amap_w, amap_h, 0, 0);
  519       gimp_pixel_rgn_get_rect(&amap_rgn, amap, 0, 0, amap_w, amap_h);
  520    }
  521 
  522    gimp_pixel_rgn_init(&src_rgn, drawable, 0, 0, width, height, 0, 0);
  523    gimp_pixel_rgn_get_rect(&src_rgn, src, 0, 0, width, height);
  524 
  525    switch(nmapvals.filter)
  526    {
  527       case FILTER_NONE:
  528          num_elements = 2;
  529          kernel_du = (kernel_element*)g_malloc(2 * sizeof(kernel_element));
  530          kernel_dv = (kernel_element*)g_malloc(2 * sizeof(kernel_element));
  531 
  532          kernel_du[0].x = -1; kernel_du[0].y = 0; kernel_du[0].w = -0.5f;
  533          kernel_du[1].x =  1; kernel_du[1].y = 0; kernel_du[1].w =  0.5f;
  534 
  535          kernel_dv[0].x = 0; kernel_dv[0].y =  1; kernel_dv[0].w =  0.5f;
  536          kernel_dv[1].x = 0; kernel_dv[1].y = -1; kernel_dv[1].w = -0.5f;
  537 
  538          break;
  539       case FILTER_SOBEL_3x3:
  540          num_elements = 6;
  541          kernel_du = (kernel_element*)g_malloc(6 * sizeof(kernel_element));
  542          kernel_dv = (kernel_element*)g_malloc(6 * sizeof(kernel_element));
  543 
  544          kernel_du[0].x = -1; kernel_du[0].y =  1; kernel_du[0].w = -1.0f;
  545          kernel_du[1].x = -1; kernel_du[1].y =  0; kernel_du[1].w = -2.0f;
  546          kernel_du[2].x = -1; kernel_du[2].y = -1; kernel_du[2].w = -1.0f;
  547          kernel_du[3].x =  1; kernel_du[3].y =  1; kernel_du[3].w =  1.0f;
  548          kernel_du[4].x =  1; kernel_du[4].y =  0; kernel_du[4].w =  2.0f;
  549          kernel_du[5].x =  1; kernel_du[5].y = -1; kernel_du[5].w =  1.0f;
  550 
  551          kernel_dv[0].x = -1; kernel_dv[0].y =  1; kernel_dv[0].w =  1.0f;
  552          kernel_dv[1].x =  0; kernel_dv[1].y =  1; kernel_dv[1].w =  2.0f;
  553          kernel_dv[2].x =  1; kernel_dv[2].y =  1; kernel_dv[2].w =  1.0f;
  554          kernel_dv[3].x = -1; kernel_dv[3].y = -1; kernel_dv[3].w = -1.0f;
  555          kernel_dv[4].x =  0; kernel_dv[4].y = -1; kernel_dv[4].w = -2.0f;
  556          kernel_dv[5].x =  1; kernel_dv[5].y = -1; kernel_dv[5].w = -1.0f;
  557 
  558          break;
  559       case FILTER_SOBEL_5x5:
  560          num_elements = 20;
  561          kernel_du = (kernel_element*)g_malloc(20 * sizeof(kernel_element));
  562          kernel_dv = (kernel_element*)g_malloc(20 * sizeof(kernel_element));
  563 
  564          kernel_du[ 0].x = -2; kernel_du[ 0].y =  2; kernel_du[ 0].w =  -1.0f;
  565          kernel_du[ 1].x = -2; kernel_du[ 1].y =  1; kernel_du[ 1].w =  -4.0f;
  566          kernel_du[ 2].x = -2; kernel_du[ 2].y =  0; kernel_du[ 2].w =  -6.0f;
  567          kernel_du[ 3].x = -2; kernel_du[ 3].y = -1; kernel_du[ 3].w =  -4.0f;
  568          kernel_du[ 4].x = -2; kernel_du[ 4].y = -2; kernel_du[ 4].w =  -1.0f;
  569          kernel_du[ 5].x = -1; kernel_du[ 5].y =  2; kernel_du[ 5].w =  -2.0f;
  570          kernel_du[ 6].x = -1; kernel_du[ 6].y =  1; kernel_du[ 6].w =  -8.0f;
  571          kernel_du[ 7].x = -1; kernel_du[ 7].y =  0; kernel_du[ 7].w = -12.0f;
  572          kernel_du[ 8].x = -1; kernel_du[ 8].y = -1; kernel_du[ 8].w =  -8.0f;
  573          kernel_du[ 9].x = -1; kernel_du[ 9].y = -2; kernel_du[ 9].w =  -2.0f;
  574          kernel_du[10].x =  1; kernel_du[10].y =  2; kernel_du[10].w =   2.0f;
  575          kernel_du[11].x =  1; kernel_du[11].y =  1; kernel_du[11].w =   8.0f;
  576          kernel_du[12].x =  1; kernel_du[12].y =  0; kernel_du[12].w =  12.0f;
  577          kernel_du[13].x =  1; kernel_du[13].y = -1; kernel_du[13].w =   8.0f;
  578          kernel_du[14].x =  1; kernel_du[14].y = -2; kernel_du[14].w =   2.0f;
  579          kernel_du[15].x =  2; kernel_du[15].y =  2; kernel_du[15].w =   1.0f;
  580          kernel_du[16].x =  2; kernel_du[16].y =  1; kernel_du[16].w =   4.0f;
  581          kernel_du[17].x =  2; kernel_du[17].y =  0; kernel_du[17].w =   6.0f;
  582          kernel_du[18].x =  2; kernel_du[18].y = -1; kernel_du[18].w =   4.0f;
  583          kernel_du[19].x =  2; kernel_du[19].y = -2; kernel_du[19].w =   1.0f;
  584 
  585          kernel_dv[ 0].x = -2; kernel_dv[ 0].y =  2; kernel_dv[ 0].w =   1.0f;
  586          kernel_dv[ 1].x = -1; kernel_dv[ 1].y =  2; kernel_dv[ 1].w =   4.0f;
  587          kernel_dv[ 2].x =  0; kernel_dv[ 2].y =  2; kernel_dv[ 2].w =   6.0f;
  588          kernel_dv[ 3].x =  1; kernel_dv[ 3].y =  2; kernel_dv[ 3].w =   4.0f;
  589          kernel_dv[ 4].x =  2; kernel_dv[ 4].y =  2; kernel_dv[ 4].w =   1.0f;
  590          kernel_dv[ 5].x = -2; kernel_dv[ 5].y =  1; kernel_dv[ 5].w =   2.0f;
  591          kernel_dv[ 6].x = -1; kernel_dv[ 6].y =  1; kernel_dv[ 6].w =   8.0f;
  592          kernel_dv[ 7].x =  0; kernel_dv[ 7].y =  1; kernel_dv[ 7].w =  12.0f;
  593          kernel_dv[ 8].x =  1; kernel_dv[ 8].y =  1; kernel_dv[ 8].w =   8.0f;
  594          kernel_dv[ 9].x =  2; kernel_dv[ 9].y =  1; kernel_dv[ 9].w =   2.0f;
  595          kernel_dv[10].x = -2; kernel_dv[10].y = -1; kernel_dv[10].w =  -2.0f;
  596          kernel_dv[11].x = -1; kernel_dv[11].y = -1; kernel_dv[11].w =  -8.0f;
  597          kernel_dv[12].x =  0; kernel_dv[12].y = -1; kernel_dv[12].w = -12.0f;
  598          kernel_dv[13].x =  1; kernel_dv[13].y = -1; kernel_dv[13].w =  -8.0f;
  599          kernel_dv[14].x =  2; kernel_dv[14].y = -1; kernel_dv[14].w =  -2.0f;
  600          kernel_dv[15].x = -2; kernel_dv[15].y = -2; kernel_dv[15].w =  -1.0f;
  601          kernel_dv[16].x = -1; kernel_dv[16].y = -2; kernel_dv[16].w =  -4.0f;
  602          kernel_dv[17].x =  0; kernel_dv[17].y = -2; kernel_dv[17].w =  -6.0f;
  603          kernel_dv[18].x =  1; kernel_dv[18].y = -2; kernel_dv[18].w =  -4.0f;
  604          kernel_dv[19].x =  2; kernel_dv[19].y = -2; kernel_dv[19].w =  -1.0f;
  605 
  606          break;
  607       case FILTER_PREWITT_3x3:
  608          num_elements = 6;
  609          kernel_du = (kernel_element*)g_malloc(6 * sizeof(kernel_element));
  610          kernel_dv = (kernel_element*)g_malloc(6 * sizeof(kernel_element));
  611 
  612          kernel_du[0].x = -1; kernel_du[0].y =  1; kernel_du[0].w = -1.0f;
  613          kernel_du[1].x = -1; kernel_du[1].y =  0; kernel_du[1].w = -1.0f;
  614          kernel_du[2].x = -1; kernel_du[2].y = -1; kernel_du[2].w = -1.0f;
  615          kernel_du[3].x =  1; kernel_du[3].y =  1; kernel_du[3].w =  1.0f;
  616          kernel_du[4].x =  1; kernel_du[4].y =  0; kernel_du[4].w =  1.0f;
  617          kernel_du[5].x =  1; kernel_du[5].y = -1; kernel_du[5].w =  1.0f;
  618 
  619          kernel_dv[0].x = -1; kernel_dv[0].y =  1; kernel_dv[0].w =  1.0f;
  620          kernel_dv[1].x =  0; kernel_dv[1].y =  1; kernel_dv[1].w =  1.0f;
  621          kernel_dv[2].x =  1; kernel_dv[2].y =  1; kernel_dv[2].w =  1.0f;
  622          kernel_dv[3].x = -1; kernel_dv[3].y = -1; kernel_dv[3].w = -1.0f;
  623          kernel_dv[4].x =  0; kernel_dv[4].y = -1; kernel_dv[4].w = -1.0f;
  624          kernel_dv[5].x =  1; kernel_dv[5].y = -1; kernel_dv[5].w = -1.0f;
  625 
  626          break;
  627       case FILTER_PREWITT_5x5:
  628          num_elements = 20;
  629          kernel_du = (kernel_element*)g_malloc(20 * sizeof(kernel_element));
  630          kernel_dv = (kernel_element*)g_malloc(20 * sizeof(kernel_element));
  631 
  632          kernel_du[ 0].x = -2; kernel_du[ 0].y =  2; kernel_du[ 0].w = -1.0f;
  633          kernel_du[ 1].x = -2; kernel_du[ 1].y =  1; kernel_du[ 1].w = -1.0f;
  634          kernel_du[ 2].x = -2; kernel_du[ 2].y =  0; kernel_du[ 2].w = -1.0f;
  635          kernel_du[ 3].x = -2; kernel_du[ 3].y = -1; kernel_du[ 3].w = -1.0f;
  636          kernel_du[ 4].x = -2; kernel_du[ 4].y = -2; kernel_du[ 4].w = -1.0f;
  637          kernel_du[ 5].x = -1; kernel_du[ 5].y =  2; kernel_du[ 5].w = -2.0f;
  638          kernel_du[ 6].x = -1; kernel_du[ 6].y =  1; kernel_du[ 6].w = -2.0f;
  639          kernel_du[ 7].x = -1; kernel_du[ 7].y =  0; kernel_du[ 7].w = -2.0f;
  640          kernel_du[ 8].x = -1; kernel_du[ 8].y = -1; kernel_du[ 8].w = -2.0f;
  641          kernel_du[ 9].x = -1; kernel_du[ 9].y = -2; kernel_du[ 9].w = -2.0f;
  642          kernel_du[10].x =  1; kernel_du[10].y =  2; kernel_du[10].w =  2.0f;
  643          kernel_du[11].x =  1; kernel_du[11].y =  1; kernel_du[11].w =  2.0f;
  644          kernel_du[12].x =  1; kernel_du[12].y =  0; kernel_du[12].w =  2.0f;
  645          kernel_du[13].x =  1; kernel_du[13].y = -1; kernel_du[13].w =  2.0f;
  646          kernel_du[14].x =  1; kernel_du[14].y = -2; kernel_du[14].w =  2.0f;
  647          kernel_du[15].x =  2; kernel_du[15].y =  2; kernel_du[15].w =  1.0f;
  648          kernel_du[16].x =  2; kernel_du[16].y =  1; kernel_du[16].w =  1.0f;
  649          kernel_du[17].x =  2; kernel_du[17].y =  0; kernel_du[17].w =  1.0f;
  650          kernel_du[18].x =  2; kernel_du[18].y = -1; kernel_du[18].w =  1.0f;
  651          kernel_du[19].x =  2; kernel_du[19].y = -2; kernel_du[19].w =  1.0f;
  652 
  653          kernel_dv[ 0].x = -2; kernel_dv[ 0].y =  2; kernel_dv[ 0].w =  1.0f;
  654          kernel_dv[ 1].x = -1; kernel_dv[ 1].y =  2; kernel_dv[ 1].w =  1.0f;
  655          kernel_dv[ 2].x =  0; kernel_dv[ 2].y =  2; kernel_dv[ 2].w =  1.0f;
  656          kernel_dv[ 3].x =  1; kernel_dv[ 3].y =  2; kernel_dv[ 3].w =  1.0f;
  657          kernel_dv[ 4].x =  2; kernel_dv[ 4].y =  2; kernel_dv[ 4].w =  1.0f;
  658          kernel_dv[ 5].x = -2; kernel_dv[ 5].y =  1; kernel_dv[ 5].w =  2.0f;
  659          kernel_dv[ 6].x = -1; kernel_dv[ 6].y =  1; kernel_dv[ 6].w =  2.0f;
  660          kernel_dv[ 7].x =  0; kernel_dv[ 7].y =  1; kernel_dv[ 7].w =  2.0f;
  661          kernel_dv[ 8].x =  1; kernel_dv[ 8].y =  1; kernel_dv[ 8].w =  2.0f;
  662          kernel_dv[ 9].x =  2; kernel_dv[ 9].y =  1; kernel_dv[ 9].w =  2.0f;
  663          kernel_dv[10].x = -2; kernel_dv[10].y = -1; kernel_dv[10].w = -2.0f;
  664          kernel_dv[11].x = -1; kernel_dv[11].y = -1; kernel_dv[11].w = -2.0f;
  665          kernel_dv[12].x =  0; kernel_dv[12].y = -1; kernel_dv[12].w = -2.0f;
  666          kernel_dv[13].x =  1; kernel_dv[13].y = -1; kernel_dv[13].w = -2.0f;
  667          kernel_dv[14].x =  2; kernel_dv[14].y = -1; kernel_dv[14].w = -2.0f;
  668          kernel_dv[15].x = -2; kernel_dv[15].y = -2; kernel_dv[15].w = -1.0f;
  669          kernel_dv[16].x = -1; kernel_dv[16].y = -2; kernel_dv[16].w = -1.0f;
  670          kernel_dv[17].x =  0; kernel_dv[17].y = -2; kernel_dv[17].w = -1.0f;
  671          kernel_dv[18].x =  1; kernel_dv[18].y = -2; kernel_dv[18].w = -1.0f;
  672          kernel_dv[19].x =  2; kernel_dv[19].y = -2; kernel_dv[19].w = -1.0f;
  673 
  674          break;
  675       case FILTER_3x3:
  676          num_elements = 6;
  677          kernel_du = (kernel_element*)g_malloc(6 * sizeof(kernel_element));
  678          kernel_dv = (kernel_element*)g_malloc(6 * sizeof(kernel_element));
  679 
  680          weight = 1.0f / 6.0f;
  681 
  682          kernel_du[0].x = -1; kernel_du[0].y =  1; kernel_du[0].w = -weight;
  683          kernel_du[1].x = -1; kernel_du[1].y =  0; kernel_du[1].w = -weight;
  684          kernel_du[2].x = -1; kernel_du[2].y = -1; kernel_du[2].w = -weight;
  685          kernel_du[3].x =  1; kernel_du[3].y =  1; kernel_du[3].w =  weight;
  686          kernel_du[4].x =  1; kernel_du[4].y =  0; kernel_du[4].w =  weight;
  687          kernel_du[5].x =  1; kernel_du[5].y = -1; kernel_du[5].w =  weight;
  688 
  689          kernel_dv[0].x = -1; kernel_dv[0].y =  1; kernel_dv[0].w =  weight;
  690          kernel_dv[1].x =  0; kernel_dv[1].y =  1; kernel_dv[1].w =  weight;
  691          kernel_dv[2].x =  1; kernel_dv[2].y =  1; kernel_dv[2].w =  weight;
  692          kernel_dv[3].x = -1; kernel_dv[3].y = -1; kernel_dv[3].w = -weight;
  693          kernel_dv[4].x =  0; kernel_dv[4].y = -1; kernel_dv[4].w = -weight;
  694          kernel_dv[5].x =  1; kernel_dv[5].y = -1; kernel_dv[5].w = -weight;
  695          break;
  696       case FILTER_5x5:
  697       {
  698          int n;
  699          float usum = 0, vsum = 0;
  700          float wt22 = 1.0f / 16.0f;
  701          float wt12 = 1.0f / 10.0f;
  702          float wt02 = 1.0f / 8.0f;
  703          float wt11 = 1.0f / 2.8f;
  704          num_elements = 20;
  705          kernel_du = (kernel_element*)g_malloc(20 * sizeof(kernel_element));
  706          kernel_dv = (kernel_element*)g_malloc(20 * sizeof(kernel_element));
  707 
  708          kernel_du[0 ].x = -2; kernel_du[0 ].y =  2; kernel_du[0 ].w = -wt22;
  709          kernel_du[1 ].x = -1; kernel_du[1 ].y =  2; kernel_du[1 ].w = -wt12;
  710          kernel_du[2 ].x =  1; kernel_du[2 ].y =  2; kernel_du[2 ].w =  wt12;
  711          kernel_du[3 ].x =  2; kernel_du[3 ].y =  2; kernel_du[3 ].w =  wt22;
  712          kernel_du[4 ].x = -2; kernel_du[4 ].y =  1; kernel_du[4 ].w = -wt12;
  713          kernel_du[5 ].x = -1; kernel_du[5 ].y =  1; kernel_du[5 ].w = -wt11;
  714          kernel_du[6 ].x =  1; kernel_du[6 ].y =  1; kernel_du[6 ].w =  wt11;
  715          kernel_du[7 ].x =  2; kernel_du[7 ].y =  1; kernel_du[7 ].w =  wt12;
  716          kernel_du[8 ].x = -2; kernel_du[8 ].y =  0; kernel_du[8 ].w = -wt02;
  717          kernel_du[9 ].x = -1; kernel_du[9 ].y =  0; kernel_du[9 ].w = -0.5f;
  718          kernel_du[10].x =  1; kernel_du[10].y =  0; kernel_du[10].w =  0.5f;
  719          kernel_du[11].x =  2; kernel_du[11].y =  0; kernel_du[11].w =  wt02;
  720          kernel_du[12].x = -2; kernel_du[12].y = -1; kernel_du[12].w = -wt12;
  721          kernel_du[13].x = -1; kernel_du[13].y = -1; kernel_du[13].w = -wt11;
  722          kernel_du[14].x =  1; kernel_du[14].y = -1; kernel_du[14].w =  wt11;
  723          kernel_du[15].x =  2; kernel_du[15].y = -1; kernel_du[15].w =  wt12;
  724          kernel_du[16].x = -2; kernel_du[16].y = -2; kernel_du[16].w = -wt22;
  725          kernel_du[17].x = -1; kernel_du[17].y = -2; kernel_du[17].w = -wt12;
  726          kernel_du[18].x =  1; kernel_du[18].y = -2; kernel_du[18].w =  wt12;
  727          kernel_du[19].x =  2; kernel_du[19].y = -2; kernel_du[19].w =  wt22;
  728 
  729          kernel_dv[0 ].x = -2; kernel_dv[0 ].y =  2; kernel_dv[0 ].w =  wt22;
  730          kernel_dv[1 ].x = -1; kernel_dv[1 ].y =  2; kernel_dv[1 ].w =  wt12;
  731          kernel_dv[2 ].x =  0; kernel_dv[2 ].y =  2; kernel_dv[2 ].w =  0.25f;
  732          kernel_dv[3 ].x =  1; kernel_dv[3 ].y =  2; kernel_dv[3 ].w =  wt12;
  733          kernel_dv[4 ].x =  2; kernel_dv[4 ].y =  2; kernel_dv[4 ].w =  wt22;
  734          kernel_dv[5 ].x = -2; kernel_dv[5 ].y =  1; kernel_dv[5 ].w =  wt12;
  735          kernel_dv[6 ].x = -1; kernel_dv[6 ].y =  1; kernel_dv[6 ].w =  wt11;
  736          kernel_dv[7 ].x =  0; kernel_dv[7 ].y =  1; kernel_dv[7 ].w =  0.5f;
  737          kernel_dv[8 ].x =  1; kernel_dv[8 ].y =  1; kernel_dv[8 ].w =  wt11;
  738          kernel_dv[9 ].x =  2; kernel_dv[9 ].y =  1; kernel_dv[9 ].w =  wt22;
  739          kernel_dv[10].x = -2; kernel_dv[10].y = -1; kernel_dv[10].w = -wt22;
  740          kernel_dv[11].x = -1; kernel_dv[11].y = -1; kernel_dv[11].w = -wt11;
  741          kernel_dv[12].x =  0; kernel_dv[12].y = -1; kernel_dv[12].w = -0.5f;
  742          kernel_dv[13].x =  1; kernel_dv[13].y = -1; kernel_dv[13].w = -wt11;
  743          kernel_dv[14].x =  2; kernel_dv[14].y = -1; kernel_dv[14].w = -wt12;
  744          kernel_dv[15].x = -2; kernel_dv[15].y = -2; kernel_dv[15].w = -wt22;
  745          kernel_dv[16].x = -1; kernel_dv[16].y = -2; kernel_dv[16].w = -wt12;
  746          kernel_dv[17].x =  0; kernel_dv[17].y = -2; kernel_dv[17].w = -0.25f;
  747          kernel_dv[18].x =  1; kernel_dv[18].y = -2; kernel_dv[18].w = -wt12;
  748          kernel_dv[19].x =  2; kernel_dv[19].y = -2; kernel_dv[19].w = -wt22;
  749 
  750          for(n = 0; n < 20; ++n)
  751          {
  752             usum += fabsf(kernel_du[n].w);
  753             vsum += fabsf(kernel_dv[n].w);
  754          }
  755          for(n = 0; n < 20; ++n)
  756          {
  757             kernel_du[n].w /= usum;
  758             kernel_dv[n].w /= vsum;
  759          }
  760 
  761          break;
  762       }
  763       case FILTER_7x7:
  764       {
  765          float du_weights[]=
  766          {
  767             -1, -2, -3, 0, 3, 2, 1,
  768             -2, -3, -4, 0, 4, 3, 2,
  769             -3, -4, -5, 0, 5, 4, 3,
  770             -4, -5, -6, 0, 6, 5, 4,
  771             -3, -4, -5, 0, 5, 4, 3,
  772             -2, -3, -4, 0, 4, 3, 2,
  773             -1, -2, -3, 0, 3, 2, 1
  774          };
  775          float dv_weights[49];
  776          int n;
  777          float usum = 0, vsum = 0;
  778 
  779          num_elements = 49;
  780          kernel_du = (kernel_element*)g_malloc(49 * sizeof(kernel_element));
  781          kernel_dv = (kernel_element*)g_malloc(49 * sizeof(kernel_element));
  782 
  783          make_kernel(kernel_du, du_weights, 7);
  784          rotate_array(dv_weights, du_weights, 7);
  785          make_kernel(kernel_dv, dv_weights, 7);
  786 
  787          for(n = 0; n < 49; ++n)
  788          {
  789             usum += fabsf(kernel_du[n].w);
  790             vsum += fabsf(kernel_dv[n].w);
  791          }
  792          for(n = 0; n < 49; ++n)
  793          {
  794             kernel_du[n].w /= usum;
  795             kernel_dv[n].w /= vsum;
  796          }
  797 
  798          break;
  799       }
  800       case FILTER_9x9:
  801       {
  802          float du_weights[]=
  803          {
  804             -1, -2, -3, -4, 0, 4, 3, 2, 1,
  805             -2, -3, -4, -5, 0, 5, 4, 3, 2,
  806             -3, -4, -5, -6, 0, 6, 5, 4, 3,
  807             -4, -5, -6, -7, 0, 7, 6, 5, 4,
  808             -5, -6, -7, -8, 0, 8, 7, 6, 5,
  809             -4, -5, -6, -7, 0, 7, 6, 5, 4,
  810             -3, -4, -5, -6, 0, 6, 5, 4, 3,
  811             -2, -3, -4, -5, 0, 5, 4, 3, 2,
  812             -1, -2, -3, -4, 0, 4, 3, 2, 1
  813          };
  814          float dv_weights[81];
  815          int n;
  816          float usum = 0, vsum = 0;
  817 
  818          num_elements = 81;
  819          kernel_du = (kernel_element*)g_malloc(81 * sizeof(kernel_element));
  820          kernel_dv = (kernel_element*)g_malloc(81 * sizeof(kernel_element));
  821 
  822          make_kernel(kernel_du, du_weights, 9);
  823          rotate_array(dv_weights, du_weights, 9);
  824          make_kernel(kernel_dv, dv_weights, 9);
  825 
  826          for(n = 0; n < 81; ++n)
  827          {
  828             usum += fabsf(kernel_du[n].w);
  829             vsum += fabsf(kernel_dv[n].w);
  830          }
  831          for(n = 0; n < 81; ++n)
  832          {
  833             kernel_du[n].w /= usum;
  834             kernel_dv[n].w /= vsum;
  835          }
  836 
  837          break;
  838       }
  839    }
  840 
  841    if(nmapvals.conversion == CONVERT_BIASED_RGB)
  842    {
  843       /* approximated average color of the image
  844        * scale to 16x16, accumulate the pixels and average */
  845       unsigned int sum[3];
  846 
  847       tmp = g_malloc(16 * 16 * bpp);
  848       scale_pixels(tmp, 16, 16, src, width, height, bpp);
  849 
  850       sum[0] = sum[1] = sum[2] = 0;
  851 
  852       s = src;
  853       for(y = 0; y < 16; ++y)
  854       {
  855          for(x = 0; x < 16; ++x)
  856          {
  857             sum[0] += *s++;
  858             sum[1] += *s++;
  859             sum[2] += *s++;
  860             if(bpp == 4) s++;
  861          }
  862       }
  863 
  864       rgb_bias[0] = (float)sum[0] / 256.0f;
  865       rgb_bias[1] = (float)sum[1] / 256.0f;
  866       rgb_bias[2] = (float)sum[2] / 256.0f;
  867 
  868       g_free(tmp);
  869    }
  870    else
  871    {
  872       rgb_bias[0] = 0;
  873       rgb_bias[1] = 0;
  874       rgb_bias[2] = 0;
  875    }
  876 
  877    if(nmapvals.conversion != CONVERT_NORMALIZE_ONLY &&
  878       nmapvals.conversion != CONVERT_DUDV_TO_NORMAL &&
  879       nmapvals.conversion != CONVERT_HEIGHTMAP)
  880    {
  881       s = src;
  882       for(y = 0; y < height; ++y)
  883       {
  884          for(x = 0; x < width; ++x)
  885          {
  886             if(!nmapvals.height_source)
  887             {
  888                switch(nmapvals.conversion)
  889                {
  890                   case CONVERT_NONE:
  891                      val = (float)s[0] * 0.3f +
  892                            (float)s[1] * 0.59f +
  893                            (float)s[2] * 0.11f;
  894                      break;
  895                   case CONVERT_BIASED_RGB:
  896                      val = (((float)max(0, s[0] - rgb_bias[0])) * 0.3f ) +
  897                            (((float)max(0, s[1] - rgb_bias[1])) * 0.59f) +
  898                            (((float)max(0, s[2] - rgb_bias[2])) * 0.11f);
  899                      break;
  900                   case CONVERT_RED:
  901                      val = (float)s[0];
  902                      break;
  903                   case CONVERT_GREEN:
  904                      val = (float)s[1];
  905                      break;
  906                   case CONVERT_BLUE:
  907                      val = (float)s[2];
  908                      break;
  909                   case CONVERT_MAX_RGB:
  910                      val = (float)max(s[0], max(s[1], s[2]));
  911                      break;
  912                   case CONVERT_MIN_RGB:
  913                      val = (float)min(s[0], min(s[1], s[2]));
  914                      break;
  915                   case CONVERT_COLORSPACE:
  916                      val = (1.0f - ((1.0f - ((float)s[0] / 255.0f)) *
  917                                     (1.0f - ((float)s[1] / 255.0f)) *
  918                                     (1.0f - ((float)s[2] / 255.0f)))) * 255.0f;
  919                      break;
  920                   default:
  921                      val = 255.0f;
  922                      break;
  923                }
  924             }
  925             else
  926                val = (float)s[3];
  927 
  928             heights[x + y * width] = val * oneover255;
  929 
  930             s += bpp;
  931          }
  932       }
  933    }
  934 
  935 #define HEIGHT(x,y) \
  936    (heights[(max(0, min(width - 1, (x)))) + (max(0, min(height - 1, (y)))) * width])
  937 #define HEIGHT_WRAP(x,y) \
  938    (heights[((x) < 0 ? (width + (x)) : ((x) >= width ? ((x) - width) : (x)))+ \
  939             (((y) < 0 ? (height + (y)) : ((y) >= height ? ((y) - height) : (y))) * width)])
  940 
  941    if(preview_mode)
  942    {
  943       cursor = gdk_cursor_new(GDK_WATCH);
  944       gdk_window_set_cursor(GDK_WINDOW(dialog->window), cursor);
  945       gdk_cursor_unref(cursor);
  946    }
  947 
  948    for(y = 0; y < height; ++y)
  949    {
  950       while(gtk_events_pending())
  951          gtk_main_iteration();
  952 
  953       for(x = 0; x < width; ++x)
  954       {
  955          d = dst + ((y * rowbytes) + (x * bpp));
  956          s = src + ((y * rowbytes) + (x * bpp));
  957 
  958          if(nmapvals.conversion == CONVERT_NORMALIZE_ONLY ||
  959             nmapvals.conversion == CONVERT_HEIGHTMAP)
  960          {
  961             n[0] = (((float)s[0] * oneover255) - 0.5f) * 2.0f;
  962             n[1] = (((float)s[1] * oneover255) - 0.5f) * 2.0f;
  963             n[2] = (((float)s[2] * oneover255) - 0.5f) * 2.0f;
  964             n[0] *= nmapvals.scale;
  965             n[1] *= nmapvals.scale;
  966          }
  967          else if(nmapvals.conversion == CONVERT_DUDV_TO_NORMAL)
  968          {
  969             n[0] = (((float)s[0] * oneover255) - 0.5f) * 2.0f;
  970             n[1] = (((float)s[1] * oneover255) - 0.5f) * 2.0f;
  971             n[2] = sqrtf(1.0f - (n[0] * n[0] - n[1] * n[1]));
  972             n[0] *= nmapvals.scale;
  973             n[1] *= nmapvals.scale;
  974          }
  975          else
  976          {
  977             du = 0; dv = 0;
  978             if(!nmapvals.wrap)
  979             {
  980                for(i = 0; i < num_elements; ++i)
  981                   du += HEIGHT(x + kernel_du[i].x,
  982                                y + kernel_du[i].y) * kernel_du[i].w;
  983                for(i = 0; i < num_elements; ++i)
  984                   dv += HEIGHT(x + kernel_dv[i].x,
  985                                y + kernel_dv[i].y) * kernel_dv[i].w;
  986             }
  987             else
  988             {
  989                for(i = 0; i < num_elements; ++i)
  990                   du += HEIGHT_WRAP(x + kernel_du[i].x,
  991                                     y + kernel_du[i].y) * kernel_du[i].w;
  992                for(i = 0; i < num_elements; ++i)
  993                   dv += HEIGHT_WRAP(x + kernel_dv[i].x,
  994                                     y + kernel_dv[i].y) * kernel_dv[i].w;
  995             }
  996 
  997             n[0] = -du * nmapvals.scale;
  998             n[1] = -dv * nmapvals.scale;
  999             n[2] = 1.0f;
 1000          }
 1001 
 1002          NORMALIZE(n);
 1003 
 1004          if(n[2] < nmapvals.minz)
 1005          {
 1006             n[2] = nmapvals.minz;
 1007             NORMALIZE(n);
 1008          }
 1009 
 1010          if(nmapvals.xinvert) n[0] = -n[0];
 1011          if(nmapvals.yinvert) n[1] = -n[1];
 1012          if(nmapvals.swapRGB)
 1013          {
 1014             val = n[0];
 1015             n[0] = n[2];
 1016             n[2] = val;
 1017          }
 1018 
 1019          if(!nmapvals.dudv)
 1020          {
 1021             *d++ = (unsigned char)((n[0] + 1.0f) * 127.5f);
 1022             *d++ = (unsigned char)((n[1] + 1.0f) * 127.5f);
 1023             *d++ = (unsigned char)((n[2] + 1.0f) * 127.5f);
 1024 
 1025             if(drawable->bpp == 4)
 1026             {
 1027                switch(nmapvals.alpha)
 1028                {
 1029                   case ALPHA_NONE:
 1030                      *d++ = s[3]; break;
 1031                   case ALPHA_HEIGHT:
 1032                      *d++ = (unsigned char)(heights[x + y * width] * 255.0f); break;
 1033                   case ALPHA_INVERSE_HEIGHT:
 1034                      *d++ = 255 - (unsigned char)(heights[x + y * width] * 255.0f); break;
 1035                   case ALPHA_ZERO:
 1036                      *d++ = 0; break;
 1037                   case ALPHA_ONE:
 1038                      *d++ = 255; break;
 1039                   case ALPHA_INVERT:
 1040                      *d++ = 255 - s[3]; break;
 1041                   case ALPHA_MAP:
 1042                      *d++ = sample_alpha_map(amap, x, y, amap_w, amap_h,
 1043                                              width, height); break;
 1044                   default:
 1045                      *d++ = s[3]; break;
 1046                }
 1047             }
 1048          }
 1049          else
 1050          {
 1051             if(nmapvals.dudv == DUDV_8BIT_SIGNED ||
 1052                nmapvals.dudv == DUDV_8BIT_UNSIGNED)
 1053             {
 1054                if(nmapvals.dudv == DUDV_8BIT_UNSIGNED)
 1055                {
 1056                   n[0] += 1.0f;
 1057                   n[1] += 1.0f;
 1058                }
 1059                *d++ = (unsigned char)(n[0] * 127.5f);
 1060                *d++ = (unsigned char)(n[1] * 127.5f);
 1061                *d++ = 0;
 1062                if(drawable->bpp == 4) *d++ = 255;
 1063             }
 1064             else if(nmapvals.dudv == DUDV_16BIT_SIGNED ||
 1065                     nmapvals.dudv == DUDV_16BIT_UNSIGNED)
 1066             {
 1067                unsigned short *d16 = (unsigned short*)d;
 1068                if(nmapvals.dudv == DUDV_16BIT_UNSIGNED)
 1069                {
 1070                   n[0] += 1.0f;
 1071                   n[1] += 1.0f;
 1072                }
 1073                *d16++ = (unsigned short)(n[0] * 32767.5f);
 1074                *d16++ = (unsigned short)(n[1] * 32767.5f);
 1075             }
 1076          }
 1077       }
 1078 
 1079       if(!preview_mode)
 1080          gimp_progress_update((double)(y - 1) / (double)(height - 2));
 1081    }
 1082 
 1083    if(nmapvals.conversion == CONVERT_HEIGHTMAP)
 1084       make_heightmap(dst, width, height, bpp);
 1085 
 1086 #undef HEIGHT
 1087 #undef HEIGHT_WRAP
 1088 
 1089    if(preview_mode)
 1090    {
 1091       update_3D_preview(width, height, bpp, dst);
 1092 
 1093       pw = GIMP_PREVIEW_AREA(preview)->width;
 1094       ph = GIMP_PREVIEW_AREA(preview)->height;
 1095       rowbytes = pw * bpp;
 1096 
 1097       tmp = g_malloc(pw * ph * bpp);
 1098       scale_pixels(tmp, pw, ph, dst, width, height, bpp);
 1099 
 1100       gimp_preview_area_draw(GIMP_PREVIEW_AREA(preview), 0, 0, pw, ph,
 1101                              (bpp == 4) ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE,
 1102                              tmp, rowbytes);
 1103 
 1104       g_free(tmp);
 1105 
 1106       gdk_window_set_cursor(GDK_WINDOW(dialog->window), 0);
 1107    }
 1108    else
 1109    {
 1110       gimp_progress_update(100.0);
 1111 
 1112       gimp_pixel_rgn_init(&dst_rgn, drawable, 0, 0, width, height, 1, 1);
 1113       gimp_pixel_rgn_set_rect(&dst_rgn, dst, 0, 0, width, height);
 1114 
 1115       gimp_drawable_flush(drawable);
 1116       gimp_drawable_merge_shadow(drawable->drawable_id, 1);
 1117       gimp_drawable_update(drawable->drawable_id, 0, 0, width, height);
 1118    }
 1119 
 1120    g_free(heights);
 1121    g_free(src);
 1122    g_free(dst);
 1123    g_free(kernel_du);
 1124    g_free(kernel_dv);
 1125    if(amap) g_free(amap);
 1126 
 1127    return(0);
 1128 }
 1129 
 1130 static void do_cleanup(gpointer data)
 1131 {
 1132    destroy_3D_preview();
 1133    gtk_main_quit();
 1134 }
 1135 
 1136 static int update_preview = 0;
 1137 
 1138 static gint idle_callback(gpointer data)
 1139 {
 1140    if(update_preview)
 1141    {
 1142       update_preview = 0;
 1143       normalmap((GimpDrawable*)data, TRUE);
 1144    }
 1145    return(1);
 1146 }
 1147 
 1148 static void filter_type_selected(GtkWidget *widget, gpointer data)
 1149 {
 1150    if(nmapvals.filter != (gint)(long)data)
 1151    {
 1152       nmapvals.filter = (gint)(long)data;
 1153       update_preview = 1;
 1154    }
 1155 }
 1156 
 1157 static void minz_changed(GtkWidget *widget, gpointer data)
 1158 {
 1159    nmapvals.minz = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
 1160    update_preview = 1;
 1161 }
 1162 
 1163 static void scale_changed(GtkWidget *widget, gpointer data)
 1164 {
 1165    nmapvals.scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
 1166    update_preview = 1;
 1167 }
 1168 
 1169 static void height_source_selected(GtkWidget *widget, gpointer data)
 1170 {
 1171    GtkWidget *opt;
 1172 
 1173    if(nmapvals.height_source == (gint)(long)data) return;
 1174 
 1175    nmapvals.height_source = (gint)(long)data;
 1176 
 1177    opt = g_object_get_data(G_OBJECT(widget), "conversion_opt");
 1178    if(!nmapvals.height_source)
 1179    {
 1180       gtk_widget_set_sensitive(opt, 1);
 1181    }
 1182    else
 1183    {
 1184       nmapvals.conversion = CONVERT_NONE;
 1185       gtk_option_menu_set_history(GTK_OPTION_MENU(opt), nmapvals.conversion);
 1186       gtk_widget_set_sensitive(opt, 0);
 1187    }
 1188 
 1189    update_preview = 1;
 1190 }
 1191 
 1192 static void alpha_result_selected(GtkWidget *widget, gpointer data)
 1193 {
 1194    if(nmapvals.alpha != (gint)(long)data)
 1195    {
 1196       nmapvals.alpha = (gint)(long)data;
 1197       update_preview = 1;
 1198    }
 1199 }
 1200 
 1201 static void conversion_selected(GtkWidget *widget, gpointer data)
 1202 {
 1203    GtkWidget *contrast_spin;
 1204 
 1205    if(nmapvals.conversion != (gint)(long)data)
 1206    {
 1207       nmapvals.conversion = (gint)(long)data;
 1208       contrast_spin = g_object_get_data(G_OBJECT(widget), "contrast_spin");
 1209       gtk_widget_set_sensitive(contrast_spin, nmapvals.conversion == CONVERT_HEIGHTMAP);
 1210       update_preview = 1;
 1211    }
 1212 }
 1213 
 1214 static void preview_clicked(GtkWidget *widget, gpointer data)
 1215 {
 1216    GimpDrawable *drawable;
 1217    if(!is_3D_preview_active())
 1218    {
 1219       drawable = g_object_get_data(G_OBJECT(widget), "drawable");
 1220       show_3D_preview(drawable);
 1221       update_preview = 1;
 1222    }
 1223 }
 1224 
 1225 static void dudv_selected(GtkWidget *widget, gpointer data)
 1226 {
 1227    GimpDrawable *drawable;
 1228    GtkWidget *opt;
 1229 
 1230    if(nmapvals.dudv == (gint)(long)data) return;
 1231 
 1232    nmapvals.dudv = (gint)(long)data;
 1233 
 1234    drawable = g_object_get_data(G_OBJECT(widget), "drawable");
 1235    opt = g_object_get_data(G_OBJECT(widget), "alpha_opt");
 1236 
 1237    if(nmapvals.dudv == DUDV_NONE)
 1238    {
 1239       if(drawable->bpp == 4)
 1240          gtk_widget_set_sensitive(opt, 1);
 1241    }
 1242    else
 1243    {
 1244       nmapvals.alpha = 0;
 1245       gtk_option_menu_set_history(GTK_OPTION_MENU(opt), nmapvals.alpha);
 1246       gtk_widget_set_sensitive(opt, 0);
 1247    }
 1248 
 1249    update_preview = 1;
 1250 }
 1251 
 1252 static void contrast_changed(GtkWidget *widget, gpointer data)
 1253 {
 1254    nmapvals.contrast = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
 1255    update_preview = 1;
 1256 }
 1257 
 1258 static void toggle_clicked(GtkWidget *widget, gpointer data)
 1259 {
 1260    *((int*)data) = !(*((int*)data));
 1261    update_preview = 1;
 1262 }
 1263 
 1264 static gint dialog_constrain(gint32 image_id, gint32 drawable_id,
 1265                              gpointer data)
 1266 {
 1267    if(drawable_id == -1) return(1);
 1268    if(gimp_drawable_is_gray(drawable_id))
 1269    {
 1270       *(int*)data += 1;
 1271       return(1);
 1272    }
 1273    return(0);
 1274 }
 1275 
 1276 static void alphamap_callback(gint32 id, gpointer data)
 1277 {
 1278    if(nmapvals.alphamap_id != id)
 1279    {
 1280       nmapvals.alphamap_id = id;
 1281       update_preview = 1;
 1282    }
 1283 }
 1284 
 1285 static void normalmap_dialog_response(GtkWidget *widget, gint response_id,
 1286                                       gpointer data)
 1287 {
 1288    switch(response_id)
 1289    {
 1290       case GTK_RESPONSE_OK:
 1291          runme = 1;
 1292       default:
 1293          gtk_widget_destroy(widget);
 1294          break;
 1295    }
 1296 }
 1297 
 1298 static gint normalmap_dialog(GimpDrawable *drawable)
 1299 {
 1300    GtkWidget *hbox, *vbox, *abox;
 1301    GtkWidget *btn;
 1302    GtkWidget *table;
 1303    GtkWidget *opt, *alpha_result_opt;
 1304    GtkWidget *menu;
 1305    GtkWidget *menuitem, *item_height_source[2];
 1306    GtkWidget *label;
 1307    GtkObject *adj;
 1308    GtkWidget *spin;
 1309    GtkWidget *frame;
 1310    GtkWidget *check;
 1311    GtkWidget *conversion_menu;
 1312    GList *curr;
 1313    int num_amaps = 0;
 1314 
 1315    if(nmapvals.alpha == ALPHA_MAP)
 1316    {
 1317       if(!gimp_drawable_get(nmapvals.alphamap_id) ||
 1318          !gimp_drawable_is_gray(nmapvals.alphamap_id))
 1319       {
 1320          nmapvals.alpha = 0;
 1321          nmapvals.alphamap_id = 0;
 1322       }
 1323    }
 1324 
 1325    gimp_ui_init("normalmap", TRUE);
 1326 
 1327    dialog = gimp_dialog_new("Normalmap", "normalmap",
 1328                             0, 0, gimp_standard_help_func, 0,
 1329                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1330                             GTK_STOCK_OK, GTK_RESPONSE_OK,
 1331                             NULL);
 1332 
 1333    gtk_signal_connect(GTK_OBJECT(dialog), "response",
 1334                       GTK_SIGNAL_FUNC(normalmap_dialog_response),
 1335                       0);
 1336    gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
 1337                       GTK_SIGNAL_FUNC(do_cleanup),
 1338                       0);
 1339 
 1340    hbox = gtk_hbox_new(0, 8);
 1341    gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
 1342    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox, 1, 1, 0);
 1343    gtk_widget_show(hbox);
 1344 
 1345    vbox = gtk_vbox_new(0, 8);
 1346    gtk_box_pack_start(GTK_BOX(hbox), vbox, 1, 1, 0);
 1347    gtk_widget_show(vbox);
 1348 
 1349    frame = gtk_frame_new("Preview");
 1350    gtk_box_pack_start(GTK_BOX(vbox), frame, 0, 0, 0);
 1351    gtk_widget_show(frame);
 1352 
 1353    abox = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
 1354    gtk_container_set_border_width(GTK_CONTAINER (abox), 4);
 1355    gtk_container_add(GTK_CONTAINER(frame), abox);
 1356    gtk_widget_show(abox);
 1357 
 1358    frame = gtk_frame_new(NULL);
 1359    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
 1360    gtk_container_add(GTK_CONTAINER(abox), frame);
 1361    gtk_widget_show(frame);
 1362 
 1363    preview = gimp_preview_area_new();
 1364    gimp_preview_area_set_max_size(GIMP_PREVIEW_AREA(preview), PREVIEW_SIZE, PREVIEW_SIZE);
 1365    gtk_drawing_area_size(GTK_DRAWING_AREA(preview), PREVIEW_SIZE, PREVIEW_SIZE);
 1366    gtk_container_add(GTK_CONTAINER(frame), preview);
 1367    gtk_widget_show(preview);
 1368 
 1369    btn = gtk_button_new_with_label("3D Preview");
 1370    gtk_signal_connect(GTK_OBJECT(btn), "clicked",
 1371                       GTK_SIGNAL_FUNC(preview_clicked), 0);
 1372    g_object_set_data(G_OBJECT(btn), "drawable", drawable);
 1373    gtk_box_pack_start(GTK_BOX(vbox), btn, 0, 0, 0);
 1374    gtk_widget_show(btn);
 1375 
 1376    label = gtk_label_new("Alpha map:");
 1377    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1378    gtk_widget_show(label);
 1379    gtk_box_pack_start(GTK_BOX(vbox), label, 0, 0, 0);
 1380 
 1381    opt = gtk_option_menu_new();
 1382    gtk_widget_show(opt);
 1383    menu = gimp_drawable_menu_new(dialog_constrain,
 1384                                  alphamap_callback,
 1385                                  &num_amaps, drawable->drawable_id);
 1386    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1387    gtk_box_pack_start(GTK_BOX(vbox), opt, 0, 0, 0);
 1388 
 1389    if(drawable->bpp != 4)
 1390       gtk_widget_set_sensitive(opt, 0);
 1391 
 1392    table = gtk_table_new(9, 2, 0);
 1393    gtk_widget_show(table);
 1394    gtk_box_pack_start(GTK_BOX(hbox), table, 1, 1, 0);
 1395    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1396    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1397 
 1398    opt = gtk_option_menu_new();
 1399    gtk_widget_show(opt);
 1400    gimp_table_attach_aligned(GTK_TABLE(table), 0, 0, "Filter:", 0, 0.5,
 1401                              opt, 1, 0);
 1402 
 1403    menu = gtk_menu_new();
 1404 
 1405    menuitem = gtk_menu_item_new_with_label("4 sample");
 1406    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1407                       GTK_SIGNAL_FUNC(filter_type_selected),
 1408                       (gpointer)FILTER_NONE);
 1409    gtk_widget_show(menuitem);
 1410    gtk_menu_append(GTK_MENU(menu), menuitem);
 1411    menuitem = gtk_menu_item_new_with_label("Sobel 3x3");
 1412    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1413                       GTK_SIGNAL_FUNC(filter_type_selected),
 1414                       (gpointer)FILTER_SOBEL_3x3);
 1415    gtk_widget_show(menuitem);
 1416    gtk_menu_append(GTK_MENU(menu), menuitem);
 1417    menuitem = gtk_menu_item_new_with_label("Sobel 5x5");
 1418    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1419                       GTK_SIGNAL_FUNC(filter_type_selected),
 1420                       (gpointer)FILTER_SOBEL_5x5);
 1421    gtk_widget_show(menuitem);
 1422    gtk_menu_append(GTK_MENU(menu), menuitem);
 1423    menuitem = gtk_menu_item_new_with_label("Prewitt 3x3");
 1424    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1425                       GTK_SIGNAL_FUNC(filter_type_selected),
 1426                       (gpointer)FILTER_PREWITT_3x3);
 1427    gtk_widget_show(menuitem);
 1428    gtk_menu_append(GTK_MENU(menu), menuitem);
 1429    menuitem = gtk_menu_item_new_with_label("Prewitt 5x5");
 1430    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1431                       GTK_SIGNAL_FUNC(filter_type_selected),
 1432                       (gpointer)FILTER_PREWITT_5x5);
 1433    gtk_widget_show(menuitem);
 1434    gtk_menu_append(GTK_MENU(menu), menuitem);
 1435    menuitem = gtk_menu_item_new_with_label("3x3");
 1436    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1437                       GTK_SIGNAL_FUNC(filter_type_selected),
 1438                       (gpointer)FILTER_3x3);
 1439    gtk_widget_show(menuitem);
 1440    gtk_menu_append(GTK_MENU(menu), menuitem);
 1441    menuitem = gtk_menu_item_new_with_label("5x5");
 1442    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1443                       GTK_SIGNAL_FUNC(filter_type_selected),
 1444                       (gpointer)FILTER_5x5);
 1445    gtk_widget_show(menuitem);
 1446    gtk_menu_append(GTK_MENU(menu), menuitem);
 1447    menuitem = gtk_menu_item_new_with_label("7x7");
 1448    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1449                       GTK_SIGNAL_FUNC(filter_type_selected),
 1450                       (gpointer)FILTER_7x7);
 1451    gtk_widget_show(menuitem);
 1452    gtk_menu_append(GTK_MENU(menu), menuitem);
 1453    menuitem = gtk_menu_item_new_with_label("9x9");
 1454    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1455                       GTK_SIGNAL_FUNC(filter_type_selected),
 1456                       (gpointer)FILTER_9x9);
 1457    gtk_widget_show(menuitem);
 1458    gtk_menu_append(GTK_MENU(menu), menuitem);
 1459    gtk_menu_set_active(GTK_MENU(menu), nmapvals.filter);
 1460    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1461 
 1462    adj = gtk_adjustment_new(nmapvals.minz, 0, 1, 0.01, 0.05, 0.1);
 1463    spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.01, 5);
 1464    gtk_widget_show(spin);
 1465    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_IF_VALID);
 1466    gtk_signal_connect(GTK_OBJECT(spin), "value_changed",
 1467                       GTK_SIGNAL_FUNC(minz_changed), 0);
 1468    gimp_table_attach_aligned(GTK_TABLE(table), 0, 1, "Minimum Z:", 0, 0.5,
 1469                              spin, 1, 0);
 1470 
 1471    adj = gtk_adjustment_new(nmapvals.scale, -100, 100, 1, 5, 5);
 1472    spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 5);
 1473    gtk_widget_show(spin);
 1474    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_IF_VALID);
 1475    gtk_signal_connect(GTK_OBJECT(spin), "value_changed",
 1476                       GTK_SIGNAL_FUNC(scale_changed), 0);
 1477    gimp_table_attach_aligned(GTK_TABLE(table), 0, 2, "Scale:", 0, 0.5,
 1478                              spin, 1, 0);
 1479 
 1480    opt = gtk_option_menu_new();
 1481    gtk_widget_show(opt);
 1482    gimp_table_attach_aligned(GTK_TABLE(table), 0, 3, "Height source:", 0, 0.5,
 1483                              opt, 1, 0);
 1484 
 1485    menu = gtk_menu_new();
 1486 
 1487    if(drawable->bpp != 4)
 1488       nmapvals.height_source = 0;
 1489 
 1490    menuitem = item_height_source[0] = gtk_menu_item_new_with_label("Average RGB");
 1491    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1492                       GTK_SIGNAL_FUNC(height_source_selected),
 1493                       (gpointer)0);
 1494    gtk_widget_show(menuitem);
 1495    gtk_menu_append(GTK_MENU(menu), menuitem);
 1496    menuitem = item_height_source[1] = gtk_menu_item_new_with_label("Alpha");
 1497    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1498                       GTK_SIGNAL_FUNC(height_source_selected),
 1499                       (gpointer)1);
 1500    gtk_widget_show(menuitem);
 1501    gtk_menu_append(GTK_MENU(menu), menuitem);
 1502 
 1503    gtk_menu_set_active(GTK_MENU(menu), nmapvals.height_source);
 1504    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1505 
 1506    if(drawable->bpp != 4)
 1507       gtk_widget_set_sensitive(opt, 0);
 1508 
 1509    opt = alpha_result_opt = gtk_option_menu_new();
 1510    gtk_widget_show(opt);
 1511    gimp_table_attach_aligned(GTK_TABLE(table), 0, 4, "Alpha channel:", 0, 0.5,
 1512                              opt, 1, 0);
 1513 
 1514    if(drawable->bpp != 4)
 1515       nmapvals.alpha = 0;
 1516 
 1517    menu = gtk_menu_new();
 1518 
 1519    menuitem = gtk_menu_item_new_with_label("Unchanged");
 1520    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1521                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1522                       (gpointer)ALPHA_NONE);
 1523    gtk_widget_show(menuitem);
 1524    gtk_menu_append(GTK_MENU(menu), menuitem);
 1525    menuitem = gtk_menu_item_new_with_label("Height");
 1526    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1527                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1528                       (gpointer)ALPHA_HEIGHT);
 1529    gtk_widget_show(menuitem);
 1530    gtk_menu_append(GTK_MENU(menu), menuitem);
 1531    menuitem = gtk_menu_item_new_with_label("Inverse height");
 1532    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1533                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1534                       (gpointer)ALPHA_INVERSE_HEIGHT);
 1535    gtk_widget_show(menuitem);
 1536    gtk_menu_append(GTK_MENU(menu), menuitem);
 1537    menuitem = gtk_menu_item_new_with_label("Set to 0");
 1538    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1539                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1540                       (gpointer)ALPHA_ZERO);
 1541    gtk_widget_show(menuitem);
 1542    gtk_menu_append(GTK_MENU(menu), menuitem);
 1543    menuitem = gtk_menu_item_new_with_label("Set to 1");
 1544    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1545                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1546                       (gpointer)ALPHA_ONE);
 1547    gtk_widget_show(menuitem);
 1548    gtk_menu_append(GTK_MENU(menu), menuitem);
 1549    menuitem = gtk_menu_item_new_with_label("Invert");
 1550    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1551                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1552                       (gpointer)ALPHA_INVERT);
 1553    gtk_widget_show(menuitem);
 1554    gtk_menu_append(GTK_MENU(menu), menuitem);
 1555    menuitem = gtk_menu_item_new_with_label("Use alpha map");
 1556    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1557                       GTK_SIGNAL_FUNC(alpha_result_selected),
 1558                       (gpointer)ALPHA_MAP);
 1559    gtk_widget_show(menuitem);
 1560    gtk_menu_append(GTK_MENU(menu), menuitem);
 1561 
 1562    if(num_amaps == 0)
 1563    {
 1564       gtk_widget_set_sensitive(menuitem, 0);
 1565       if(nmapvals.alpha == ALPHA_MAP)
 1566          nmapvals.alpha = 0;
 1567    }
 1568 
 1569    gtk_menu_set_active(GTK_MENU(menu), nmapvals.alpha);
 1570    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1571 
 1572    if(drawable->bpp !=4 || nmapvals.dudv != DUDV_NONE)
 1573       gtk_widget_set_sensitive(opt, 0);
 1574 
 1575    opt = gtk_option_menu_new();
 1576    gtk_widget_show(opt);
 1577    gimp_table_attach_aligned(GTK_TABLE(table), 0, 5, "Conversion:", 0, 0.5,
 1578                              opt, 1, 0);
 1579 
 1580    g_object_set_data(G_OBJECT(item_height_source[0]), "conversion_opt", opt);
 1581    g_object_set_data(G_OBJECT(item_height_source[1]), "conversion_opt", opt);
 1582 
 1583    conversion_menu = menu = gtk_menu_new();
 1584 
 1585    menuitem = gtk_menu_item_new_with_label("None");
 1586    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1587                       GTK_SIGNAL_FUNC(conversion_selected),
 1588                       (gpointer)CONVERT_NONE);
 1589    gtk_widget_show(menuitem);
 1590    gtk_menu_append(GTK_MENU(menu), menuitem);
 1591    menuitem = gtk_menu_item_new_with_label("Biased RGB");
 1592    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1593                       GTK_SIGNAL_FUNC(conversion_selected),
 1594                       (gpointer)CONVERT_BIASED_RGB);
 1595    gtk_widget_show(menuitem);
 1596    gtk_menu_append(GTK_MENU(menu), menuitem);
 1597    menuitem = gtk_menu_item_new_with_label("Red");
 1598    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1599                       GTK_SIGNAL_FUNC(conversion_selected),
 1600                       (gpointer)CONVERT_RED);
 1601    gtk_widget_show(menuitem);
 1602    gtk_menu_append(GTK_MENU(menu), menuitem);
 1603    menuitem = gtk_menu_item_new_with_label("Green");
 1604    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1605                       GTK_SIGNAL_FUNC(conversion_selected),
 1606                       (gpointer)CONVERT_GREEN);
 1607    gtk_widget_show(menuitem);
 1608    gtk_menu_append(GTK_MENU(menu), menuitem);
 1609    menuitem = gtk_menu_item_new_with_label("Blue");
 1610    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1611                       GTK_SIGNAL_FUNC(conversion_selected),
 1612                       (gpointer)CONVERT_BLUE);
 1613    gtk_widget_show(menuitem);
 1614    gtk_menu_append(GTK_MENU(menu), menuitem);
 1615    menuitem = gtk_menu_item_new_with_label("Max RGB");
 1616    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1617                       GTK_SIGNAL_FUNC(conversion_selected),
 1618                       (gpointer)CONVERT_MAX_RGB);
 1619    gtk_widget_show(menuitem);
 1620    gtk_menu_append(GTK_MENU(menu), menuitem);
 1621    menuitem = gtk_menu_item_new_with_label("Min RGB");
 1622    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1623                       GTK_SIGNAL_FUNC(conversion_selected),
 1624                       (gpointer)CONVERT_MIN_RGB);
 1625    gtk_widget_show(menuitem);
 1626    gtk_menu_append(GTK_MENU(menu), menuitem);
 1627    menuitem = gtk_menu_item_new_with_label("Colorspace");
 1628    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1629                       GTK_SIGNAL_FUNC(conversion_selected),
 1630                       (gpointer)CONVERT_COLORSPACE);
 1631    gtk_widget_show(menuitem);
 1632    gtk_menu_append(GTK_MENU(menu), menuitem);
 1633    menuitem = gtk_menu_item_new_with_label("Normalize only");
 1634    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1635                       GTK_SIGNAL_FUNC(conversion_selected),
 1636                       (gpointer)CONVERT_NORMALIZE_ONLY);
 1637    gtk_widget_show(menuitem);
 1638    gtk_menu_append(GTK_MENU(menu), menuitem);
 1639    menuitem = gtk_menu_item_new_with_label("DUDV to Normal");
 1640    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1641                       GTK_SIGNAL_FUNC(conversion_selected),
 1642                       (gpointer)CONVERT_DUDV_TO_NORMAL);
 1643    gtk_widget_show(menuitem);
 1644    gtk_menu_append(GTK_MENU(menu), menuitem);
 1645    menuitem = gtk_menu_item_new_with_label("Convert to height");
 1646    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1647                       GTK_SIGNAL_FUNC(conversion_selected),
 1648                       (gpointer)CONVERT_HEIGHTMAP);
 1649    gtk_widget_show(menuitem);
 1650    gtk_menu_append(GTK_MENU(menu), menuitem);
 1651 
 1652    gtk_menu_set_active(GTK_MENU(menu), nmapvals.conversion);
 1653    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1654 
 1655    if(nmapvals.height_source)
 1656       gtk_widget_set_sensitive(opt, 0);
 1657 
 1658    opt = gtk_option_menu_new();
 1659    gtk_widget_show(opt);
 1660    gimp_table_attach_aligned(GTK_TABLE(table), 0, 6, "DU/DV map:", 0, 0.5,
 1661                              opt, 1, 0);
 1662 
 1663    if(drawable->bpp != 4 && (nmapvals.dudv == DUDV_16BIT_SIGNED ||
 1664                              nmapvals.dudv == DUDV_16BIT_UNSIGNED))
 1665       nmapvals.dudv = DUDV_NONE;
 1666 
 1667    menu = gtk_menu_new();
 1668 
 1669    menuitem = gtk_menu_item_new_with_label("None");
 1670    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1671                       GTK_SIGNAL_FUNC(dudv_selected),
 1672                       (gpointer)DUDV_NONE);
 1673    g_object_set_data(G_OBJECT(menuitem), "drawable", drawable);
 1674    g_object_set_data(G_OBJECT(menuitem), "alpha_opt", alpha_result_opt);
 1675    gtk_widget_show(menuitem);
 1676    gtk_menu_append(GTK_MENU(menu), menuitem);
 1677    menuitem = gtk_menu_item_new_with_label("8 bits");
 1678    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1679                       GTK_SIGNAL_FUNC(dudv_selected),
 1680                       (gpointer)DUDV_8BIT_SIGNED);
 1681    g_object_set_data(G_OBJECT(menuitem), "drawable", drawable);
 1682    g_object_set_data(G_OBJECT(menuitem), "alpha_opt", alpha_result_opt);
 1683    gtk_widget_show(menuitem);
 1684    gtk_menu_append(GTK_MENU(menu), menuitem);
 1685    menuitem = gtk_menu_item_new_with_label("8 bits (unsigned)");
 1686    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1687                       GTK_SIGNAL_FUNC(dudv_selected),
 1688                       (gpointer)DUDV_8BIT_UNSIGNED);
 1689    g_object_set_data(G_OBJECT(menuitem), "drawable", drawable);
 1690    g_object_set_data(G_OBJECT(menuitem), "alpha_opt", alpha_result_opt);
 1691    gtk_widget_show(menuitem);
 1692    gtk_menu_append(GTK_MENU(menu), menuitem);
 1693    menuitem = gtk_menu_item_new_with_label("16 bits");
 1694    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1695                       GTK_SIGNAL_FUNC(dudv_selected),
 1696                       (gpointer)DUDV_16BIT_SIGNED);
 1697    g_object_set_data(G_OBJECT(menuitem), "drawable", drawable);
 1698    g_object_set_data(G_OBJECT(menuitem), "alpha_opt", alpha_result_opt);
 1699    gtk_widget_show(menuitem);
 1700    gtk_menu_append(GTK_MENU(menu), menuitem);
 1701    if(drawable->bpp != 4)
 1702       gtk_widget_set_sensitive(menuitem, 0);
 1703    menuitem = gtk_menu_item_new_with_label("16 bits (unsigned)");
 1704    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1705                       GTK_SIGNAL_FUNC(dudv_selected),
 1706                       (gpointer)DUDV_16BIT_UNSIGNED);
 1707    g_object_set_data(G_OBJECT(menuitem), "drawable", drawable);
 1708    g_object_set_data(G_OBJECT(menuitem), "alpha_opt", alpha_result_opt);
 1709    gtk_widget_show(menuitem);
 1710    gtk_menu_append(GTK_MENU(menu), menuitem);
 1711    if(drawable->bpp != 4)
 1712       gtk_widget_set_sensitive(menuitem, 0);
 1713 
 1714    gtk_menu_set_active(GTK_MENU(menu), nmapvals.dudv);
 1715    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1716 
 1717    adj = gtk_adjustment_new(nmapvals.contrast, 0, 1, 0.01, 0.05, 0.1);
 1718    spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.01, 5);
 1719    gtk_widget_show(spin);
 1720    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_IF_VALID);
 1721    gtk_signal_connect(GTK_OBJECT(spin), "value_changed",
 1722                       GTK_SIGNAL_FUNC(contrast_changed), 0);
 1723    gimp_table_attach_aligned(GTK_TABLE(table), 0, 7, "Contrast:", 0, 0.5,
 1724                              spin, 1, 0);
 1725 
 1726    gtk_widget_set_sensitive(spin, nmapvals.conversion == CONVERT_HEIGHTMAP);
 1727 
 1728    curr = gtk_container_get_children(GTK_CONTAINER(conversion_menu));
 1729    while(curr)
 1730    {
 1731       g_object_set_data(G_OBJECT(curr->data), "contrast_spin", spin);
 1732       curr = curr->next;
 1733    }
 1734 
 1735    frame = gtk_frame_new("Options");
 1736    gtk_box_pack_start(GTK_BOX(hbox), frame, 0, 1, 0);
 1737    gtk_widget_show(frame);
 1738 
 1739    vbox = gtk_vbox_new(0, 0);
 1740    gtk_widget_show(vbox);
 1741    gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
 1742    gtk_container_add(GTK_CONTAINER(frame), vbox);
 1743 
 1744    check = gtk_check_button_new_with_label("Wrap");
 1745    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), nmapvals.wrap);
 1746    gtk_widget_show(check);
 1747    gtk_box_pack_start(GTK_BOX(vbox), check, 0, 1, 0);
 1748    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1749                       GTK_SIGNAL_FUNC(toggle_clicked), &nmapvals.wrap);
 1750    check = gtk_check_button_new_with_label("Invert X");
 1751    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), nmapvals.xinvert);
 1752    gtk_widget_show(check);
 1753    gtk_box_pack_start(GTK_BOX(vbox), check, 0, 1, 0);
 1754    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1755                       GTK_SIGNAL_FUNC(toggle_clicked), &nmapvals.xinvert);
 1756    check = gtk_check_button_new_with_label("Invert Y");
 1757    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), nmapvals.yinvert);
 1758    gtk_widget_show(check);
 1759    gtk_box_pack_start(GTK_BOX(vbox), check, 0, 1, 0);
 1760    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1761                       GTK_SIGNAL_FUNC(toggle_clicked), &nmapvals.yinvert);
 1762    check = gtk_check_button_new_with_label("Swap RGB");
 1763    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), nmapvals.swapRGB);
 1764    gtk_widget_show(check);
 1765    gtk_box_pack_start(GTK_BOX(vbox), check, 0, 1, 0);
 1766    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1767                       GTK_SIGNAL_FUNC(toggle_clicked), &nmapvals.swapRGB);
 1768 
 1769    gtk_widget_show(dialog);
 1770 
 1771    update_preview = 1;
 1772    gtk_timeout_add(100, idle_callback, drawable);
 1773 
 1774    runme = 0;
 1775 
 1776    gtk_main();
 1777 
 1778    return(runme);
 1779 }

ViewVC Help
Powered by ViewVC 1.0.4