[gimp-dds] / tags / release-2.0.1 / ddswrite.c Repository:
ViewVC logotype

View of /tags/release-2.0.1/ddswrite.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 88 - (download) (as text) (annotate)
Wed Nov 7 23:49:28 2007 UTC (2 years ago) by cocidius
File size: 48825 byte(s)
Replacing 2.0.1 release tag, phase 2 of 2
    1 /*
    2    DDS GIMP plugin
    3 
    4    Copyright (C) 2004 Shawn Kirst <skirst@fuse.net>,
    5    with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
    6 
    7    This program is free software; you can redistribute it and/or
    8    modify it under the terms of the GNU General Public
    9    License as published by the Free Software Foundation; either
   10    version 2 of the License, or (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 GNU
   15    General Public License for more details.
   16 
   17    You should have received a copy of the GNU General Public License
   18    along with this program; see the file COPYING.  If not, write to
   19    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   20    Boston, MA 02111-1307, USA.
   21 */
   22 
   23 #include <stdio.h>
   24 #include <stdlib.h>
   25 #include <string.h>
   26 
   27 #include <gtk/gtk.h>
   28 
   29 #include <libgimp/gimp.h>
   30 #include <libgimp/gimpui.h>
   31 
   32 #include "ddsplugin.h"
   33 #include "dds.h"
   34 #include "dxt.h"
   35 #include "mipmap.h"
   36 #include "endian.h"
   37 
   38 static gint save_dialog(gint32 image_id, gint32 drawable);
   39 static void save_dialog_response(GtkWidget *widget, gint response_id, gpointer data);
   40 static void compression_selected(GtkWidget *widget, gpointer data);
   41 static void toggle_clicked(GtkWidget *widget, gpointer data);
   42 static int write_image(FILE *fp, gint32 image_id, gint32 drawable_id);
   43 
   44 static int runme = 0;
   45 
   46 const char *cubemap_face_names[4][6] =
   47 {
   48    {
   49       "positive x", "negative x",
   50       "positive y", "negative y",
   51       "positive z", "negative z"
   52    },
   53    {
   54       "pos x", "neg x",
   55       "pos y", "neg y",
   56       "pos z", "neg z",
   57    },
   58    {
   59       "+x", "-x",
   60       "+y", "-y",
   61       "+z", "-z"
   62    },
   63    {
   64       "right", "left",
   65       "top", "bottom",
   66       "back", "front"
   67    }
   68 };
   69 
   70 static gint cubemap_faces[6];
   71 static gint is_cubemap = 0;
   72 static gint is_volume = 0;
   73 
   74 GtkWidget *mipmap_check;
   75 GtkWidget *compress_opt;
   76 GtkWidget *compress_menu;
   77 GtkWidget *format_opt;
   78 GtkWidget *color_type_opt;
   79 GtkWidget *dither_chk;
   80 
   81 static struct
   82 {
   83    int compression;
   84    char *string;
   85 } compression_strings[] =
   86 {
   87    {DDS_COMPRESS_NONE,   "None"},
   88    {DDS_COMPRESS_BC1,    "BC1 / DXT1"},
   89    {DDS_COMPRESS_BC2,    "BC2 / DXT3"},
   90    {DDS_COMPRESS_BC3,    "BC3 / DXT5"},
   91    {DDS_COMPRESS_BC3N,   "BC3n / DXT5n"},
   92    {DDS_COMPRESS_BC4,    "BC4 / ATI1"},
   93    {DDS_COMPRESS_BC5,    "BC5 / ATI2"},
   94    {DDS_COMPRESS_AEXP,   "Alpha Exponent (DXT5)"},
   95    {DDS_COMPRESS_YCOCG,  "YCoCg (DXT5)"},
   96    {DDS_COMPRESS_YCOCGS, "YCoCg scaled (DXT5)"},
   97    {-1, 0}
   98 };
   99 
  100 static struct
  101 {
  102    int format;
  103    char *string;
  104 } format_strings[] =
  105 {
  106    {DDS_FORMAT_DEFAULT, "Default"},
  107    {DDS_FORMAT_RGB8, "RGB8"},
  108    {DDS_FORMAT_RGBA8, "RGBA8"},
  109    {DDS_FORMAT_BGR8, "BGR8"},
  110    {DDS_FORMAT_ABGR8, "ABGR8"},
  111    {DDS_FORMAT_R5G6B5, "R5G6B5"},
  112    {DDS_FORMAT_RGBA4, "RGBA4"},
  113    {DDS_FORMAT_RGB5A1, "RGB5A1"},
  114    {DDS_FORMAT_RGB10A2, "RGB10A2"},
  115    {DDS_FORMAT_R3G3B2, "R3G3B2"},
  116    {DDS_FORMAT_L8, "L8"},
  117    {DDS_FORMAT_L8A8, "L8A8"},
  118    {DDS_FORMAT_YCOCG, "YCoCg"},
  119    {-1, 0}
  120 };
  121 
  122 static struct
  123 {
  124    int type;
  125    char *string;
  126 } color_type_strings[] =
  127 {
  128    {DDS_COLOR_DEFAULT,    "Default"},
  129    {DDS_COLOR_DISTANCE,   "Distance"},
  130    {DDS_COLOR_LUMINANCE,  "Luminance"},
  131    {DDS_COLOR_INSET_BBOX, "Inset bounding box"},
  132    {-1, 0}
  133 };
  134 
  135 static int check_cubemap(gint32 image_id)
  136 {
  137    gint *layers, num_layers;
  138    int cubemap = 0, i, j, k, w, h;
  139    char *layer_name;
  140    GimpDrawable *drawable;
  141    GimpImageType type;
  142 
  143    layers = gimp_image_get_layers(image_id, &num_layers);
  144 
  145    if(num_layers == 6)
  146    {
  147       for(i = 0; i < 6; ++i)
  148          cubemap_faces[i] = -1;
  149 
  150       for(i = 0; i < 6; ++i)
  151       {
  152          layer_name = (char*)gimp_drawable_get_name(layers[i]);
  153          for(j = 0; j < 6; ++j)
  154          {
  155             for(k = 0; k < 4; ++k)
  156             {
  157                if(strstr(layer_name, cubemap_face_names[k][j]))
  158                {
  159                   if(cubemap_faces[j] == -1)
  160                   {
  161                      cubemap_faces[j] = layers[i];
  162                      break;
  163                   }
  164                }
  165             }
  166          }
  167       }
  168 
  169       cubemap = 1;
  170 
  171       /* check for 6 valid faces */
  172       for(i = 0; i < 6; ++i)
  173       {
  174          if(cubemap_faces[i] == -1)
  175          {
  176             cubemap = 0;
  177             break;
  178          }
  179       }
  180 
  181       /* make sure they are all the same size */
  182       if(cubemap)
  183       {
  184          drawable = gimp_drawable_get(cubemap_faces[0]);
  185          w = drawable->width;
  186          h = drawable->height;
  187          gimp_drawable_detach(drawable);
  188          for(i = 1; i < 6 && cubemap; ++i)
  189          {
  190             drawable = gimp_drawable_get(cubemap_faces[i]);
  191             if(drawable->width  != w ||
  192                drawable->height != h)
  193             {
  194                cubemap = 0;
  195             }
  196             gimp_drawable_detach(drawable);
  197          }
  198 
  199          if(cubemap == 0)
  200          {
  201             g_message("DDS: It appears that your image is a cube map,\n"
  202                       "but not all layers are the same size, thus a cube\n"
  203                       "map cannot be written.");
  204          }
  205       }
  206 
  207       /* make sure they are all the same type */
  208       if(cubemap)
  209       {
  210          type = gimp_drawable_type(cubemap_faces[0]);
  211          for(i = 1; i < 6; ++i)
  212          {
  213             if(gimp_drawable_type(cubemap_faces[i]) != type)
  214             {
  215                cubemap = 0;
  216                break;
  217             }
  218          }
  219 
  220          if(cubemap == 0)
  221          {
  222             g_message("DDS: It appears that your image is a cube map,\n"
  223                       "but not all layers are the same type, thus a cube\n"
  224                       "map cannot be written (Perhaps some layers have\n"
  225                       "transparency and others do not?).");
  226          }
  227       }
  228    }
  229 
  230    return(cubemap);
  231 }
  232 
  233 static int check_volume(gint32 image_id)
  234 {
  235    gint *layers, num_layers;
  236    int volume = 0, i, w, h;
  237    GimpDrawable *drawable;
  238    GimpImageType type;
  239 
  240    layers = gimp_image_get_layers(image_id, &num_layers);
  241 
  242    if(num_layers > 1)
  243    {
  244       volume = 1;
  245 
  246       drawable = gimp_drawable_get(layers[0]);
  247       w = drawable->width;
  248       h = drawable->height;
  249       gimp_drawable_detach(drawable);
  250       for(i = 1; i < num_layers && volume; ++i)
  251       {
  252          drawable = gimp_drawable_get(layers[i]);
  253          if(drawable->width  != w ||
  254             drawable->height != h)
  255          {
  256             volume = 0;
  257          }
  258          gimp_drawable_detach(drawable);
  259       }
  260 
  261       if(!volume)
  262       {
  263          g_message("DDS: It appears your image may be a volume map,\n"
  264                    "but not all layers are the same size, thus a volume\n"
  265                    "map cannot be written.");
  266       }
  267 
  268       if(volume)
  269       {
  270          type = gimp_drawable_type(layers[0]);
  271          for(i = 1; i < num_layers; ++i)
  272          {
  273             if(gimp_drawable_type(layers[i]) != type)
  274             {
  275                volume = 0;
  276                break;
  277             }
  278          }
  279 
  280          if(!volume)
  281          {
  282             g_message("DDS: It appears your image may be a volume map,\n"
  283                       "but not all layers are the same type, thus a volume\n"
  284                       "map cannot be written (Perhaps some layers have\n"
  285                       "transparency and others do not?).");
  286          }
  287       }
  288    }
  289 
  290    return(volume);
  291 }
  292 
  293 GimpPDBStatusType write_dds(gchar *filename, gint32 image_id, gint32 drawable_id)
  294 {
  295    FILE *fp;
  296    gchar *tmp;
  297    int rc = 0;
  298 
  299    is_cubemap = check_cubemap(image_id);
  300    is_volume = check_volume(image_id);
  301 
  302    if(interactive_dds)
  303    {
  304       if(!save_dialog(image_id, drawable_id))
  305          return(GIMP_PDB_CANCEL);
  306    }
  307    else
  308    {
  309       if(ddsvals.savetype == DDS_SAVE_CUBEMAP && !is_cubemap)
  310       {
  311          g_message("DDS: Cannot save image as cube map");
  312          return(GIMP_PDB_EXECUTION_ERROR);
  313       }
  314 
  315       if(ddsvals.savetype == DDS_SAVE_VOLUMEMAP && !is_volume)
  316       {
  317          g_message("DDS: Cannot save image as volume map");
  318          return(GIMP_PDB_EXECUTION_ERROR);
  319       }
  320 
  321       if(ddsvals.savetype == DDS_SAVE_VOLUMEMAP &&
  322          ddsvals.compression != DDS_COMPRESS_NONE)
  323       {
  324          g_message("DDS: Cannot save volume map with compression");
  325          return(GIMP_PDB_EXECUTION_ERROR);
  326       }
  327    }
  328 
  329    fp = fopen(filename, "wb");
  330    if(fp == 0)
  331    {
  332       g_message("Error opening %s", filename);
  333       return(GIMP_PDB_EXECUTION_ERROR);
  334    }
  335 
  336    if(interactive_dds)
  337    {
  338       if(strrchr(filename, '/'))
  339          tmp = g_strdup_printf("Saving %s:", strrchr(filename, '/') + 1);
  340       else
  341          tmp = g_strdup_printf("Saving %s:", filename);
  342       gimp_progress_init(tmp);
  343       g_free(tmp);
  344    }
  345 
  346    rc = write_image(fp, image_id, drawable_id);
  347 
  348    fclose(fp);
  349 
  350    return(rc ? GIMP_PDB_SUCCESS : GIMP_PDB_EXECUTION_ERROR);
  351 }
  352 
  353 #define TO_R5G6B5(r, g, b) \
  354    (unsigned short)((unsigned short)((((r) >> 3) & 0x1f) << 11) |\
  355                     (unsigned short)((((g) >> 2) & 0x3f) <<  5) |\
  356                     (unsigned short)((((b) >> 3) & 0x1f)      ))
  357 #define TO_RGBA4(r, g, b, a) \
  358    (unsigned short)((unsigned short)((((a) >> 4) & 0x0f) << 12) |\
  359                     (unsigned short)((((r) >> 4) & 0x0f) <<  8) |\
  360                     (unsigned short)((((g) >> 4) & 0x0f) <<  4) |\
  361                     (unsigned short)((((b) >> 4) & 0x0f)      ))
  362 #define TO_RGB5A1(r, g, b, a) \
  363    (unsigned short)((unsigned short)((((a) >> 7) & 0x01) << 15) |\
  364                     (unsigned short)((((r) >> 3) & 0x1f) << 10) |\
  365                     (unsigned short)((((g) >> 3) & 0x1f) <<  5) |\
  366                     (unsigned short)((((b) >> 3) & 0x1f)      ))
  367 #define TO_RGB10A2(r, g, b, a) \
  368    (unsigned int)((unsigned int)((((a) >> 6) & 0x003) << 30) | \
  369                   (unsigned int)((((r) << 2) & 0x3ff) << 20) | \
  370                   (unsigned int)((((g) << 2) & 0x3ff) << 10) | \
  371                   (unsigned int)((((b) << 2) & 0x3ff)      ))
  372 #define TO_R3G3B2(r, g, b) \
  373    (unsigned char)(((((r) >> 5) & 0x07) << 5) |\
  374                    ((((g) >> 5) & 0x07) << 2) |\
  375                    ((((b) >> 6) & 0x03)     ))
  376 
  377 #define TO_YCOCG_Y(r, g, b)  (((  (r) +      ((g) << 1) +  (b)      ) + 2) >> 2)
  378 #define TO_YCOCG_CO(r, g, b) ((( ((r) << 1)             - ((b) << 1)) + 2) >> 2)
  379 #define TO_YCOCG_CG(r, g, b) ((( -(r) +      ((g) << 1) -  (b)      ) + 2) >> 2)
  380 
  381 #define TO_LUMINANCE(r, g, b) (((r) * 54 + (g) * 182 + (b) * 20) >> 8)
  382 
  383 static void swap_rb(unsigned char *pixels, unsigned int n, int bpp)
  384 {
  385    unsigned int i;
  386    unsigned char t;
  387 
  388    for(i = 0; i < n; ++i)
  389    {
  390       t = pixels[bpp * i + 0];
  391       pixels[bpp * i + 0] = pixels[bpp * i + 2];
  392       pixels[bpp * i + 2] = t;
  393    }
  394 }
  395 
  396 static void alpha_exp(unsigned char *dst, int r, int g, int b, int a)
  397 {
  398    float ar, ag, ab, aa;
  399 
  400    ar = (float)r / 255.0f;
  401    ag = (float)g / 255.0f;
  402    ab = (float)b / 255.0f;
  403 
  404    if(ar > ag)
  405    {
  406       if(ar > ab)
  407          aa = ar;
  408       else
  409          aa = ab;
  410    }
  411    else if(ag > ab)
  412       aa = ag;
  413    else
  414       aa = ab;
  415 
  416    if(aa < 1e-04f)
  417    {
  418       dst[0] = b;
  419       dst[1] = g;
  420       dst[2] = r;
  421       dst[3] = a;
  422       return;
  423    }
  424 
  425    ar /= aa;
  426    ag /= aa;
  427    ab /= aa;
  428 
  429    dst[0] = (int)(ab * 255);
  430    dst[1] = (int)(ag * 255);
  431    dst[2] = (int)(ar * 255);
  432    dst[3] = (int)(aa * a);
  433 }
  434 
  435 static void convert_pixels(unsigned char *dst, unsigned char *src,
  436                            int format, int w, int h, int bpp,
  437                            unsigned char *palette, int mipmaps)
  438 {
  439    unsigned int i, num_pixels;
  440    unsigned char r, g, b, a;
  441 
  442    num_pixels = get_mipmapped_size(w, h, 1, 0, mipmaps, DDS_COMPRESS_NONE);
  443 
  444    for(i = 0; i < num_pixels; ++i)
  445    {
  446       if(bpp == 1)
  447       {
  448          if(palette)
  449          {
  450             r = palette[3 * src[i] + 0];
  451             g = palette[3 * src[i] + 1];
  452             b = palette[3 * src[i] + 2];
  453          }
  454          else
  455             r = g = b = src[i];
  456 
  457          a = 255;
  458       }
  459       else if(bpp == 2)
  460       {
  461          r = g = b = src[2 * i];
  462          a = src[2 * i + 1];
  463       }
  464       else if(bpp == 3)
  465       {
  466          b = src[3 * i + 0];
  467          g = src[3 * i + 1];
  468          r = src[3 * i + 2];
  469          a = 255;
  470       }
  471       else
  472       {
  473          b = src[4 * i + 0];
  474          g = src[4 * i + 1];
  475          r = src[4 * i + 2];
  476          a = src[4 * i + 3];
  477       }
  478 
  479       switch(format)
  480       {
  481          case DDS_FORMAT_RGB8:
  482             dst[3 * i + 0] = b;
  483             dst[3 * i + 1] = g;
  484             dst[3 * i + 2] = r;
  485             break;
  486          case DDS_FORMAT_RGBA8:
  487             dst[4 * i + 0] = b;
  488             dst[4 * i + 1] = g;
  489             dst[4 * i + 2] = r;
  490             dst[4 * i + 3] = a;
  491             break;
  492          case DDS_FORMAT_BGR8:
  493             dst[4 * i + 0] = r;
  494             dst[4 * i + 1] = g;
  495             dst[4 * i + 2] = b;
  496             dst[4 * i + 3] = 255;
  497             break;
  498          case DDS_FORMAT_ABGR8:
  499             dst[4 * i + 0] = r;
  500             dst[4 * i + 1] = g;
  501             dst[4 * i + 2] = b;
  502             dst[4 * i + 3] = a;
  503             break;
  504          case DDS_FORMAT_R5G6B5:
  505             *((unsigned short*)(&dst[2 * i])) = TO_R5G6B5(r, g, b);
  506             break;
  507          case DDS_FORMAT_RGBA4:
  508             *((unsigned short*)(&dst[2 * i])) = TO_RGBA4(r, g, b, a);
  509             break;
  510          case DDS_FORMAT_RGB5A1:
  511             *((unsigned short*)(&dst[2 * i])) = TO_RGB5A1(r, g, b, a);
  512             break;
  513          case DDS_FORMAT_RGB10A2:
  514             *((unsigned int*)(&dst[4 * i])) = TO_RGB10A2(r, g, b, a);
  515             break;
  516          case DDS_FORMAT_R3G3B2:
  517             dst[i] = TO_R3G3B2(r, g, b);
  518             break;
  519          case DDS_FORMAT_L8:
  520             dst[i] = TO_LUMINANCE(r, g, b);
  521             break;
  522          case DDS_FORMAT_L8A8:
  523             dst[2 * i + 0] = TO_LUMINANCE(r, g, b);
  524             dst[2 * i + 1] = a;
  525             break;
  526          case DDS_FORMAT_YCOCG:
  527          {
  528             int co = TO_YCOCG_CO(r, g, b) + 128;
  529             int cg = TO_YCOCG_CG(r, g, b) + 128;
  530             dst[4 * i + 0] = a;
  531             dst[4 * i + 1] = (cg < 0 ? 0 : (cg > 255 ? 255 : cg));
  532             dst[4 * i + 2] = (co < 0 ? 0 : (co > 255 ? 255 : co));
  533             dst[4 * i + 3] = TO_YCOCG_Y(r, g, b);
  534             break;
  535          }
  536          case DDS_FORMAT_AEXP:
  537             alpha_exp(&dst[4 * i], r, g, b, a);
  538             break;
  539          default:
  540             break;
  541       }
  542    }
  543 }
  544 
  545 static void convert_volume_pixels(unsigned char *dst, unsigned char *src,
  546                                   int format, int w, int h, int d, int bpp,
  547                                   unsigned char *palette, int mipmaps)
  548 {
  549    unsigned int i, num_pixels;
  550    unsigned char r, g, b, a;
  551 
  552    num_pixels = get_volume_mipmapped_size(w, h, d, 1, 0, mipmaps,
  553                                           DDS_COMPRESS_NONE);
  554 
  555    for(i = 0; i < num_pixels; ++i)
  556    {
  557       if(bpp == 1)
  558       {
  559          if(palette)
  560          {
  561             r = palette[3 * src[i] + 0];
  562             g = palette[3 * src[i] + 1];
  563             b = palette[3 * src[i] + 2];
  564          }
  565          else
  566             r = g = b = src[i];
  567 
  568          a = 255;
  569       }
  570       else if(bpp == 2)
  571       {
  572          r = g = b = src[2 * i];
  573          a = src[2 * i + 1];
  574       }
  575       else if(bpp == 3)
  576       {
  577          b = src[3 * i + 0];
  578          g = src[3 * i + 1];
  579          r = src[3 * i + 2];
  580          a = 255;
  581       }
  582       else
  583       {
  584          b = src[4 * i + 0];
  585          g = src[4 * i + 1];
  586          r = src[4 * i + 2];
  587          a = src[4 * i + 3];
  588       }
  589 
  590       switch(format)
  591       {
  592          case DDS_FORMAT_RGB8:
  593             dst[3 * i + 0] = b;
  594             dst[3 * i + 1] = g;
  595             dst[3 * i + 2] = r;
  596             break;
  597          case DDS_FORMAT_RGBA8:
  598             dst[4 * i + 0] = b;
  599             dst[4 * i + 1] = g;
  600             dst[4 * i + 2] = r;
  601             dst[4 * i + 3] = a;
  602             break;
  603          case DDS_FORMAT_BGR8:
  604             dst[4 * i + 0] = r;
  605             dst[4 * i + 1] = g;
  606             dst[4 * i + 2] = b;
  607             dst[4 * i + 3] = 255;
  608             break;
  609          case DDS_FORMAT_ABGR8:
  610             dst[4 * i + 0] = r;
  611             dst[4 * i + 1] = g;
  612             dst[4 * i + 2] = b;
  613             dst[4 * i + 3] = a;
  614             break;
  615          case DDS_FORMAT_R5G6B5:
  616             *((unsigned short*)(&dst[2 * i])) = TO_R5G6B5(r, g, b);
  617             break;
  618          case DDS_FORMAT_RGBA4:
  619             *((unsigned short*)(&dst[2 * i])) = TO_RGBA4(r, g, b, a);
  620             break;
  621          case DDS_FORMAT_RGB5A1:
  622             *((unsigned short*)(&dst[2 * i])) = TO_RGB5A1(r, g, b, a);
  623             break;
  624          case DDS_FORMAT_RGB10A2:
  625             *((unsigned int*)(&dst[4 * i])) = TO_RGB10A2(r, g, b, a);
  626             break;
  627          case DDS_FORMAT_R3G3B2:
  628             dst[i] = TO_R3G3B2(r, g, b);
  629             break;
  630          case DDS_FORMAT_L8:
  631             dst[i] = TO_LUMINANCE(r, g, b);
  632             break;
  633          case DDS_FORMAT_L8A8:
  634             dst[2 * i + 0] = TO_LUMINANCE(r, g, b);
  635             dst[2 * i + 1] = a;
  636             break;
  637          case DDS_FORMAT_YCOCG:
  638          {
  639             int co = TO_YCOCG_CO(r, g, b) + 128;
  640             int cg = TO_YCOCG_CG(r, g, b) + 128;
  641             dst[4 * i + 0] = a;
  642             dst[4 * i + 1] = (cg < 0 ? 0 : (cg > 255 ? 255 : cg));
  643             dst[4 * i + 2] = (co < 0 ? 0 : (co > 255 ? 255 : co));
  644             dst[4 * i + 3] = TO_YCOCG_Y(r, g, b);
  645             break;
  646          }
  647          case DDS_FORMAT_AEXP:
  648             alpha_exp(&dst[4 * i], r, g, b, a);
  649             break;
  650          default:
  651             break;
  652       }
  653    }
  654 }
  655 
  656 static void write_layer(FILE *fp, gint32 image_id, gint32 drawable_id,
  657                         int w, int h, int bpp, int fmtbpp, int mipmaps)
  658 {
  659    GimpDrawable *drawable;
  660    GimpPixelRgn rgn;
  661    GimpImageType basetype, type;
  662    unsigned char *src, *dst, *fmtdst, *tmp, c;
  663    unsigned char *palette = NULL;
  664    int i, x, y, size, fmtsize, offset, colors;
  665    int compression = ddsvals.compression;
  666 
  667    basetype = gimp_image_base_type(image_id);
  668    type = gimp_drawable_type(drawable_id);
  669 
  670    drawable = gimp_drawable_get(drawable_id);
  671    src = g_malloc(w * h * bpp);
  672    gimp_pixel_rgn_init(&rgn, drawable, 0, 0, w, h, 0, 0);
  673    gimp_pixel_rgn_get_rect(&rgn, src, 0, 0, w, h);
  674 
  675    if(basetype == GIMP_INDEXED)
  676    {
  677       palette = gimp_image_get_colormap(image_id, &colors);
  678 
  679       if(type == GIMP_INDEXEDA_IMAGE)
  680       {
  681          tmp = g_malloc(w * h);
  682          for(i = 0; i < w * h; ++i)
  683             tmp[i] = src[2 * i];
  684          g_free(src);
  685          src = tmp;
  686          bpp = 1;
  687       }
  688    }
  689 
  690    if(bpp >= 3)
  691       swap_rb(src, w * h, bpp);
  692 
  693    if(compression == DDS_COMPRESS_BC3N)
  694    {
  695       if(bpp != 4)
  696       {
  697          fmtsize = w * h * 4;
  698          fmtdst = g_malloc(fmtsize);
  699          convert_pixels(fmtdst, src, DDS_FORMAT_RGBA8, w, h, bpp,
  700                         palette, 1);
  701          g_free(src);
  702          src = fmtdst;
  703          bpp = 4;
  704       }
  705 
  706       for(y = 0; y < drawable->height; ++y)
  707       {
  708          for(x = 0; x < drawable->width; ++x)
  709          {
  710             c = src[y * (drawable->width * 4) + (x * 4) + 2];
  711             src[y * (drawable->width * 4) + (x * 4) + 2] =
  712                src[y * (drawable->width * 4) + (x * 4) + 3];
  713             src[y * (drawable->width * 4) + (x * 4) + 3] = c;
  714          }
  715       }
  716 
  717       compression = DDS_COMPRESS_BC3;
  718    }
  719 
  720    if(compression == DDS_COMPRESS_YCOCG ||
  721       compression == DDS_COMPRESS_YCOCGS) /* convert to YCoCG */
  722    {
  723       fmtsize = w * h * 4;
  724       fmtdst = g_malloc(fmtsize);
  725       convert_pixels(fmtdst, src, DDS_FORMAT_YCOCG, w, h, bpp,
  726                      palette, 1);
  727       g_free(src);
  728       src = fmtdst;
  729       bpp = 4;
  730 
  731       if(compression == DDS_COMPRESS_YCOCG)
  732          compression = DDS_COMPRESS_BC3;
  733    }
  734 
  735    if(compression == DDS_COMPRESS_AEXP)
  736    {
  737       fmtsize = w * h * 4;
  738       fmtdst = g_malloc(fmtsize);
  739       convert_pixels(fmtdst, src, DDS_FORMAT_AEXP, w, h, bpp,
  740                      palette, 1);
  741       g_free(src);
  742       src = fmtdst;
  743       bpp = 4;
  744 
  745       compression = DDS_COMPRESS_BC3;
  746    }
  747 
  748    if(compression == DDS_COMPRESS_NONE)
  749    {
  750       if(mipmaps > 1)
  751       {
  752          /* pre-convert indexed images to RGB for better quality mipmaps
  753             if a pixel format conversion is requested */
  754          if(ddsvals.format > DDS_FORMAT_DEFAULT && basetype == GIMP_INDEXED)
  755          {
  756             fmtsize = get_mipmapped_size(w, h, 3, 0, mipmaps, DDS_COMPRESS_NONE);
  757             fmtdst = g_malloc(fmtsize);
  758             convert_pixels(fmtdst, src, DDS_FORMAT_RGB8, w, h, bpp,
  759                            palette, 1);
  760             g_free(src);
  761             src = fmtdst;
  762             bpp = 3;
  763             palette = NULL;
  764          }
  765 
  766          size = get_mipmapped_size(w, h, bpp, 0, mipmaps, DDS_COMPRESS_NONE);
  767          dst = g_malloc(size);
  768          generate_mipmaps(dst, src, w, h, bpp, palette != NULL, mipmaps);
  769 
  770          offset = 0;
  771 
  772          if(ddsvals.format > DDS_FORMAT_DEFAULT)
  773          {
  774             fmtsize = get_mipmapped_size(w, h, fmtbpp, 0, mipmaps,
  775                                          DDS_COMPRESS_NONE);
  776             fmtdst = g_malloc(fmtsize);
  777 
  778             convert_pixels(fmtdst, dst, ddsvals.format, w, h, bpp,
  779                            palette, mipmaps);
  780 
  781             g_free(dst);
  782             dst = fmtdst;
  783             bpp = fmtbpp;
  784          }
  785 
  786          for(i = 0; i < mipmaps; ++i)
  787          {
  788             size = get_mipmapped_size(w, h, bpp, i, 1, DDS_COMPRESS_NONE);
  789             fwrite(dst + offset, 1, size, fp);
  790             offset += size;
  791          }
  792 
  793          g_free(dst);
  794       }
  795       else
  796       {
  797          if(ddsvals.format > DDS_FORMAT_DEFAULT)
  798          {
  799             fmtdst = g_malloc(h * w * fmtbpp);
  800             convert_pixels(fmtdst, src, ddsvals.format, w, h, bpp,
  801                            palette, 1);
  802             g_free(src);
  803             src = fmtdst;
  804             bpp = fmtbpp;
  805          }
  806 
  807          fwrite(src, 1, h * w * bpp, fp);
  808       }
  809    }
  810    else
  811    {
  812       size = get_mipmapped_size(w, h, bpp, 0, mipmaps, compression);
  813 
  814       dst = g_malloc(size);
  815 
  816       if(basetype == GIMP_INDEXED)
  817       {
  818          fmtsize = get_mipmapped_size(w, h, 3, 0, mipmaps,
  819                                       DDS_COMPRESS_NONE);
  820          fmtdst = g_malloc(fmtsize);
  821          convert_pixels(fmtdst, src, DDS_FORMAT_RGB8, w, h, bpp,
  822                         palette, mipmaps);
  823          g_free(src);
  824          src = fmtdst;
  825          bpp = 3;
  826       }
  827 
  828       dxt_compress(dst, src, compression, w, h, bpp, mipmaps,
  829                    ddsvals.color_type, ddsvals.dither);
  830 
  831       offset = 0;
  832 
  833       for(i = 0; i < mipmaps; ++i)
  834       {
  835          size = get_mipmapped_size(w, h, bpp, i, 1, compression);
  836          fwrite(dst + offset, 1, size, fp);
  837          offset += size;
  838       }
  839 
  840       g_free(dst);
  841    }
  842 
  843    g_free(src);
  844 
  845    gimp_drawable_detach(drawable);
  846 }
  847 
  848 static void write_volume_mipmaps(FILE *fp, gint32 image_id, gint32 *layers,
  849                                  int w, int h, int d, int bpp, int fmtbpp,
  850                                  int mipmaps)
  851 {
  852    int i, size, offset, colors;
  853    unsigned char *src, *dst, *tmp, *fmtdst;
  854    unsigned char *palette = 0;
  855    GimpDrawable *drawable;
  856    GimpPixelRgn rgn;
  857    GimpImageType type;
  858 
  859    type = gimp_image_base_type(image_id);
  860 
  861    if(ddsvals.compression != DDS_COMPRESS_NONE) return;
  862 
  863    src = g_malloc(w * h * bpp * d);
  864 
  865    if(gimp_image_base_type(image_id) == GIMP_INDEXED)
  866       palette = gimp_image_get_colormap(image_id, &colors);
  867 
  868    offset = 0;
  869    for(i = 0; i < d; ++i)
  870    {
  871       drawable = gimp_drawable_get(layers[i]);
  872       gimp_pixel_rgn_init(&rgn, drawable, 0, 0, w, h, 0, 0);
  873       gimp_pixel_rgn_get_rect(&rgn, src + offset, 0, 0, w, h);
  874       offset += (w * h * bpp);
  875       gimp_drawable_detach(drawable);
  876    }
  877 
  878    if(gimp_drawable_type(layers[0]) == GIMP_INDEXEDA_IMAGE)
  879    {
  880       tmp = g_malloc(w * h * d);
  881       for(i = 0; i < w * h * d; ++i)
  882          tmp[i] = src[2 * i];
  883       g_free(src);
  884       src = tmp;
  885       bpp = 1;
  886    }
  887 
  888    if(bpp >= 3)
  889       swap_rb(src, w * h * d, bpp);
  890 
  891    /* pre-convert indexed images to RGB for better mipmaps if a
  892       pixel format conversion is requested */
  893    if(ddsvals.format > DDS_FORMAT_DEFAULT && type == GIMP_INDEXED)
  894    {
  895       size = get_volume_mipmapped_size(w, h, d, 3, 0, mipmaps,
  896                                        DDS_COMPRESS_NONE);
  897       dst = g_malloc(size);
  898       convert_volume_pixels(dst, src, DDS_FORMAT_RGB8, w, h, d, bpp,
  899                             palette, 1);
  900       g_free(src);
  901       src = dst;
  902       bpp = 3;
  903       palette = NULL;
  904    }
  905 
  906    size = get_volume_mipmapped_size(w, h, d, bpp, 0, mipmaps,
  907                                     ddsvals.compression);
  908 
  909    dst = g_malloc(size);
  910 
  911    offset = get_volume_mipmapped_size(w, h, d, bpp, 0, 1,
  912                                       ddsvals.compression);
  913 
  914    generate_volume_mipmaps(dst, src, w, h, d, bpp,
  915                            palette != NULL, mipmaps);
  916 
  917    if(ddsvals.format > DDS_FORMAT_DEFAULT)
  918    {
  919       size = get_volume_mipmapped_size(w, h, d, fmtbpp, 0, mipmaps,
  920                                        ddsvals.compression);
  921       offset = get_volume_mipmapped_size(w, h, d, fmtbpp, 0, 1,
  922                                          ddsvals.compression);
  923       fmtdst = g_malloc(size);
  924 
  925       convert_volume_pixels(fmtdst, dst, ddsvals.format, w, h, d, bpp,
  926                             palette, mipmaps);
  927       g_free(dst);
  928       dst = fmtdst;
  929    }
  930 
  931    fwrite(dst + offset, 1, size, fp);
  932 
  933    g_free(src);
  934    g_free(dst);
  935 }
  936 
  937 static int write_image(FILE *fp, gint32 image_id, gint32 drawable_id)
  938 {
  939    GimpDrawable *drawable;
  940    GimpImageType drawable_type, basetype;
  941    GimpPixelRgn rgn;
  942    int i, w, h, bpp = 0, fmtbpp = 0, has_alpha = 0;
  943    int num_mipmaps;
  944    unsigned char hdr[DDS_HEADERSIZE];
  945    unsigned int flags = 0, pflags = 0, caps = 0, caps2 = 0, size = 0;
  946    unsigned int rmask = 0, gmask = 0, bmask = 0, amask = 0;
  947    char *format = "XXXX";
  948    gint32 num_layers, *layers;
  949    guchar *cmap;
  950    gint colors;
  951    unsigned char zero[4] = {0, 0, 0, 0};
  952 
  953    layers = gimp_image_get_layers(image_id, &num_layers);
  954 
  955    drawable = gimp_drawable_get(drawable_id);
  956 
  957    w = drawable->width;
  958    h = drawable->height;
  959 
  960    basetype = gimp_image_base_type(image_id);
  961    drawable_type = gimp_drawable_type(drawable_id);
  962    gimp_pixel_rgn_init(&rgn, drawable, 0, 0, w, h, 0, 0);
  963 
  964    if((ddsvals.compression != DDS_COMPRESS_NONE) &&
  965       !(IS_POT(w) && IS_POT(h)))
  966    {
  967       ddsvals.compression = DDS_COMPRESS_NONE;
  968       g_message("DDS: Cannot compress non power-of-2 sized images.\n"
  969                 "Saved image will not be compressed.");
  970    }
  971 
  972    switch(drawable_type)
  973    {
  974       case GIMP_RGB_IMAGE:      bpp = 3; break;
  975       case GIMP_RGBA_IMAGE:     bpp = 4; break;
  976       case GIMP_GRAY_IMAGE:     bpp = 1; break;
  977       case GIMP_GRAYA_IMAGE:    bpp = 2; break;
  978       case GIMP_INDEXED_IMAGE:  bpp = 1; break;
  979       case GIMP_INDEXEDA_IMAGE: bpp = 2; break;
  980       default:
  981          break;
  982    }
  983 
  984    if(ddsvals.format > DDS_FORMAT_DEFAULT)
  985    {
  986       switch(ddsvals.format)
  987       {
  988          case DDS_FORMAT_RGB8:
  989             fmtbpp = 3;
  990             rmask = 0x00ff0000;
  991             gmask = 0x0000ff00;
  992             bmask = 0x000000ff;
  993             amask = 0xff000000;
  994             break;
  995          case DDS_FORMAT_RGBA8:
  996             fmtbpp = 4;
  997             has_alpha = 1;
  998             rmask = 0x00ff0000;
  999             gmask = 0x0000ff00;
 1000             bmask = 0x000000ff;
 1001             amask = 0xff000000;
 1002             break;
 1003          case DDS_FORMAT_BGR8:
 1004             fmtbpp = 4;
 1005             rmask = 0x000000ff;
 1006             gmask = 0x0000ff00;
 1007             bmask = 0x00ff0000;
 1008             amask = 0x00000000;
 1009             break;
 1010          case DDS_FORMAT_ABGR8:
 1011             fmtbpp = 4;
 1012             has_alpha = 1;
 1013             rmask = 0x000000ff;
 1014             gmask = 0x0000ff00;
 1015             bmask = 0x00ff0000;
 1016             amask = 0xff000000;
 1017             break;
 1018          case DDS_FORMAT_R5G6B5:
 1019             fmtbpp = 2;
 1020             rmask = 0x0000f800;
 1021             gmask = 0x000007e0;
 1022             bmask = 0x0000001f;
 1023             amask = 0x00000000;
 1024             break;
 1025          case DDS_FORMAT_RGBA4:
 1026             fmtbpp = 2;
 1027             has_alpha = 1;
 1028             rmask = 0x00000f00;
 1029             gmask = 0x000000f0;
 1030             bmask = 0x0000000f;
 1031             amask = 0x0000f000;
 1032             break;
 1033          case DDS_FORMAT_RGB5A1:
 1034             fmtbpp = 2;
 1035             has_alpha = 1;
 1036             rmask = 0x00007c00;
 1037             gmask = 0x000003e0;
 1038             bmask = 0x0000001f;
 1039             amask = 0x00008000;
 1040             break;
 1041          case DDS_FORMAT_RGB10A2:
 1042             fmtbpp = 4;
 1043             has_alpha = 1;
 1044             rmask = 0x3ff00000;
 1045             gmask = 0x000ffc00;
 1046             bmask = 0x000003ff;
 1047             amask = 0xc0000000;
 1048             break;
 1049          case DDS_FORMAT_R3G3B2:
 1050             fmtbpp = 1;
 1051             has_alpha = 0;
 1052             rmask = 0x000000e0;
 1053             gmask = 0x0000001c;
 1054             bmask = 0x00000003;
 1055             amask = 0x00000000;
 1056             break;
 1057          case DDS_FORMAT_L8:
 1058             fmtbpp = 1;
 1059             has_alpha = 0;
 1060             rmask = 0x000000ff;
 1061             gmask = 0x000000ff;
 1062             bmask = 0x000000ff;
 1063             amask = 0x00000000;
 1064             break;
 1065          case DDS_FORMAT_L8A8:
 1066             fmtbpp = 2;
 1067             has_alpha = 1;
 1068             rmask = 0x000000ff;
 1069             gmask = 0x000000ff;
 1070             bmask = 0x000000ff;
 1071             amask = 0x0000ff00;
 1072             break;
 1073          case DDS_FORMAT_YCOCG:
 1074             fmtbpp = 4;
 1075             has_alpha = 1;
 1076             rmask = 0x00ff0000;
 1077             gmask = 0x0000ff00;
 1078             bmask = 0x000000ff;
 1079             amask = 0xff000000;
 1080             break;
 1081          default:
 1082             break;
 1083       }
 1084    }
 1085    else if(bpp == 1)
 1086    {
 1087       if(basetype == GIMP_INDEXED)
 1088       {
 1089          fmtbpp = 1;
 1090          has_alpha = 0;
 1091          rmask = bmask = gmask = amask = 0;
 1092       }
 1093       else
 1094       {
 1095          fmtbpp = 1;
 1096          has_alpha = 0;
 1097          rmask = 0x000000ff;
 1098          gmask = bmask = amask = 0;
 1099       }
 1100    }
 1101    else if(bpp == 2)
 1102    {
 1103       if(basetype == GIMP_INDEXED)
 1104       {
 1105          fmtbpp = 1;
 1106          has_alpha = 0;
 1107          rmask = gmask = bmask = amask = 0;
 1108       }
 1109       else
 1110       {
 1111          fmtbpp = 2;
 1112          has_alpha = 1;
 1113          rmask = 0x000000ff;
 1114          gmask = 0x000000ff;
 1115          bmask = 0x000000ff;
 1116          amask = 0x0000ff00;
 1117       }
 1118    }
 1119    else if(bpp == 3)
 1120    {
 1121       fmtbpp = 3;
 1122       rmask = 0x00ff0000;
 1123       gmask = 0x0000ff00;
 1124       bmask = 0x000000ff;
 1125       amask = 0x00000000;
 1126    }
 1127    else
 1128    {
 1129       fmtbpp = 4;
 1130       has_alpha = 1;
 1131       rmask = 0x00ff0000;
 1132       gmask = 0x0000ff00;
 1133       bmask = 0x000000ff;
 1134       amask = 0xff000000;
 1135    }
 1136 
 1137    memset(hdr, 0, DDS_HEADERSIZE);
 1138 
 1139    memcpy(hdr, "DDS ", 4);
 1140    PUTL32(hdr + 4, 124);
 1141    PUTL32(hdr + 12, h);
 1142    PUTL32(hdr + 16, w);
 1143    PUTL32(hdr + 76, 32);
 1144    PUTL32(hdr + 88, fmtbpp << 3);
 1145    PUTL32(hdr + 92,  rmask);
 1146    PUTL32(hdr + 96,  gmask);
 1147    PUTL32(hdr + 100, bmask);
 1148    PUTL32(hdr + 104, amask);
 1149 
 1150    flags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
 1151 
 1152    caps = DDSCAPS_TEXTURE;
 1153    if(ddsvals.mipmaps)
 1154    {
 1155       flags |= DDSD_MIPMAPCOUNT;
 1156       caps |= (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP);
 1157       num_mipmaps = get_num_mipmaps(w, h);
 1158    }
 1159    else
 1160       num_mipmaps = 1;
 1161 
 1162    if(ddsvals.savetype == DDS_SAVE_CUBEMAP && is_cubemap)
 1163    {
 1164       caps |= DDSCAPS_COMPLEX;
 1165       caps2 |= (DDSCAPS2_CUBEMAP |
 1166                 DDSCAPS2_CUBEMAP_POSITIVEX |
 1167                 DDSCAPS2_CUBEMAP_NEGATIVEX |
 1168                 DDSCAPS2_CUBEMAP_POSITIVEY |
 1169                 DDSCAPS2_CUBEMAP_NEGATIVEY |
 1170                 DDSCAPS2_CUBEMAP_POSITIVEZ |
 1171                 DDSCAPS2_CUBEMAP_NEGATIVEZ);
 1172    }
 1173    else if(ddsvals.savetype == DDS_SAVE_VOLUMEMAP && is_volume)
 1174    {
 1175       PUTL32(hdr + 24, num_layers);
 1176       flags |= DDSD_DEPTH;
 1177       caps |= DDSCAPS_COMPLEX;
 1178       caps2 |= DDSCAPS2_VOLUME;
 1179    }
 1180 
 1181    PUTL32(hdr + 28, num_mipmaps);
 1182    PUTL32(hdr + 108, caps);
 1183    PUTL32(hdr + 112, caps2);
 1184 
 1185    if(ddsvals.compression == DDS_COMPRESS_NONE)
 1186    {
 1187       flags |= DDSD_PITCH;
 1188 
 1189       if(ddsvals.format > DDS_FORMAT_DEFAULT)
 1190       {
 1191          if((fmtbpp == 1 || ddsvals.format == DDS_FORMAT_L8A8) &&
 1192             (ddsvals.format != DDS_FORMAT_R3G3B2))
 1193             pflags |= DDPF_LUMINANCE;
 1194          else
 1195             pflags |= DDPF_RGB;
 1196       }
 1197       else
 1198       {
 1199          if(bpp == 1)
 1200          {
 1201             if(basetype == GIMP_INDEXED)
 1202                pflags |= DDPF_PALETTEINDEXED8;
 1203             else
 1204                pflags |= DDPF_LUMINANCE;
 1205          }
 1206          else if(bpp == 2 && basetype == GIMP_INDEXED)
 1207             pflags |= DDPF_PALETTEINDEXED8;
 1208          else
 1209             pflags |= DDPF_RGB;
 1210       }
 1211 
 1212       if(has_alpha) pflags |= DDPF_ALPHAPIXELS;
 1213 
 1214       PUTL32(hdr + 8, flags);
 1215       PUTL32(hdr + 20, w * fmtbpp);
 1216       PUTL32(hdr + 80, pflags);
 1217    }
 1218    else
 1219    {
 1220       flags |= DDSD_LINEARSIZE;
 1221       PUTL32(hdr + 8, flags);
 1222       PUTL32(hdr + 80, DDPF_FOURCC);
 1223       switch(ddsvals.compression)
 1224       {
 1225          case DDS_COMPRESS_BC1:    format = "DXT1"; break;
 1226          case DDS_COMPRESS_BC2:    format = "DXT3"; break;
 1227          case DDS_COMPRESS_BC3:
 1228          case DDS_COMPRESS_BC3N:
 1229          case DDS_COMPRESS_YCOCG:
 1230          case DDS_COMPRESS_YCOCGS:
 1231          case DDS_COMPRESS_AEXP:   format = "DXT5"; break;
 1232          case DDS_COMPRESS_BC4:    format = "ATI1"; break;
 1233          case DDS_COMPRESS_BC5:    format = "ATI2"; break;
 1234       }
 1235       memcpy(hdr + 84, format, 4);
 1236 
 1237       size = ((w + 3) >> 2) * ((h + 3) >> 2);
 1238       if(ddsvals.compression == DDS_COMPRESS_BC1 ||
 1239          ddsvals.compression == DDS_COMPRESS_BC4)
 1240          size *= 8;
 1241       else
 1242          size *= 16;
 1243 
 1244       PUTL32(hdr + 20, size);
 1245    }
 1246 
 1247    fwrite(hdr, DDS_HEADERSIZE, 1, fp);
 1248 
 1249    if(basetype == GIMP_INDEXED && ddsvals.format == DDS_FORMAT_DEFAULT &&
 1250       ddsvals.compression == DDS_COMPRESS_NONE)
 1251    {
 1252       cmap = gimp_image_get_colormap(image_id, &colors);
 1253       for(i = 0; i < colors; ++i)
 1254       {
 1255          fwrite(&cmap[3 * i], 1, 3, fp);
 1256          if(i == ddsvals.transindex)
 1257             fputc(0, fp);
 1258          else
 1259             fputc(255, fp);
 1260       }
 1261       for(; i < 256; ++i)
 1262          fwrite(zero, 1, 4, fp);
 1263    }
 1264 
 1265    if(ddsvals.savetype == DDS_SAVE_CUBEMAP)
 1266    {
 1267       for(i = 0; i < 6; ++i)
 1268       {
 1269          write_layer(fp, image_id, cubemap_faces[i], w, h, bpp, fmtbpp,
 1270                      num_mipmaps);
 1271          if(interactive_dds)
 1272             gimp_progress_update((float)(i + 1) / 6.0);
 1273       }
 1274    }
 1275    else if(ddsvals.savetype == DDS_SAVE_VOLUMEMAP)
 1276    {
 1277       for(i = 0; i < num_layers; ++i)
 1278       {
 1279          write_layer(fp, image_id, layers[i], w, h, bpp, fmtbpp, 1);
 1280          if(interactive_dds)
 1281             gimp_progress_update((float)i / (float)num_layers);
 1282       }
 1283 
 1284       if(num_mipmaps > 1)
 1285          write_volume_mipmaps(fp, image_id, layers, w, h, num_layers,
 1286                               bpp, fmtbpp, num_mipmaps);
 1287    }
 1288    else
 1289    {
 1290       write_layer(fp, image_id, drawable_id, w, h, bpp, fmtbpp,
 1291                   num_mipmaps);
 1292    }
 1293 
 1294    if(interactive_dds)
 1295       gimp_progress_update(1.0);
 1296 
 1297    gimp_drawable_detach(drawable);
 1298 
 1299    return(1);
 1300 }
 1301 
 1302 static void save_dialog_response(GtkWidget *widget, gint response_id,
 1303                                  gpointer data)
 1304 {
 1305    switch(response_id)
 1306    {
 1307       case GTK_RESPONSE_OK:
 1308          runme = 1;
 1309       default:
 1310          gtk_widget_destroy(widget);
 1311          break;
 1312    }
 1313 }
 1314 
 1315 static void compression_selected(GtkWidget *widget, gpointer data)
 1316 {
 1317    ddsvals.compression = (gint)(long)data;
 1318    gtk_widget_set_sensitive(format_opt, ddsvals.compression == DDS_COMPRESS_NONE);
 1319    gtk_widget_set_sensitive(color_type_opt,
 1320                             ddsvals.compression != DDS_COMPRESS_NONE &&
 1321                             ddsvals.compression != DDS_COMPRESS_BC4 &&
 1322                             ddsvals.compression != DDS_COMPRESS_BC5 &&
 1323                             ddsvals.compression != DDS_COMPRESS_YCOCGS);
 1324    gtk_widget_set_sensitive(dither_chk,
 1325                             ddsvals.compression != DDS_COMPRESS_NONE &&
 1326                             ddsvals.compression != DDS_COMPRESS_BC4 &&
 1327                             ddsvals.compression != DDS_COMPRESS_BC5 &&
 1328                             ddsvals.compression != DDS_COMPRESS_YCOCGS);
 1329 }
 1330 
 1331 static void savetype_selected(GtkWidget *widget, gpointer data)
 1332 {
 1333    int n = (int)(long)data;
 1334 
 1335    ddsvals.savetype = n;
 1336 
 1337    switch(n)
 1338    {
 1339       case 0:
 1340       case 1:
 1341          gtk_widget_set_sensitive(compress_opt, 1);
 1342          break;
 1343       case 2:
 1344          ddsvals.compression = DDS_COMPRESS_NONE;
 1345          gtk_menu_set_active(GTK_MENU(compress_menu), DDS_COMPRESS_NONE);
 1346          gtk_widget_set_sensitive(compress_opt, 0);
 1347          break;
 1348    }
 1349 }
 1350 
 1351 static void format_selected(GtkWidget *widget, gpointer data)
 1352 {
 1353    ddsvals.format = (gint)(long)data;
 1354 }
 1355 
 1356 static void toggle_clicked(GtkWidget *widget, gpointer data)
 1357 {
 1358    int *flag = (int*)data;
 1359    (*flag) = !(*flag);
 1360 }
 1361 
 1362 static void transindex_clicked(GtkWidget *widget, gpointer data)
 1363 {
 1364    GtkWidget *spin = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "spin"));
 1365 
 1366    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
 1367    {
 1368       ddsvals.transindex = 0;
 1369       gtk_widget_set_sensitive(spin, 1);
 1370       gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), 0);
 1371    }
 1372    else
 1373    {
 1374       gtk_widget_set_sensitive(spin, 0);
 1375       ddsvals.transindex = -1;
 1376    }
 1377 }
 1378 
 1379 static void transindex_changed(GtkWidget *widget, gpointer data)
 1380 {
 1381    ddsvals.transindex = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
 1382 }
 1383 
 1384 static void adv_opt_expanded(GtkWidget *widget, gpointer data)
 1385 {
 1386    ddsvals.show_adv_opt = !gtk_expander_get_expanded(GTK_EXPANDER(widget));
 1387 }
 1388 
 1389 static void color_type_selected(GtkWidget *widget, gpointer data)
 1390 {
 1391    ddsvals.color_type = (gint)(long)data;
 1392 }
 1393 
 1394 static gint save_dialog(gint32 image_id, gint32 drawable_id)
 1395 {
 1396    GtkWidget *dlg;
 1397    GtkWidget *vbox, *hbox;
 1398    GtkWidget *table;
 1399    GtkWidget *label;
 1400    GtkWidget *opt;
 1401    GtkWidget *menu;
 1402    GtkWidget *menuitem;
 1403    GtkWidget *check;
 1404    GtkWidget *spin;
 1405    GtkWidget *expander;
 1406    GimpImageType type, basetype;
 1407    int i, w, h;
 1408 
 1409    if(is_cubemap)
 1410       ddsvals.savetype = DDS_SAVE_CUBEMAP;
 1411    else if(is_volume)
 1412       ddsvals.savetype = DDS_SAVE_VOLUMEMAP;
 1413    else
 1414       ddsvals.savetype = DDS_SAVE_SELECTED_LAYER;
 1415 
 1416    basetype = gimp_image_base_type(image_id);
 1417    type = gimp_drawable_type(drawable_id);
 1418 
 1419    w = gimp_image_width(image_id);
 1420    h = gimp_image_height(image_id);
 1421 
 1422    dlg = gimp_dialog_new("Save as DDS", "dds", NULL, GTK_WIN_POS_MOUSE,
 1423                          gimp_standard_help_func, SAVE_PROC,
 1424                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1425                          GTK_STOCK_OK, GTK_RESPONSE_OK,
 1426                          NULL);
 1427 
 1428    gtk_signal_connect(GTK_OBJECT(dlg), "response",
 1429                       GTK_SIGNAL_FUNC(save_dialog_response),
 1430                       0);
 1431    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
 1432                       GTK_SIGNAL_FUNC(gtk_main_quit),
 1433                       0);
 1434 
 1435    vbox = gtk_vbox_new(0, 8);
 1436    gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
 1437    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), vbox, 1, 1, 0);
 1438    gtk_widget_show(vbox);
 1439 
 1440    table = gtk_table_new(3, 2, 0);
 1441    gtk_widget_show(table);
 1442    gtk_box_pack_start(GTK_BOX(vbox), table, 1, 1, 0);
 1443    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1444    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1445 
 1446    label = gtk_label_new("Compression:");
 1447    gtk_widget_show(label);
 1448    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
 1449                     (GtkAttachOptions)(GTK_FILL),
 1450                     (GtkAttachOptions)(0), 0, 0);
 1451    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1452 
 1453    opt = gtk_option_menu_new();
 1454    gtk_widget_show(opt);
 1455    gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1,
 1456                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1457                     (GtkAttachOptions)(GTK_EXPAND), 0, 0);
 1458 
 1459    menu = gtk_menu_new();
 1460 
 1461    for(i = 0; compression_strings[i].string; ++i)
 1462    {
 1463       menuitem = gtk_menu_item_new_with_label(compression_strings[i].string);
 1464       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1465                          GTK_SIGNAL_FUNC(compression_selected),
 1466                          (gpointer)(long)compression_strings[i].compression);
 1467       gtk_widget_show(menuitem);
 1468       gtk_menu_append(GTK_MENU(menu), menuitem);
 1469    }
 1470 
 1471    gtk_menu_set_active(GTK_MENU(menu), ddsvals.compression);
 1472 
 1473    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1474 
 1475    compress_opt = opt;
 1476    compress_menu = menu;
 1477 
 1478    label = gtk_label_new("Format:");
 1479    gtk_widget_show(label);
 1480    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
 1481                     (GtkAttachOptions)(GTK_FILL),
 1482                     (GtkAttachOptions)(0), 0, 0);
 1483    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1484 
 1485    opt = gtk_option_menu_new();
 1486    gtk_widget_show(opt);
 1487    gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 1, 2,
 1488                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1489                     (GtkAttachOptions)(GTK_EXPAND), 0, 0);
 1490 
 1491    menu = gtk_menu_new();
 1492 
 1493    for(i = 0; format_strings[i].string; ++i)
 1494    {
 1495       menuitem = gtk_menu_item_new_with_label(format_strings[i].string);
 1496       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1497                          GTK_SIGNAL_FUNC(format_selected),
 1498                          (gpointer)(long)format_strings[i].format);
 1499       gtk_widget_show(menuitem);
 1500       gtk_menu_append(GTK_MENU(menu), menuitem);
 1501    }
 1502 
 1503    gtk_menu_set_active(GTK_MENU(menu), ddsvals.format);
 1504 
 1505    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1506 
 1507    gtk_widget_set_sensitive(opt, ddsvals.compression == DDS_COMPRESS_NONE);
 1508 
 1509    format_opt = opt;
 1510 
 1511    label = gtk_label_new("Save:");
 1512    gtk_widget_show(label);
 1513    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3,
 1514                     (GtkAttachOptions)(GTK_FILL),
 1515                     (GtkAttachOptions)(0), 0, 0);
 1516    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1517 
 1518    opt = gtk_option_menu_new();
 1519    gtk_widget_show(opt);
 1520    gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 2, 3,
 1521                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1522                     (GtkAttachOptions)(GTK_EXPAND), 0, 0);
 1523 
 1524    menu = gtk_menu_new();
 1525 
 1526    menuitem = gtk_menu_item_new_with_label("Selected layer");
 1527    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1528                       GTK_SIGNAL_FUNC(savetype_selected),
 1529                       (gpointer)DDS_SAVE_SELECTED_LAYER);
 1530    gtk_widget_show(menuitem);
 1531    gtk_menu_append(GTK_MENU(menu), menuitem);
 1532    menuitem = gtk_menu_item_new_with_label("As cube map");
 1533    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1534                       GTK_SIGNAL_FUNC(savetype_selected),
 1535                       (gpointer)DDS_SAVE_CUBEMAP);
 1536    gtk_widget_show(menuitem);
 1537    gtk_menu_append(GTK_MENU(menu), menuitem);
 1538    gtk_widget_set_sensitive(menuitem, is_cubemap);
 1539    menuitem = gtk_menu_item_new_with_label("As volume map");
 1540    gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1541                       GTK_SIGNAL_FUNC(savetype_selected),
 1542                       (gpointer)DDS_SAVE_VOLUMEMAP);
 1543    gtk_widget_show(menuitem);
 1544    gtk_menu_append(GTK_MENU(menu), menuitem);
 1545    gtk_widget_set_sensitive(menuitem, is_volume);
 1546 
 1547    gtk_menu_set_active(GTK_MENU(menu), ddsvals.savetype);
 1548 
 1549    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1550 
 1551    gtk_widget_set_sensitive(opt, is_cubemap || is_volume);
 1552 
 1553    check = gtk_check_button_new_with_label("Generate mipmaps");
 1554    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), ddsvals.mipmaps);
 1555    gtk_box_pack_start(GTK_BOX(vbox), check, 0, 0, 0);
 1556    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1557                       GTK_SIGNAL_FUNC(toggle_clicked), &ddsvals.mipmaps);
 1558    gtk_widget_show(check);
 1559    mipmap_check = check;
 1560 
 1561    if(is_volume && ddsvals.savetype == DDS_SAVE_VOLUMEMAP)
 1562    {
 1563       ddsvals.compression = DDS_COMPRESS_NONE;
 1564       gtk_menu_set_active(GTK_MENU(compress_menu), DDS_COMPRESS_NONE);
 1565       gtk_widget_set_sensitive(compress_opt, 0);
 1566    }
 1567 
 1568    hbox = gtk_hbox_new(0, 8);
 1569    gtk_box_pack_start(GTK_BOX(vbox), hbox, 1, 1, 0);
 1570    gtk_widget_show(hbox);
 1571 
 1572    check = gtk_check_button_new_with_label("Transparent index:");
 1573    gtk_box_pack_start(GTK_BOX(hbox), check, 0, 0, 0);
 1574    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1575                       GTK_SIGNAL_FUNC(transindex_clicked), 0);
 1576    gtk_widget_show(check);
 1577 
 1578    spin = gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 255, 1, 1, 0)), 1, 0);
 1579    gtk_box_pack_start(GTK_BOX(hbox), spin, 1, 1, 0);
 1580    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin),
 1581                                      GTK_UPDATE_IF_VALID);
 1582    gtk_signal_connect(GTK_OBJECT(spin), "value_changed",
 1583                       GTK_SIGNAL_FUNC(transindex_changed), 0);
 1584    gtk_widget_show(spin);
 1585 
 1586    g_object_set_data(G_OBJECT(check), "spin", spin);
 1587 
 1588    if(basetype != GIMP_INDEXED)
 1589    {
 1590       gtk_widget_set_sensitive(check, 0);
 1591       gtk_widget_set_sensitive(spin, 0);
 1592    }
 1593    else if(ddsvals.transindex < 0)
 1594    {
 1595       gtk_widget_set_sensitive(spin, 0);
 1596    }
 1597    else if(ddsvals.transindex >= 0)
 1598    {
 1599       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), 1);
 1600       gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), ddsvals.transindex);
 1601    }
 1602 
 1603    expander = gtk_expander_new("Advanced Options");
 1604    gtk_expander_set_expanded(GTK_EXPANDER(expander), ddsvals.show_adv_opt);
 1605    gtk_expander_set_spacing(GTK_EXPANDER(expander), 8);
 1606    gtk_signal_connect(GTK_OBJECT(expander), "activate",
 1607                       GTK_SIGNAL_FUNC(adv_opt_expanded), 0);
 1608    gtk_box_pack_start(GTK_BOX(vbox), expander, 1, 1, 0);
 1609    gtk_widget_show(expander);
 1610 
 1611    table = gtk_table_new(2, 2, 0);
 1612    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1613    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1614    gtk_container_add(GTK_CONTAINER(expander), table);
 1615    gtk_widget_show(table);
 1616 
 1617    label = gtk_label_new("Color selection:");
 1618    gtk_widget_show(label);
 1619    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
 1620                     (GtkAttachOptions)(GTK_FILL),
 1621                     (GtkAttachOptions)(0), 0, 0);
 1622    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1623 
 1624    opt = gtk_option_menu_new();
 1625    gtk_widget_show(opt);
 1626    gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1,
 1627                     (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
 1628                     (GtkAttachOptions)(GTK_EXPAND), 0, 0);
 1629 
 1630    menu = gtk_menu_new();
 1631 
 1632    for(i = 0; color_type_strings[i].string; ++i)
 1633    {
 1634       menuitem = gtk_menu_item_new_with_label(color_type_strings[i].string);
 1635       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
 1636                          GTK_SIGNAL_FUNC(color_type_selected),
 1637                          (gpointer)(long)color_type_strings[i].type);
 1638       gtk_widget_show(menuitem);
 1639       gtk_menu_append(GTK_MENU(menu), menuitem);
 1640    }
 1641 
 1642    gtk_menu_set_active(GTK_MENU(menu), ddsvals.color_type);
 1643 
 1644    gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu);
 1645 
 1646    color_type_opt = opt;
 1647 
 1648    check = gtk_check_button_new_with_label("Use dithering");
 1649    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), ddsvals.dither);
 1650    gtk_table_attach(GTK_TABLE(table), check, 0, 2, 1, 2,
 1651                     (GtkAttachOptions)(GTK_FILL),
 1652                     (GtkAttachOptions)(0), 0, 0);
 1653    gtk_signal_connect(GTK_OBJECT(check), "clicked",
 1654                       GTK_SIGNAL_FUNC(toggle_clicked), &ddsvals.dither);
 1655    gtk_widget_show(check);
 1656 
 1657    dither_chk = check;
 1658 
 1659    gtk_widget_set_sensitive(color_type_opt,
 1660                             ddsvals.compression != DDS_COMPRESS_NONE &&
 1661                             ddsvals.compression != DDS_COMPRESS_BC4 &&
 1662                             ddsvals.compression != DDS_COMPRESS_BC5 &&
 1663                             ddsvals.compression != DDS_COMPRESS_YCOCGS);
 1664    gtk_widget_set_sensitive(dither_chk,
 1665                             ddsvals.compression != DDS_COMPRESS_NONE &&
 1666                             ddsvals.compression != DDS_COMPRESS_BC4 &&
 1667                             ddsvals.compression != DDS_COMPRESS_BC5 &&
 1668                             ddsvals.compression != DDS_COMPRESS_YCOCGS);
 1669 
 1670    gtk_widget_show(dlg);
 1671 
 1672    runme = 0;
 1673 
 1674    gtk_main();
 1675 
 1676    return(runme);
 1677 }

ViewVC Help
Powered by ViewVC 1.0.4