Bitmap loader
Hi,
I''m currently working on a 2d tile-based engine. About 2 weeks ago, I decided to write my own custom bitmap loader, to take advantage of the access of the buffer, in order to dynamically change the color depth of bitmaps to suit the color depth the program is running in. I wrote a prelinary loader (read: EXTREMELY stripped), just to get something to work from. However, upon running it, I encountered the error:
"Debug Assertion Failed
Dbgheap.c
line: 1017
Expression: BLOCK_TYPE_IS_VALID(pHead->nBlockUse)"
I know the pHead->nBlockUse means something to do with thrashing memory, but I can''t seem to rid myself of the problem. Perhaps a little code would help:
Here is the structure which holds the bitmap...
class Bitmap
{
public:
BITMAPFILEHEADER *bitmapfileheader; // this contains the bitmapfile header
BITMAPINFOHEADER *bitmapinfoheader; // this is all the info including the palette
UCHAR *buffer; // this is a pointer to the data
};
And the function which loads the bitmap from file to surface....
LPDIRECTDRAWSURFACE7 Graphics::DDrawLoadBitmapToSurface(char *filename, LPDIRECTDRAWSURFACE7 lpdds)
{
// Loads a 24-bit bitmap from a file, then copies the bitmap
// to the surface. Returns pointer to surface.
// Note: this function performs almost NO error checking, and makes
// a lot of assumptions of the correctness of the bitmap file
Bitmap bitmap; // All bitmap data stored here
// create file handle
ifstream BitmapFile;
// open bitmap
BitmapFile.open(filename, ios::binary, NULL);
// allocate memory for fileheader
bitmap.bitmapfileheader = (BITMAPFILEHEADER *)(malloc(sizeof(BITMAPFILEHEADER)));
// read data into fileheader
BitmapFile.read((char *)bitmap.bitmapfileheader, sizeof(BITMAPFILEHEADER));
// allocate memory for infoheader
bitmap.bitmapinfoheader = (BITMAPINFOHEADER *)(malloc(sizeof(BITMAPINFOHEADER)));
// read data into infoheader
BitmapFile.read((char *)bitmap.bitmapinfoheader, sizeof(BITMAPINFOHEADER));
// allocate memory for buffer
bitmap.buffer = (UCHAR *)(malloc(bitmap.bitmapinfoheader->biSizeImage));
// read data into buffer
BitmapFile.read(bitmap.buffer, (UCHAR)bitmap.bitmapinfoheader->biSizeImage);
// close file
BitmapFile.close();
int bytes_per_line = bitmap.bitmapinfoheader->biWidth*3;
FlipBitmap(bitmap.buffer, bytes_per_line, bitmap.bitmapinfoheader->biHeight);
// *********** Now put the bitmap onto the surface ****************
// lock the surface
if (FAILED(lpdds->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL)))
{
myEngine.myError.Write_Error("Couldn''t lock surface.");
return 0;
}
// get video pointer to the surface passed in the function (lpdds)
UCHAR *lpdds_buffer = (UCHAR *)ddsd.lpSurface;
for (unsigned int index_y = 0; index_y < bitmap.bitmapinfoheader->biHeight; index_y++)
{
// copy next line of data to destination
if(!memcpy(lpdds_buffer, bitmap.buffer, bytes_per_line))
{
myEngine.myError.Write_Error("Couldn''t copy memory from bitmap buffer to surface.");
return 0;
}
// advance pointers
lpdds_buffer += (UCHAR)bytes_per_line;
bitmap.buffer += (UCHAR)bytes_per_line;
}
// now unlock the surface
if (FAILED(lpdds->Unlock(NULL)))
return(0);
free(bitmap.bitmapfileheader);
free(bitmap.bitmapinfoheader);
free(bitmap.buffer);
return lpdds;
}
I have narrowed the source of the error down to the line:
bitmap.buffer += (UCHAR)bytes_per_line;
Where the pointer is advanced to the next line on the surface. For some reason, which I can''t, for the life of me seem to figure out, the pointer cannot be advanced at all. Even incrementing the pointer like so:
bitmap.buffer++;
Returns the same "Debug Assertion Failed" error.
I think the problem is caused by the pointer pointing to the wrong portion of memory, and I believe the line:
BitmapFile.read(bitmap.buffer, (UCHAR)bitmap.bitmapinfoheader->biSizeImage);
Is to blame. I''ve tried all sorts of typecasting, but nothing seems to work. As it is, I''m trying to typecast the biSizeImage variable to UCHAR, so it corresponds with the same type as bitmap.buffer. But I just can''t seem to get it right.
Any help would be greatly appreciated.
Regards,
Estese
"If I have seen farther than other men, it is because I have stood on the shoulders of giants." -- sir Isaac Newton
Hmm, it maybe that biSizeImage is 0 and therefore the buffer you are allocating can not be accessed. You should check for such condition and manually calculate the size of the buffer.
Make sure that you are loading 24bit bitmaps, otherwise you''ll read past the end of the array, hence bad problems. Also, because you are typecasting to UCHAR when you advance your pointer, it means that you cannot have a more than 256 bytes per line, which is 85 pixels. Beware of that also.
If at first you don't succeed, redefine success.
Get rid of the UCHAR typecasting. When you read the file into the buffer, you are only reading in a max of 256 bytes of color data. It appears that this is written only for loading 24-bit color bitmaps, make sure the one you are loading is 24 or the bitmap will not contain enough data. Also, don''t forget that bitmaps are DWORD aligned.
In your loop, you are incrementing the pointer bitmap.buffer Unfortunately, this means you lose the pointer to the beginning of the allocated block. You then tried to free it from its current position (very bad) at the end of the block. You should create an alias to the bitmap data and increment that in your loop, keeping bitmap.buffer as the pointer to the beginning. Then throw away the alias and free the pointer to the beginning.
Final note: you should''t be incrementing the lpdds_buffer pointer by the bytes_per_line of the bitmap, you want to increment it by the destination surface''s pitch: lpdds_buffer += ddsd.lPitch;
In your loop, you are incrementing the pointer bitmap.buffer Unfortunately, this means you lose the pointer to the beginning of the allocated block. You then tried to free it from its current position (very bad) at the end of the block. You should create an alias to the bitmap data and increment that in your loop, keeping bitmap.buffer as the pointer to the beginning. Then throw away the alias and free the pointer to the beginning.
Final note: you should''t be incrementing the lpdds_buffer pointer by the bytes_per_line of the bitmap, you want to increment it by the destination surface''s pitch: lpdds_buffer += ddsd.lPitch;
You could always do something like this (borrowed liberally from from ddutil):
Then call GetDIBits to retrieve the actual pixels of the bitmap.
I hand wrote a bitmap loader a while back, and it got to be a big pain in the ass (wait until you get to deltas...ugh). Why not let the OS do your dirty work?
Happy Coding.
-Rabid
HBITMAP hbm;BITMAP bm;int iWidth; // Width of the bitmapint iHeight; // Height of the bitmap/* Try to load the bitmap as a resource, if that fails, try it as a file*/hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, iWidth, iHeight, LR_CREATEDIBSECTION);if (hbm == NULL){ hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, iWidth, iHeight, LR_LOADFROMFILE | LR_CREATEDIBSECTION);}if (hbm == NULL){ return NULL;}
Then call GetDIBits to retrieve the actual pixels of the bitmap.
I hand wrote a bitmap loader a while back, and it got to be a big pain in the ass (wait until you get to deltas...ugh). Why not let the OS do your dirty work?
Happy Coding.
-Rabid
"Why not let the OS do your dirty work?"
Because, as I''ve previously stated, I need control of the buffer in order to scale down the color depth of the bitmap, so I can select a valid color key.
For example, my game will run in 16-bit mode, and it loads 24-bit bitmaps. I can''t select a color key to be transparent this way, so I have to scale the bitmap down to 16-bit first, then supply an RGB value for transparency.
Regards,
Estese
"If I have seen farther than other men, it is because I have stood on the shoulders of giants." -- sir Isaac Newton
Thanks for all the help guys, but I got it working using a different algorithm for transfering the data from bitmap buffer to surface. Not to say the advice I received here didn''t help
I learnt a few things. Again, thanks.
Regards,
Estese
![](smile.gif)
Regards,
Estese
"If I have seen farther than other men, it is because I have stood on the shoulders of giants." -- sir Isaac Newton
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement