Initial commit
This commit is contained in:
190
engines/stark/formats/dds.cpp
Normal file
190
engines/stark/formats/dds.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* 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 3 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/formats/dds.h"
|
||||
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Formats {
|
||||
|
||||
// Based on xoreos' DDS code
|
||||
|
||||
static const uint32 kDDSID = MKTAG('D', 'D', 'S', ' ');
|
||||
|
||||
static const uint32 kHeaderFlagsHasMipMaps = 0x00020000;
|
||||
|
||||
static const uint32 kPixelFlagsHasAlpha = 0x00000001;
|
||||
static const uint32 kPixelFlagsHasFourCC = 0x00000004;
|
||||
static const uint32 kPixelFlagsIsIndexed = 0x00000020;
|
||||
static const uint32 kPixelFlagsIsRGB = 0x00000040;
|
||||
|
||||
DDS::~DDS() {
|
||||
for (uint i = 0; i < _mipmaps.size(); i++) {
|
||||
_mipmaps[i].free();
|
||||
}
|
||||
}
|
||||
|
||||
bool DDS::load(Common::SeekableReadStream &dds, const Common::String &name) {
|
||||
assert(_mipmaps.empty());
|
||||
|
||||
_name = name;
|
||||
|
||||
if (!readHeader(dds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return readData(dds);
|
||||
}
|
||||
|
||||
const DDS::MipMaps &DDS::getMipMaps() const {
|
||||
return _mipmaps;
|
||||
}
|
||||
|
||||
bool DDS::readHeader(Common::SeekableReadStream &dds) {
|
||||
// We found the FourCC of a standard DDS
|
||||
uint32 magic = dds.readUint32BE();
|
||||
if (magic != kDDSID) {
|
||||
warning("Invalid DDS magic number: %d for %s", magic, _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// All DDS header should be 124 bytes (+ 4 for the FourCC)
|
||||
uint32 headerSize = dds.readUint32LE();
|
||||
if (headerSize != 124) {
|
||||
warning("Invalid DDS header size: %d for %s", headerSize, _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// DDS features
|
||||
uint32 flags = dds.readUint32LE();
|
||||
|
||||
// Image dimensions
|
||||
uint32 height = dds.readUint32LE();
|
||||
uint32 width = dds.readUint32LE();
|
||||
|
||||
if ((width >= 0x8000) || (height >= 0x8000)) {
|
||||
warning("Unsupported DDS image dimensions (%ux%u) for %s", width, height, _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
dds.skip(4 + 4); // Pitch + Depth
|
||||
//uint32 pitchOrLineSize = dds.readUint32LE();
|
||||
//uint32 depth = dds.readUint32LE();
|
||||
uint32 mipMapCount = dds.readUint32LE();
|
||||
|
||||
// DDS doesn't provide any mip maps, only one full-size image
|
||||
if ((flags & kHeaderFlagsHasMipMaps) == 0) {
|
||||
mipMapCount = 1;
|
||||
}
|
||||
|
||||
dds.skip(44); // Reserved
|
||||
|
||||
// Read the pixel data format
|
||||
DDSPixelFormat format;
|
||||
format.size = dds.readUint32LE();
|
||||
format.flags = dds.readUint32LE();
|
||||
format.fourCC = dds.readUint32BE();
|
||||
format.bitCount = dds.readUint32LE();
|
||||
format.rBitMask = dds.readUint32LE();
|
||||
format.gBitMask = dds.readUint32LE();
|
||||
format.bBitMask = dds.readUint32LE();
|
||||
format.aBitMask = dds.readUint32LE();
|
||||
|
||||
// Detect which specific format it describes
|
||||
if (!detectFormat(format)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dds.skip(16 + 4); // DDCAPS2 + Reserved
|
||||
|
||||
_mipmaps.resize(mipMapCount);
|
||||
for (uint32 i = 0; i < mipMapCount; i++) {
|
||||
_mipmaps[i].create(width, height, _format);
|
||||
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DDS::readData(Common::SeekableReadStream &dds) {
|
||||
for (uint i = 0; i < _mipmaps.size(); i++) {
|
||||
Graphics::Surface &mipmap = _mipmaps[i];
|
||||
|
||||
uint32 size = mipmap.pitch * mipmap.h;
|
||||
uint32 readSize = dds.read(mipmap.getPixels(), size);
|
||||
|
||||
if (readSize != size) {
|
||||
warning("Inconsistent read size in DDS file: %d, expected %d for %s level %d",
|
||||
readSize, size, _name.c_str(), i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DDS::detectFormat(const DDSPixelFormat &format) {
|
||||
if (format.flags & kPixelFlagsHasFourCC) {
|
||||
warning("Unsupported DDS feature: FourCC pixel format %d for %s", format.fourCC, _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format.flags & kPixelFlagsIsIndexed) {
|
||||
warning("Unsupported DDS feature: Indexed %d-bits pixel format for %s", format.bitCount, _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(format.flags & kPixelFlagsIsRGB)) {
|
||||
warning("Only RGB DDS files are supported for %s", _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format.bitCount != 24 && format.bitCount != 32) {
|
||||
warning("Only 24-bits and 32-bits DDS files are supported for %s", _name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((format.flags & kPixelFlagsHasAlpha) &&
|
||||
(format.bitCount == 32) &&
|
||||
(format.rBitMask == 0x00FF0000) && (format.gBitMask == 0x0000FF00) &&
|
||||
(format.bBitMask == 0x000000FF) && (format.aBitMask == 0xFF000000)) {
|
||||
_format = Graphics::PixelFormat::createFormatBGRA32();
|
||||
return true;
|
||||
} else if (!(format.flags & kPixelFlagsHasAlpha) &&
|
||||
(format.bitCount == 24) &&
|
||||
(format.rBitMask == 0x00FF0000) && (format.gBitMask == 0x0000FF00) &&
|
||||
(format.bBitMask == 0x000000FF)) {
|
||||
_format = Graphics::PixelFormat::createFormatBGR24();
|
||||
return true;
|
||||
} else {
|
||||
warning("Unsupported pixel format (%X, %X, %d, %X, %X, %X, %X) for %s",
|
||||
format.flags, format.fourCC, format.bitCount,
|
||||
format.rBitMask, format.gBitMask, format.bBitMask, format.aBitMask,
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Formats
|
||||
} // End of namespace Stark
|
||||
Reference in New Issue
Block a user