Archived

This topic is now archived and is closed to further replies.

Image loading method crashes program!!

This topic is 5511 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

This is probably just a simple typing mistake somewhere, but I''ve been staring at my code for a couple hours and finally just gave up =[ Here''s the problem: I''m working on the preliminary stages for a GUI for my game and I need to load images for buttons and pictures and whatnot. Naturally, images in an interface can''t always conform to the power-of-two rule for texture dimensions in OpenGL, and glDrawPixels() is far too slow to be useful. My solution was to split an image into a bunch of pieces that DO have power-of-two dimensions, then load them as textures and draw them together. This worked fine for the first image I loaded (256x256, which didn''t use much of the splitting code, heh), but when I tried to load an 800x600 image, something went horribly awry. The program crashes when I call glTexImage2D() for the third piece, which is 32x512 pixels. Here is the code for the loading function.
bool GraphicsDataManager::LoadBitmap( const Texture& t, TextureHandle* handle )
{
	// Make sure this texture is loadable
	// Textures without names and without any graphical data are not usuable
	if ( t.name.Length() == 0 ||
             t.width == 0 ||
	     t.height == 0 ||
	     t.data == NULL )
	{
		game->errorlog->Log( "GraphicsDataManager", "Attempt to load unusable texture", 2 );
		return false;
	}

	// Load t into the list before anything happens to it
	// All textures and bitmaps are loaded into a linked list "textures"
	TextureHandle h;

	textures.AddAtHead( t );
	h = &(textures.Begin()->data);	// we will refer to the image to be loaded as "h" from now on
	if ( handle != NULL )
		*handle = h;

	// Figure out how many images we are going to split t into
	// Since OpenGL can only handle textures with dimensions that are
	// powers of two, we must decompose the bitmap into a bunch of smaller
	// textures. Since each bit in a binary number is a power of two, we
	// simply figure out how many bits are "on" in the image''s dimensions.
	unsigned char wbits = 0; 	// bits in the width
	unsigned char hbits = 0;		// bits in the height

	for ( int i = 15; i >= 0; i-- )	// width and height are 16-bit unsigned int''s, so we test bits 0-15
	{
		if ( (unsigned short) pow( 2, i ) & h->width )
			wbits++;

		if ( (unsigned short) pow( 2, i ) & h->height )
			hbits++;
	}

	// Figure out coordinates for those images with two arrays of coordinates
	// We will cut the image along these coordinates, and later, we will draw the
	// pieces along these coordinates so it looks like its still one image
	unsigned short* x_vertices;
	unsigned short* y_vertices;
	int xci = 1;		// x-coordinate iterator; we start at one because already know x_vertices[0] is 0
	int yci = 1;		// same

	x_vertices = new unsigned short[wbits + 1];	// we need one more coordinate so every piece has a right and left coordinate
	y_vertices = new unsigned short[hbits + 1];
	x_vertices[0] = 0;   	// don''t need to calculate the top left of the image ;]
	y_vertices[0] = 0;

	for ( int i = 15; i >= 0; i-- )		// calculate the rest
	{
		if ( (unsigned short) pow( 2, i ) & h->width )
		{
			x_vertices[xci] = (unsigned short) pow( 2, i ) + x_vertices[xci - 1];
			xci++;
		}
		if ( (unsigned short) pow( 2, i ) & h->height )
		{
			y_vertices[yci] = (unsigned short) pow( 2, i ) + y_vertices[yci - 1];
			yci++;
		}
	}

	// Create a matrix of textures to hold the pieces of the bitmap
	// Load each texture into the GL
	// Create a display list for each texture
	Texture* t_matrix = new Texture[wbits * hbits];
	unsigned int listbase;

	listbase = glGenLists( wbits * hbits + 1 );		// wbits * hbits lists to draw each piece
											// one more list to draw all the other lists

	for ( int row = 0; row < hbits; row++ )			// for each row (y)
	{
		for ( int col = 0; col < wbits; col++ )		// for each column (x)
		{
			// Copy a piece of the image
			h->Blit( x_vertices[col],					// top left corner
				    y_vertices[row],					// bottom right corner
				    x_vertices[col + 1] - x_vertices[col],	// width
				    y_vertices[row + 1] - y_vertices[row],	// height
				    &t_matrix[row*wbits + col] );			// pointer to the texture

			// Load the texture into the GL
			glGenTextures( 1, &t_matrix[row*wbits + col].id );
			glBindTexture( GL_TEXTURE_2D, t_matrix[row*wbits + col].id );

			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );


/**** PROGRAM CRASHES HERE!!! AHHHH!!! ****/
			glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, t_matrix[row*wbits + col].width, t_matrix[row*wbits + col].height, 0, GL_RGB, GL_UNSIGNED_BYTE, t_matrix[row*wbits + col].data );
			delete [] t_matrix[row*wbits + col].data;		// don''t need this anymore

			// Create a display list with the new texture
			glNewList( listbase + (row*wbits + col) + 1, GL_COMPILE );
				glBindTexture( GL_TEXTURE_2D, t_matrix[row*wbits + col].id );
				glBegin( GL_QUADS );
					glTexCoord2f( 0.0f, 1.0f );
					glVertex2i( x_vertices[col], y_vertices[row] );
					glTexCoord2f( 0.0f, 0.0f );
					glVertex2i( x_vertices[col], y_vertices[row + 1] );
					glTexCoord2f( 1.0f, 0.0f );
					glVertex2i( x_vertices[col + 1], y_vertices[row + 1] );
					glTexCoord2f( 1.0f, 1.0f );
					glVertex2i( x_vertices[col + 1], y_vertices[row] );
				glEnd();
			glEndList();
		}
	}

	// Now create one big list that calls all the other lists
	glNewList( listbase, GL_COMPILE );
		for ( int i = 0; i < wbits * hbits; i++ )
			glCallList( listbase + i + 1 );
	glEndList();
	h->id = listbase;

	// Clean up
	delete [] h->data;

	delete [] x_vertices;
	delete [] y_vertices;

	delete [] t_matrix;  		// VIDEO MEMORY LEAK HERE!!! FIX IT!!!

	game->errorlog->Log( "GraphicsDataManager", "Bitmap \"" + h->name + "\" loaded successfully", 1 );

	return true;
}
 
Also of interest is the Texture::Blit() method, which I use to copy a section of the image.
void Texture::Blit( unsigned short xc, unsigned short yc, unsigned short size_x, unsigned short size_y, Texture* image )
{
	// Error check parameters
	if ( xc >= width ||				// coordinates must be inside the image
          yc >= height ||
          size_x == 0 ||				// we must blit _some_ image data
		size_y == 0 ||
		xc + size_x > width ||		// the size of the image cannot be outside the image
		yc + size_y > height ||
		image == NULL )			// we must not have already cleared data
		return;

	// Count the blit number for the image name
	// Each image must have a unique name
	// This is not important now, but eventually, these images will be part
	// of the linked list in the GraphicsDataManager to prevent memory leaks
	static char blit_x0 = ''0'';
	static char blit_0x = ''0'';

	blit_0x++;
	if ( blit_0x == ''9'' + 1 )	// overflow, count up
	{
		blit_x0++;
		blit_0x = ''0'';
	}

	// Prepare the image
	image->Release();			// clean out anything already in there

	image->name = name + blit_x0 + blit_0x;
	image->width = size_x;
	image->height = size_y;
	image->data = new unsigned char[image->width * image->height * 3];

	// Copy that section
	for ( int y = yc; y < yc + size_y; y++ )
	{
		for ( int x = xc; x < xc + size_x; x++ )
		{
			image->data[y*image->width*3 + x*3 + 0] = data[(yc+y)*width*3 + (xc+x)*3 + 0];
			image->data[y*image->width*3 + x*3 + 1] = data[(yc+y)*width*3 + (xc+x)*3 + 1];
			image->data[y*image->width*3 + x*3 + 2] = data[(yc+y)*width*3 + (xc+x)*3 + 2];
		}
	}
}
 
If anyone has any suggestions on how I can make this work, I would _really_ appreciate it. Thanks in advance for your help.

Share this post


Link to post
Share on other sites
You''ve probably tryied this already, but here it goes anyway: Some graphic cards don''t support textures bigger than 256x256. Try to split the 32x512 texture in two 32x256 pieces and see if it works.

Share this post


Link to post
Share on other sites
Yeah, it's probably the width and height you're passing to glTexImage2D. My progam was crashing at the same execution point. I found out I was passing an invalid width and height.

[edited by - Brian Jones on November 11, 2002 2:40:52 PM]

Share this post


Link to post
Share on other sites
Thanks for the help guys. I figured out what was wrong with it. It turned out to be a weird memory error in the double loops in the Texture::Blit() method. I started x and y at xc and yc and then offset them by xc and yc later, meaning that I was offsetting them twice and going out of bounds. I just initialized them to zero and it worked fine (except that it was upsidedown, but that was unrelated to that =] ).

Share this post


Link to post
Share on other sites