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