ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

dds.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/stark/formats/dds.h"
00024 
00025 #include "common/textconsole.h"
00026 
00027 namespace Stark {
00028 namespace Formats {
00029 
00030 // Based on xoreos' DDS code
00031 
00032 static const uint32 kDDSID  = MKTAG('D', 'D', 'S', ' ');
00033 
00034 static const uint32 kHeaderFlagsHasMipMaps = 0x00020000;
00035 
00036 static const uint32 kPixelFlagsHasAlpha  = 0x00000001;
00037 static const uint32 kPixelFlagsHasFourCC = 0x00000004;
00038 static const uint32 kPixelFlagsIsIndexed = 0x00000020;
00039 static const uint32 kPixelFlagsIsRGB     = 0x00000040;
00040 
00041 DDS::~DDS() {
00042     for (uint i = 0; i < _mipmaps.size(); i++) {
00043         _mipmaps[i].free();
00044     }
00045 }
00046 
00047 bool DDS::load(Common::SeekableReadStream &dds, const Common::String &name) {
00048     assert(_mipmaps.empty());
00049 
00050     _name = name;
00051 
00052     if (!readHeader(dds)) {
00053         return false;
00054     }
00055 
00056     return readData(dds);
00057 }
00058 
00059 const DDS::MipMaps &DDS::getMipMaps() const {
00060     return _mipmaps;
00061 }
00062 
00063 bool DDS::readHeader(Common::SeekableReadStream &dds) {
00064     // We found the FourCC of a standard DDS
00065     uint32 magic = dds.readUint32BE();
00066     if (magic != kDDSID) {
00067         warning("Invalid DDS magic number: %d for %s", magic, _name.c_str());
00068         return false;
00069     }
00070 
00071     // All DDS header should be 124 bytes (+ 4 for the FourCC)
00072     uint32 headerSize = dds.readUint32LE();
00073     if (headerSize != 124) {
00074         warning("Invalid DDS header size: %d for %s", headerSize, _name.c_str());
00075         return false;
00076     }
00077 
00078     // DDS features
00079     uint32 flags = dds.readUint32LE();
00080 
00081     // Image dimensions
00082     uint32 height = dds.readUint32LE();
00083     uint32 width  = dds.readUint32LE();
00084 
00085     if ((width >= 0x8000) || (height >= 0x8000)) {
00086         warning("Unsupported DDS image dimensions (%ux%u) for %s", width, height, _name.c_str());
00087         return false;
00088     }
00089 
00090     dds.skip(4 + 4); // Pitch + Depth
00091     //uint32 pitchOrLineSize = dds.readUint32LE();
00092     //uint32 depth           = dds.readUint32LE();
00093     uint32 mipMapCount     = dds.readUint32LE();
00094 
00095     // DDS doesn't provide any mip maps, only one full-size image
00096     if ((flags & kHeaderFlagsHasMipMaps) == 0) {
00097         mipMapCount = 1;
00098     }
00099 
00100     dds.skip(44); // Reserved
00101 
00102     // Read the pixel data format
00103     DDSPixelFormat format;
00104     format.size     = dds.readUint32LE();
00105     format.flags    = dds.readUint32LE();
00106     format.fourCC   = dds.readUint32BE();
00107     format.bitCount = dds.readUint32LE();
00108     format.rBitMask = dds.readUint32LE();
00109     format.gBitMask = dds.readUint32LE();
00110     format.bBitMask = dds.readUint32LE();
00111     format.aBitMask = dds.readUint32LE();
00112 
00113     // Detect which specific format it describes
00114     if (!detectFormat(format)) {
00115         return false;
00116     }
00117 
00118     dds.skip(16 + 4); // DDCAPS2 + Reserved
00119 
00120     _mipmaps.resize(mipMapCount);
00121     for (uint32 i = 0; i < mipMapCount; i++) {
00122         _mipmaps[i].create(width, height, _format);
00123 
00124         width  >>= 1;
00125         height >>= 1;
00126     }
00127 
00128     return true;
00129 }
00130 
00131 bool DDS::readData(Common::SeekableReadStream &dds) {
00132     for (uint i = 0; i < _mipmaps.size(); i++) {
00133         Graphics::Surface &mipmap = _mipmaps[i];
00134 
00135         uint32 size = mipmap.pitch * mipmap.h;
00136         uint32 readSize = dds.read(mipmap.getPixels(), size);
00137 
00138         if (readSize != size) {
00139             warning("Inconsistent read size in DDS file: %d, expected %d for %s level %d",
00140                     readSize, size, _name.c_str(), i);
00141             return false;
00142         }
00143     }
00144 
00145     return true;
00146 }
00147 
00148 bool DDS::detectFormat(const DDSPixelFormat &format) {
00149     if (format.flags & kPixelFlagsHasFourCC) {
00150         warning("Unsupported DDS feature: FourCC pixel format %d for %s", format.fourCC, _name.c_str());
00151         return false;
00152     }
00153 
00154     if (format.flags & kPixelFlagsIsIndexed) {
00155         warning("Unsupported DDS feature: Indexed %d-bits pixel format for %s", format.bitCount, _name.c_str());
00156         return false;
00157     }
00158 
00159     if (!(format.flags & kPixelFlagsIsRGB)) {
00160         warning("Only RGB DDS files are supported for %s", _name.c_str());
00161         return false;
00162     }
00163 
00164     if (format.bitCount != 24 && format.bitCount != 32) {
00165         warning("Only 24-bits and 32-bits DDS files are supported for %s", _name.c_str());
00166         return false;
00167     }
00168 
00169     if ((format.flags & kPixelFlagsHasAlpha) &&
00170                (format.bitCount == 32) &&
00171                (format.rBitMask == 0x00FF0000) && (format.gBitMask == 0x0000FF00) &&
00172                (format.bBitMask == 0x000000FF) && (format.aBitMask == 0xFF000000)) {
00173 #ifdef SCUMM_BIG_ENDIAN
00174         _format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 0, 8, 16);
00175 #else
00176         _format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
00177 #endif
00178         return true;
00179     } else if (!(format.flags & kPixelFlagsHasAlpha) &&
00180                (format.bitCount == 24) &&
00181                (format.rBitMask == 0x00FF0000) && (format.gBitMask == 0x0000FF00) &&
00182                (format.bBitMask == 0x000000FF)) {
00183 #ifdef SCUMM_BIG_ENDIAN
00184         _format = Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0);
00185 #else
00186         _format = Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0);
00187 #endif
00188         return true;
00189     } else {
00190         warning("Unsupported pixel format (%X, %X, %d, %X, %X, %X, %X) for %s",
00191                 format.flags, format.fourCC, format.bitCount,
00192                 format.rBitMask, format.gBitMask, format.bBitMask, format.aBitMask,
00193                 _name.c_str());
00194         return false;
00195     }
00196 }
00197 
00198 } // End of namespace Formats
00199 } // End of namespace Stark


Generated on Sat Oct 19 2019 05:01:08 for ResidualVM by doxygen 1.7.1
curved edge   curved edge