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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

ViewVC Help
Powered by ViewVC 1.0.4