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