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