1 /*
2  * DDS GIMP plugin
3  *
4  * Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.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, 51 Franklin Street, Fifth Floor
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <gtk/gtk.h>
30 
31 #include <libgimp/gimp.h>
32 #include <libgimp/gimpui.h>
33 
34 #include <libgimp/stdplugins-intl.h>
35 
36 #include "ddsplugin.h"
37 #include "dds.h"
38 #include "misc.h"
39 
40 
41 static void query (void);
42 static void run   (const gchar     *name,
43                    gint             nparams,
44                    const GimpParam *param,
45                    gint            *nreturn_vals,
46                    GimpParam      **return_vals);
47 
48 
49 GimpPlugInInfo PLUG_IN_INFO =
50 {
51   0,
52   0,
53   query,
54   run
55 };
56 
57 DDSWriteVals dds_write_vals =
58 {
59   DDS_COMPRESS_NONE,
60   DDS_MIPMAP_NONE,
61   DDS_SAVE_SELECTED_LAYER,
62   DDS_FORMAT_DEFAULT,
63   -1,
64   DDS_MIPMAP_FILTER_DEFAULT,
65   DDS_MIPMAP_WRAP_DEFAULT,
66   0,
67   0,
68   0.0,
69   0,
70   0,
71   0,
72   0.5
73 };
74 
75 DDSReadVals dds_read_vals =
76 {
77   1,
78   1
79 };
80 
81 static GimpParamDef load_args[] =
82 {
83   { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
84   { GIMP_PDB_STRING, "filename", "The name of the file to load"},
85   { GIMP_PDB_STRING, "raw_filename", "The name entered"},
86   { GIMP_PDB_INT32, "load_mipmaps", "Load mipmaps if present"},
87   { GIMP_PDB_INT32, "decode_images", "Decode YCoCg/AExp images when detected"}
88 };
89 
90 static GimpParamDef load_return_vals[] =
91 {
92   { GIMP_PDB_IMAGE, "image", "Output image"}
93 };
94 
95 static GimpParamDef save_args[] =
96 {
97   { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
98   { GIMP_PDB_IMAGE, "image", "Input image"},
99   { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save"},
100   { GIMP_PDB_STRING, "filename", "The name of the file to save the image as"},
101   { GIMP_PDB_STRING, "raw_filename", "The name entered"},
102   { GIMP_PDB_INT32, "compression_format", "Compression format (0 = None, 1 = BC1/DXT1, 2 = BC2/DXT3, 3 = BC3/DXT5, 4 = BC3n/DXT5nm, 5 = BC4/ATI1N, 6 = BC5/ATI2N, 7 = RXGB (DXT5), 8 = Alpha Exponent (DXT5), 9 = YCoCg (DXT5), 10 = YCoCg scaled (DXT5))"},
103   { GIMP_PDB_INT32, "mipmaps", "How to handle mipmaps (0 = No mipmaps, 1 = Generate mipmaps, 2 = Use existing mipmaps (layers)"},
104   { GIMP_PDB_INT32, "savetype", "How to save the image (0 = selected layer, 1 = cube map, 2 = volume map, 3 = texture array"},
105   { GIMP_PDB_INT32, "format", "Custom pixel format (0 = default, 1 = R5G6B5, 2 = RGBA4, 3 = RGB5A1, 4 = RGB10A2)"},
106   { GIMP_PDB_INT32, "transparent_index", "Index of transparent color or -1 to disable (for indexed images only)."},
107   { GIMP_PDB_INT32, "mipmap_filter", "Filtering to use when generating mipmaps (0 = default, 1 = nearest, 2 = box, 3 = triangle, 4 = quadratic, 5 = bspline, 6 = mitchell, 7 = lanczos, 8 = kaiser)"},
108   { GIMP_PDB_INT32, "mipmap_wrap", "Wrap mode to use when generating mipmaps (0 = default, 1 = mirror, 2 = repeat, 3 = clamp)"},
109   { GIMP_PDB_INT32, "gamma_correct", "Use gamma correct mipmap filtering"},
110   { GIMP_PDB_INT32, "srgb", "Use sRGB colorspace for gamma correction"},
111   { GIMP_PDB_FLOAT, "gamma", "Gamma value to use for gamma correction (i.e. 2.2)"},
112   { GIMP_PDB_INT32, "perceptual_metric", "Use a perceptual error metric during compression"},
113   { GIMP_PDB_INT32, "preserve_alpha_coverage", "Preserve alpha test converage for alpha channel maps"},
114   { GIMP_PDB_FLOAT, "alpha_test_threshold", "Alpha test threshold value for which alpha test converage should be preserved"}
115 };
116 
117 #if 0
118 static GimpParamDef decode_args[] =
119 {
120   { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
121   { GIMP_PDB_IMAGE, "image", "Input image"},
122   { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save"}
123 };
124 #endif
125 
126 
MAIN()127 MAIN ()
128 
129 
130 static void
131 query (void)
132 {
133   gimp_install_procedure (LOAD_PROC,
134                           "Loads files in DDS image format",
135                           "Loads files in DDS image format",
136                           "Shawn Kirst",
137                           "Shawn Kirst",
138                           "2008",
139                           N_("DDS image"),
140                           0,
141                           GIMP_PLUGIN,
142                           G_N_ELEMENTS (load_args),
143                           G_N_ELEMENTS (load_return_vals),
144                           load_args, load_return_vals);
145 
146   gimp_register_file_handler_mime (LOAD_PROC, "image/dds");
147   gimp_register_magic_load_handler (LOAD_PROC,
148                                     "dds",
149                                     "",
150                                     "0,string,DDS");
151 
152   gimp_install_procedure (SAVE_PROC,
153                           "Saves files in DDS image format",
154                           "Saves files in DDS image format",
155                           "Shawn Kirst",
156                           "Shawn Kirst",
157                           "2008",
158                           N_("DDS image"),
159                           "INDEXED, GRAY, RGB",
160                           GIMP_PLUGIN,
161                           G_N_ELEMENTS (save_args), 0,
162                           save_args, 0);
163 
164   gimp_register_file_handler_mime (SAVE_PROC, "image/dds");
165   gimp_register_save_handler (SAVE_PROC,
166                               "dds",
167                               "");
168 
169 #if 0
170   gimp_install_procedure (DECODE_YCOCG_PROC,
171                           "Converts YCoCg encoded pixels to RGB",
172                           "Converts YCoCg encoded pixels to RGB",
173                           "Shawn Kirst",
174                           "Shawn Kirst",
175                           "2008",
176                           N_("Decode YCoCg"),
177                           "RGBA",
178                           GIMP_PLUGIN,
179                           G_N_ELEMENTS (decode_args), 0,
180                           decode_args, 0);
181   /*gimp_plugin_menu_register (DECODE_YCOCG_PROC, "<Image>/Filters/Colors");*/
182 
183   gimp_install_procedure (DECODE_YCOCG_SCALED_PROC,
184                           "Converts YCoCg (scaled) encoded pixels to RGB",
185                           "Converts YCoCg (scaled) encoded pixels to RGB",
186                           "Shawn Kirst",
187                           "Shawn Kirst",
188                           "2008",
189                           N_("Decode YCoCg (scaled)"),
190                           "RGBA",
191                           GIMP_PLUGIN,
192                           G_N_ELEMENTS (decode_args), 0,
193                           decode_args, 0);
194   /*gimp_plugin_menu_register (DECODE_YCOCG_SCALED_PROC, "<Image>/Filters/Colors");*/
195 
196   gimp_install_procedure (DECODE_ALPHA_EXP_PROC,
197                           "Converts alpha exponent encoded pixels to RGB",
198                           "Converts alpha exponent encoded pixels to RGB",
199                           "Shawn Kirst",
200                           "Shawn Kirst",
201                           "2008",
202                           N_("Decode Alpha exponent"),
203                           "RGBA",
204                           GIMP_PLUGIN,
205                           G_N_ELEMENTS (decode_args), 0,
206                           decode_args, 0);
207   /*gimp_plugin_menu_register (DECODE_ALPHA_EXP_PROC, "<Image>/Filters/Colors");*/
208 #endif
209 }
210 
211 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)212 run (const gchar      *name,
213      gint              nparams,
214      const GimpParam  *param,
215      gint             *nreturn_vals,
216      GimpParam       **return_vals)
217 {
218   static GimpParam  values[2];
219   GimpRunMode       run_mode;
220   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
221   gint32            imageID;
222   gint32            drawableID;
223   GimpExportReturn  export = GIMP_EXPORT_CANCEL;
224 
225   gegl_init (NULL, NULL);
226 
227   run_mode = param[0].data.d_int32;
228 
229   *nreturn_vals = 1;
230   *return_vals = values;
231 
232   values[0].type = GIMP_PDB_STATUS;
233   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
234 
235   if (! strcmp (name, LOAD_PROC))
236     {
237       switch (run_mode)
238         {
239         case GIMP_RUN_INTERACTIVE:
240           gimp_ui_init ("dds", 0);
241           gimp_get_data (LOAD_PROC, &dds_read_vals);
242           break;
243 
244         case GIMP_RUN_NONINTERACTIVE:
245           dds_read_vals.mipmaps = param[3].data.d_int32;
246           dds_read_vals.decode_images = param[4].data.d_int32;
247           if (nparams != G_N_ELEMENTS (load_args))
248             status = GIMP_PDB_CALLING_ERROR;
249           break;
250 
251         default:
252           break;
253         }
254 
255       if (status == GIMP_PDB_SUCCESS)
256         {
257           status = read_dds (param[1].data.d_string, &imageID,
258                              run_mode == GIMP_RUN_INTERACTIVE);
259           if (status == GIMP_PDB_SUCCESS && imageID != -1)
260             {
261               *nreturn_vals = 2;
262               values[1].type = GIMP_PDB_IMAGE;
263               values[1].data.d_image = imageID;
264               if (run_mode == GIMP_RUN_INTERACTIVE)
265                 gimp_set_data (LOAD_PROC, &dds_read_vals, sizeof (dds_read_vals));
266             }
267           else if (status != GIMP_PDB_CANCEL)
268             {
269               status = GIMP_PDB_EXECUTION_ERROR;
270             }
271         }
272     }
273   else if (! strcmp (name, SAVE_PROC))
274     {
275       imageID    = param[1].data.d_int32;
276       drawableID = param[2].data.d_int32;
277 
278       switch (run_mode)
279         {
280         case GIMP_RUN_INTERACTIVE:
281         case GIMP_RUN_WITH_LAST_VALS:
282           gimp_ui_init ("dds", 0);
283           export = gimp_export_image (&imageID, &drawableID, "DDS",
284                                      (GIMP_EXPORT_CAN_HANDLE_RGB |
285                                       GIMP_EXPORT_CAN_HANDLE_GRAY |
286                                       GIMP_EXPORT_CAN_HANDLE_INDEXED |
287                                       GIMP_EXPORT_CAN_HANDLE_ALPHA |
288                                       GIMP_EXPORT_CAN_HANDLE_LAYERS));
289           if (export == GIMP_EXPORT_CANCEL)
290             {
291               values[0].data.d_status = GIMP_PDB_CANCEL;
292               return;
293             }
294 
295         default:
296           break;
297         }
298 
299       switch (run_mode)
300         {
301         case GIMP_RUN_INTERACTIVE:
302           gimp_get_data (SAVE_PROC, &dds_write_vals);
303           break;
304 
305         case GIMP_RUN_NONINTERACTIVE:
306           if (nparams != G_N_ELEMENTS (save_args))
307             {
308               status = GIMP_PDB_CALLING_ERROR;
309             }
310           else
311             {
312               dds_write_vals.compression             = param[5].data.d_int32;
313               dds_write_vals.mipmaps                 = param[6].data.d_int32;
314               dds_write_vals.savetype                = param[7].data.d_int32;
315               dds_write_vals.format                  = param[8].data.d_int32;
316               dds_write_vals.transindex              = param[9].data.d_int32;
317               dds_write_vals.mipmap_filter           = param[10].data.d_int32;
318               dds_write_vals.mipmap_wrap             = param[11].data.d_int32;
319               dds_write_vals.gamma_correct           = param[12].data.d_int32;
320               dds_write_vals.srgb                    = param[13].data.d_int32;
321               dds_write_vals.gamma                   = param[14].data.d_float;
322               dds_write_vals.perceptual_metric       = param[15].data.d_int32;
323               dds_write_vals.preserve_alpha_coverage = param[16].data.d_int32;
324               dds_write_vals.alpha_test_threshold    = param[17].data.d_float;
325 
326               if ((dds_write_vals.compression <  DDS_COMPRESS_NONE) ||
327                  (dds_write_vals.compression >= DDS_COMPRESS_MAX))
328                 {
329                   status = GIMP_PDB_CALLING_ERROR;
330                 }
331 
332               if ((dds_write_vals.mipmaps <  DDS_MIPMAP_NONE) ||
333                  (dds_write_vals.mipmaps >= DDS_MIPMAP_MAX))
334                 {
335                   status = GIMP_PDB_CALLING_ERROR;
336                 }
337 
338               if ((dds_write_vals.savetype <  DDS_SAVE_SELECTED_LAYER) ||
339                  (dds_write_vals.savetype >= DDS_SAVE_MAX))
340                 {
341                   status = GIMP_PDB_CALLING_ERROR;
342                 }
343 
344               if ((dds_write_vals.format <  DDS_FORMAT_DEFAULT) ||
345                  (dds_write_vals.format >= DDS_FORMAT_MAX))
346                 {
347                   status = GIMP_PDB_CALLING_ERROR;
348                 }
349 
350               if ((dds_write_vals.mipmap_filter <  DDS_MIPMAP_FILTER_DEFAULT) ||
351                  (dds_write_vals.mipmap_filter >= DDS_MIPMAP_FILTER_MAX))
352                 {
353                   status = GIMP_PDB_CALLING_ERROR;
354                 }
355 
356               if ((dds_write_vals.mipmap_wrap <  DDS_MIPMAP_WRAP_DEFAULT) ||
357                  (dds_write_vals.mipmap_wrap >= DDS_MIPMAP_WRAP_MAX))
358                 {
359                   status = GIMP_PDB_CALLING_ERROR;
360                 }
361             }
362           break;
363 
364         case GIMP_RUN_WITH_LAST_VALS:
365           gimp_get_data (SAVE_PROC, &dds_write_vals);
366           break;
367 
368         default:
369           break;
370         }
371 
372       if (dds_write_vals.gamma < 1e-04f)
373         /* gimp_gamma () got removed and was always returning 2.2 anyway.
374          * XXX Review this piece of code if we expect gamma value could
375          * be parameterized.
376          */
377         dds_write_vals.gamma = 2.2;
378 
379       if (status == GIMP_PDB_SUCCESS)
380         {
381           status = write_dds (param[3].data.d_string, imageID, drawableID,
382                               run_mode == GIMP_RUN_INTERACTIVE);
383           if (status == GIMP_PDB_SUCCESS)
384             gimp_set_data (SAVE_PROC, &dds_write_vals, sizeof (dds_write_vals));
385         }
386 
387       if (export == GIMP_EXPORT_EXPORT)
388         gimp_image_delete (imageID);
389     }
390 #if 0
391   else if (! strcmp (name, DECODE_YCOCG_PROC))
392     {
393       imageID = param[1].data.d_int32;
394       drawableID = param[2].data.d_int32;
395 
396       decode_ycocg_image (drawableID, TRUE);
397 
398       status = GIMP_PDB_SUCCESS;
399 
400       if (run_mode != GIMP_RUN_NONINTERACTIVE)
401         gimp_displays_flush ();
402     }
403   else if (! strcmp (name, DECODE_YCOCG_SCALED_PROC))
404     {
405       imageID = param[1].data.d_int32;
406       drawableID = param[2].data.d_int32;
407 
408       decode_ycocg_scaled_image (drawableID, TRUE);
409 
410       status = GIMP_PDB_SUCCESS;
411 
412       if (run_mode != GIMP_RUN_NONINTERACTIVE)
413         gimp_displays_flush ();
414     }
415   else if (! strcmp (name, DECODE_ALPHA_EXP_PROC))
416     {
417       imageID = param[1].data.d_int32;
418       drawableID = param[2].data.d_int32;
419 
420       decode_alpha_exp_image (drawableID, TRUE);
421 
422       status = GIMP_PDB_SUCCESS;
423 
424       if (run_mode != GIMP_RUN_NONINTERACTIVE)
425         gimp_displays_flush ();
426     }
427 #endif
428   else
429     {
430       status = GIMP_PDB_CALLING_ERROR;
431     }
432 
433   values[0].data.d_status = status;
434 }
435