2018-11-13 07:35:07 +08:00
|
|
|
/*
|
2019-01-03 04:32:17 +08:00
|
|
|
* DDS GIMP plugin
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2012 Shawn Kirst <skirst@gmail.com>,
|
|
|
|
* with parts (C) 2003 Arne Reuter <homepage@arnereuter.de> where specified.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
2018-11-13 07:35:07 +08:00
|
|
|
|
|
|
|
/*
|
2019-01-03 04:32:17 +08:00
|
|
|
** !!! COPYRIGHT NOTICE !!!
|
|
|
|
**
|
|
|
|
** The following is based on code (C) 2003 Arne Reuter <homepage@arnereuter.de>
|
|
|
|
** URL: http://www.dr-reuter.de/arne/dds.html
|
|
|
|
**
|
|
|
|
*/
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2018-11-14 21:56:15 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-11-13 07:35:07 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <glib/gstdio.h>
|
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
|
|
|
|
2018-11-14 21:56:15 +08:00
|
|
|
#include <libgimp/stdplugins-intl.h>
|
|
|
|
|
2019-10-03 02:54:16 +08:00
|
|
|
#include "ddsread.h"
|
2018-11-13 07:35:07 +08:00
|
|
|
#include "dds.h"
|
|
|
|
#include "dxt.h"
|
2019-02-18 02:33:10 +08:00
|
|
|
#include "endian_rw.h"
|
2018-11-13 07:35:07 +08:00
|
|
|
#include "misc.h"
|
|
|
|
#include "imath.h"
|
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
|
2018-11-13 07:35:07 +08:00
|
|
|
typedef struct
|
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guchar rshift, gshift, bshift, ashift;
|
|
|
|
guchar rbits, gbits, bbits, abits;
|
|
|
|
guint rmask, gmask, bmask, amask;
|
|
|
|
guint bpp, gimp_bpp;
|
|
|
|
gint tile_height;
|
|
|
|
guchar *palette;
|
2018-11-13 07:35:07 +08:00
|
|
|
} dds_load_info_t;
|
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean read_header (dds_header_t *hdr,
|
2019-01-03 04:32:17 +08:00
|
|
|
FILE *fp);
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean read_header_dx10 (dds_header_dx10_t *hdr,
|
2019-01-03 04:32:17 +08:00
|
|
|
FILE *fp);
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean validate_header (dds_header_t *hdr);
|
|
|
|
static gboolean setup_dxgi_format (dds_header_t *hdr,
|
2019-01-03 04:32:17 +08:00
|
|
|
dds_header_dx10_t *dx10hdr);
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean load_layer (FILE *fp,
|
2019-01-03 04:32:17 +08:00
|
|
|
dds_header_t *hdr,
|
|
|
|
dds_load_info_t *d,
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpImage *image,
|
2019-09-30 21:28:42 +08:00
|
|
|
guint level,
|
|
|
|
gchar *prefix,
|
|
|
|
guint *l,
|
2019-01-03 04:32:17 +08:00
|
|
|
guchar *pixels,
|
2019-10-02 05:31:06 +08:00
|
|
|
guchar *buf,
|
|
|
|
gboolean decode_images);
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean load_mipmaps (FILE *fp,
|
2019-01-03 04:32:17 +08:00
|
|
|
dds_header_t *hdr,
|
|
|
|
dds_load_info_t *d,
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpImage *image,
|
2019-09-30 21:28:42 +08:00
|
|
|
gchar *prefix,
|
|
|
|
guint *l,
|
2019-01-03 04:32:17 +08:00
|
|
|
guchar *pixels,
|
2019-10-02 05:31:06 +08:00
|
|
|
guchar *buf,
|
|
|
|
gboolean read_mipmaps,
|
|
|
|
gboolean decode_images);
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean load_face (FILE *fp,
|
2019-01-03 04:32:17 +08:00
|
|
|
dds_header_t *hdr,
|
|
|
|
dds_load_info_t *d,
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpImage *image,
|
2019-01-03 04:32:17 +08:00
|
|
|
char *prefix,
|
2019-09-30 21:28:42 +08:00
|
|
|
guint *l,
|
2019-01-03 04:32:17 +08:00
|
|
|
guchar *pixels,
|
2019-10-02 05:31:06 +08:00
|
|
|
guchar *buf,
|
|
|
|
gboolean read_mipmaps,
|
|
|
|
gboolean decode_images);
|
2019-09-30 21:28:42 +08:00
|
|
|
static guchar color_bits (guint mask);
|
|
|
|
static guchar color_shift (guint mask);
|
2019-10-02 05:31:06 +08:00
|
|
|
static gboolean load_dialog (GimpProcedure *procedure,
|
|
|
|
GObject *config);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
GimpPDBStatusType
|
2019-10-02 05:31:06 +08:00
|
|
|
read_dds (GFile *file,
|
|
|
|
GimpImage **ret_image,
|
|
|
|
gboolean interactive,
|
|
|
|
GimpProcedure *procedure,
|
|
|
|
GObject *config)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-10-02 05:31:06 +08:00
|
|
|
GimpImage *image = NULL;
|
|
|
|
guchar *buf;
|
|
|
|
guint l = 0;
|
|
|
|
guchar *pixels;
|
|
|
|
gchar *filename;
|
|
|
|
FILE *fp;
|
|
|
|
dds_header_t hdr;
|
|
|
|
dds_header_dx10_t dx10hdr;
|
|
|
|
dds_load_info_t d;
|
2019-09-30 21:28:42 +08:00
|
|
|
GList *layers;
|
|
|
|
GimpImageBaseType type;
|
2019-10-02 05:31:06 +08:00
|
|
|
gboolean read_mipmaps;
|
|
|
|
gboolean decode_images;
|
2019-09-30 21:28:42 +08:00
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if (interactive)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2019-10-02 05:31:06 +08:00
|
|
|
gimp_ui_init ("dds");
|
|
|
|
|
|
|
|
if (! load_dialog (procedure, config))
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_CANCEL;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
g_object_get (config,
|
|
|
|
"load-mipmaps", &read_mipmaps,
|
|
|
|
"decode-images", &decode_images,
|
|
|
|
NULL);
|
|
|
|
|
2019-09-12 03:48:34 +08:00
|
|
|
filename = g_file_get_path (file);
|
2019-01-03 04:32:17 +08:00
|
|
|
fp = g_fopen (filename, "rb");
|
2019-09-12 03:48:34 +08:00
|
|
|
g_free (filename);
|
|
|
|
|
|
|
|
if (! fp)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
g_message ("Error opening file.\n");
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_progress_init_printf ("Loading %s:", gimp_file_get_utf8_name (file));
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
/* read header */
|
|
|
|
read_header (&hdr, fp);
|
|
|
|
|
|
|
|
memset (&dx10hdr, 0, sizeof (dds_header_dx10_t));
|
|
|
|
|
|
|
|
/* read DX10 header if necessary */
|
2019-10-01 00:50:23 +08:00
|
|
|
if (GETL32 (hdr.pixelfmt.fourcc) == FOURCC ('D','X','1','0'))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2019-10-01 00:50:23 +08:00
|
|
|
read_header_dx10 (&dx10hdr, fp);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
if (! setup_dxgi_format (&hdr, &dx10hdr))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
if (! validate_header (&hdr))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
g_message ("Invalid DDS header!\n");
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* a lot of DDS images out there don't have this for some reason -_- */
|
|
|
|
if (hdr.pitch_or_linsize == 0)
|
|
|
|
{
|
|
|
|
if (hdr.pixelfmt.flags & DDPF_FOURCC) /* assume linear size */
|
|
|
|
{
|
|
|
|
hdr.pitch_or_linsize = ((hdr.width + 3) >> 2) * ((hdr.height + 3) >> 2);
|
2019-10-01 00:50:23 +08:00
|
|
|
switch (GETL32 (hdr.pixelfmt.fourcc))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
case FOURCC ('D','X','T','1'):
|
|
|
|
case FOURCC ('A','T','I','1'):
|
|
|
|
case FOURCC ('B','C','4','U'):
|
|
|
|
case FOURCC ('B','C','4','S'):
|
|
|
|
hdr.pitch_or_linsize *= 8;
|
|
|
|
break;
|
2018-11-13 07:35:07 +08:00
|
|
|
default:
|
2019-01-03 04:32:17 +08:00
|
|
|
hdr.pitch_or_linsize *= 16;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
else /* assume pitch */
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
hdr.pitch_or_linsize = hdr.height * hdr.width * (hdr.pixelfmt.bpp >> 3);
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if (hdr.pixelfmt.flags & DDPF_FOURCC)
|
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
/* fourcc is dXt* or rXgb */
|
2019-01-03 04:32:17 +08:00
|
|
|
if (hdr.pixelfmt.fourcc[1] == 'X')
|
|
|
|
hdr.pixelfmt.flags |= DDPF_ALPHAPIXELS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr.pixelfmt.flags & DDPF_FOURCC)
|
|
|
|
{
|
2019-10-01 00:50:23 +08:00
|
|
|
switch (GETL32 (hdr.pixelfmt.fourcc))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
case FOURCC ('A','T','I','1'):
|
|
|
|
case FOURCC ('B','C','4','U'):
|
|
|
|
case FOURCC ('B','C','4','S'):
|
|
|
|
d.bpp = d.gimp_bpp = 1;
|
|
|
|
type = GIMP_GRAY;
|
|
|
|
break;
|
|
|
|
case FOURCC ('A','T','I','2'):
|
|
|
|
case FOURCC ('B','C','5','U'):
|
|
|
|
case FOURCC ('B','C','5','S'):
|
|
|
|
d.bpp = d.gimp_bpp = 3;
|
|
|
|
type = GIMP_RGB;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
d.bpp = d.gimp_bpp = 4;
|
|
|
|
type = GIMP_RGB;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
d.bpp = hdr.pixelfmt.bpp >> 3;
|
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if (d.bpp == 2)
|
|
|
|
{
|
|
|
|
if (hdr.pixelfmt.amask == 0xf000) // RGBA4
|
|
|
|
{
|
|
|
|
d.gimp_bpp = 4;
|
|
|
|
type = GIMP_RGB;
|
|
|
|
}
|
|
|
|
else if (hdr.pixelfmt.amask == 0xff00) //L8A8
|
|
|
|
{
|
|
|
|
d.gimp_bpp = 2;
|
|
|
|
type = GIMP_GRAY;
|
|
|
|
}
|
|
|
|
else if (hdr.pixelfmt.bmask == 0x1f) //R5G6B5 or RGB5A1
|
|
|
|
{
|
|
|
|
if (hdr.pixelfmt.amask == 0x8000) // RGB5A1
|
|
|
|
d.gimp_bpp = 4;
|
|
|
|
else
|
|
|
|
d.gimp_bpp = 3;
|
|
|
|
|
|
|
|
type = GIMP_RGB;
|
|
|
|
}
|
|
|
|
else //L16
|
|
|
|
{
|
|
|
|
d.gimp_bpp = 1;
|
|
|
|
type = GIMP_GRAY;
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
else
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
if (hdr.pixelfmt.flags & DDPF_PALETTEINDEXED8)
|
|
|
|
{
|
|
|
|
type = GIMP_INDEXED;
|
|
|
|
d.gimp_bpp = 1;
|
|
|
|
}
|
|
|
|
else if (hdr.pixelfmt.rmask == 0xe0) // R3G3B2
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
type = GIMP_RGB;
|
|
|
|
d.gimp_bpp = 3;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
else
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
/* test alpha only image */
|
|
|
|
if (d.bpp == 1 && (hdr.pixelfmt.flags & DDPF_ALPHA))
|
|
|
|
{
|
|
|
|
d.gimp_bpp = 2;
|
|
|
|
type = GIMP_GRAY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d.gimp_bpp = d.bpp;
|
|
|
|
type = (d.bpp == 1) ? GIMP_GRAY : GIMP_RGB;
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
image = gimp_image_new (hdr.width, hdr.height, type);
|
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
if (! image)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
g_message ("Can't allocate new image.\n");
|
|
|
|
fclose (fp);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
2019-09-12 03:48:34 +08:00
|
|
|
gimp_image_set_file (image, file);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
if (hdr.pixelfmt.flags & DDPF_PALETTEINDEXED8)
|
|
|
|
{
|
|
|
|
d.palette = g_malloc (256 * 4);
|
|
|
|
if (fread (d.palette, 1, 1024, fp) != 1024)
|
|
|
|
{
|
|
|
|
g_message ("Error reading palette.\n");
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
for (i = j = 0; i < 768; i += 3, j += 4)
|
|
|
|
{
|
|
|
|
d.palette[i + 0] = d.palette[j + 0];
|
|
|
|
d.palette[i + 1] = d.palette[j + 1];
|
|
|
|
d.palette[i + 2] = d.palette[j + 2];
|
|
|
|
}
|
|
|
|
gimp_image_set_colormap (image, d.palette, 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
d.tile_height = gimp_tile_height ();
|
|
|
|
|
|
|
|
pixels = g_new (guchar, d.tile_height * hdr.width * d.gimp_bpp);
|
|
|
|
buf = g_malloc (hdr.pitch_or_linsize);
|
|
|
|
|
|
|
|
d.rshift = color_shift (hdr.pixelfmt.rmask);
|
|
|
|
d.gshift = color_shift (hdr.pixelfmt.gmask);
|
|
|
|
d.bshift = color_shift (hdr.pixelfmt.bmask);
|
|
|
|
d.ashift = color_shift (hdr.pixelfmt.amask);
|
2019-10-01 00:50:23 +08:00
|
|
|
d.rbits = color_bits (hdr.pixelfmt.rmask);
|
|
|
|
d.gbits = color_bits (hdr.pixelfmt.gmask);
|
|
|
|
d.bbits = color_bits (hdr.pixelfmt.bmask);
|
|
|
|
d.abits = color_bits (hdr.pixelfmt.amask);
|
|
|
|
d.rmask = (hdr.pixelfmt.rmask >> d.rshift) << (8 - d.rbits);
|
|
|
|
d.gmask = (hdr.pixelfmt.gmask >> d.gshift) << (8 - d.gbits);
|
|
|
|
d.bmask = (hdr.pixelfmt.bmask >> d.bshift) << (8 - d.bbits);
|
|
|
|
d.amask = (hdr.pixelfmt.amask >> d.ashift) << (8 - d.abits);
|
|
|
|
|
|
|
|
if (! (hdr.caps.caps2 & DDSCAPS2_CUBEMAP) &&
|
|
|
|
! (hdr.caps.caps2 & DDSCAPS2_VOLUME) &&
|
2018-11-13 07:35:07 +08:00
|
|
|
dx10hdr.arraySize == 0)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_layer (fp, &hdr, &d, image, 0, "", &l, pixels, buf,
|
|
|
|
decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_mipmaps (fp, &hdr, &d, image, "", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (hdr.caps.caps2 & DDSCAPS2_CUBEMAP)
|
|
|
|
{
|
|
|
|
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
! load_face (fp, &hdr, &d, image, "(positive x)", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
! load_face (fp, &hdr, &d, image, "(negative x)", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
! load_face (fp, &hdr, &d, image, "(positive y)", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
! load_face (fp, &hdr, &d, image, "(negative y)", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
! load_face (fp, &hdr, &d, image, "(positive z)", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((hdr.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
! load_face (fp, &hdr, &d, image, "(negative z)", &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((hdr.caps.caps2 & DDSCAPS2_VOLUME) &&
|
|
|
|
(hdr.flags & DDSD_DEPTH))
|
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guint i, level;
|
|
|
|
gchar *plane;
|
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
for (i = 0; i < hdr.depth; ++i)
|
|
|
|
{
|
|
|
|
plane = g_strdup_printf ("(z = %d)", i);
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_layer (fp, &hdr, &d, image, 0, plane, &l, pixels, buf,
|
|
|
|
decode_images))
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
g_free (plane);
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
g_free (plane);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((hdr.flags & DDSD_MIPMAPCOUNT) &&
|
|
|
|
(hdr.caps.caps1 & DDSCAPS_MIPMAP) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
read_mipmaps)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
for (level = 1; level < hdr.num_mipmaps; ++level)
|
|
|
|
{
|
|
|
|
int n = hdr.depth >> level;
|
2019-10-01 00:50:23 +08:00
|
|
|
|
|
|
|
if (n < 1)
|
|
|
|
n = 1;
|
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
for (i = 0; i < n; ++i)
|
|
|
|
{
|
|
|
|
plane = g_strdup_printf ("(z = %d)", i);
|
2019-10-01 00:50:23 +08:00
|
|
|
|
|
|
|
if (! load_layer (fp, &hdr, &d, image, level, plane, &l,
|
2019-10-02 05:31:06 +08:00
|
|
|
pixels, buf,
|
|
|
|
decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
g_free (plane);
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
g_free (plane);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (dx10hdr.arraySize > 0)
|
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guint i;
|
|
|
|
gchar *elem;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
for (i = 0; i < dx10hdr.arraySize; ++i)
|
|
|
|
{
|
|
|
|
elem = g_strdup_printf ("(array element %d)", i);
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_layer (fp, &hdr, &d, image, 0, elem, &l, pixels, buf,
|
|
|
|
decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_mipmaps (fp, &hdr, &d, image, elem, &l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
fclose (fp);
|
|
|
|
gimp_image_delete (image);
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-10-01 00:50:23 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
g_free (elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_progress_update (1.0);
|
|
|
|
|
|
|
|
if (hdr.pixelfmt.flags & DDPF_PALETTEINDEXED8)
|
|
|
|
g_free (d.palette);
|
|
|
|
|
|
|
|
g_free (buf);
|
|
|
|
g_free (pixels);
|
|
|
|
fclose (fp);
|
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
layers = gimp_image_list_layers (image);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
if (! layers)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
g_message ("Oops! NULL image read! Please report this!");
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
gimp_image_set_active_layer (image, layers->data);
|
|
|
|
g_list_free (layers);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
*ret_image = image;
|
2019-01-03 04:32:17 +08:00
|
|
|
|
2019-05-23 20:34:00 +08:00
|
|
|
return GIMP_PDB_SUCCESS;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-01-03 04:32:17 +08:00
|
|
|
read_header (dds_header_t *hdr,
|
|
|
|
FILE *fp)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guchar buf[DDS_HEADERSIZE];
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
memset (hdr, 0, sizeof (dds_header_t));
|
|
|
|
|
|
|
|
if (fread (buf, 1, DDS_HEADERSIZE, fp) != DDS_HEADERSIZE)
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
hdr->magic = GETL32(buf);
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
hdr->size = GETL32 (buf + 4);
|
|
|
|
hdr->flags = GETL32 (buf + 8);
|
|
|
|
hdr->height = GETL32 (buf + 12);
|
|
|
|
hdr->width = GETL32 (buf + 16);
|
|
|
|
hdr->pitch_or_linsize = GETL32 (buf + 20);
|
|
|
|
hdr->depth = GETL32 (buf + 24);
|
|
|
|
hdr->num_mipmaps = GETL32 (buf + 28);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
hdr->pixelfmt.size = GETL32 (buf + 76);
|
|
|
|
hdr->pixelfmt.flags = GETL32 (buf + 80);
|
2019-01-03 04:32:17 +08:00
|
|
|
hdr->pixelfmt.fourcc[0] = buf[84];
|
|
|
|
hdr->pixelfmt.fourcc[1] = buf[85];
|
|
|
|
hdr->pixelfmt.fourcc[2] = buf[86];
|
|
|
|
hdr->pixelfmt.fourcc[3] = buf[87];
|
2019-10-01 00:50:23 +08:00
|
|
|
hdr->pixelfmt.bpp = GETL32 (buf + 88);
|
|
|
|
hdr->pixelfmt.rmask = GETL32 (buf + 92);
|
|
|
|
hdr->pixelfmt.gmask = GETL32 (buf + 96);
|
|
|
|
hdr->pixelfmt.bmask = GETL32 (buf + 100);
|
|
|
|
hdr->pixelfmt.amask = GETL32 (buf + 104);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
hdr->caps.caps1 = GETL32 (buf + 108);
|
|
|
|
hdr->caps.caps2 = GETL32 (buf + 112);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
/* GIMP-DDS special info */
|
2019-10-01 00:50:23 +08:00
|
|
|
if (GETL32 (buf + 32) == FOURCC ('G','I','M','P') &&
|
|
|
|
GETL32 (buf + 36) == FOURCC ('-','D','D','S'))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2019-10-01 00:50:23 +08:00
|
|
|
hdr->reserved.gimp_dds_special.magic1 = GETL32 (buf + 32);
|
|
|
|
hdr->reserved.gimp_dds_special.magic2 = GETL32 (buf + 36);
|
|
|
|
hdr->reserved.gimp_dds_special.version = GETL32 (buf + 40);
|
|
|
|
hdr->reserved.gimp_dds_special.extra_fourcc = GETL32 (buf + 44);
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
return TRUE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-05-23 20:34:00 +08:00
|
|
|
read_header_dx10 (dds_header_dx10_t *hdr,
|
|
|
|
FILE *fp)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
gchar buf[DDS_HEADERSIZE_DX10];
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
memset (hdr, 0, sizeof (dds_header_dx10_t));
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if (fread (buf, 1, DDS_HEADERSIZE_DX10, fp) != DDS_HEADERSIZE_DX10)
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
hdr->dxgiFormat = GETL32 (buf);
|
|
|
|
hdr->resourceDimension = GETL32 (buf + 4);
|
|
|
|
hdr->miscFlag = GETL32 (buf + 8);
|
|
|
|
hdr->arraySize = GETL32 (buf + 12);
|
|
|
|
hdr->reserved = GETL32 (buf + 16);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
return TRUE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-01-03 04:32:17 +08:00
|
|
|
validate_header (dds_header_t *hdr)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guint fourcc;
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
if (hdr->magic != FOURCC ('D','D','S',' '))
|
|
|
|
{
|
|
|
|
g_message ("Invalid DDS file.\n");
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
2020-07-09 10:53:15 +08:00
|
|
|
if (hdr->pixelfmt.flags & DDPF_FOURCC)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2020-07-09 10:53:15 +08:00
|
|
|
if (hdr->flags & DDSD_PITCH)
|
|
|
|
{
|
|
|
|
g_message ("Warning: DDSD_PITCH is incorrectly set for DDPF_FOURCC!");
|
|
|
|
hdr->flags &= DDSD_PITCH;
|
|
|
|
}
|
|
|
|
if (! (hdr->flags & DDSD_LINEARSIZE))
|
|
|
|
{
|
|
|
|
g_message ("Warning: DDSD_LINEARSIZE is incorrectly not set for DDPF_FOURCC!");
|
|
|
|
hdr->flags |= DDSD_LINEARSIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (! (hdr->flags & DDSD_PITCH))
|
|
|
|
{
|
|
|
|
g_message ("Warning: DDSD_PITCH is not set!");
|
|
|
|
hdr->flags |= DDSD_PITCH;
|
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2020-07-09 10:53:15 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
/*
|
|
|
|
if ((hdr->pixelfmt.flags & DDPF_FOURCC) ==
|
|
|
|
(hdr->pixelfmt.flags & DDPF_RGB))
|
|
|
|
{
|
|
|
|
g_message ("Invalid pixel format.\n");
|
2019-05-23 20:34:00 +08:00
|
|
|
return 0;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
*/
|
|
|
|
fourcc = GETL32(hdr->pixelfmt.fourcc);
|
|
|
|
|
|
|
|
if ((hdr->pixelfmt.flags & DDPF_FOURCC) &&
|
|
|
|
fourcc != FOURCC ('D','X','T','1') &&
|
|
|
|
fourcc != FOURCC ('D','X','T','2') &&
|
|
|
|
fourcc != FOURCC ('D','X','T','3') &&
|
|
|
|
fourcc != FOURCC ('D','X','T','4') &&
|
|
|
|
fourcc != FOURCC ('D','X','T','5') &&
|
|
|
|
fourcc != FOURCC ('R','X','G','B') &&
|
|
|
|
fourcc != FOURCC ('A','T','I','1') &&
|
|
|
|
fourcc != FOURCC ('B','C','4','U') &&
|
|
|
|
fourcc != FOURCC ('B','C','4','S') &&
|
|
|
|
fourcc != FOURCC ('A','T','I','2') &&
|
|
|
|
fourcc != FOURCC ('B','C','5','U') &&
|
|
|
|
fourcc != FOURCC ('B','C','5','S') &&
|
|
|
|
fourcc != FOURCC ('D','X','1','0'))
|
|
|
|
{
|
|
|
|
g_message ("Unsupported format (FOURCC: %c%c%c%c, hex: %08x).\n",
|
|
|
|
hdr->pixelfmt.fourcc[0],
|
|
|
|
hdr->pixelfmt.fourcc[1],
|
|
|
|
hdr->pixelfmt.fourcc[2],
|
|
|
|
hdr->pixelfmt.fourcc[3],
|
|
|
|
GETL32(hdr->pixelfmt.fourcc));
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr->pixelfmt.flags & DDPF_RGB)
|
|
|
|
{
|
|
|
|
if ((hdr->pixelfmt.bpp != 8) &&
|
|
|
|
(hdr->pixelfmt.bpp != 16) &&
|
|
|
|
(hdr->pixelfmt.bpp != 24) &&
|
|
|
|
(hdr->pixelfmt.bpp != 32))
|
|
|
|
{
|
|
|
|
g_message ("Invalid BPP.\n");
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.flags & DDPF_LUMINANCE)
|
|
|
|
{
|
|
|
|
if ((hdr->pixelfmt.bpp != 8) &&
|
|
|
|
(hdr->pixelfmt.bpp != 16))
|
|
|
|
{
|
|
|
|
g_message ("Invalid BPP.\n");
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
|
|
|
hdr->pixelfmt.flags |= DDPF_RGB;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.flags & DDPF_PALETTEINDEXED8)
|
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
hdr->pixelfmt.flags |= DDPF_RGB;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
if (! (hdr->pixelfmt.flags & DDPF_RGB) &&
|
|
|
|
! (hdr->pixelfmt.flags & DDPF_ALPHA) &&
|
|
|
|
! (hdr->pixelfmt.flags & DDPF_FOURCC) &&
|
|
|
|
! (hdr->pixelfmt.flags & DDPF_LUMINANCE))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
g_message ("Unknown pixel format! Taking a guess, expect trouble!");
|
|
|
|
switch (fourcc)
|
|
|
|
{
|
|
|
|
case FOURCC ('D','X','T','1'):
|
|
|
|
case FOURCC ('D','X','T','2'):
|
|
|
|
case FOURCC ('D','X','T','3'):
|
|
|
|
case FOURCC ('D','X','T','4'):
|
|
|
|
case FOURCC ('D','X','T','5'):
|
|
|
|
case FOURCC ('R','X','G','B'):
|
|
|
|
case FOURCC ('A','T','I','1'):
|
|
|
|
case FOURCC ('B','C','4','U'):
|
|
|
|
case FOURCC ('B','C','4','S'):
|
|
|
|
case FOURCC ('A','T','I','2'):
|
|
|
|
case FOURCC ('B','C','5','U'):
|
|
|
|
case FOURCC ('B','C','5','S'):
|
|
|
|
hdr->pixelfmt.flags |= DDPF_FOURCC;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch (hdr->pixelfmt.bpp)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
case 8:
|
|
|
|
if (hdr->pixelfmt.flags & DDPF_ALPHAPIXELS)
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHA;
|
|
|
|
else
|
|
|
|
hdr->pixelfmt.flags |= DDPF_LUMINANCE;
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
case 24:
|
|
|
|
case 32:
|
|
|
|
hdr->pixelfmt.flags |= DDPF_RGB;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_message ("Invalid pixel format.");
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
return TRUE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function will set the necessary flags and attributes in the standard
|
|
|
|
* dds header using the information found in the DX10 header.
|
|
|
|
*/
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-01-03 04:32:17 +08:00
|
|
|
setup_dxgi_format (dds_header_t *hdr,
|
|
|
|
dds_header_dx10_t *dx10hdr)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((dx10hdr->resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE2D) &&
|
2018-11-13 07:35:07 +08:00
|
|
|
(dx10hdr->miscFlag & D3D10_RESOURCE_MISC_TEXTURECUBE))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
hdr->caps.caps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
else if (dx10hdr->resourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D)
|
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
hdr->flags |= DDSD_DEPTH;
|
|
|
|
hdr->caps.caps2 |= DDSCAPS2_VOLUME;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((dx10hdr->resourceDimension != D3D10_RESOURCE_DIMENSION_TEXTURE1D) &&
|
2018-11-13 07:35:07 +08:00
|
|
|
(dx10hdr->resourceDimension != D3D10_RESOURCE_DIMENSION_TEXTURE2D) &&
|
|
|
|
(dx10hdr->resourceDimension != D3D10_RESOURCE_DIMENSION_TEXTURE3D))
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
// check for a compressed DXGI format
|
|
|
|
if ((dx10hdr->dxgiFormat >= DXGI_FORMAT_BC1_TYPELESS) &&
|
2018-11-13 07:35:07 +08:00
|
|
|
(dx10hdr->dxgiFormat <= DXGI_FORMAT_BC5_SNORM))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
// set flag and replace FOURCC
|
|
|
|
hdr->pixelfmt.flags |= DDPF_FOURCC;
|
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
switch (dx10hdr->dxgiFormat)
|
|
|
|
{
|
|
|
|
case DXGI_FORMAT_BC1_TYPELESS:
|
|
|
|
case DXGI_FORMAT_BC1_UNORM:
|
|
|
|
case DXGI_FORMAT_BC1_UNORM_SRGB:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('D','X','T','1'));
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_BC2_TYPELESS:
|
|
|
|
case DXGI_FORMAT_BC2_UNORM:
|
|
|
|
case DXGI_FORMAT_BC2_UNORM_SRGB:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('D','X','T','3'));
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_BC3_TYPELESS:
|
|
|
|
case DXGI_FORMAT_BC3_UNORM:
|
|
|
|
case DXGI_FORMAT_BC3_UNORM_SRGB:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('D','X','T','5'));
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_BC4_TYPELESS:
|
|
|
|
case DXGI_FORMAT_BC4_UNORM:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('A','T','I','1'));
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_BC4_SNORM:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('B','C','4','S'));
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_BC5_TYPELESS:
|
|
|
|
case DXGI_FORMAT_BC5_UNORM:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('A','T','I','2'));
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_BC5_SNORM:
|
|
|
|
PUTL32(hdr->pixelfmt.fourcc, FOURCC ('B','C','5','S'));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
/* unset the FOURCC flag */
|
|
|
|
hdr->pixelfmt.flags &= ~DDPF_FOURCC;
|
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
switch (dx10hdr->dxgiFormat)
|
|
|
|
{
|
|
|
|
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
|
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
|
|
hdr->pixelfmt.bpp = 32;
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHAPIXELS;
|
|
|
|
hdr->pixelfmt.rmask = 0x00ff0000;
|
|
|
|
hdr->pixelfmt.gmask = 0x0000ff00;
|
|
|
|
hdr->pixelfmt.bmask = 0x000000ff;
|
|
|
|
hdr->pixelfmt.amask = 0xff000000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
|
|
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
|
|
hdr->pixelfmt.bpp = 32;
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHAPIXELS;
|
|
|
|
hdr->pixelfmt.rmask = 0x00ff0000;
|
|
|
|
hdr->pixelfmt.gmask = 0x0000ff00;
|
|
|
|
hdr->pixelfmt.bmask = 0x000000ff;
|
|
|
|
hdr->pixelfmt.amask = 0x00000000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_UINT:
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SNORM:
|
|
|
|
case DXGI_FORMAT_R8G8B8A8_SINT:
|
|
|
|
hdr->pixelfmt.bpp = 32;
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHAPIXELS;
|
|
|
|
hdr->pixelfmt.rmask = 0x000000ff;
|
|
|
|
hdr->pixelfmt.gmask = 0x0000ff00;
|
|
|
|
hdr->pixelfmt.bmask = 0x00ff0000;
|
|
|
|
hdr->pixelfmt.amask = 0xff000000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
|
|
hdr->pixelfmt.bpp = 16;
|
|
|
|
hdr->pixelfmt.rmask = 0x0000f800;
|
|
|
|
hdr->pixelfmt.gmask = 0x000007e0;
|
|
|
|
hdr->pixelfmt.bmask = 0x0000001f;
|
|
|
|
hdr->pixelfmt.amask = 0x00000000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
|
|
hdr->pixelfmt.bpp = 16;
|
|
|
|
hdr->pixelfmt.rmask = 0x00007c00;
|
|
|
|
hdr->pixelfmt.gmask = 0x000003e0;
|
|
|
|
hdr->pixelfmt.bmask = 0x0000001f;
|
|
|
|
hdr->pixelfmt.amask = 0x00008000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
|
|
|
case DXGI_FORMAT_R10G10B10A2_UINT:
|
|
|
|
hdr->pixelfmt.bpp = 32;
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHAPIXELS;
|
|
|
|
hdr->pixelfmt.rmask = 0x000003ff;
|
|
|
|
hdr->pixelfmt.gmask = 0x000ffc00;
|
|
|
|
hdr->pixelfmt.bmask = 0x3ff00000;
|
|
|
|
hdr->pixelfmt.amask = 0xc0000000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
|
|
hdr->pixelfmt.bpp = 8;
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHA | DDPF_ALPHAPIXELS;
|
|
|
|
hdr->pixelfmt.rmask = hdr->pixelfmt.gmask = hdr->pixelfmt.bmask = 0;
|
|
|
|
hdr->pixelfmt.amask = 0x000000ff;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_R8_TYPELESS:
|
|
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
|
|
case DXGI_FORMAT_R8_UINT:
|
|
|
|
case DXGI_FORMAT_R8_SNORM:
|
|
|
|
case DXGI_FORMAT_R8_SINT:
|
|
|
|
hdr->pixelfmt.bpp = 8;
|
|
|
|
hdr->pixelfmt.rmask = 0x000000ff;
|
|
|
|
hdr->pixelfmt.gmask = hdr->pixelfmt.bmask = hdr->pixelfmt.amask = 0;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
|
|
hdr->pixelfmt.bpp = 16;
|
|
|
|
hdr->pixelfmt.flags |= DDPF_ALPHAPIXELS;
|
|
|
|
hdr->pixelfmt.rmask = 0x00000f00;
|
|
|
|
hdr->pixelfmt.gmask = 0x000000f0;
|
|
|
|
hdr->pixelfmt.bmask = 0x0000000f;
|
|
|
|
hdr->pixelfmt.amask = 0x0000f000;
|
|
|
|
break;
|
|
|
|
case DXGI_FORMAT_UNKNOWN:
|
|
|
|
g_message ("Unknown DXGI format. Expect problems...");
|
|
|
|
break;
|
|
|
|
default: /* unsupported DXGI format */
|
|
|
|
g_message ("Unsupported DXGI format (%d)", dx10hdr->dxgiFormat);
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
return TRUE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2018-11-13 07:44:11 +08:00
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
static const Babl *
|
2018-11-13 07:44:11 +08:00
|
|
|
premultiplied_variant (const Babl* format)
|
|
|
|
{
|
|
|
|
if (format == babl_format ("R'G'B'A u8"))
|
|
|
|
return babl_format ("R'aG'aB'aA u8");
|
|
|
|
else
|
2019-09-30 21:28:42 +08:00
|
|
|
g_printerr ("Add format %s to premultiplied_variant () %s: %d\n",
|
|
|
|
babl_get_name (format), __FILE__, __LINE__);
|
2018-11-13 07:44:11 +08:00
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-01-03 04:32:17 +08:00
|
|
|
load_layer (FILE *fp,
|
|
|
|
dds_header_t *hdr,
|
|
|
|
dds_load_info_t *d,
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpImage *image,
|
2019-09-30 21:28:42 +08:00
|
|
|
guint level,
|
2019-01-03 04:32:17 +08:00
|
|
|
char *prefix,
|
2019-09-30 21:28:42 +08:00
|
|
|
guint *l,
|
2019-01-03 04:32:17 +08:00
|
|
|
guchar *pixels,
|
2019-10-02 05:31:06 +08:00
|
|
|
guchar *buf,
|
|
|
|
gboolean decode_images)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
GeglBuffer *buffer;
|
|
|
|
const Babl *bablfmt = NULL;
|
|
|
|
GimpImageType type = GIMP_RGBA_IMAGE;
|
|
|
|
gchar *layer_name;
|
|
|
|
gint x, y, z, n;
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpLayer *layer;
|
2019-09-30 21:28:42 +08:00
|
|
|
guint width = hdr->width >> level;
|
|
|
|
guint height = hdr->height >> level;
|
|
|
|
guint size = hdr->pitch_or_linsize >> (2 * level);
|
|
|
|
guint layerw;
|
|
|
|
gint format = DDS_COMPRESS_NONE;
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
if (width < 1) width = 1;
|
|
|
|
if (height < 1) height = 1;
|
|
|
|
|
|
|
|
switch (d->bpp)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
if (hdr->pixelfmt.flags & DDPF_PALETTEINDEXED8)
|
|
|
|
{
|
|
|
|
type = GIMP_INDEXED_IMAGE;
|
|
|
|
bablfmt = babl_format ("R'G'B' u8");
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.rmask == 0xe0)
|
|
|
|
{
|
|
|
|
type = GIMP_RGB_IMAGE;
|
|
|
|
bablfmt = babl_format ("R'G'B' u8");
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.flags & DDPF_ALPHA)
|
|
|
|
{
|
|
|
|
type = GIMP_GRAYA_IMAGE;
|
|
|
|
bablfmt = babl_format ("Y'A u8");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
type = GIMP_GRAY_IMAGE;
|
|
|
|
bablfmt = babl_format ("Y' u8");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (hdr->pixelfmt.amask == 0xf000) /* RGBA4 */
|
|
|
|
{
|
|
|
|
type = GIMP_RGBA_IMAGE;
|
|
|
|
bablfmt = babl_format ("R'G'B'A u8");
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.amask == 0xff00) /* L8A8 */
|
|
|
|
{
|
|
|
|
type = GIMP_GRAYA_IMAGE;
|
|
|
|
bablfmt = babl_format ("Y'A u8");
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.bmask == 0x1f) /* R5G6B5 or RGB5A1 */
|
|
|
|
{
|
|
|
|
type = (hdr->pixelfmt.amask == 0x8000) ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
|
|
|
|
bablfmt = (hdr->pixelfmt.amask == 0x8000) ? babl_format ("R'G'B'A u8") : babl_format ("R'G'B' u8");
|
|
|
|
}
|
|
|
|
else /* L16 */
|
|
|
|
{
|
|
|
|
type = GIMP_GRAY_IMAGE;
|
|
|
|
bablfmt = babl_format ("Y' u8");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: type = GIMP_RGB_IMAGE; bablfmt = babl_format ("R'G'B' u8"); break;
|
|
|
|
case 4: type = GIMP_RGBA_IMAGE; bablfmt = babl_format ("R'G'B'A u8"); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
layer_name = (level) ? g_strdup_printf ("mipmap %d %s", level, prefix) :
|
|
|
|
g_strdup_printf ("main surface %s", prefix);
|
|
|
|
|
|
|
|
layer = gimp_layer_new (image, layer_name, width, height, type, 100,
|
2019-08-27 20:43:38 +08:00
|
|
|
gimp_image_get_default_new_layer_mode (image));
|
2019-01-03 04:32:17 +08:00
|
|
|
g_free (layer_name);
|
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
gimp_image_insert_layer (image, layer, NULL, *l);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
if ((*l)++) gimp_item_set_visible (GIMP_ITEM (layer), FALSE);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-08-27 20:43:38 +08:00
|
|
|
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
layerw = gegl_buffer_get_width (buffer);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if (hdr->pixelfmt.flags & DDPF_FOURCC)
|
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guint w = (width + 3) >> 2;
|
|
|
|
guint h = (height + 3) >> 2;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
switch (GETL32(hdr->pixelfmt.fourcc))
|
|
|
|
{
|
|
|
|
case FOURCC ('D','X','T','1'): format = DDS_COMPRESS_BC1; break;
|
|
|
|
case FOURCC ('D','X','T','2'): bablfmt = premultiplied_variant (bablfmt);
|
|
|
|
case FOURCC ('D','X','T','3'): format = DDS_COMPRESS_BC2; break;
|
|
|
|
case FOURCC ('D','X','T','4'): bablfmt = premultiplied_variant (bablfmt);
|
|
|
|
case FOURCC ('D','X','T','5'): format = DDS_COMPRESS_BC3; break;
|
|
|
|
case FOURCC ('R','X','G','B'): format = DDS_COMPRESS_BC3; break;
|
|
|
|
case FOURCC ('A','T','I','1'):
|
|
|
|
case FOURCC ('B','C','4','U'):
|
|
|
|
case FOURCC ('B','C','4','S'): format = DDS_COMPRESS_BC4; break;
|
|
|
|
case FOURCC ('A','T','I','2'):
|
|
|
|
case FOURCC ('B','C','5','U'):
|
|
|
|
case FOURCC ('B','C','5','S'): format = DDS_COMPRESS_BC5; break;
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
|
|
|
size = w * h;
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((format == DDS_COMPRESS_BC1) || (format == DDS_COMPRESS_BC4))
|
|
|
|
size *= 8;
|
2018-11-13 07:35:07 +08:00
|
|
|
else
|
2019-01-03 04:32:17 +08:00
|
|
|
size *= 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((hdr->flags & DDSD_LINEARSIZE) &&
|
|
|
|
!fread (buf, size, 1, fp))
|
|
|
|
{
|
|
|
|
g_message ("Unexpected EOF.\n");
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 20:34:00 +08:00
|
|
|
if ((hdr->pixelfmt.flags & DDPF_RGB) ||
|
|
|
|
(hdr->pixelfmt.flags & DDPF_ALPHA))
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
2018-11-13 07:35:07 +08:00
|
|
|
z = 0;
|
2019-01-03 04:32:17 +08:00
|
|
|
for (y = 0, n = 0; y < height; ++y, ++n)
|
|
|
|
{
|
|
|
|
if (n >= d->tile_height)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, y - n, layerw, n), 0,
|
|
|
|
bablfmt, pixels, GEGL_AUTO_ROWSTRIDE);
|
|
|
|
n = 0;
|
2019-09-30 21:28:42 +08:00
|
|
|
gimp_progress_update ((double) y / (double) hdr->height);
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
if ((hdr->flags & DDSD_PITCH) &&
|
2019-10-01 00:50:23 +08:00
|
|
|
! fread (buf, width * d->bpp, 1, fp))
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-01-03 04:32:17 +08:00
|
|
|
g_message ("Unexpected EOF.\n");
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
if (!(hdr->flags & DDSD_LINEARSIZE)) z = 0;
|
|
|
|
|
|
|
|
for (x = 0; x < layerw; ++x)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guint pixel = buf[z];
|
|
|
|
guint pos = (n * layerw + x) * d->gimp_bpp;
|
2019-01-03 04:32:17 +08:00
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
if (d->bpp > 1) pixel += ((guint) buf[z + 1] << 8);
|
|
|
|
if (d->bpp > 2) pixel += ((guint) buf[z + 2] << 16);
|
|
|
|
if (d->bpp > 3) pixel += ((guint) buf[z + 3] << 24);
|
2019-01-03 04:32:17 +08:00
|
|
|
|
|
|
|
if (d->bpp >= 3)
|
|
|
|
{
|
|
|
|
if (hdr->pixelfmt.amask == 0xc0000000) // handle RGB10A2
|
|
|
|
{
|
|
|
|
pixels[pos + 0] = (pixel >> d->bshift) >> 2;
|
|
|
|
pixels[pos + 1] = (pixel >> d->gshift) >> 2;
|
|
|
|
pixels[pos + 2] = (pixel >> d->rshift) >> 2;
|
|
|
|
if (hdr->pixelfmt.flags & DDPF_ALPHAPIXELS)
|
|
|
|
pixels[pos + 3] = (pixel >> d->ashift << (8 - d->abits) & d->amask) * 255 / d->amask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pixels[pos] =
|
|
|
|
(pixel >> d->rshift << (8 - d->rbits) & d->rmask) * 255 / d->rmask;
|
|
|
|
pixels[pos + 1] =
|
|
|
|
(pixel >> d->gshift << (8 - d->gbits) & d->gmask) * 255 / d->gmask;
|
|
|
|
pixels[pos + 2] =
|
|
|
|
(pixel >> d->bshift << (8 - d->bbits) & d->bmask) * 255 / d->bmask;
|
|
|
|
if (hdr->pixelfmt.flags & DDPF_ALPHAPIXELS)
|
|
|
|
{
|
|
|
|
pixels[pos + 3] =
|
|
|
|
(pixel >> d->ashift << (8 - d->abits) & d->amask) * 255 / d->amask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (d->bpp == 2)
|
|
|
|
{
|
|
|
|
if (hdr->pixelfmt.amask == 0xf000) //RGBA4
|
|
|
|
{
|
|
|
|
pixels[pos] =
|
|
|
|
(pixel >> d->rshift << (8 - d->rbits) & d->rmask) * 255 / d->rmask;
|
|
|
|
pixels[pos + 1] =
|
|
|
|
(pixel >> d->gshift << (8 - d->gbits) & d->gmask) * 255 / d->gmask;
|
|
|
|
pixels[pos + 2] =
|
|
|
|
(pixel >> d->bshift << (8 - d->bbits) & d->bmask) * 255 / d->bmask;
|
|
|
|
pixels[pos + 3] =
|
|
|
|
(pixel >> d->ashift << (8 - d->abits) & d->amask) * 255 / d->amask;
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.amask == 0xff00) //L8A8
|
|
|
|
{
|
|
|
|
pixels[pos] =
|
|
|
|
(pixel >> d->rshift << (8 - d->rbits) & d->rmask) * 255 / d->rmask;
|
|
|
|
pixels[pos + 1] =
|
|
|
|
(pixel >> d->ashift << (8 - d->abits) & d->amask) * 255 / d->amask;
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.bmask == 0x1f) //R5G6B5 or RGB5A1
|
|
|
|
{
|
|
|
|
pixels[pos] =
|
|
|
|
(pixel >> d->rshift << (8 - d->rbits) & d->rmask) * 255 / d->rmask;
|
|
|
|
pixels[pos + 1] =
|
|
|
|
(pixel >> d->gshift << (8 - d->gbits) & d->gmask) * 255 / d->gmask;
|
|
|
|
pixels[pos + 2] =
|
|
|
|
(pixel >> d->bshift << (8 - d->bbits) & d->bmask) * 255 / d->bmask;
|
|
|
|
if (hdr->pixelfmt.amask == 0x8000)
|
|
|
|
{
|
|
|
|
pixels[pos + 3] =
|
|
|
|
(pixel >> d->ashift << (8 - d->abits) & d->amask) * 255 / d->amask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else //L16
|
2019-09-30 21:28:42 +08:00
|
|
|
pixels[pos] = (guchar) (255 * ((float)(pixel & 0xffff) / 65535.0f));
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (hdr->pixelfmt.flags & DDPF_PALETTEINDEXED8)
|
|
|
|
{
|
|
|
|
pixels[pos] = pixel & 0xff;
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.rmask == 0xe0) // R3G3B2
|
|
|
|
{
|
|
|
|
pixels[pos] =
|
|
|
|
(pixel >> d->rshift << (8 - d->rbits) & d->rmask) * 255 / d->rmask;
|
|
|
|
pixels[pos + 1] =
|
|
|
|
(pixel >> d->gshift << (8 - d->gbits) & d->gmask) * 255 / d->gmask;
|
|
|
|
pixels[pos + 2] =
|
|
|
|
(pixel >> d->bshift << (8 - d->bbits) & d->bmask) * 255 / d->bmask;
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.flags & DDPF_ALPHA)
|
|
|
|
{
|
|
|
|
pixels[pos + 0] = 255;
|
|
|
|
pixels[pos + 1] = pixel & 0xff;
|
|
|
|
}
|
|
|
|
else // LUMINANCE
|
|
|
|
{
|
|
|
|
pixels[pos] = pixel & 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
z += d->bpp;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, y - n, layerw, n), 0,
|
|
|
|
bablfmt, pixels, GEGL_AUTO_ROWSTRIDE);
|
|
|
|
}
|
|
|
|
else if (hdr->pixelfmt.flags & DDPF_FOURCC)
|
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guchar *dst;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
dst = g_malloc (width * height * d->gimp_bpp);
|
|
|
|
memset (dst, 0, width * height * d->gimp_bpp);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if (d->gimp_bpp == 4)
|
|
|
|
{
|
|
|
|
for (y = 0; y < height; ++y)
|
|
|
|
for (x = 0; x < width; ++x)
|
|
|
|
dst[y * (width * 4) + (x * 4) + 3] = 255;
|
|
|
|
}
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
dxt_decompress (dst, buf, format, size, width, height, d->gimp_bpp,
|
|
|
|
hdr->pixelfmt.flags & DDPF_NORMAL);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
|
|
|
z = 0;
|
2019-01-03 04:32:17 +08:00
|
|
|
for (y = 0, n = 0; y < height; ++y, ++n)
|
|
|
|
{
|
|
|
|
if (n >= d->tile_height)
|
|
|
|
{
|
|
|
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, y - n, layerw, n), 0,
|
|
|
|
bablfmt, pixels, GEGL_AUTO_ROWSTRIDE);
|
|
|
|
n = 0;
|
|
|
|
gimp_progress_update ((double)y / (double)hdr->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy (pixels + n * layerw * d->gimp_bpp,
|
|
|
|
dst + y * layerw * d->gimp_bpp,
|
|
|
|
width * d->gimp_bpp);
|
|
|
|
}
|
|
|
|
|
|
|
|
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, y - n, layerw, n), 0,
|
|
|
|
bablfmt, pixels, GEGL_AUTO_ROWSTRIDE);
|
|
|
|
|
|
|
|
g_free (dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
gegl_buffer_flush (buffer);
|
|
|
|
|
|
|
|
g_object_unref (buffer);
|
|
|
|
|
|
|
|
/* gimp dds specific. decode encoded images */
|
2019-10-02 05:31:06 +08:00
|
|
|
if (decode_images &&
|
2019-01-03 04:32:17 +08:00
|
|
|
hdr->reserved.gimp_dds_special.magic1 == FOURCC ('G','I','M','P') &&
|
|
|
|
hdr->reserved.gimp_dds_special.magic2 == FOURCC ('-','D','D','S'))
|
|
|
|
{
|
|
|
|
switch (hdr->reserved.gimp_dds_special.extra_fourcc)
|
|
|
|
{
|
|
|
|
case FOURCC ('A','E','X','P'):
|
2019-08-27 20:43:38 +08:00
|
|
|
decode_alpha_exp_image (GIMP_DRAWABLE (layer), FALSE);
|
2019-01-03 04:32:17 +08:00
|
|
|
break;
|
|
|
|
case FOURCC ('Y','C','G','1'):
|
2019-08-27 20:43:38 +08:00
|
|
|
decode_ycocg_image (GIMP_DRAWABLE (layer), FALSE);
|
2019-01-03 04:32:17 +08:00
|
|
|
break;
|
|
|
|
case FOURCC ('Y','C','G','2'):
|
2019-08-27 20:43:38 +08:00
|
|
|
decode_ycocg_scaled_image (GIMP_DRAWABLE (layer), FALSE);
|
2019-01-03 04:32:17 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
return TRUE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-05-23 20:34:00 +08:00
|
|
|
load_mipmaps (FILE *fp,
|
2019-01-03 04:32:17 +08:00
|
|
|
dds_header_t *hdr,
|
|
|
|
dds_load_info_t *d,
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpImage *image,
|
2019-01-03 04:32:17 +08:00
|
|
|
char *prefix,
|
|
|
|
unsigned int *l,
|
|
|
|
guchar *pixels,
|
2019-10-02 05:31:06 +08:00
|
|
|
guchar *buf,
|
|
|
|
gboolean read_mipmaps,
|
|
|
|
gboolean decode_images)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guint level;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
if ((hdr->flags & DDSD_MIPMAPCOUNT) &&
|
2018-11-13 07:35:07 +08:00
|
|
|
(hdr->caps.caps1 & DDSCAPS_MIPMAP) &&
|
2019-10-02 05:31:06 +08:00
|
|
|
read_mipmaps)
|
2019-01-03 04:32:17 +08:00
|
|
|
{
|
|
|
|
for (level = 1; level < hdr->num_mipmaps; ++level)
|
|
|
|
{
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_layer (fp, hdr, d, image, level, prefix, l, pixels, buf,
|
|
|
|
decode_images))
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
2019-05-23 20:34:00 +08:00
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
return TRUE;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-10-01 00:50:23 +08:00
|
|
|
static gboolean
|
2019-01-03 04:32:17 +08:00
|
|
|
load_face (FILE *fp,
|
|
|
|
dds_header_t *hdr,
|
|
|
|
dds_load_info_t *d,
|
2019-08-27 20:43:38 +08:00
|
|
|
GimpImage *image,
|
2019-09-30 21:28:42 +08:00
|
|
|
gchar *prefix,
|
|
|
|
guint *l,
|
2019-01-03 04:32:17 +08:00
|
|
|
guchar *pixels,
|
2019-10-02 05:31:06 +08:00
|
|
|
guchar *buf,
|
|
|
|
gboolean read_mipmaps,
|
|
|
|
gboolean decode_images)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-10-02 05:31:06 +08:00
|
|
|
if (! load_layer (fp, hdr, d, image, 0, prefix, l, pixels, buf,
|
|
|
|
decode_images))
|
2019-10-01 00:50:23 +08:00
|
|
|
return FALSE;
|
2019-05-23 20:34:00 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
return load_mipmaps (fp, hdr, d, image, prefix, l, pixels, buf,
|
|
|
|
read_mipmaps, decode_images);
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
static guchar
|
|
|
|
color_bits (guint mask)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
guchar i = 0;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
while (mask)
|
|
|
|
{
|
|
|
|
if (mask & 1) ++i;
|
2018-11-13 07:35:07 +08:00
|
|
|
mask >>= 1;
|
2019-01-03 04:32:17 +08:00
|
|
|
}
|
2019-05-23 20:34:00 +08:00
|
|
|
|
|
|
|
return i;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
static guchar
|
|
|
|
color_shift (guint mask)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-05-23 20:34:00 +08:00
|
|
|
guchar i = 0;
|
|
|
|
|
|
|
|
if (! mask)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (!((mask >> i) & 1))
|
|
|
|
++i;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-05-23 20:34:00 +08:00
|
|
|
return i;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
static gboolean
|
2019-10-02 05:31:06 +08:00
|
|
|
load_dialog (GimpProcedure *procedure,
|
|
|
|
GObject *config)
|
2018-11-13 07:35:07 +08:00
|
|
|
{
|
2019-09-30 21:28:42 +08:00
|
|
|
GtkWidget *dialog;
|
2019-01-03 04:32:17 +08:00
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *check;
|
2019-09-30 21:28:42 +08:00
|
|
|
gboolean run;
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
dialog = gimp_procedure_dialog_new (procedure,
|
|
|
|
GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
_("Open DDS"));
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-01-03 04:32:17 +08:00
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
|
2019-09-30 21:28:42 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
|
2018-11-14 21:56:15 +08:00
|
|
|
vbox, 1, 1, 0);
|
2019-01-03 04:32:17 +08:00
|
|
|
gtk_widget_show (vbox);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
check = gimp_prop_check_button_new (config, "load-mipmaps",
|
|
|
|
_("_Load mipmaps"));
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
check = gimp_prop_check_button_new (config, "decode-images",
|
|
|
|
_("_Automatically decode YCoCg/AExp "
|
|
|
|
"images when detected"));
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0);
|
2019-09-30 21:28:42 +08:00
|
|
|
|
|
|
|
gtk_widget_show (dialog);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-10-02 05:31:06 +08:00
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
gtk_widget_destroy (dialog);
|
2018-11-13 07:35:07 +08:00
|
|
|
|
2019-09-30 21:28:42 +08:00
|
|
|
return run;
|
2018-11-13 07:35:07 +08:00
|
|
|
}
|