title: DDS file loader in OpenGL, corrupted images
body: <p>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? </p>
  
  <pre><code>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(&amp;dds_file, name, "r");
  if (dds_file == NULL)
      return -1;
  
  // Read in the DDS Header data
  fread(&amp;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 &amp; 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 &amp; DDPF_FOURCC) != 0);
  
  // Does the DDS have an alpha element
  has_alpha_element = ((header.dds_pixel_format.dds_flags &amp; DDPF_ALPHAPIXELS) != 0);
  
  // Is the DDS a mipmap
  is_mipmap = ((header.dds_caps1 &amp; DDSCAPS_MIPMAP) &amp;&amp; (header.dds_mipmap_count &gt; 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 &amp; 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 &amp; 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, &amp;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(&amp;(data[0]), 1, size, dds_file);
  
      for (U32 i = 0; i &lt; mipmap_count; i++)
      {
          size = Max(1, ((mipmap_x + 3) / divide)) * Max(1, ((mipmap_y + 3) / divide)) * blocks;
  
          extensions-&gt;glCompressedTexImage2D(GL_TEXTURE_2D, i, internal_format, mipmap_x, mipmap_y, 0, size, &amp;data[offset]);
  
          offset += size;
  
          mipmap_x &gt;&gt;= 1;
          mipmap_y &gt;&gt;= 1;
  
      }
  
      Shutdown();
  }
  else
  {
      ASSERT(false, "Texture is not compressed!\n");
      return -1;
  }
  
  return handle;
  </code></pre>
  
  <p>} // end BindDDSFile</p>