Jump to content
  • Advertisement
Sign in to follow this  
harshman_chris

OpenGL Loading DDS textures in OpenGL, Black Texture Showing

This topic is 2162 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am loading DDS textures with the code below, and it works fine for square textures power of two textures, but it will not load textures that are 256*128 for example. I am not sure why that is, it should work as far as I can see. Any suggestions on this?

 

GLuint ImageUtils::loadDDS(const char * filename)
{
	Logger::getInstance()->write(StringUtils::format("Loading DDS Image %s",filename));

	unsigned char header[124];
 
	FILE *fp;
 
	/* try to open the file */
	fp = fopen(filename, "rb");
	if (fp == NULL)
	{
		Logger::getInstance()->write("Failed to load Image: could not open the file");
		return 0;
	}
 
	/* verify the type of file */
	char filecode[4];
	fread(filecode, 1, 4, fp);
	if (strncmp(filecode, "DDS ", 4) != 0) 
	{
		fclose(fp);
		Logger::getInstance()->write("Failed to load Image: not a direct draw surface file");
		return 0;
	}
 
	/* get the surface desc */
	fread(&header, 124, 1, fp); 
 
	unsigned int height = *(unsigned int*)&(header[8 ]);
	unsigned int width = *(unsigned int*)&(header[12]);
	unsigned int linearSize = *(unsigned int*)&(header[16]);
	unsigned int mipMapCount = *(unsigned int*)&(header[24]);
	unsigned int fourCC = *(unsigned int*)&(header[80]);

	unsigned char * buffer;
	unsigned int bufsize;

	/* how big is it going to be including all mipmaps? */
	bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;
	buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
	fread(buffer, 1, bufsize, fp);

	/* close the file pointer */
	fclose(fp);

	unsigned int components = (fourCC == FOURCC_DXT1) ? 3 : 4;
	unsigned int format;
	switch(fourCC)
	{
		case FOURCC_DXT1:
			format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
			break;
		case FOURCC_DXT3:
			format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
			break;
		case FOURCC_DXT5:
			format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
			break;
		default:
			free(buffer);
			Logger::getInstance()->write("Failed to load Image: dds file format not supported (supported formats: DXT1, DXT3, DXT5)");
			return 0;
	}

	// Create one OpenGL texture
	GLuint textureID;
	glGenTextures(1, &textureID);
 
	// "Bind" the newly created texture : all future texture functions will modify this texture
	glBindTexture(GL_TEXTURE_2D, textureID);
	glPixelStorei(GL_UNPACK_ALIGNMENT,1);  

	unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
	unsigned int offset = 0;
 
	/* load the mipmaps */
	for (unsigned int level = 0; level < mipMapCount && (width || height); ++level)
	{
		unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
		glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 
			0, size, buffer + offset);
 
		offset += size;
		width  /= 2;
		height /= 2;
	}

	free(buffer); 

	//Unbind the texture
	glBindTexture(GL_TEXTURE_2D, 0);

	Logger::getInstance()->write(StringUtils::format("Loaded DDS Image %s",filename));

	return textureID;
}

 

 

Share this post


Link to post
Share on other sites
Advertisement

When you reach the last few mip-maps, one of width or height will reach zero before the other reaches one (and thus the mipmap will have zero dimension and be rendered as black).

 

You should change:

 

width  /= 2;
height /= 2;

 

To be something like this:

 

width = max(width/2, 1);
height = max(height/2, 1);

 

To ensure that neither dimension ever becomes zero.

Share this post


Link to post
Share on other sites

I forgot to mention that you might actually want to not produce those last few mipmaps, rather than clamping their size.

 

When you reach the last few mipmaps of a square texture, it looks like this: 8x8, 4x4, 2x2, 1x1. For a rectangular texture, it looks like this: 8x4, 4x2, 2x1, 1x1. There probably isn't a whole lot of value to having both a 2x1 and a 1x1 mipmap around - in which case you can just exit the loop as soon as either dimension reaches 1.

 

(on the other hand, these higher mipmaps don't really consume any memory - at most a few bytes, so up to you)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!