You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kfile-plugins/dds/kfile_dds.cpp

318 lines
8.0 KiB

/* This file is part of the KDE project
* Copyright (C) 2002 Ignacio Casta<EFBFBD>o <castano@ludicon.com>
*
* 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 version 2.
*
* 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, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include <config.h>
#include "kfile_dds.h"
#include <kprocess.h>
#include <klocale.h>
#include <kgenericfactory.h>
#include <kstringvalidator.h>
#include <kdebug.h>
#include <qdict.h>
#include <qvalidator.h>
#include <qcstring.h>
#include <qfile.h>
#include <qdatetime.h>
typedef KGenericFactory<KDdsPlugin> DdsFactory;
typedef Q_UINT32 uint;
typedef Q_UINT16 ushort;
typedef Q_UINT8 uchar;
namespace { // Private.
#if !defined(MAKEFOURCC)
# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
(uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \
(uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 ))
#endif
static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
static const uint DDSD_CAPS = 0x00000001l;
static const uint DDSD_PIXELFORMAT = 0x00001000l;
static const uint DDSD_WIDTH = 0x00000004l;
static const uint DDSD_HEIGHT = 0x00000002l;
static const uint DDSD_PITCH = 0x00000008l;
static const uint DDSCAPS_TEXTURE = 0x00001000l;
static const uint DDSCAPS2_VOLUME = 0x00200000l;
static const uint DDSCAPS2_CUBEMAP = 0x00000200l;
static const uint DDPF_RGB = 0x00000040l;
static const uint DDPF_FOURCC = 0x00000004l;
static const uint DDPF_ALPHAPIXELS = 0x00000001l;
enum DDSType {
DDS_A8R8G8B8 = 0,
DDS_A1R5G5B5 = 1,
DDS_A4R4G4B4 = 2,
DDS_R8G8B8 = 3,
DDS_R5G6B5 = 4,
DDS_DXT1 = 5,
DDS_DXT2 = 6,
DDS_DXT3 = 7,
DDS_DXT4 = 8,
DDS_DXT5 = 9,
DDS_RXGB = 10,
DDS_UNKNOWN
};
struct DDSPixelFormat {
uint size;
uint flags;
uint fourcc;
uint bitcount;
uint rmask;
uint gmask;
uint bmask;
uint amask;
};
QDataStream & operator>> ( QDataStream & s, DDSPixelFormat & pf )
{
s >> pf.size;
s >> pf.flags;
s >> pf.fourcc;
s >> pf.bitcount;
s >> pf.rmask;
s >> pf.gmask;
s >> pf.bmask;
s >> pf.amask;
return s;
}
struct DDSCaps {
uint caps1;
uint caps2;
uint caps3;
uint caps4;
};
QDataStream & operator>> ( QDataStream & s, DDSCaps & caps )
{
s >> caps.caps1;
s >> caps.caps2;
s >> caps.caps3;
s >> caps.caps4;
return s;
}
struct DDSHeader {
uint size;
uint flags;
uint height;
uint width;
uint pitch;
uint depth;
uint mipmapcount;
uint reserved[11];
DDSPixelFormat pf;
DDSCaps caps;
uint notused;
};
QDataStream & operator>> ( QDataStream & s, DDSHeader & header )
{
s >> header.size;
s >> header.flags;
s >> header.height;
s >> header.width;
s >> header.pitch;
s >> header.depth;
s >> header.mipmapcount;
for( int i = 0; i < 11; i++ ) {
s >> header.reserved[i];
}
s >> header.pf;
s >> header.caps;
s >> header.notused;
return s;
}
static bool IsValid( const DDSHeader & header )
{
if( header.size != 124 ) {
return false;
}
const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
if( (header.flags & required) != required ) {
return false;
}
if( header.pf.size != 32 ) {
return false;
}
if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
return false;
}
return true;
}
} // namespace
K_EXPORT_COMPONENT_FACTORY(kfile_dds, DdsFactory( "kfile_dds" ))
// Constructor, init mime type info.
KDdsPlugin::KDdsPlugin(QObject *parent, const char *name, const QStringList &args) :
KFilePlugin(parent, name, args)
{
KFileMimeTypeInfo * info = addMimeTypeInfo( "image/x-dds" );
KFileMimeTypeInfo::GroupInfo * group = 0L;
group = addGroupInfo(info, "Technical", i18n("Technical Details"));
KFileMimeTypeInfo::ItemInfo * item;
item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
setHint(item, KFileMimeTypeInfo::Size);
setUnit(item, KFileMimeTypeInfo::Pixels);
item = addItemInfo(group, "Depth", i18n("Depth"), QVariant::Int);
setUnit(item, KFileMimeTypeInfo::Pixels);
item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
addItemInfo(group, "MipmapCount", i18n("Mipmap Count"), QVariant::Int);
addItemInfo(group, "Type", i18n("Type"), QVariant::String);
addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String);
addItemInfo(group, "Compression", i18n("Compression"), QVariant::String);
}
// Read mime type info.
bool KDdsPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
{
QFile file(info.path());
if (!file.open(IO_ReadOnly)) {
kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
return false;
}
QDataStream s(&file);
s.setByteOrder(QDataStream::LittleEndian);
// Validate header.
uint fourcc;
s >> fourcc;
if( fourcc != FOURCC_DDS ) {
kdDebug(7034) << QFile::encodeName(info.path()) << " is not a DDS file." << endl;
return false;
}
// Read image header.
DDSHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) ) {
kdDebug(7034) << QFile::encodeName(info.path()) << " is not a valid DDS file." << endl;
return false;
}
// Set file info.
KFileMetaInfoGroup group = appendGroup(info, "Technical");
appendItem(group, "Dimensions", QSize(header.width, header.height));
appendItem(group, "MipmapCount", header.mipmapcount);
// Set file type.
if( header.caps.caps2 & DDSCAPS2_CUBEMAP ) {
appendItem(group, "Type", i18n("Cube Map Texture"));
}
else if( header.caps.caps2 & DDSCAPS2_VOLUME ) {
appendItem(group, "Type", i18n("Volume Texture"));
appendItem(group, "Depth", header.depth);
}
else {
appendItem(group, "Type", i18n("2D Texture"));
}
// Set file color depth and compression.
if( header.pf.flags & DDPF_RGB ) {
appendItem(group, "BitDepth", header.pf.bitcount);
appendItem(group, "Compression", i18n("Uncompressed"));
if( header.pf.flags & DDPF_ALPHAPIXELS ) {
appendItem(group, "ColorMode", "RGB/Alpha");
}
else {
appendItem(group, "ColorMode", "RGB");
}
}
else if( header.pf.flags & DDPF_FOURCC ) {
switch( header.pf.fourcc ) {
case FOURCC_DXT1:
appendItem(group, "BitDepth", 4);
appendItem(group, "Compression", "DXT1");
appendItem(group, "ColorMode", "RGB");
break;
case FOURCC_DXT2:
appendItem(group, "BitDepth", 16);
appendItem(group, "Compression", "DXT2");
appendItem(group, "ColorMode", "RGB/Alpha");
break;
case FOURCC_DXT3:
appendItem(group, "BitDepth", 16);
appendItem(group, "Compression", "DXT3");
appendItem(group, "ColorMode", "RGB/Alpha");
break;
case FOURCC_DXT4:
appendItem(group, "BitDepth", 16);
appendItem(group, "Compression", "DXT4");
appendItem(group, "ColorMode", "RGB/Alpha");
break;
case FOURCC_DXT5:
appendItem(group, "BitDepth", 16);
appendItem(group, "Compression", "DXT5");
appendItem(group, "ColorMode", "RGB/Alpha");
break;
case FOURCC_RXGB:
appendItem(group, "BitDepth", 16);
appendItem(group, "Compression", "RXGB");
appendItem(group, "ColorMode", "RGB");
break;
default:
appendItem(group, "Compression", "Unknown");
break;
}
}
else {
appendItem(group, "Compression", "Unknown");
}
return true;
}
#include "kfile_dds.moc"