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