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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

ViewVC Help
Powered by ViewVC 1.0.4