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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

ViewVC Help
Powered by ViewVC 1.0.4