Reputation: 67
I wrote a simple program that loads compressed and mipmapped DDS files in OpenGL with the "glCompressedTexImage2D" function. I only use DXT1, DXT3 or DXT5 file formats. On some DDS files it works great, on others some or much of the mipmaps are corrupt. I compared a dds file that works versus a dds file that is corrupt and the headers are identical. The images are a perfect square 512x512. A few times I would take a corrupt dds, convert to a few different formats, maybe perform a light Gaussian blur, change it back to a dds and then it worked great with no corruption. Does anyone know what I am doing wrong? Are there any better compressed bound alternatives to DDS files for OpenGL?
I32 DDSFileDecoder::BindDDSFile(const I8 *name)
{
FILE *dds_file;
DDSHeader header;
I32 image_x = 0;
I32 image_y = 0;
I32 image_z = 0;
I32 mipmap_x = 0;
I32 mipmap_y = 0;
I32 factor = 0;
U32 divide = 1;
U32 blocks = 1;
U32 internal_format = 0;
B8 is_compressed = false;
B8 has_alpha_element = false;
B8 is_mipmap = false;
B8 is_cubemap = false;
I32 mipmap_count = 0;
DDS_TYPE dds_type;
U32 handle = 0;
// Open DDS file name
fopen_s(&dds_file, name, "r");
if (dds_file == NULL)
return -1;
// Read in the DDS Header data
fread(&header, sizeof(header), 1, dds_file);
// DDS Magic must be for little Endian " SDD", Big Endian "DDS "
ASSERT(header.dds_magic == DDS_MAGIC_LITTLE_ENDIAN, "DDS Magic Number Invalid!\n");
// Header size must be 124 bytes long
ASSERT(header.dds_size == 124, "DDS Size Number Invalid!\n");
// Header flags must contain 0x1007 A texture file.
ASSERT((header.dds_flags & DDS_HEADER_FLAGS_TEXTURE) == DDS_HEADER_FLAGS_TEXTURE, "DDS is not a Texture!\n");
// Pixel Format must be 32 bytes
ASSERT(header.dds_pixel_format.dds_size == 32, "DDS Pixel Format Invalid!\n");
// Is the DDS Compressed
is_compressed = ((header.dds_pixel_format.dds_flags & DDPF_FOURCC) != 0);
// Does the DDS have an alpha element
has_alpha_element = ((header.dds_pixel_format.dds_flags & DDPF_ALPHAPIXELS) != 0);
// Is the DDS a mipmap
is_mipmap = ((header.dds_caps1 & DDSCAPS_MIPMAP) && (header.dds_mipmap_count > 1));
if (is_mipmap == true)
mipmap_count = header.dds_mipmap_count;
else
mipmap_count = 1;
// Is the DDS a cubemap
is_cubemap = (header.dds_caps2 & DDSCAPS2_CUBEMAP);
// Obtain Image width and height
image_x = header.dds_width;
image_y = header.dds_height;
image_z = header.dds_depth;
//Determine DDS type (note: Only going to support DXT1, DXT3, or DXT5)
if ((header.dds_pixel_format.dds_flags & DDPF_FOURCC) != 0)
{
if (header.dds_pixel_format.dds_fourCC == D3DFMT_DXT1)
{
dds_type = DDS_DXT1;
divide = 4;
blocks = 8;
factor = 4;
internal_format = GL_COMPRESSED_RGBA_S3TC_DXT1;
}
else if (header.dds_pixel_format.dds_fourCC == D3DFMT_DXT3)
{
dds_type = DDS_DXT3;
divide = 4;
blocks = 16;
factor = 4;
internal_format = GL_COMPRESSED_RGBA_S3TC_DXT3;
}
else if (header.dds_pixel_format.dds_fourCC == D3DFMT_DXT5)
{
dds_type = DDS_DXT5;
divide = 4;
blocks = 16;
factor = 4;
internal_format = GL_COMPRESSED_RGBA_S3TC_DXT5;
}
else
{
ASSERT(false, "Attempting to Bind unsupported DDS format\n");
dds_type = UNKNOWN;
}
}
else
{
ASSERT(false, "Attempting to Bind unsupported DDS format\n");
dds_type = UNKNOWN;
}
// Set up Mipmap x and y
mipmap_x = image_x;
mipmap_y = image_y;
glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);
// In the event mipmap is missing, set to texture max quality
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmap_count - 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (is_compressed == true)
{
image_was_bound = true;
U32 size = Max(1, ((mipmap_x + 3) / divide)) * Max(1, ((mipmap_y + 3) / divide)) * blocks * factor;
U32 offset = 0;
if (dds_was_startup == false)
Startup(size);
fread(&(data[0]), 1, size, dds_file);
for (U32 i = 0; i < mipmap_count; i++)
{
size = Max(1, ((mipmap_x + 3) / divide)) * Max(1, ((mipmap_y + 3) / divide)) * blocks;
extensions->glCompressedTexImage2D(GL_TEXTURE_2D, i, internal_format, mipmap_x, mipmap_y, 0, size, &data[offset]);
offset += size;
mipmap_x >>= 1;
mipmap_y >>= 1;
}
Shutdown();
}
else
{
ASSERT(false, "Texture is not compressed!\n");
return -1;
}
return handle;
} // end BindDDSFile
Upvotes: 0
Views: 2029
Reputation: 67
This is more of a workaround than an answer. I found that by converting the corrupt image into a jpeg and then downgrading the quality slightly, then converted to a mipmapped DDS, seems to fix the problem.
Upvotes: -1