How to do backbuffering with GDI ?
Posted on 2001-12-26 06:41:52 by Dr. Manhattan
Just create an off-screen DC with a bitmap associated to it (use CreateCompatibleDC, CreateCompatibleBitmap). Bitblt or draw anything on this DC, then blit the whole thing on the DC of your display.
My mosaic tutorial (download at http://exagone.cjb.net) uses a backbuffer, take a look at it.

Thomas
Posted on 2001-12-26 08:40:29 by Thomas
For what sounds like such a complicated topic, the actual code is very simple:

.data
gWd dd 320
gHt dd 200

.data?
bDc dd ?
bBm dd ?

.code
invoke CreateCompatibleDC,0
mov bDc,eax
invoke CreateBitmap,gWd,gHt,1,32,0
mov bBm,eax
invoke SelectObject,bDc,eax

The act of displaying the buffer is a simple BitBlt:

invoke BitBlt,hDc,0,0,gWd,gHt,bDc,0,0,SRCCOPY
Posted on 2001-12-26 09:53:20 by Eóin
Thank you Thomas. Do I have to create a compatible bitmap and a compatible DC every time I receive a WM_PAINT message, or can I reuse them ?

Thank you Eoin (I was answering to Thomas when you post your message! hehehe it's not a forum it's a chat)
Posted on 2001-12-26 09:56:39 by Dr. Manhattan
Of course you can reuse them. Simply draw to the back buffer dc as if it were the main window dc. Only do the BitBlt during WM_PAINT messages.

You may later want to move on to DIBSections, a more powerful form of backbufferer. Heres a link to a tutorial on them.
Posted on 2001-12-26 10:06:04 by Eóin
I tried but it doesn't work. First I create the DCs with this code :


InitDC PROC

INVOKE DeleteDC, gBackDC
INVOKE DeleteDC, compatDC

INVOKE CreateCompatibleDC, NULL
mov gBackDC, eax

INVOKE CreateCompatibleDC, gBackDC
mov compatDC, eax

ret
InitDC ENDP

I repaint the screen with this code :



; repaint function

Draw PROC

INVOKE GetDC, hWnd
mov gHdc, eax

; display the background

INVOKE SelectObject, compatDC, hBackground

; copy to the back buffer
INVOKE BitBlt, gBackDC, 0, 0,
BACKGROUND_WIDTH,
BACKGROUND_HEIGHT,
compatDC, 0, 0, SRCCOPY

; copy the back buffer to the window dc
INVOKE BitBlt, gHdc, 0, 0, winW, winH, gBackDC, 0, 0, SRCCOPY
INVOKE ReleaseDC, hWnd, gHdc
INVOKE ValidateRect, hWnd, NULL

ret
Draw ENDP

When I replace gBackDC with gHdc (no back buffer) it works. Where is the problem ?
Posted on 2001-12-26 10:48:09 by Dr. Manhattan
Firstly, why do you create two DCs? Do you need two backbuffers?

A DC should be though of as only a structre with information about the bitmap associated with it. However you also have to create a bitmap for it, the CreateBitmap function is the easiest way to do this.

Looking at your code, and assuming hBackground is a valid bitmap handle then the only problem is that you don't create a bitmap for gBackDC.

Simply add the following to InitDC and it should be sorted.

InitDC PROC

INVOKE DeleteDC, gBackDC
INVOKE DeleteDC, compatDC

INVOKE CreateCompatibleDC, NULL
mov gBackDC, eax

invoke CreateBitmap,BACKGROUND_WIDTH, BACKGROUND_HEIGHT,1,32,0
mov gBackBm,eax
invoke SelectObject gBackDC,eax

INVOKE CreateCompatibleDC, gBackDC
mov compatDC, eax

ret
InitDC ENDP

Don't forget to delete all bitmaps and DCs at the end of your program to free resources.
Posted on 2001-12-26 11:09:01 by Eóin
Sorry, I don't understand :confused:
I use one backbuffer but I need a compatible DC every time I need to write a bitmap in the back buffer. Is it correct ? I've added the lines but it doesn't work. All the functions return OK but the bitmap is not displayed.
Posted on 2001-12-27 04:39:34 by Dr. Manhattan
A rule of thumb is that for every bitmap or whatever you are using *every* time the draw procedure is called, you create a DC + bitmap for it in the initialization procedure, and destroy it on exit. Don't create it on every redraw.



Initialize proc

invoke CreateCompatibleDC, NULL
mov gBackDC, eax

invoke CreateBitmap,BACKGROUND_WIDTH, BACKGROUND_HEIGHT,1,32,0
mov gBackBm,eax
invoke SelectObject, gBackDC, eax

invoke CreateCompatibleDC, NULL
mov backgroundDC, eax

;create hBackground bitmap handle somehow

invoke SelectObject, backgroundDC, hBackGround

ret
Initialize endp

Draw proc
;btw: if you use this proc on WM_PAINT, you should use
; BeginPaint/EndPaint instead of GetDC/ReleaseDC
invoke GetDC, hWnd
mov gHdc, eax

; Copy background to backbuffer
invoke BitBlt, gBackDC, 0, 0, BACKGROUND_WIDTH, BACKGROUND_HEIGHT,\
backgroundDC, 0, 0, SRCCOPY

; Copy other things to the backbuffer here:
...

; copy the back buffer to the window dc
invoke BitBlt, gHdc, 0, 0, winW, winH, gBackDC, 0, 0, SRCCOPY

; cleanup
invoke ReleaseDC, hWnd, gHdc
invoke ValidateRect, hWnd, NULL
ret
Draw endp


The initialize proc is called at program startup, only once.

Thomas
Posted on 2001-12-27 11:33:53 by Thomas
I'll try it. Thanks for your help !
Posted on 2001-12-27 14:01:44 by Dr. Manhattan