Regular old GDI bitmaps

Started by
5 comments, last by breakscience 22 years, 2 months ago
How do you use bitmaps outside of the WM_PAINT message?...I know what you''re going to tell me: " GetDC(), BitBlt(), then ReleaseDC()" Seems like it should work, huh? But it doesn''t. I have the book "Zen of Direct 3D Game Programming Even Though Some Of The Examples Do Not Work"...oops, I added that last part. The GDI bitmap example in chapter 7 causes my PC and the one at my work to hang. I would like to post the code here but I think it would be a waste of space...so, If anyone has this book let me know what the problem is. Thanks for your help. Break.
Break;
Advertisement
Ok, nobody seems to be responding so here''s the complete code:

////////////////////////////////////////////
// Chapter 7, Example 14
// bitmaps



#define WIN32_LEAN_AND_MEAN

// The main windows include file
#include <windows.h>
#include <stdlib.h>

int GameInit();
int GameLoop();
int GameShutdown();

HWND g_hWndMain;

// The window procedure to handle events
long CALLBACK WndProc( HWND hWnd, UINT uMessage,
WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT PaintStruct; // Structure used during windows painting
HDC hDC; // Handle to device context for painting

// Switch the windows message to figure out what it is
switch( uMessage )
{
case WM_CREATE: // The CreateWindow() function was just called
{
// One Time Initialization
return 0;
}

case WM_PAINT: // The window needs to be redrawn
{
// Tell windows we want to start updating the window
hDC = BeginPaint( hWnd, &PaintStruct );

// Tell windows we have finished updating the window
EndPaint( hWnd, &PaintStruct );
return 0;
}

case WM_DESTROY: // The window is about to be closed
{
// Our main window is closing. This means we want our app to exit.
// Tell windows to put a WM_QUIT message in our message queue
PostQuitMessage( 0 );
return 0;
}

default: // Some other message
{
// Let windows handle this message
return DefWindowProc( hWnd, uMessage, wParam, lParam );
}
}
}

// The windows entry point. The application will start executing here
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR pstrCmdLine, int iCmdShow )
{
HWND hWnd; // The handle to our main window
MSG msg; // The message windows is sending us
WNDCLASSEX wc; // The window class used to create our window

// The name of our class and also the title to our window
static char strAppName[] = "Bitmaps";

// Fill in the window class with the attributes for our main window

// The size of this struture in bytes
wc.cbSize = sizeof( WNDCLASSEX );

// The style of the window.
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
// Useless information. Just set to zero.
wc.cbClsExtra = 0;
// Useless information. Just set to zero.
wc.cbWndExtra = 0;
// The name of our event handler
wc.lpfnWndProc = WndProc;
// A handle to the applications instance
wc.hInstance = hInstance;
// The handle to the brush to use for the window background
wc.hbrBackground = (HBRUSH)GetStockObject( DKGRAY_BRUSH );
// A handle to the icon to use for the window
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
// A handle to a smaller version of the apps icon
wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
// A handle to the cursor to use while the mouse is over our window
wc.hCursor = LoadCursor( NULL, IDC_CROSS );
// A handle to the resource to use as our menu
wc.lpszMenuName = NULL;
// The human readable name for this class
wc.lpszClassName = strAppName;

// Register the class with windows
RegisterClassEx( &wc );

// Create the window based on the previous class
hWnd = CreateWindowEx( NULL, // Advanced style settings
strAppName, // The name of the class
strAppName, // The window caption
WS_OVERLAPPEDWINDOW,// The window style
CW_USEDEFAULT, // The initial x position
CW_USEDEFAULT, // The initial y position
512, 512, // The intiial width / height
NULL, // Handle to parent window
NULL, // Handle to the menu
hInstance, // Handle to the apps instance
NULL ); // Advanced context

g_hWndMain = hWnd;

GameInit();

// Display the window we just created
ShowWindow( hWnd, iCmdShow );
// Draw the window contents for the first time
UpdateWindow( hWnd );


// Start the message loop
while( TRUE )
{
// Check if a message is waiting for processing
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
// Check if the message is to quit the application
if( msg.message == WM_QUIT )
// Exit the message loop
break;

// Change the format of certain messages
TranslateMessage( &msg );
// Pass the message to WndProc() for processing
DispatchMessage( &msg );
}
else
{
GameLoop();
}
}


GameShutdown();

// Return control to windows with the exit code
return msg.wParam;
}


// Global handle to the image
HANDLE hImage;

// Game Initialization can be done here
int GameInit()
{
// Create a string to hold the path to the bitmap
char Path[] = "ZEN PIC.BMP";

// Load the image from disk into memory
hImage = LoadImage( NULL, Path, IMAGE_BITMAP,
0, 0, LR_LOADFROMFILE );
return 0;
}

int GameLoop()
{
// Get a handle to the DC for the client area
HDC hDC = GetDC( g_hWndMain );
// Create a DC that is compatible with the main DC
HDC hImageDC = CreateCompatibleDC( hDC );

// Structure to hold information about the bitmap
BITMAP Bitmap;

// Holds the dimensions of the bitmap
SIZE ImageSize;

// Get information about the bitmap we loaded in GameInit()
GetObject( hImage, sizeof( BITMAP ), &Bitmap );

// Get the dimensions for the bitmap
ImageSize.cx = Bitmap.bmWidth;
ImageSize.cy = Bitmap.bmHeight;

// Select the image into the device context
SelectObject( hImageDC, hImage );

// Copy the image to the main device context
BitBlt( hDC, 0, 0, ImageSize.cx, ImageSize.cy, hImageDC, 0, 0, SRCCOPY );

// Delete the DC for the bitmap
DeleteDC( hImageDC );
// Release the main DC
ReleaseDC( g_hWndMain, hDC );

return 0;
}

int GameShutdown()
{
// Delete the bitmap from memory
DeleteObject( hImage );

return 0;
}





///////////Why doesn''t this work??
Break;
It worked for me. Only one compilation error. I changed CreateWindowEx( NULL, to CreateWindowEx( 0, and it compiled without error - C v C++ . I copied over another bmp and renamed it "zen pic.bmp", tossed it in with the exe and it runs. Maybe you're forgeting to put the bmp into the same directory as the exe?

Looking at the results in the task manager, i see that the program is a cpu hog. That's a side effect of the way the message loop is set up. I suspected that might be the problem when I first looked at the code. The assumption is that a game will take all of the users focus and therefore it's ok to hog the cpu.

Monitoring the prog with Feng Yuan's GDIObject prog, I notice that it thrashes about on it's dc usage. Mostimes 7, sometimes 6, others 8. Using a memory dc might help that - that must be something covered in another chapter. Here's a more simpler approach.

When CS_OWNDC is used, you don't have to use GetDC every time.
Make the two dc variables global. Declare them near hImage
HDC hDC;HDC hImageDC;HANDLE hImage;  

Move this code into the init routine and
hDC = GetDC( g_hWndMain );hImageDC = CreateCompatibleDC( hDC );  

Move this code into the shutdown routine - after calling DeleteObject on hImage
DeleteObject( hImage );DeleteDC( hImageDC );ReleaseDC( g_hWndMain, hDC );  


The program will still be a cpu hog, but it won't thrash about with the gdi resources.


Edited by - lessbread on February 19, 2002 8:46:02 PM
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
I have another book that suggests that exactly, but didn''t use a game loop...strictly WM_PAINT. The "Zen" guy has a different way of doing things(not always good). Thanks for the tip.

Break.
Break;
The message loop in that demo is standard for win32 games - overkill for a demo app, but my guess is the Zen guy wants to lay down a framework and stick to it throughout the book. WM_PAINT would have been better for this windowed app, but once you go fullscreen this approach will work nicely. Be certain however, to build in a means to reduce cpu usage when the prog doesn''t have focus.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
That makes sense. I still can''t get this thing to work. But I am going to make a little windowed game anyways (I''ll use DX for full-screen). Let me ask you another question. Any time I have a background blitting in WM_PAINT, and blit a sprite inside my game loop, I get a lot of flicker. Is there some way to pause the PAINT message until Im done blitting? If so, or if there is something else wrong here, let me know. Thanks.

Break.
Break;
That''s where the memory dc comes into play. You blit your sprite to the memory dc and the memory dc to the screen dc via WM_PAINT. The memory dc provides a back buffer. In the code here, hImageDC is the memdc. Blit everything to that first, and blit that to the screen after you''ve finished blitting the sprites.

Flicker can also be caused by the system repainting the background. Specify a NULL background brush in the WNDCLASS or return TRUE for the WM_ERASEBKGROUND message in the WndProc.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man

This topic is closed to new replies.

Advertisement