Parent Directory
|
Revision Log
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 |