Introduction
I assume that you know what a back buffer is (also known as a double or offscreen buffer). If not see wikipedia – Double Buffering. In brief, it’s a byte array used to prepare graphics off-screen to prevent flicker. Once the desired image is complete, it is copied to screen.
Here is a first stab at back buffer class. It is deliberately simple and meant to be a starting point only, functionality will be added.
This is the header file…
CBackBuffer.h
// BackBuffer class definition
// Carl Bateman based on snippets by Geoff Howland
// October 2005
#include <windows.h>
class CBackBuffer{
public:
// own user defined functions
CBackBuffer() {}; // over ride default constructor
~CBackBuffer() {}; // over ride default destructor
void Create();
void Destroy();
void Display();
// simple accessors
int Height(void) const
{ return m_iHeight; };
int Width(void) const
{ return m_iWidth; };
BYTE* BackData(void)
{ return m_bmpBackData; };
protected:
// generic back buffer info
BYTE* m_bmpBackData;
int m_iHeight;
int m_iWidth;
// MS Windows specific data
BITMAP m_bitmap; // The BITMAP structure defines the type, width, height, color format, and bit values of a bitmap
BITMAPINFO m_BitmapInfo; // The BITMAPINFO structure defines the dimensions and color information for a Win32 DIB
HBITMAP m_hBitmap;
HDC m_hdcSource;
HDC m_hdcDestination;
};
This is the implementation file…
CBackBuffer.cpp
// BackBuffer class implementation
// Carl Bateman based on snippets by Geoff Howland
// October 2005
#include "CBackBuffer.h"
void CBackBuffer::Create () {
HWND hwndActive = GetActiveWindow();
if(hwndActive == NULL)
return;
RECT lpRect;
GetClientRect(hwndActive, &lpRect);
m_iWidth = lpRect.right ;
m_iHeight = lpRect.bottom ;
// Set up BitmapInfoHeader
m_BitmapInfo.bmiHeader.biBitCount = 24;
m_BitmapInfo.bmiHeader.biClrImportant = 0;
m_BitmapInfo.bmiHeader.biClrUsed = 0;
m_BitmapInfo.bmiHeader.biCompression = BI_RGB;
m_BitmapInfo.bmiHeader.biHeight = -m_iHeight;
m_BitmapInfo.bmiHeader.biPlanes = 1;
m_BitmapInfo.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
m_BitmapInfo.bmiHeader.biSizeImage = m_iWidth * m_iHeight * (m_BitmapInfo.bmiHeader.biBitCount / 8);
m_BitmapInfo.bmiHeader.biWidth = m_iWidth;
m_BitmapInfo.bmiHeader.biXPelsPerMeter = 0;
m_BitmapInfo.bmiHeader.biYPelsPerMeter = 0;
m_BitmapInfo.bmiColors[0].rgbRed = 0;
m_BitmapInfo.bmiColors[0].rgbGreen = 0;
m_BitmapInfo.bmiColors[0].rgbBlue = 0;
m_BitmapInfo.bmiColors[0].rgbReserved = 0;
// Create the DIB section with CreateDIBSection
m_hdcDestination = GetDC(hwndActive);
m_hdcSource = CreateCompatibleDC(m_hdcDestination);
m_hBitmap = CreateDIBSection (m_hdcSource, (BITMAPINFO *) &m_BitmapInfo, 0, (void **) &m_bmpBackData, NULL, 0);
GetObject (m_hBitmap, sizeof (BITMAP), &m_bitmap);
m_bmpBackData = (BYTE*) m_bitmap.bmBits;
SelectObject (m_hdcSource, m_hBitmap);
}
void CBackBuffer::Destroy () {
// if we have a bitmap destroy
if (m_hBitmap != NULL) {
DeleteObject (m_hBitmap);
m_hBitmap = NULL;
DeleteDC (m_hdcSource);
DeleteDC (m_hdcDestination);
}
}
void CBackBuffer::Display() {
// Display from CreateDIBSection creation
BitBlt (m_hdcDestination, 0, 0, m_bitmap.bmWidth, m_bitmap.bmHeight, m_hdcSource, 0, 0, SRCCOPY);
}
And this is the test file… and frankly it’s a mess, I’m still messing around with the code to make it as clear as possible.
winmain.cpp
// winmain.cpp
// Back Buffer test app
// -- INCLUDES --
#define WIN32_LEAN_AND_MEAN // just say no to MFC - set as project option
#include <windows.h> // include important windows stuff
#include "CBackBuffer.h"
// defines for windows
#define WINDOW_CLASS_NAME "WINCLASS1"
HWND hwnd; // track main window
HINSTANCE hinstance; // track hinstance
HDC hdc; // graphics device context
RECT rcClient; // client rectangle area
CBackBuffer* pBackBuffer;
int cxWindow=640, cyWindow=480;
int cxClient=0, cyClient=0; //int cxWindow=1000, cyWindow=500;
// -------------
// -- WINPROC --
// -------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
// this is the main message handler of the system
PAINTSTRUCT ps; // used in WM_PAINT
static HMENU hMenu;
// what is the message
switch(msg) {
case WM_CREATE :
// if buffer created here window has no width or height, must use default values
return(0);
case WM_ACTIVATE :
// if buffer created here window may be activated many times
if(pBackBuffer==NULL) {
hdc=hdc;
pBackBuffer = new CBackBuffer;
pBackBuffer->Create();
};
return(0);
case WM_PAINT :
hdc = BeginPaint(hwnd,&ps);
pBackBuffer->Display();
EndPaint(hwnd,&ps);
return(0);
case WM_SIZING :
// change back buffer size on the fly here if so desired
return(0);
case WM_SIZE :
// change back buffer size after sizing finished here
return(0);
case WM_DESTROY :
pBackBuffer->Destroy();
PostQuitMessage(0);
return(0);
default:break;
} // end switch
// process any messages that we didn't take care of
return (DefWindowProc(hwnd, msg, wparam, lparam));
} // end WinProc
// -------------
// -- WINMAIN --
// -------------
int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hprevinstance,
LPSTR lpcmdline, int ncmdshow)
{
WNDCLASSEX winclass; // this will hold the class we create
MSG msg; // generic message
// first fill in the window class stucture
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = NULL;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// register the window class
if (!RegisterClassEx(&winclass))
return(0);
// create the window
if (!(hwnd = CreateWindowEx(
NULL, // extended style
WINDOW_CLASS_NAME, // class
"BackBuffer - Part1", // title
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, // initial top left, right
cxWindow, cyWindow, // initial width,height
NULL, // handle to parent
NULL, // handle to menu
hinstance, // handle to instance of this application
NULL))) // extra creation parms
return(0);
// enter main event loop
while(TRUE) { // test if there is a message in queue, if so get it
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
if (msg.message == WM_QUIT) // test if this is a quit
{ break; }
TranslateMessage(&msg); // translate any accelerator keys
DispatchMessage(&msg); // send the message to the window proc
}
}
ReleaseDC(hwnd, hdc);
return(msg.wParam); // return to Windows like this
} // end WinMain
This is pretty much the simplest Windows program I could come up with, I’ve included the WM_ messages I think may be useful.
All being well, it should look like this (after resizing the window).
Bit dull, I know, but early days yet. Next up I’ll implement line and triangle drawing.
house insurance online comparison buytolet mortgage uk mortgage |