Jump to content
  • Advertisement

Archived

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

LuckyNewbie

Okay, how do I load a 32-bit bitmap

This topic is 5437 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'm talking specifically about direct draw and how I would make a 32-bit LPDIRECTDRAWSURFACE4 surface from a 24-bit file (the DirectDraw 6 interface used in LaMothe's Tricks of the Windows Game Programming Gurus So far I've managed to do a 16-bit bitmap with no problem, but I want to have this new program I'm making be a nice windowed directdraw application capable of taking the 24-bit art and displaying it in a 16 or 32-bit mode, depending on what the user is running... and not have some lame error message like UnrealEd saying "You have to be in 32-bit mode to run this program." Googling has revelead no clues, I don't think I should bother Lamothe over such a silly question, and I know it's been done before and someone probably has working code... or knowledge of how to fix my code. Any help at all would be appreciated. Here's the code, in case you are interested... it's from a class so all I have to do to load and display a bitmap would be something like this: SimpleBitmap.Load("Art1.bmp"); SimpleBitmap.Display(); And now for a code dump...
#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24)) // declared elsewhere, from Tricks part ii



int SimpleBitmap::Load(char * filename)
{
// DEBUG INFO

g_printError("*Loading SimpleBitmap File");

	// Variables for the image loading

	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

	UCHAR			 *temp_buffer;		// to convert 24 bits to 32 or 16


	int file_handle;			// the file handle

	OFSTRUCT file_data;			// the file data information


// Load the file into memory ////////////////////////////

	// first open the file

	if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
	{
		g_printError("Error in SimpleBitmap.Load(): File not Found!");
		return -1;
	}

	// now load the bitmap file header

	_lread(file_handle, &bitmapfileheader,sizeof(BITMAPFILEHEADER));

	// test if this is a bitmap file

	if (bitmapfileheader.bfType!=BITMAP_ID)
	{
		g_printError("Error in SimpleBimap.Load(): This is not a bitmap!");
		_lclose(file_handle);
		return(-1);
	} // end if


	// now load the info header

	_lread(file_handle, &bitmapinfoheader,sizeof(BITMAPINFOHEADER));

	// finally load the image data itself

	_lseek(file_handle,-(int)(bitmapinfoheader.biSizeImage),SEEK_END);

	// now read in the image

	if (bitmapinfoheader.biBitCount==24)
	{
		// allocate the memory for the temp buffer

		if (!(temp_buffer = (UCHAR*)malloc(bitmapinfoheader.biSizeImage)))
		  {
			// close the file and return error

			g_printError("SimpleBitmap.Load() Error: Couldn't allocate memory for buffer");
			_lclose(file_handle);
			return(-1);
		  } // end if


		// allocate the memory for the image

		if (!(buffer=(UCHAR*)malloc((SCREEN_BPP/2)*bitmapinfoheader.biWidth*bitmapinfoheader.biHeight)))
		  {
			// close the file and return error

			g_printError("SimpleBitmap.Load() Error: Couldn't allocate memory2 for buffer");
			_lclose(file_handle);
			return(-1);
		  } // end if


		// now read it in

		_lread(file_handle,temp_buffer,bitmapinfoheader.biSizeImage);

	} // end if

	else
	{
		g_printError("SimpleBitmap.Load() Error -- Not a 24 bit image");
		return -1;// serious problem

	}	
	
	// close the file

	_lclose(file_handle);


	// now convert the 24-bit "temp buffer" into the 16 or 32-bit buffer

	if (SCREEN_BPP == 16)
	{
		g_printError("Converting 24-bit bitmap to 16-bit bitmap");
		// get the pixel format of the primary surface

		DDPIXELFORMAT primaryPixelFormat;		//	This is used to determine if we

		DDRAW_INIT_STRUCT(primaryPixelFormat);	//	use the 555 macro, or the 565 macro

		lpddsprimary->GetPixelFormat(&primaryPixelFormat);

		// now convert each 24 bit RGB value into a 16 bit value

		for (int index=0; index < bitmapinfoheader.biWidth*bitmapinfoheader.biHeight; index++)
		{
			USHORT color;
			// extract RGB components (in BGR order), note the scaling

			UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
				  green = (temp_buffer[index*3 + 1] >> 2),
				  red   = (temp_buffer[index*3 + 2] >> 3);

	
			if (primaryPixelFormat.dwGBitMask == 0x000007E0)// use the 565 macro

				color = _RGB16BIT565(red,green,blue);
			else											// use the 555 macro

				color = _RGB16BIT555(red,green,blue);
			((USHORT*)buffer)[index] = color;
		}
		bitmapinfoheader.biBitCount = 16;
		// release working buffer

		free(temp_buffer);
	}
	else if (SCREEN_BPP == 32)
	{
//////////////////////////////////////////////////////////

//			AM I DOING SOMETHING WRONG HERE???

//////////////////////////////////////////////////////////

		g_printError("Converting 24-bit bitmap to 32-bit bitmap");
		// now convert each 24 bit RGB value into a 32 bit value

		for (int index=0; index < bitmapinfoheader.biWidth*bitmapinfoheader.biHeight; index++)
		{
			USHORT color;
			// extract RGB components (in BGR order), note the scaling

			UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
				  green = (temp_buffer[index*3 + 1] >> 2),
				  red   = (temp_buffer[index*3 + 2] >> 3);

			color = _RGB32BIT(0,red,green,blue);

			((USHORT*)buffer)[index] = color;
		}
		bitmapinfoheader.biBitCount = 32;
		// release working buffer

		free(temp_buffer);
	}
	/////////////////////////////

	// FLIP THE BITMAP HERE (REMOVED FOR NOW)

	/////////////////////////////

/*if ( bitmapinfoheader.biHeight > 0) // We must flip the bitmap
{
	int bytes_per_line = bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8);
	int tHeight =   bitmapinfoheader.biHeight;
	UCHAR *new_buffer; // used to perform the image processing
	int index;     // looping index

	// allocate the temporary buffer
	if (!(new_buffer = (UCHAR *)malloc(bytes_per_line*tHeight)))
	   return -1;
	g_printError("New Surface Created");
	// copy the image onto a temporary buffer
	memcpy( new_buffer, buffer, bytes_per_line*tHeight);

	// copy last line from temp buffer onto the first line of the image buffer
	for (index=0; index < tHeight; index++)
		memcpy(&buffer[((tHeight-1) - index)*bytes_per_line],	// destination
			   &new_buffer[index*bytes_per_line],				// source
			   bytes_per_line);									// amount to copy

	// release the memory
	free(new_buffer);
}*/


// Create a LPDIRECTDRAWSURFACE4 Structure for this new image

	DDSURFACEDESC2 ddsd_surface;
	// LPDIRECTDRAWSURFACE4 surface; <--- Already declared in class itself

    memset(&ddsd_surface,0,sizeof(ddsd_surface));
    ddsd_surface.dwSize  = sizeof(ddsd_surface);
    ddsd_surface.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;

    ddsd_surface.dwWidth  = bitmapinfoheader.biWidth;
    ddsd_surface.dwHeight = bitmapinfoheader.biHeight;

    // set surface to offscreen plain

    ddsd_surface.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;

    // create the surfaces, return failure if problem

    if (FAILED(lpdd4->CreateSurface(&ddsd_surface,&this->surface,NULL)))
	{
		// destroy our bitmap data

		free(buffer);
		// reset pointer

		buffer = NULL;
		g_printError("SimpleBitmap.Load() Error: Couldn't Create  New Surface");
        return -1;
	};

    // set color key to color 0

    DDCOLORKEY color_key; // used to set color key

    color_key.dwColorSpaceLowValue  = 0;
    color_key.dwColorSpaceHighValue = 0;

    // now set the color key for source blitting

    surface->SetColorKey(DDCKEY_SRCBLT, &color_key);


// Now copy the Buffer data into the newly-created surface



	// lock the surface

	if FAILED(this->surface->Lock(
		NULL,&ddsd_surface, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL))
	{
		// destroy our bitmap data

		free(buffer);
		// reset pointer

		buffer = NULL;
		g_printError("SimpleBitmap.Load() Error: Locking surface failed");
		return -1;
	}	
	USHORT *source_ptr, *dest_ptr;
	source_ptr = (USHORT*)buffer;
	dest_ptr = (USHORT*)ddsd_surface.lpSurface;

	long pitch = ddsd_surface.lPitch;

	Write_Error("bitmapinfoheader.biWidth = %d \n",bitmapinfoheader.biWidth);
	Write_Error("ddsd_surface.lPitch	  = %d\n", pitch);
	Write_Error("ddsd_surface.lPitch >> 1 = %d\n", pitch >> 1);
//////////////////////////////////////////////////////////

//			AM I DOING SOMETHING WRONG HERE???

//////////////////////////////////////////////////////////

	for (int index_y=0; index_y < bitmapinfoheader.biHeight; index_y++)
    {
		// copy next line of data to destination

		memcpy(dest_ptr, source_ptr,
			(bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/2)));
		// advance pointers

		dest_ptr   +=  (ddsd_surface.lPitch >> 1);
		source_ptr +=  (ddsd_surface.lPitch >> 1); /*bitmapinfoheader.biWidth * 3;*/
    } // end for index_y


	// now unlock the surface

	if (FAILED(surface->Unlock(NULL)))
	{
		g_printError("SimpleBitmap.Load() Error: Unlocked failed!");
		// destroy our bitmap data

		free(buffer);
		// reset pointer

		buffer = NULL;
		return(-1);
	}

	// destroy our bitmap data

	free(buffer);
	// reset pointer

	buffer = NULL;

	g_printError("*SimpleBitmap.Load() returns A-OK!");
	
	this->x = 0;
	this->y = 0;
	this->width = bitmapinfoheader.biWidth;
	this->height = bitmapinfoheader.biHeight;

	return 0;
}

EDIT: Kinda fixed the source around [edited by - LuckyNewbie on August 15, 2003 2:09:01 PM]

Share this post


Link to post
Share on other sites
Advertisement
Strange how these things work out, but I figured out what I was doing wrong within two minutes of posting this... after going over the problem for days on end. Hopefully some schmo like me will find this later when the forum search works properly and reading this post will help. Here is what I did:

first, dest_ptr was changed from USHORT to DWORD to take in this bigger data. Just look at the code between the lock/unlock and replace it with this:

USHORT *source_ptr;//, *dest_ptr;

source_ptr = (USHORT*)buffer;
// dest_ptr = (USHORT*)ddsd_surface.lpSurface;

DWORD *dest_ptr = (DWORD*)ddsd_surface.lpSurface;

for (int index_y=0; index_y < bitmapinfoheader.biHeight; index_y++)
{
// copy next line of data to destination

memcpy(dest_ptr, source_ptr,
(bitmapinfoheader.biWidth*(bitmapinfoheader.biBitCount/8)));
// advance pointers

dest_ptr += (ddsd_surface.lPitch >> 2);
source_ptr += (ddsd_surface.lPitch >> 1); /*bitmapinfoheader.biWidth * 3;*/
} // end for index_y





The second major change I did was in the color shifting near the first "AM I DOING SOMETHING WRONG HERE" comment. Replace the contents of the for loop with this:


for (int index=0; index < bitmapinfoheader.biWidth*bitmapinfoheader.biHeight; index++)
{
DWORD color;
// extract RGB components (in BGR order), note the scaling

UCHAR blue = (temp_buffer[index*3 + 0]),
green = (temp_buffer[index*3 + 1]),
red = (temp_buffer[index*3 + 2]);

color = _RGB32BIT(0,red,green,blue);

//((USHORT*)buffer)[index] = color;

((DWORD*)buffer)[index] = color;
}


Sorry for making you click on a post, but I'm sure this hasn't been the first time some bozo like me has done this.



"Let me just ejaculate some ideas"

[edited by - LuckyNewbie on August 15, 2003 2:26:14 PM]

[edited by - LuckyNewbie on August 30, 2003 5:54:34 PM]

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!