3

I'm attempting to draw to an off-screen device context / bitmap and move the image to the main hdc using bitblt. Here's the result I'm currently seeing:

enter image description here

The blue, yellow, and green bars on the left are being drawn directly to the window's hdc. The strange-looking ones on the right were drawn to the back buffer and copied over as a single frame. They should be identical, but clearly that's not the case.

Here's the code I'm using, reduced to a minimal example:

COLORREF color_yellow = RGB (224, 224, 0);
COLORREF color_green = RGB (0, 192, 0);
COLORREF color_blue = RGB (0, 0, 192);

HBRUSH brush_yellow = CreateSolidBrush (color_yellow);
HBRUSH brush_green = CreateSolidBrush (color_green);
HBRUSH brush_blue = CreateSolidBrush (color_blue);

HDC hdc = GetDC (Window);
HDC hdc_buffer = CreateCompatibleDC (hdc);
HBITMAP bitmap_buffer = CreateCompatibleBitmap (hdc_buffer, blit.screen_width, blit.screen_height);
SelectObject (hdc_buffer, bitmap_buffer);

draw_rectangle (hdc, 0, 0, 100, 30, brush_blue);
draw_rectangle (hdc, 0, 30, 100, 60, brush_yellow);
draw_rectangle (hdc, 0, 60, 100, 90, brush_green);

draw_rectangle (hdc_buffer, 0, 0, 100, 30, brush_blue);
draw_rectangle (hdc_buffer, 0, 30, 100, 60, brush_yellow);
draw_rectangle (hdc_buffer, 0, 60, 100, 90, brush_green);

BitBlt (hdc, 120, 0, 100, 90, hdc_buffer, 0, 0, SRCCOPY);

void draw_rectangle (HDC hdc, int left, int top, int right, int bottom, HBRUSH brush)
  {
  RECT rect;
  SetRect (&rect, left, top, right, bottom);
  FillRect (hdc, &rect, brush);
  }

I'm creating a new hdc (compatible with the window's), creating a compatible bitmap, selecting it, drawing the rectangles, and bit blitting over with SRCCOPY. All of this looks right to me.

I'm sure there's some small thing I'm not doing, but I can't find it.

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
Nightmare Games
  • 2,205
  • 6
  • 28
  • 46
  • Try creating your memory DC that is compatible with the *desktop* window. Don't really know why, but this has worked for me, on many occasions. – Adrian Mole Sep 25 '19 at 08:11
  • Side note, normally you want to paint in response to `WM_PAINT`, so you have to call `hdc = BeginPaint/EndPaint` routine, not `GetDC/ReleaseDC`. If you just want to create memory dc, then you can use `GetDC(0)` as suggested by @Adrian. But `CreateCompatibleDC` should still use a actual device context (`hdc`), not memory dc. – Barmak Shemirani Sep 25 '19 at 18:07
  • @BarmakShemirani - Normally, yes. This actually renders in a continuous, variable FPS loop rather than only repainting on WM_PAINT, but I left that code out to keep the example small. – Nightmare Games Sep 27 '19 at 17:59

1 Answers1

1

This is explained in documentation for CreateCompatibleBitmap:

Note: When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it. If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap. To create a color bitmap, use the HDC that was used to create the memory device context

Therefore, change

CreateCompatibleBitmap(hdc_buffer, width, height);//monochrome

to

CreateCompatibleBitmap(hdc, width, height);//colored bitmap
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • Thanks for pointing that out - it's a bit counter-intuitive and not immediately obvious that the new context wouldn't be an exact duplicate of the original. The word "compatible" must have thrown me off. – Nightmare Games Sep 27 '19 at 18:01