Original Post
I am trying to write a DDS loader but I am having problems. After parsing the file the image data appears to be corrupted (as shown below). I am pretty sure that I parse the header properly but I cannot figure how to properly access the image data.
I upload the texture with the following code. The code for the LoadDDS function is shown below.
unsigned char *pixels;
int width, height, compressFormat;
bool mipmapped;
LoadDDS("wall.dds", pixels, width, height, mipmapped, compressFormat);
int imgSize = std::max(1, width / 4) * std::max(1, height / 4) * 8; //DXT1
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, compressFormat, width, height, 0, imgSize, pixels);
delete [] pixels;
struct DDSHeader_t
{
unsigned magic;
unsigned surfaceSize;
unsigned surfaceFlags;
unsigned surfaceHeight;
unsigned surfaceWidth;
unsigned surfacePitchOrLinearSize;
unsigned surfaceDepth;
unsigned surfaceMipMapCount;
unsigned surfaceReserved[11];
unsigned PFSize;
unsigned PFFlags;
unsigned PFFourCC;
unsigned PFBPP;
unsigned PFRedMask;
unsigned PFGreenMask;
unsigned PFBlueMask;
unsigned PFAlphaMask;
unsigned caps1;
unsigned caps2;
unsigned capsReserved[2];
unsigned reserved;
};
void LoadDDS(const char *filename, unsigned char *&pixels,
int &width, int &height, bool &mipmapped, int &compressFormat)
{
std::ifstream inFile(filename);
unsigned char *buffer;
unsigned char *data;
DDSHeader_t ddsHeader;
bool compressed;
pixels = NULL;
compressFormat = 0;
inFile.seekg(0, std::ios::end);
int length = inFile.tellg();
inFile.seekg(0, std::ios::beg);
data = new unsigned char[length];
inFile.read((char *)data, length);
inFile.close();
inFile.clear();
buffer = data;
ddsHeader.magic = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfaceSize = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfaceFlags = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfaceHeight = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfaceWidth = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfacePitchOrLinearSize = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfaceDepth = *(unsigned *)buffer;
buffer += 4;
ddsHeader.surfaceMipMapCount = *(unsigned *)buffer;
buffer += 4;
//Skip over reserved bytes.
buffer += 44;
ddsHeader.PFSize = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFFlags = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFFourCC = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFBPP = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFRedMask = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFGreenMask = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFBlueMask = *(unsigned *)buffer;
buffer += 4;
ddsHeader.PFAlphaMask = *(unsigned *)buffer;
buffer += 4;
ddsHeader.caps1 = *(unsigned *)buffer;
buffer += 4;
ddsHeader.caps2 = *(unsigned *)buffer;
buffer += 4;
//Skip reserved stuff.
buffer += 12;
switch (ddsHeader.PFFourCC)
{
case DXT1:
if (ddsHeader.PFFlags & DDPF_ALPHAPIXELS)
compressFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
else
compressFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
case DXT2:
delete [] data;
return;
case DXT3:
compressFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case DXT4:
delete [] data;
return;
case DXT5:
compressFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
default:
delete [] data;
return;
}
mipmapped = (ddsHeader.surfaceMipMapCount > 1);
compressed = ((ddsHeader.PFFlags & DDPF_FOURCC) && (ddsHeader.surfaceFlags & DDSD_LINEARSIZE));
width = ddsHeader.surfaceWidth;
height = ddsHeader.surfaceHeight;
if (compressed )
{
unsigned pSize = 0;
int factor = 16;
int w = width;
int h = height;
if (ddsHeader.PFFourCC == DXT1)
factor = 8;
//Compute the buffer size.
for (unsigned i = 0; i < ddsHeader.surfaceMipMapCount; i++)
{
pSize += std::max(1, w / 4) * std::max(1, h / 4) * factor;
w /= 2;
h /= 2;
}
pixels = new unsigned char[pSize];
//Copy the image data?
memcpy(pixels, buffer, pSize);
}
else
{
//Ignore uncompressed files for now.
}
delete [] data;
}