Sign in to follow this  

Windows API - Double Buffer

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

OK....I don't know what to do. I've searched you forums and I feel like i've done everything correctly and I just can't get it to double buffer correctly. The main concerns are WM_PAINT and WM_CREATE. For some reason, it actually paints correctly the first time when CreateWindow is run, but any repainting after results in a white screen. ANy help is appreciated Thanks in advance Code...........................
/* animation_shell.c
** -- Bare bones windows animation program.
** cs230 2/07
*/

#include <stdlib.h>
#include <time.h>
#include <windows.h>

#define SCREEN_SIZE_X 320
#define SCREEN_SIZE_Y 240

#define BOARD_SIZE_X 200
#define BOARD_SIZE_Y 220

#define BLOCK1_SIZE_X 20
#define BLOCK1_SIZE_Y 20

void draw(HWND win);

char *block1     = "block1.bmp";
char *board1      = "board1.bmp";
char *background = "background.bmp";

COORD block1Coord = {20, 20};

;

LRESULT CALLBACK WinProc(HWND win, UINT msg, WPARAM wp, LPARAM lp) {

  HDC dc;
  PAINTSTRUCT ps;
  static HBITMAP g_hbmBackground = NULL;
  static HBITMAP g_hbmBoard1 = NULL;
  static HBITMAP g_hbmBlock1 = NULL;

  static BITMAP bmp_Board1;
  static BITMAP bmp_Background;
  static BITMAP bmp_Block1;

  static HDC hdcMem;

  static HDC tempDC;

  RECT redrawRect;

  switch (msg) {

    case WM_CREATE:

      dc = GetDC(win);
      // Create the HANDLES for all my bitmaps
		  g_hbmBoard1      = (HBITMAP) LoadImage(NULL, board1,     IMAGE_BITMAP, BOARD_SIZE_X,  BOARD_SIZE_Y,  LR_VGACOLOR | LR_LOADFROMFILE | LR_LOADTRANSPARENT);

      g_hbmBackground  = (HBITMAP) LoadImage(NULL, background, IMAGE_BITMAP, SCREEN_SIZE_X, SCREEN_SIZE_Y, LR_LOADFROMFILE | LR_VGACOLOR );

      g_hbmBlock1      = (HBITMAP) LoadImage(NULL, block1,     IMAGE_BITMAP, block1Coord.X, block1Coord.Y, LR_LOADFROMFILE);

      // Make sure the Handles were created
      if(g_hbmBackground  == NULL || g_hbmBoard1 == NULL || g_hbmBlock1 == NULL)
        MessageBox(win, "Image Loaded Incorrectly", "Error", MB_OK | MB_ICONEXCLAMATION);

      // Place the bitmaps into there proper place
      GetObject(g_hbmBackground , sizeof(bmp_Background), &bmp_Background);
      GetObject(g_hbmBlock1     , sizeof(bmp_Block1)    , &bmp_Block1);
      GetObject(g_hbmBoard1     , sizeof(bmp_Board1)    , &bmp_Board1);



      ReleaseDC(win, dc);
      srand((unsigned int)time(NULL));
      break;

    case WM_PAINT:
      {

      dc = BeginPaint(win, &ps);
      
      // Setup 2 Temp DC for writting

      HDC tempDC_1 = CreateCompatibleDC(dc);  // This one will hold the final screen to be BitBlt'ed

      HDC tempDC_2 = CreateCompatibleDC(dc);  // This one will temporarily hold the bitmaps

      // These should not be monocrome bitmaps since there loaded with the same DC as the windows

      HBITMAP hTempBmp1 = CreateCompatibleBitmap(dc, SCREEN_SIZE_X, SCREEN_SIZE_Y);

      HBITMAP hTempBmp2 = CreateCompatibleBitmap(dc, SCREEN_SIZE_X, SCREEN_SIZE_Y);

      // Load these compatible BMP's into each tempDC
      HBITMAP hOldBmp1 = (HBITMAP) SelectObject(tempDC_1, hTempBmp1);
      HBITMAP hOldBmp2 = (HBITMAP) SelectObject(tempDC_2, hTempBmp2);

      // Color in the tempDC's before I load anything in
      // I will use the Default White Brush
      Rectangle(tempDC_1, 0, 0, SCREEN_SIZE_X, SCREEN_SIZE_Y);
      Rectangle(tempDC_2, 0, 0, SCREEN_SIZE_X, SCREEN_SIZE_Y);
      
      // Select a bitmap and write it to the temporary DC
      SelectObject(tempDC_1, g_hbmBackground );

      // Write to the Temp Screen
      BitBlt(tempDC_2, 0, 0, 320, 240, tempDC_1, 0, 0, SRCCOPY);

      // Do the same as above
      SelectObject(tempDC_1, g_hbmBoard1);

      BitBlt(tempDC_2, 0, 0, BOARD_SIZE_X, BOARD_SIZE_Y, tempDC_1, 0, 0, SRCCOPY);
      

      //SelectObject(tempDC_1, g_hbmBlock1);

      //BitBlt(tempDC_2, block1Coord.X, block1Coord.Y, 
                 //   BLOCK1_SIZE_X, 
                   // BLOCK1_SIZE_Y,
                   // tempDC_1, 0, 0, SRCCOPY);

      BitBlt(dc, 0, 0, 320, 240, tempDC_2, 0, 0, SRCCOPY);

      // Always select the old bitmap back into the device context
      SelectObject(tempDC_1, hOldBmp1);
      SelectObject(tempDC_2, hOldBmp2);
      DeleteObject(hTempBmp1);
      DeleteObject(hTempBmp2);
      DeleteDC(tempDC_1);
      DeleteDC(tempDC_2);

      EndPaint(win, &ps);

      break;
      }
    case WM_CHAR:
      if (wp == 0x1b)
        DestroyWindow(win);
      break;
    case WM_KEYDOWN:

      switch (wp)
      {
      case VK_RIGHT:

        block1Coord.X += 3;
        InvalidateRect(win, NULL, true);
        break;

      case VK_LEFT:

        block1Coord.X -= 3;
        InvalidateRect(win, NULL, true);
        break;

      case VK_UP:

        block1Coord.Y -= 3;
        InvalidateRect(win, NULL, true);
        break;

      case VK_DOWN:
        
        block1Coord.Y += 3;
        InvalidateRect(win, NULL, true);
        break;

      default:
        break;
      }

    case WM_DESTROY:

      DeleteObject(g_hbmBackground);
      DeleteObject(g_hbmBoard1);
      DeleteObject(g_hbmBlock1);

      PostQuitMessage(0);
      break;

    default:
      return DefWindowProc(win,msg,wp,lp);
  }
  return 0;
}


int WINAPI WinMain(HINSTANCE instance, HINSTANCE ignore,
                   LPSTR command_line, int show) {
  char *window_title = "Tetris Initial Development",
       *class_name = "Tetris";
  WNDCLASS wc;
  HWND win;
  MSG msg;

  wc.style = 0;//CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = WinProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = instance;
  wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  wc.hbrBackground = NULL;
  wc.lpszMenuName = NULL;
  wc.lpszClassName = class_name;
  RegisterClass(&wc);

  win = CreateWindow(class_name,window_title,
          WS_VISIBLE | WS_CAPTION | WS_SYSMENU ,0 ,0,
          320, 240,NULL,NULL,instance,NULL);
  ShowWindow(win,show);

  // Animation Styple "greedy" event loop
  while (IsWindow(win)) {
    if (PeekMessage(&msg,win,0,0,PM_REMOVE)) {
      //^^^^^^^^^^^ Non-Blocking - looks at event queue, returns nonzero
      // if there is no message; zero otherwise
      // Note: it is possible to look for a specific message
      // or messages; however,   
      // 
      TranslateMessage(&msg);
      DispatchMessage(&msg); }
    //else
      // draw stuff if there is no messages on the queue:
      //draw(win);
      // give some cycles back to the CPU
      //Sleep(10);
  }
  
  UnregisterClass(class_name,instance);

  return msg.wParam;
}


[Edited by - LessBread on March 7, 2007 9:38:48 PM]

Share this post


Link to post
Share on other sites
1) In your WM_CREATE you dont need to call GetDC() / ReleaseDC(). You dont even use dc anywhere. In fact, you dont need (since you dont use) any of the bmp_* variables.

2) What's the point of hTempBmp1? You draw a rectangle on it but then you go and select your background bitmap into the DC and thereby select hTempBmp1 out. You never use it again.

As for your actual problem, I dont see anything standing out as obviously wrong. Are the functions all succeeding? If not, what does GetLastError() return?

Share this post


Link to post
Share on other sites
I also can't spot what is wrong with your code. How about try drawing it without double buffering, direct to dc first, and see if it works?
If its of any help, you can take a look at the source code for my tetris implementation which also uses win32 and double buffering.

Share this post


Link to post
Share on other sites
I've pasted your code into a new Win32 project and it works. Even BoundsChecker can't find anything wrong (which is quite a miracle in itself :) ).

Are you using more than the snippet you showed us to test? This snippet by itself is ok, just:

For the love of [favourite godly deity], move the return DefWindowProc call OUTSIDE THE DAMN switch/case. Numberless kittens have been killed because of that. It will bite you later on, because not every Windows message has 0 as a valid return code.

Share this post


Link to post
Share on other sites
Thanks for the response. Try running the program and hitting an Arrow key. WHen the Invalidate rect is called, It turns to a white screen.

Thanks in advance

stringa

Share this post


Link to post
Share on other sites
That was a good one!! :)

Insert a break at the end of WM_KEYDOWN otherwise you fall through to WM_DESTROY which deletes your BMPs.

You should still move the return DefWindowProc call outside the switch/case and also do not use the window handle in the message loop (PeekMessage). You'll never get WM_QUIT for instance if you provide a HWND.

Share this post


Link to post
Share on other sites

This topic is 3937 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this