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