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