• Advertisement

Archived

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

Win32: Displaying BMP with transparent BG - bug I can't cope with!

This topic is 5099 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 think the overall time I've spent trying to fix this is about 4-5 hours now... and I don't know... Below is the code! The TransparentBlit function I leeched from gametutorials (100% copy). Problem is that sometimes it wont work properly. While the image I want to be displayed works fine, the "to-be-transparent" background doesn't. What is displayed, are stripes: 2 blue (color I use for transparency), 1 white (background color), 2 blue, 1 white etc... So it looks as if only every 3rd line is displayed as transparent properly. And I have no idea why...... Here's the code (I added fullscreen function just so you can "zoom in" and see the patter I described better). For this code you'll need a 24-bit BMP with this (or something like this) resolution : 30x100 pixels. The "transparency" color is pure blue (R:0 G:0 B:255). name it "monster.bmp" and check this out:
#include <windows.h>

#define WIDTH 320
#define HEIGHT 200

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);


HBITMAP hbitmap;

void FullScreen(int,int);
void TransparentBlit(HDC hdc, int destX, int destY, int destWidth, int destHeight,
					 HDC hdc2, int srcX, int srcY, UINT tranparency);

BOOL bFullScreen = 0;

HDC gdc;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
 HWND hwnd;
 MSG msg;
 WNDCLASSEX wndclass={0};
 DWORD style;

 wndclass.cbSize=sizeof(wndclass);
 wndclass.style = CS_HREDRAW | CS_VREDRAW;
 wndclass.lpfnWndProc = WndProc;
 wndclass.hInstance = hInstance;
 wndclass.hIcon = LoadIcon(0, IDI_WINLOGO);
 wndclass.hCursor = LoadCursor(0, IDC_ARROW);
 wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 wndclass.lpszClassName = "Transparent Blit";
 wndclass.hIconSm = LoadIcon (0, IDI_WINLOGO);

 RegisterClassEx(&wndclass);

     if(MessageBox(0,"Change to Fullscreen ?","Fullscreen?", MB_YESNO)==IDYES)
   	{
       bFullScreen=1;
       style=WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |WS_VISIBLE;
       FullScreen(WIDTH,HEIGHT);
      }
    else
    	{
       style = WS_VISIBLE | WS_OVERLAPPEDWINDOW;

      }

 hwnd = CreateWindow("Transparent Blit",
 							"Transparent Blit",
                     style,
                     CW_USEDEFAULT,
                     CW_USEDEFAULT,
                     WIDTH,
                     HEIGHT,
                     NULL,
                     NULL,
                     hInstance,
                     NULL);
 ShowWindow(hwnd, iCmdShow);
 UpdateWindow(hwnd);

 gdc = GetDC(hwnd);
 hbitmap=(HBITMAP)LoadImage(hInstance,"monster.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
 HDC HdcBit;
 HBITMAP oldbit;

 while(1)
 	{
    if(PeekMessage(&msg, 0,0,0,PM_REMOVE))
    	{
       if(msg.message==WM_QUIT)
         	break;

       TranslateMessage(&msg);
       DispatchMessage(&msg);

       HdcBit=CreateCompatibleDC(gdc);
       oldbit=(HBITMAP)SelectObject(HdcBit,hbitmap);
		 TransparentBlit(gdc, 50, 50, 30, 100, HdcBit, 1, 1, RGB(0,0,255));

       SelectObject(HdcBit, oldbit);
       DeleteObject(HdcBit);

      }
     else
     	{

		}

   }

 if(bFullScreen)
 		ChangeDisplaySettings(NULL, 0);

 UnregisterClass("Transparent Blit", hInstance);

 return msg.wParam;
}



LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
 PAINTSTRUCT ps;
 switch(iMsg)
 	{

    case WM_PAINT:
    	BeginPaint(hwnd, &ps);
      EndPaint(hwnd, &ps);
      break;

    case WM_SIZE:
    	break;

    case WM_CREATE:
    	break;

	 case WM_KEYDOWN:
    	if(wParam==VK_ESCAPE);
			PostQuitMessage(0);
      break;
    case WM_CLOSE:
    case WM_DESTROY:
	    PostQuitMessage(0);

	    break;
    }
 return DefWindowProc(hwnd,iMsg,wParam,lParam);
}

void TransparentBlit(HDC hdc, int destX, int destY, int destWidth, int destHeight,
					 HDC hdc2, int srcX, int srcY, UINT tranparency)
{
	unsigned char* pImageBits;
	unsigned char* pBackBits;
	BITMAPINFO bmBitmapInfo = {0};
	HBITMAP hBitmap, hBitmap2, hOldBitmap, hOldBitmap2;
	HDC compHDC;
	HDC compHDC2;

	// Fill in our BitmapInfo structure (we want a 24 bit image)

	bmBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmBitmapInfo.bmiHeader.biCompression = BI_RGB;
	bmBitmapInfo.bmiHeader.biHeight = destHeight;
	bmBitmapInfo.bmiHeader.biWidth = destWidth;	
	bmBitmapInfo.bmiHeader.biBitCount = 24;
	bmBitmapInfo.bmiHeader.biClrUsed = 0;
	bmBitmapInfo.bmiHeader.biPlanes = 1;

	// Create 2 DIB Sections.  One for the Front Buffer and one for the BackBuffer

	hBitmap  = CreateDIBSection(hdc,  &bmBitmapInfo, DIB_RGB_COLORS,(void **)&pImageBits, 0,0);	
	hBitmap2  = CreateDIBSection(hdc,  &bmBitmapInfo, DIB_RGB_COLORS,(void **)&pBackBits, 0,0);

	// Create a compatible DC for the front buffer and Select our Dib Section into it

	compHDC = CreateCompatibleDC(hdc);
	hOldBitmap = (HBITMAP)SelectObject(compHDC, hBitmap);
	
	// Create a compatible DC for the back buffer and Select our Dib Section into it

	compHDC2 = CreateCompatibleDC(hdc2);
	hOldBitmap2 = (HBITMAP)SelectObject(compHDC2, hBitmap2);

	// Blit the front buffer to our compatible DC that will hold the destination bits

	BitBlt(compHDC, 0, 0, destWidth, destHeight, hdc, destX, destY, SRCCOPY);

	// Blit the back buffer to our compatible DC that will hold the source bits

	BitBlt(compHDC2, 0, 0, destWidth, destHeight, hdc2, srcX, srcY, SRCCOPY);

	// Loop through the 24 bit image (Times 3 for R G and B)

	for(int i = 0; i < destHeight * destWidth * 3; i +=3)
	{
		// Check if the current pixel being examined isn't the transparent color

		// Remember, the image bits are stored (Blue, Green, Red), not (Red, Green, Blue)

		// We use the system macros to abstract the R G B data

		if((pBackBits[i]   != GetBValue(tranparency)) || 
		   (pBackBits[i+1] != GetGValue(tranparency)) || 
		   (pBackBits[i+2] != GetRValue(tranparency)))
		{
			// Assign the desired pixel to the foreground

			pImageBits[i]     = pBackBits[i];
			pImageBits[i + 1] = pBackBits[i + 1];
			pImageBits[i + 2] = pBackBits[i + 2];
		}
	}  

	
	// Blit the transparent image to the front buffer (Voila!)

	BitBlt(hdc, destX, destY, destWidth, destHeight, compHDC, 0, 0, SRCCOPY);

	// Cleanup the monochrome bitmaps

	SelectObject(compHDC, hOldBitmap);
	SelectObject(compHDC2, hOldBitmap2);	

	// Free GDI Resources

	DeleteObject(hBitmap);
	DeleteObject(hBitmap2);
	DeleteDC(compHDC);
	DeleteDC(compHDC2);
}

//=========================================

void FullScreen(int width,int height)
{
		DEVMODE devmode = {0};

		devmode.dmSize = sizeof(DEVMODE);
		devmode.dmPelsWidth	= width;
		devmode.dmPelsHeight = height;
		devmode.dmBitsPerPel = 16; // Bits per pixel

		devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		if(ChangeDisplaySettings(&devmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
		{
			// Display the error message and quit the program

			MessageBox(NULL, "Display Mode Not Compatible", "Error", MB_OK);
			PostQuitMessage(0);
		}

}
Now that you see my problem go to this line:
TransparentBlit(gdc, 50, 50, 30, 100, HdcBit, 1, 1, RGB(0,0,255));
 
and change the fourth value (30) to 20 and viola - now it works! I noticed this bug when using my double buffering library and while resizing the window (the size of the window would go into the place of 30 and 100 in the above function). It appears that for SOME destWidth values passed to the function, it doesn't work properly... Help GREATILY appreciated... yeah... [edited by - Koobazaur on March 5, 2004 9:16:00 PM]

Share this post


Link to post
Share on other sites
Advertisement
I'm not entirely sure how that function works... but I don't like it... there's no reason why you should have to make three BitBlts and a for loop just to do a transparent blit... you should only need two BitBlts... check out this tutorial


BTW: That for loop looks like it's going through every pixel in the image... and if it insists on doing something so dumb it might as well do all the transparent stuff there and just do one BitBlt... heck... why doesn't it just copy the pixels it wants over to the destination DC and skip BitBlt all together?

[edited by - TempusElf on March 6, 2004 10:30:15 AM]

Share this post


Link to post
Share on other sites
Thanks for the reply, I''ll look into that...

Why this code is the way it is because I copied it from gametutorials.com not fully understanding it yet ... but after trying to fix it for 4 hours I think I now undastand every single line of it you bring up a good point with the multiple-blitting...
one thing I don''t get - why is going through a bmp pixel-by-pixel a dumb thing?

Share this post


Link to post
Share on other sites

  • Advertisement