I have recently used basic API functions to load a bitmap and make it 'bounce' around the screen. The program implements a wrapper class which does all the loading, blitting, drawing, and creating of the bitmap being used.
I am currently having problems with the "draw" function of my program, which takes as parameters the Device Context of the window to blit to, and the (x, y) location of the window to draw to, then performs the BitBlt function using these parameters as a basis and uses default values for every other argument in the API function. Originally, before learning of the GetDC(), ReleaseDC() system, I simply called the function like this:
myBitmap.draw(x, y, GetDC(hWnd));
This method got me fantastic frame rates and relatively good results, except for the fact that it had a memory leak, responsible for making BitBlt fail ever 9978th time.
After realizing this, I quickly embedded the new ReleaseDC() function into the program after placing the HDC into a variable and passing it into the function. The code then looked something like this:
HDC windowDC;
.
.
.
<start main loop>
windowDC = GetDC(hWnd);
myBitmap.draw(x, y, windowDC);
ReleaseDC(hWnd, windowDC);
UpdateWindow(hWnd);
<end main loop>
.
.
.
DeleteDC(windowDC);
This still compiles, runs, and responds. However, even though the frame rate has technically increased (quite dramatically as a matter of fact), the refresh rate seems to have dropped to a crawl. What at one point was a smooth bouncing action has now become a choppy slide show with the image not behaving with the same physical activity as before. I have posted the code in completion below. If anyone has any comments or possible solutions, they would be greatly appreciated. Thank You.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <String.h>
#include "Bitmap.h"
#include "Input.h"
LRESULT CALLBACK WndProc( HWND hWnd, UINT messg,
WPARAM wParam, LPARAM lParam );
bool running = true;
const int RESWIDTH = 1280;
const int RESHEIGHT = 1024;
const double XMAXVELOCITY = 750.0;
const double YACC = 1500.0;
const double XACC = 2000.0;
const LPTSTR PATH = "C:/Bounce.bmp";
int WINAPI WinMain(HINSTANCE hInst, /*Win32 entry-point routine */
HINSTANCE hPreInst,
LPSTR lpszCmdLine,
int nCmdShow)
{
#pragma unused(lpszCmdLine)
HWND hWnd;
MSG lpMsg;
WNDCLASS wc;
clsBitmap testBitmap;
clsKeyboard keyboard;
DEVMODE dm;
HDC windowHDC;
double currentTick = 0;
double x = 0;
double y = 0;
long numFrames = 0;
double totalTime = 0;
double averageFR = 0;
double currentTime = 0;
bool forward = true;
bool up = false;
double yVelocity = 0;
double xVelocity = 0;
bool acc;
if(!hPreInst) /*set up window class and register it */
{
wc.lpszClassName = szProgName;
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.lpszMenuName = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.style = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
if(!RegisterClass(&wc))
return false;
}
hWnd = CreateWindow(szProgName, /* now create the window */
"CodeWarrior Win32 stationery",
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0,
0,
RESWIDTH,
RESHEIGHT,
(HWND)NULL,
(HMENU)NULL,
hInst,
(LPSTR)NULL);
ShowWindow(hWnd, nCmdShow );
UpdateWindow( hWnd );
memset(&dm,0,sizeof(dm));
if(!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
{
MessageBox(NULL, "Could Not Enum Display Settings", "Error", MB_OK);
}
dm.dmPelsWidth = RESWIDTH;
dm.dmPelsHeight = RESHEIGHT;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
int result = ChangeDisplaySettings(&dm,CDS_FULLSCREEN);
RECT windowRect;
GetWindowRect(hWnd, &windowRect);
testBitmap.load(PATH);
ShowCursor(false);
windowHDC = GetDC(hWnd);
totalTime = GetTickCount();
currentTick = GetTickCount();
while(running) /* begin the message loop */
{
if(keyboard.keyIsDown(VK_ESCAPE))
running = false;
currentTime = GetTickCount() - currentTick;
currentTick = GetTickCount();
if((keyboard.keyIsDown(VK_RIGHT) && !keyboard.keyIsDown(VK_LEFT)))
{
xVelocity += XACC * (currentTime / 1000);
if(xVelocity > XMAXVELOCITY)
xVelocity = XMAXVELOCITY;
}
else if(xVelocity > 0)
{
xVelocity -= XACC * (currentTime / 1000);
if(xVelocity < 0)
xVelocity = 0;
}
if(keyboard.keyIsDown(VK_LEFT) && !keyboard.keyIsDown(VK_RIGHT))
{
xVelocity -= XACC * (currentTime / 1000);
if(xVelocity < -XMAXVELOCITY)
xVelocity = -XMAXVELOCITY;
}
else if(xVelocity < 0)
{
xVelocity += XACC * (currentTime / 1000);
if(xVelocity > 0)
xVelocity = 0;
}
if(x < windowRect.left)
{
xVelocity = 0;
x = windowRect.left;
}
else if(x > (windowRect.right - windowRect.left) - testBitmap.getWidth())
{
xVelocity = 0;
x = (windowRect.right - windowRect.left) - testBitmap.getWidth();
}
x += xVelocity * (currentTime / 1000);
if(acc)
yVelocity += YACC * (currentTime / 1000);
else
{
yVelocity -= YACC * (currentTime / 1000);
if(yVelocity <= 0)
{
yVelocity = -yVelocity;
acc = !acc;
up = !up;
}
}
if(up)
y -= yVelocity * (currentTime / 1000);
else
y += yVelocity * (currentTime / 1000);
if((!up && y >= (windowRect.bottom - windowRect.top) - testBitmap.getHeight()))
{
acc = !acc;
up = !up;
y = 2 * (windowRect.bottom - windowRect.top - testBitmap.getHeight()) - y;
}
windowDC = GetDC(hWnd);
if(!testBitmap.draw(x, y, windowHDC))
{
running = false;
ReleaseDC(hWnd, windowDC);
}
else
{
if(GetMessage(&lpMsg, NULL, 0, 0))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
UpdateWindow(hWnd);
numFrames++;
}
}
DeleteDC(hWnd, windowHDC);
totalTime = GetTickCount() - totalTime;
ShowCursor(true);
ChangeDisplaySettings(NULL, 0);
averageFR = numFrames / (totalTime / 1000);
return(lpMsg.wParam);
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT messg, /*callback procedure */
WPARAM wParam, LPARAM lParam )
{
switch(messg)
{
case WM_PAINT:
break;
case WM_DESTROY:
PostQuitMessage(0);
running = false;
break;
default:
return( DefWindowProc( hWnd, messg, wParam, lParam ) );
}
return(0L);
}
I am currently having problems with the "draw" function of my program, which takes as parameters the Device Context of the window to blit to, and the (x, y) location of the window to draw to, then performs the BitBlt function using these parameters as a basis and uses default values for every other argument in the API function. Originally, before learning of the GetDC(), ReleaseDC() system, I simply called the function like this:
myBitmap.draw(x, y, GetDC(hWnd));
This method got me fantastic frame rates and relatively good results, except for the fact that it had a memory leak, responsible for making BitBlt fail ever 9978th time.
After realizing this, I quickly embedded the new ReleaseDC() function into the program after placing the HDC into a variable and passing it into the function. The code then looked something like this:
HDC windowDC;
.
.
.
<start main loop>
windowDC = GetDC(hWnd);
myBitmap.draw(x, y, windowDC);
ReleaseDC(hWnd, windowDC);
UpdateWindow(hWnd);
<end main loop>
.
.
.
DeleteDC(windowDC);
This still compiles, runs, and responds. However, even though the frame rate has technically increased (quite dramatically as a matter of fact), the refresh rate seems to have dropped to a crawl. What at one point was a smooth bouncing action has now become a choppy slide show with the image not behaving with the same physical activity as before. I have posted the code in completion below. If anyone has any comments or possible solutions, they would be greatly appreciated. Thank You.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <String.h>
#include "Bitmap.h"
#include "Input.h"
LRESULT CALLBACK WndProc( HWND hWnd, UINT messg,
WPARAM wParam, LPARAM lParam );
bool running = true;
const int RESWIDTH = 1280;
const int RESHEIGHT = 1024;
const double XMAXVELOCITY = 750.0;
const double YACC = 1500.0;
const double XACC = 2000.0;
const LPTSTR PATH = "C:/Bounce.bmp";
int WINAPI WinMain(HINSTANCE hInst, /*Win32 entry-point routine */
HINSTANCE hPreInst,
LPSTR lpszCmdLine,
int nCmdShow)
{
#pragma unused(lpszCmdLine)
HWND hWnd;
MSG lpMsg;
WNDCLASS wc;
clsBitmap testBitmap;
clsKeyboard keyboard;
DEVMODE dm;
HDC windowHDC;
double currentTick = 0;
double x = 0;
double y = 0;
long numFrames = 0;
double totalTime = 0;
double averageFR = 0;
double currentTime = 0;
bool forward = true;
bool up = false;
double yVelocity = 0;
double xVelocity = 0;
bool acc;
if(!hPreInst) /*set up window class and register it */
{
wc.lpszClassName = szProgName;
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.lpszMenuName = NULL;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.style = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
if(!RegisterClass(&wc))
return false;
}
hWnd = CreateWindow(szProgName, /* now create the window */
"CodeWarrior Win32 stationery",
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0,
0,
RESWIDTH,
RESHEIGHT,
(HWND)NULL,
(HMENU)NULL,
hInst,
(LPSTR)NULL);
ShowWindow(hWnd, nCmdShow );
UpdateWindow( hWnd );
memset(&dm,0,sizeof(dm));
if(!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
{
MessageBox(NULL, "Could Not Enum Display Settings", "Error", MB_OK);
}
dm.dmPelsWidth = RESWIDTH;
dm.dmPelsHeight = RESHEIGHT;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
int result = ChangeDisplaySettings(&dm,CDS_FULLSCREEN);
RECT windowRect;
GetWindowRect(hWnd, &windowRect);
testBitmap.load(PATH);
ShowCursor(false);
windowHDC = GetDC(hWnd);
totalTime = GetTickCount();
currentTick = GetTickCount();
while(running) /* begin the message loop */
{
if(keyboard.keyIsDown(VK_ESCAPE))
running = false;
currentTime = GetTickCount() - currentTick;
currentTick = GetTickCount();
if((keyboard.keyIsDown(VK_RIGHT) && !keyboard.keyIsDown(VK_LEFT)))
{
xVelocity += XACC * (currentTime / 1000);
if(xVelocity > XMAXVELOCITY)
xVelocity = XMAXVELOCITY;
}
else if(xVelocity > 0)
{
xVelocity -= XACC * (currentTime / 1000);
if(xVelocity < 0)
xVelocity = 0;
}
if(keyboard.keyIsDown(VK_LEFT) && !keyboard.keyIsDown(VK_RIGHT))
{
xVelocity -= XACC * (currentTime / 1000);
if(xVelocity < -XMAXVELOCITY)
xVelocity = -XMAXVELOCITY;
}
else if(xVelocity < 0)
{
xVelocity += XACC * (currentTime / 1000);
if(xVelocity > 0)
xVelocity = 0;
}
if(x < windowRect.left)
{
xVelocity = 0;
x = windowRect.left;
}
else if(x > (windowRect.right - windowRect.left) - testBitmap.getWidth())
{
xVelocity = 0;
x = (windowRect.right - windowRect.left) - testBitmap.getWidth();
}
x += xVelocity * (currentTime / 1000);
if(acc)
yVelocity += YACC * (currentTime / 1000);
else
{
yVelocity -= YACC * (currentTime / 1000);
if(yVelocity <= 0)
{
yVelocity = -yVelocity;
acc = !acc;
up = !up;
}
}
if(up)
y -= yVelocity * (currentTime / 1000);
else
y += yVelocity * (currentTime / 1000);
if((!up && y >= (windowRect.bottom - windowRect.top) - testBitmap.getHeight()))
{
acc = !acc;
up = !up;
y = 2 * (windowRect.bottom - windowRect.top - testBitmap.getHeight()) - y;
}
windowDC = GetDC(hWnd);
if(!testBitmap.draw(x, y, windowHDC))
{
running = false;
ReleaseDC(hWnd, windowDC);
}
else
{
if(GetMessage(&lpMsg, NULL, 0, 0))
{
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
UpdateWindow(hWnd);
numFrames++;
}
}
DeleteDC(hWnd, windowHDC);
totalTime = GetTickCount() - totalTime;
ShowCursor(true);
ChangeDisplaySettings(NULL, 0);
averageFR = numFrames / (totalTime / 1000);
return(lpMsg.wParam);
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT messg, /*callback procedure */
WPARAM wParam, LPARAM lParam )
{
switch(messg)
{
case WM_PAINT:
break;
case WM_DESTROY:
PostQuitMessage(0);
running = false;
break;
default:
return( DefWindowProc( hWnd, messg, wParam, lParam ) );
}
return(0L);
}