Archived

This topic is now archived and is closed to further replies.

flukus

Help with GDI drawing!

Recommended Posts

OK, I''m having a few problems getting GDI to work correctly. First of all I have this:
RECT fillrect;
fillrect.top = 0;
fillrect.left = 0;
fillrect.right = 640;
fillrect.bottom = 480;
//clear the backbuffer
FillRect(backbuffer, &fillrect, (HBRUSH)GetStockObject(WHITE_BRUSH));

 
Which basicly clears the bitmap that I have serving as the back buffer, but it only clears about 3/4 of the width of the bitmap, even if I set fillrect.right to 800+. Then theres this bit:
//get the client rectangle for blitting the back buffer
GetClientRect(hwnd, &clientRect);

//get the window DC
hdc = GetDC(hwnd);
//blitthe back buffer
BitBlt(hdc, clientRect.top, clientRect.left, clientRect.bottom, clientRect.right, backbuffer, 0, 0, SRCCOPY); 
//release the window dc
ReleaseDC(hwnd, hdc);

 
Which blits the back buffer to the window, this bit seems to be working correctly. But then when I try to draw to the back buffer: for (int i = 0; i <100; i++) { int x = rand()%640; int y = rand()%480; int r = rand()%255; int g = rand()%255; int b = rand()%255; SetPixel(backbuffer, x, y, RGB(r,g,b)); }//end for I get nothing. Sooo any ideas?

Share this post


Link to post
Share on other sites
Here''s a link to my backbuffer thing with full screen GDI. You can use it to figure out where you went wrong. I got most of this from GameTutorials.com -- displays some polygon asteroids in full screen GDI with backbuffer. You have to set up your window correctly, and make sure it matches your ChangeDisplaySettings if you want full screen.

AsteroidsFullScreen.cpp | EXE

I''m about to "graduate" to DirectDraw though since I find GDI is too slow on slower machines (Pent II 300), but just fine with modern fast machines.

Phil P

Share this post


Link to post
Share on other sites
Look up SetPixelV (think its the newest version)
at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_25fa.asp

And of course, look over the obvious error-prone items such as, making sure you are seeding your rand calls correctly (and calling, not sure of the syntax)..flipping the back to the hdc, etc.

Pixel manipulation would be much faster tho (like lightning fast compared to setpixel), by converting the bitmap to a DIB then using [y*x+c]=RGB(.,.,.)..

I fseek, therefore I fam.

[edited by - drarem on November 18, 2003 2:54:41 AM]

Share this post


Link to post
Share on other sites
philVaz, I had a look through your code and I can''t see anything different to mine, but I''ll check again tommorow when I''ve had more sleep. Have fun with directx though, it''s so much nicer, no worrying about dc and selecting objects ect. DX won''t co-operate with my graphics card though unfortuneately.

Share this post


Link to post
Share on other sites
Ok, I've looked through and compared the code thourougly and can't see anything wrong. I'll try posting the whole code:

console.cpp:



/////Tetris V2


#define WIN32_LEAN_AND_MEAN


//////////includes//////////////

#include "mainheader.h"


/////GLOBALS//////////////


//window handle

HWND hwnd;
//message for the event handler

MSG msg;
//the window DC

HDC hdc;


//the dc for the backbuffer

HDC backbuffer = NULL;
//the bitmap back buffer

HBITMAP bb = NULL;
//the old bitmap to return when the program ends

HBITMAP hbmOld = NULL;

//to hold the varios states of the game, mainly used in gamemain.cpp

const int GAME_LOAD = 0;
const int GAME_PLAY = 1;
const int GAME_SHUTDOWN = 2;
int GAME_STATE = GAME_LOAD;




//////the event handler

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
//used in VM_PAINT

PAINTSTRUCT ps;



//process the message

switch (msg)
{
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);

return(0);
} break;

case WM_DESTROY:
{
//kill the app

PostQuitMessage(0);
return(0);
}break;

default: break;
}//end switch



//let windows deal with anything this didn't

return(DefWindowProc(hwnd, msg, wparam, lparam));
}//end WindowProc



//main function

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpCmdLine, int ShowCmd)
{

//to hold the client rect of the window

RECT clientRect;


////////////CREATE THE WINDOW OBJECT

WNDCLASSEX winclass;
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
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)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = "winclass";
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

//register the window

RegisterClassEx(&winclass);


//create the window

hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, NULL, WS_OVERLAPPED | WS_VISIBLE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hinstance, NULL);

//get the window DC

hdc = GetDC(hwnd);
//create a compatible dc

backbuffer = CreateCompatibleDC(hdc);
//CREATE A NEW BITMAP TO SERVE AS THE BACK BUFFER

bb = CreateCompatibleBitmap(backbuffer, SCREEN_WIDTH, SCREEN_HEIGHT);
//release the window bitmap

ReleaseDC(hwnd, hdc);
//select the bitmap into the DC

hbmOld = (HBITMAP)SelectObject(backbuffer, bb);


//initialize the game state

InitGameState();


////ENTER THE MAIN LOOP

while (true)
{
//see if thers a message and act

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{

//test for a quit

if (msg.message == WM_QUIT)
break;

//translate accelerator keys????

TranslateMessage(&msg);

//send the message to the event handler

DispatchMessage(&msg);

}//end if


RECT fillrect;
fillrect.top = 0;
fillrect.left = 0;
fillrect.right = 640;
fillrect.bottom = 480;
//clear the backbuffer

FillRect(backbuffer, &fillrect, (HBRUSH)GetStockObject(WHITE_BRUSH));


//call the game specific loop

GameMain();


//get the client rectangle for blitting the back buffer

GetClientRect(hwnd, &clientRect);

//get the window DC

hdc = GetDC(hwnd);
//blitthe back buffer

BitBlt(hdc, clientRect.top, clientRect.left, clientRect.bottom, clientRect.right, backbuffer, 0, 0, SRCCOPY);
//release the window dc

ReleaseDC(hwnd, hdc);

//test for escape

if (KeyDown(VK_ESCAPE))
break;

}//end while


//SHUTDOWN GAME SPECIFIC STUFF

GameShutdown();


//restore the old bitmap to the dc

SelectObject(backbuffer, hbmOld);
//Delete the bitmap

DeleteObject(bb);
//delete the DC

DeleteDC(backbuffer);

//exit

return(msg.wParam);

}//end WinMain







gamemain.cpp:



#include "mainheader.h"

RECT paddle = {320, 240, 380, 250};


void GameMain()
{
switch (GAME_STATE)
{
case 1: { GamePlay(); break;}

case 0: { GameLoad(); break;}

case 2: { GameShutdown(); break;}

default : {}

}//end switch

}//end gameMain()



void GamePlay()
{
if (KeyDown(VK_LEFT))
{
paddle.left--;
paddle.right--;
}//end if


if (KeyDown(VK_RIGHT))
{
paddle.left++;
paddle.right++;
}//end if



for (int i = 0; i <100000; i++)
{
int x = rand()%640;
int y = rand()%480;
int r = rand()%255;
int g = rand()%255;
int b = rand()%255;

SetPixelV(backbuffer, x, y, RGB(r,g,b));

}//end for


//FillRect(backbuffer, &paddle, (HBRUSH)GetStockObject(WHITE_BRUSH));


}//end game play


void GameShutdown()
{
}//end game shutdown


void GameLoad()
{

srand(GetTickCount());
}//end game load


void InitGameState()
{
//this function is called befor the game loop is entered

GAME_STATE = 0;
}//end init game state




[edited by - flukus on November 18, 2003 11:48:25 PM]

Share this post


Link to post
Share on other sites
In your WM_PAINT message, you are overwriting your hdc.

Do the hdc=GetDC(hwnd) in your WM_CREATE message of your WndProc().. get rid of the hdc=beginpaint() in your WM_PAINT and just use beginpaint/endpaint to paint your screen..
think of it as minimizing and maximizing, what GDI 'surfaces' do you need to restore (repaint)?

edit: after looking at it some more, you want to get rid of the other hdc=GetDC() call, and put your bitblt(hdc,...,backbuffer..) call into a render() function to make it easier.. that way you can call render() from WM_PAINT's BeginPaint/EndPaint. Then add a timer, so in pseudocode:

[PeekMessage]
translate()
getmessage()..
ELSE
WaitTime 0.005 uSeconds (or whatever interval you want)
mainloop();
ELSE
quit this game.
};

mainloop() {

if key=left arrow then do...
if key=right...

..
render(); //this is where bitblt could be to make it easy.
}

WndProc(....) {
case WM_CREATE:
hdc=GetDC(hwnd);
break;
case WM_PAINT:
BeginPaint(..,..);
render(); //this will call the bitblt function directly.
EndPaint..
..
};



I fseek, therefore I fam.

[edited by - drarem on November 18, 2003 12:34:42 AM]

Share this post


Link to post
Share on other sites
OK, I rearanged the code as you said but it still doesn''t want to work.

I solved the first problem of the fill rect not clearing the whole back buffer, I had clientRect.right/bottom switched.

The problem seems to be that I can''t do anything with the backbuffer from the gamemain.cpp file.

Share this post


Link to post
Share on other sites
Doh! You can''t CreateCompatibleBitmap(backbuffer,..) because no bitmap object exists for it yet..

try:

CreateCompatibleBitmap(hdc,wid,hgt);

since you already (hopefully) did a hdc=GetDC(hwnd);
before it to move the value in the eax register returned from GetDC into variable hdc.

also, in your bitblt, your .left and .top are switched also,s/b:
bitblt(hdc,x,y,wdth,height,backdc,0,0,srccopy)



I fseek, therefore I fam.

Share this post


Link to post
Share on other sites
I tried putting the pixel drawing loop in render section and that works, sort of. The pixels show but there all in black and white. I tried making a using CreateBitmap instead of CreateCompatibleBitmap but when I do that the pixel plotting won''t work at all.

Share this post


Link to post
Share on other sites
email me the source and I will see what I can do with it.. check my profile sig. for email addy.

You need to stick to CreateCompatibleBitmap(hdc...)

CreateCompatibleBitmap(backbuffer...) won't work, backbuffer is a non-existant object at this point.


Yes, you need to use:

backbuffer=CreateCompatibleDC(hdc)..
backBMP = CreateCompatibleBitmap(hdc,...,...);
SelectObject(backbuffer,backBMP);

but backbuffer doesn't have a bitmap associated with it (via SelectObject), so it aint gonna work.

I fseek, therefore I fam.

[edited by - drarem on November 19, 2003 4:54:40 AM]

Share this post


Link to post
Share on other sites
"bb = CreateCompatibleBitmap(hdc, SCREEN_WIDTH, SCREEN_HEIGHT);"

Works perfectly now, thanks for the help

As for it not working from the other cpp file, that was an incredibly stupid mistake from me. At the end of GameLoad() I didn''t change the GAME_STATE.

Share this post


Link to post
Share on other sites