Skip to main content
GameDev.net gamedev.net
🔒 Locked

Trying to load DDS DXT1 image, causes crash, help!

Started by Emark Nov 13, 2009 at 6:14 AM 7 replies 3.5k views
Original Post
Emark
Emark
Any idea whats wrong with my code? when i execute glCompressedTexImage2D() the program just crashes (comes the Windows XP crash message thing...) I'm trying to load DDS image without mipmaps, the image format is DDS DXT1. Am i missing some include file, or what did i do wrong? I downloaded the included files from: http://sourceforge.net/projects/glew/files/glew/1.5.1/glew-1.5.1-win32.zip/download I have glew32.dll in the same folder as my .exe is. The code below has only the parts i changed to be able to load DDS images:

#pragma comment(lib, "glew32.lib")
#include <GL\glew.h>
#include <GL\gl.h>


...


typedef struct {
	GLuint dwSize;
	GLuint dwFlags;
	GLuint dwFourCC;
	GLuint dwRGBBitCount;
	GLuint dwRBitMask;
	GLuint dwGBitMask;
	GLuint dwBBitMask;
	GLuint dwABitMask;
} DDS_PIXELFORMAT;

typedef struct {
	GLuint dwMagic;
	GLuint dwSize;
	GLuint dwFlags;
	GLuint dwHeight;
	GLuint dwWidth;
	GLuint dwLinearSize;
	GLuint dwDepth;
	GLuint dwMipMapCount;
	GLuint dwReserved1[11];
	DDS_PIXELFORMAT ddpf;
	GLuint dwCaps;
	GLuint dwCaps2;
	GLuint dwCaps3;
	GLuint dwCaps4;
	GLuint dwReserved2;
} DDS_HEADER;

DDS_HEADER DDS_headers;


...


FILE *fp = fopen("test.dds", "rb");
fread(&DDS_headers, 1, sizeof(DDS_headers), fp);

img_width = DDS_headers.dwWidth;
img_height = DDS_headers.dwHeight;

maxsize = (img_width*img_height)/2;
unsigned char *imgdata = (unsigned char *)malloc(maxsize);

fread(imgdata, 1, maxsize, fp);

fclose(fp);

GLuint texID;

glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_PALETTE4_R5_G6_B5_OES, img_width, img_height, 0, maxsize, imgdata);
I've also tried with function: glCompressedTexImage2DARB(); and internalformats: GL_COMPRESSED_RGB_S3TC_DXT1_EXT and all of the possible formats... its not a format error. My GFX card supports DDS compression, that is a fact.
GenPFault
GenPFault
Why are you passing an OpenGL ES token (GL_PALETTE4_R5_G6_B5_OES) to OpenGL?
Emark
Emark
it was from some example code, in fact, im using OpenGL ES in my program too.

and still, thats not what the problem should be, as i said, ive tried with those other tokens too... all of them gives the same result (crash).
Emark
Emark
anyone?
Moeller
Moeller
you should calculate the size of your image with this formula
size = blockSize * ceil(width / 4) * ceil(height / 4)

where blockSize = 8 for DXT1.

your code could fail there if the width and height of your texture is not a multiple of 4.

and of course you need to use GL_COMPRESSED_RGB_S3TC_DXT1_EXT
Emark
Emark
the width/height and filesize is correct, and even if the format was wrong, it would be able to read the data and generate buggy image out of it. but now it just crashes, which makes no sense...

ive tried with every format setting, also with GL_COMPRESSED_RGB_S3TC_DXT1_EXT
Illasera
Illasera
Quote:
Original post by Emark

maxsize = (img_width*img_height)/2;


What?

1.)I dont think thats the way to calculate your image size - Reading past the image size can and most likely will cause an error.
2.)I noticed you cutted part of the dds header. There is a chance you are reading the wrong data, Use the entire header from ddraw.h.
3.)Make sure you initialized the Load2DCompressedImages(), Since its an extension, you need to get the function address , wglGetProcAddress

*.)Most likely your program crashes because its an attempt to read past the buffer, Otherwise an openGL error would get silently invoked and the image wont get drawn, But no crash.

*.)Afaik , what effects DDS raw data size is , if its mipmapped and the compression format. Get the right compression format from the header "ddpfPixelFormat.dwFourCC", and if its mipmapped by "Header.dwMipMapCount", Use them to calculate your real image size (like Moeller method) and don
t forget to include the mipmap data as well.

In my opinion, am quite sure its the image size that is wrong and you are trying to read past that.

[Edited by - Illasera on November 21, 2009 6:38:22 AM]
Prune
Prune
Here's my loading code, derived from several examples out there and modified to fit generic image class from which textures can be loaded. The corresponding OpenGL texture formats are:
DXT1 -- GL_COMPRESSED_RGB_S3TC_DXT1_EXT or GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
DXT1 & ALPHAPIXELS -- GL_COMPRESSED_RGBA_S3TC_DXT1_EXT or GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
DXT3 -- GL_COMPRESSED_RGBA_S3TC_DXT3_EXT or GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
DXT5 -- GL_COMPRESSED_RGBA_S3TC_DXT5_EXT or GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
ATI1 -- GL_COMPRESSED_RED_RGTC1
ATI2 -- GL_COMPRESSED_RG_RGTC2
Make sure to use an appropriate GL_UNPACK_ALIGNMENT
// Author: Borislav Trifonov#define MAKEFCC(ch0, ch1, ch2, ch3) (static_cast<unsigned int>(static_cast<unsigned char>(ch0))| static_cast<unsigned int>(static_cast<unsigned char>(ch1)) << 8| static_cast<unsigned int>(static_cast<unsigned char>(ch2)) << 16| static_cast<unsigned int>(static_cast<unsigned char>(ch3)) << 24)DDSImage::DDSImage(char const fname[], int const chans, int const imgH, int const imgW) : Image(CMP){	STATIC_ASSERT(sizeof(int) == 4);	unsigned int const MAGIC = MAKEFCC('D', 'D', 'S', ' ');	unsigned int const FCC_DXT1 = MAKEFCC('D', 'X', 'T', '1');	unsigned int const FCC_DXT3 = MAKEFCC('D', 'X', 'T', '3');	unsigned int const FCC_DXT5 = MAKEFCC('D', 'X', 'T', '5');	unsigned int const FCC_ATI1 = MAKEFCC('A', 'T', 'I', '1');	unsigned int const FCC_ATI2 = MAKEFCC('A', 'T', 'I', '2');	unsigned int const DDS_ALPHAPIXELS = 0x00000001;	unsigned int const DDS_FOURCC = 0x00000004;	unsigned int const DDS_CUBEMAP = 0x00000200;	unsigned int const DDS_VOLUME = 0x00200000;	struct DDColK	{		unsigned int lo;		unsigned int hi;	};	struct DDPixFmt	{		unsigned int sz;		unsigned int flags;		unsigned int fourCC;		unsigned int bpp;		unsigned int rMask;		unsigned int gMask;		unsigned int bMask;		unsigned int aMask;	};	struct DDSCaps	{		unsigned int c;		unsigned int c2;		unsigned int c3;		unsigned int c4;	};	struct DDSufDesc	{		unsigned int sz;		unsigned int flags;		unsigned int h;		unsigned int w;		unsigned int pitch;		unsigned int depth;		unsigned int mipLevs;		unsigned int alphaBits;		unsigned int reserved;		unsigned int surf;		struct DDColK dstOverlay;		struct DDColK dstBlt;		struct DDColK srcOverlay;		struct DDColK srcBlt;		struct DDPixFmt fmt;		struct DDSCaps caps;		unsigned int texStage;	} ddsd;	ifstream inf(fname, ios::binary);	if (inf.fail()) THROW(Exc, "Couldn't open " << fname)	unsigned int magic;	inf.read(reinterpret_cast<char *>(&magic), sizeof(magic));	if (!inf) THROW(Exc, "Error reading or unexpected end of file in " << fname)	if (magic != MAGIC) THROW(Exc, fname << " not DDS")	inf.read(reinterpret_cast<char *>(&ddsd), sizeof(ddsd));	if (!inf) THROW(Exc, "Error reading or unexpected end of file in " << fname)	_w = ddsd.w;	_h = ddsd.h;	if (imgW && imgW != _w || imgH && imgH != _h) THROW(Exc, fname << " is not the expected size")	_mipLevs = ddsd.mipLevs;	if (!(ddsd.fmt.flags & DDS_FOURCC)) THROW(Exc, fname << " is not a fourCC file");	switch (ddsd.fmt.fourCC)    {	case FCC_DXT1:		if (ddsd.fmt.flags & DDS_ALPHAPIXELS) _format = DXT1A;		else _format = DXT1;		break;	case FCC_DXT3:		_format = DXT3A;		break;	case FCC_DXT5:		_format = DXT5A;		break;	case FCC_ATI1:		_format = ATI1;		break;	case FCC_ATI2:		_format = ATI2;		break;	default:		THROW(Exc, "Unrecognized fourCC value in " << fname)		break;	}	if (chans)	{		switch (_format)		{		case ATI1:			if (chans != 1) THROW(Exc, fname << " is 1 channel")			break;		case ATI2:			if (chans != 2) THROW(Exc, fname << " is 2 channel")			break;		case DXT1:			if (chans != 3) THROW(Exc, fname << " is 3 channel")			break;		default:			if (chans != 4) THROW(Exc, fname << " is 4 channel")			break;		}		_ch = chans;	}	else	{		switch (_format)		{		case ATI1:			_ch = 1;			break;		case ATI2:			_ch = 2;			break;		case DXT1:			_ch = 3;			break;		default:			_ch = 4;		}	}	if (ddsd.caps.c2 & DDS_CUBEMAP) ...... // TODO: Handle cubemaps	if (ddsd.caps.c2 & DDS_VOLUME) THROW(Exc, "Did not expect " << fname << " to be a volume texture") // Should not happen if DDSF_FOURCC, but just in case	int const sz(((_w + 3) / 4) * ((_h + 3) / 4) * (_format == DXT1 || _format == DXT1A || _format == ATI1 ? 8 : 16) * (_mipLevs > 1 ? 2 : 1)); // The +3 is for celing	if (!(_data = static_cast<unsigned char *>(_mm_malloc(sz * sizeof(unsigned char), 8)))) THROW(Exc, "Couldn't allocate memory for image data from " << fname)	inf.read(reinterpret_cast<char *>(_data), sz);	if (!inf.eof() && !inf) THROW(Exc, "Error reading " << fname)	inf.close();	_dp = _data;}

Where THROW is the macro
#define THROW(exc, msg) { std::stringstream buffer; buffer << msg << "; thrown from " << __FILE__ << ", " << __FUNCTION__ << "() on line " << __LINE__ << std::flush; throw exc(buffer.str().c_str()); }
and STATIC_ASSERT is a compile-time assert I use in a number of places since I often build on 64 bit machines.
template struct CompileError;
template<> struct CompileError
{
};
#define STATIC_ASSERT(X) (CompileError<(X)>())
Of course, once your compiler supports static_assert you'd use that.

[Edit] Here's code to set the GL_UNPACK_ALIGNMENT I use in my Texture::Load()

// Author: Borislav Trifonovunsigned int rs;if (image.GetType() == Image::LDR) rs = imgW * chans; // PNGelse if (image.GetType() == Image::HDR) rs = imgW * chans * 2; // EXRelse // DDS{	DDSImage const &dds(reinterpret_cast<DDSImage const &>(image));	rs = ((imgW + 3) / 4) * ((imgH + 3) / 4) * (dds.GetFmt() == DDSImage::DXT1 || dds.GetFmt() == DDSImage::DXT1A || dds.GetFmt() == DDSImage::ATI1 ? 8 : 16);}// Determine row alignment based on divisibilityif (rs & 0x7 || rs < 8){	if (rs & 0x3 || rs < 4)	{		if (rs & 0x1 || rs < 2) glPixelStorei(GL_UNPACK_ALIGNMENT, 1);		else glPixelStorei(GL_UNPACK_ALIGNMENT, 2);	}	else glPixelStorei(GL_UNPACK_ALIGNMENT, 4);}else glPixelStorei(GL_UNPACK_ALIGNMENT, 8);

I didn't use RTTI and instead explicitly stored image type as enabling it in the compiler tends to result in slower executables, and this is the only place in my program where it would be useful.

[Edited by - Prune on November 20, 2009 12:14:09 PM]
"But who prays for Satan? Who, in eighteen centuries, has had the common humanity to pray for the one sinner that needed it most?" --Mark Twain

~~~~~~~~~~~~~~~Looking for a high-performance, easy to use, and lightweight math library? http://www.cmldev.net/ (note: I'm not associated with that project; just a user)
Emark
Emark
Quote:
Original post by Illasera
Quote:
Original post by Emark

maxsize = (img_width*img_height)/2;


What?

1.)I dont think thats the way to calculate your image size - Reading past the image size can and most likely will cause an error.
yes it is, because i know my DDS image format, and im not gonna use any other type of format.
Quote:
Original post by Illasera
2.)I noticed you cutted part of the dds header. There is a chance you are reading the wrong data, Use the entire header from ddraw.h.
how so? the header is 128 bytes, and so is mine. Ive tested the headers, and they return the correct values.
Quote:
Original post by Illasera
3.)Make sure you initialized the Load2DCompressedImages(), Since its an extension, you need to get the function address , wglGetProcAddress
how exactly i do that initialization? i dont have a clue, and im not even using that function Load2DCompressedImages()

Quote:
Original post by Illasera
*.)Most likely your program crashes because its an attempt to read past the buffer, Otherwise an openGL error would get silently invoked and the image wont get drawn, But no crash.
past? in which part of code i incremented the pointer value? it clearly gives the pointer to that image data... not past or anything, exactly the place where my image data starts.

Quote:
Original post by Illasera
*.)Afaik , what effects DDS raw data size is , if its mipmapped and the compression format. Get the right compression format from the header "ddpfPixelFormat.dwFourCC", and if its mipmapped by "Header.dwMipMapCount", Use them to calculate your real image size (like Moeller method) and dont forget to include the mipmap data as well.

In my opinion, am quite sure its the image size that is wrong and you are trying to read past that.
yeah i know, but as i said earlier, i dont need to use those calculation formulaes since i know my format and im not attempting to use other formats.


--


Prune, i will try that code later, it looks too complex to ponder it right now

i wish there was some simplier way to fix my code :/

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.