Archived

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

mix_MasterMix

GDI and Back Buffer Headaches

Recommended Posts

I''m just starting to learn game programming in C++, and I''ve been going through the "Game Programming Genesis" series. I decided to take a moment after the 3rd article to write a simple pong game using only GDI. I wrote a simple bitmap and sprite class, and was successful in getting a few graphics on the screen, but after putting more than one graphic up, I noticed terrible flicker. I figured a back buffer would help, so I tried to implement one using a memory device context. All I got was a blank screen. Here''s my main loop:
  
        CSprite* board  = new CSprite(0, 0, BOARD, hInstance);
	CSprite* paddle = new CSprite(20, p1Y, PADDLE1, hInstance);

	
	// main loop - inifinite (can only be exited by encountering WM_QUIT)

	while(TRUE)
	{
		// check the message queue

		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if (msg.message == WM_QUIT) // exit loop on quit

				break;

			// send the message on its merry way

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

		// GetTickCount() returns the number of milliseconds since

		// the system was started. It''s a good way to lock your display

		// to a certain frame rate, 

		nStartTime = GetTickCount();

		// update the display 

		paddle->draw(hBackDC);
		board->draw(hBackDC);
		
                //  Swap the surfaces

		BitBlt(hMainDC,0,0,scrWidth,scrHeight,hBackDC,0,0,SRCCOPY);

		DeleteObject(WhiteBrush);

		if (KEYSTATE(VK_UP))
			paddle->SetY(p1Y++);

		if (KEYSTATE(VK_DOWN))
			paddle->SetY(p1Y--);

		// lock to 30 FPS - 33ms per frame

		while ((GetTickCount() - nStartTime) < 33);

		// post a WM_CLOSE message if escape key is being pressed

		if (KEYSTATE(VK_ESCAPE))
			PostMessage(hwnd, WM_CLOSE, 0, 0);
	}
  
as well as the class definitions:
  
class CBitmap
{
public:
	//Constuctors

	CBitmap() { mWidth=mHeight=0; }
	CBitmap( int nResID ) { mResID=nResID; }
	~CBitmap() { DeleteDC(mSrcDC); }

	// Member Functions

	int LoadBitmapResource(HINSTANCE hinst);
	void SetRes( int nResID ) { mResID=nResID; }
	HDC GetSrcDC() { return mSrcDC; }
	int GetWidth() { return mWidth; }
	int GetHeight() { return mHeight; }

private:
	int mWidth, mHeight;
	int mResID;
	HDC mSrcDC;
	HBITMAP mHbitmap;
};


class CSprite
{
public:
	//Constuctors

	CSprite() { mX=mY=mWidth=mHeight=0; }
	CSprite( int nX, int nY, int nResID, HINSTANCE hinst );
	~CSprite() { delete mBitmap; }

	// Member Functions

	void draw(HDC &hDestDC);
	void SetY( int nY ) { mY = nY; }

private:
	int mX, mY, mWidth, mHeight;
	int mResID;	
	CBitmap* mBitmap;
};
  
and the class implementations:
  
int CBitmap::LoadBitmapResource(HINSTANCE hinst)
{
  BITMAP bmp;           // structure for bitmap info


  // first load the bitmap resource

  if ((mHbitmap = (HBITMAP)LoadImage(hinst, MAKEINTRESOURCE(mResID),
                                    IMAGE_BITMAP, 0, 0,
                                    LR_CREATEDIBSECTION)) == NULL)
    return(FALSE);

  // create a DC for the bitmap to use

  if ((mSrcDC = CreateCompatibleDC(NULL)) == NULL)
    return(FALSE);

  // select the bitmap into the DC

  if (SelectObject(mSrcDC, mHbitmap) == NULL)
    return(FALSE);

  // get image dimensions

  if (GetObject(mHbitmap, sizeof(BITMAP), &bmp) == 0)
    return(FALSE);

  mWidth = bmp.bmWidth;
  mHeight = bmp.bmHeight;

  // return success!

  return(TRUE);
}


// CSprite Implementations

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

CSprite::CSprite( int nX, int nY, int nResID, HINSTANCE hinst )
{
	mX=nX;
	mY=nY;
	
	mResID=nResID;

	mBitmap = new CBitmap();

	mBitmap->SetRes(mResID);
	mBitmap->LoadBitmapResource(hinst);
	
	mWidth=mBitmap->GetWidth();
	mHeight=mBitmap->GetHeight();
}


void CSprite::draw(HDC &hDestDC)
{
  // copy image from one DC to the other

  BitBlt(hDestDC, mX, mY, mWidth, mHeight, mBitmap->GetSrcDC(), 0, 0, SRCCOPY);
}
  
I know that''s a lot of code, but I''m really lost, and I''m sure I''m just inexperienced enough to miss what''s going on. Any help would be appreciated. Matt ''''Mix'''' Fox mix@coil-inc.com

Share this post


Link to post
Share on other sites
You are on the right track, but instead of using a second DC, you need to use a BITMAP. I''d give you links, but most MFC books talk about this, and there are a few articles (try codeguru.com). Anyways, you do the GDI calls onto the bitmap, and then copy the bitmap to the DC. That''s a simplified way to doing it.

-ZaneX

Share this post


Link to post
Share on other sites
Thanks for the reply.

I actually found the solution looking through some code to another GDI Pong game. Now I just have to code the gameplay!

Onward and upward....

Matt ''''Mix'''' Fox
mix@coil-inc.com

Share this post


Link to post
Share on other sites