From: Sascha on
Hello

I have made a simple 2d Game engine in Win32 C++. I use double
buffering to draw the objects onto the client HDC. But I think I maybe
drawing too many times to a HDC causing an error or something?

[b]I have the executable that really simply shows my problem so I
really encourage you to download it instead of having to read all the
below. It shows exactly where the drawing fails at loop 50 (see the
console window).[/b] PS how do you add links in this forum?

http://www.mediafire.com/?gz0xzktmryt

The 2d engine works pretty well, each object controls its own movement
then informs the 2d engine saying "Draw me, Audio me, Keep me in the
action/input queue etc." And the 2d engine draws an object's new
position every loop well.

[b]But One funny problem I am getting is:[/b]

- If I have n objects to draw, after the n*100th gameloop the drawing
onto the window HDC of each objects new coordinates stops. The game
loop is still looping perfectly, the actual code/function to draw the
objects onto the Buffer hdc still runs(I checked), the function to
copy the BufferHDC to the WindowHDC still runs BUT the window is not
displaying the new HDC image therefore each objects new position(they
are moving).

So in the case when I have [b]5[/b] objects to draw & they all are
moving to the same point on the window (100,100):

- For the 1st 500 game loops the 2d engine draws all the objects
(every loop) perfectly(in their new position, coloured etc.) But then
the window doesn't get updated after the 501st loop?

In the case when I have [b]55[/b] objects to draw & they all are
moving to the same point on the window (100,100):

- For the 1st 50 game loops the 2d engine draws all the objects (every
loop) perfectly(in their new position, coloured etc.) But then the
window doesn't get updated after the 51st loop & the window HDC just
continually shows the HDC image of the 50th frame?


[b]So after that long winded explaination I have come to believe that
maybe I can only[/b] draw on a HDC so many times OR I can only copy to
the window HDC so many times OR maybe I am overloading the variables
or system concerned with copying the BufferHDC to the WindowHDC?

My algorithm is simple:
- The graphic engine has a draw queue that contains all the objects
that need to be drawn in the next game loop
- When the next loop begins I call the function ExecuteDrawLogic().
Where every object inside the Draw Queue is told "I am passing you the
BufferHDC, draw over your old position with the bK colour, draw
yourself at your new position" then I remove the object from the
queue.
- After all objects have done their drawing I copy the BufferHDC to
the main WindowHDC which has/shows each objects new position & makes
it look they r moving.

So again after this really long explanation, do you know why the
WindowHDC does not get updated after nth game loop? Am I overloading
the bufferHDC or something?

Graphic Engine Class:
[source lang="cpp"]
class GraphicEngine
{
public:

GraphicEngine( Engine2d *ParentEng, HWND Hwnd );
~GraphicEngine();
void StoreSiblingEngines( SystemEngine *SystemEng,
InputEngine *InputEng,
AudioEngine *AudioEng );
void SetHwnd( HWND Hwnd );
void CopyWindowHDC( HWND Hwnd, HDC WindowHDC );
void Clear();
int AddToDrawQueue( Object *Obj );
bool ExecuteDrawLogic( HDC WindowHDC );


private:

HWND hwnd;
RECT ClientRect;
HDC BufferCanvas;
HBITMAP hBlt;
HGDIOBJ hMCBmp;
queue <Object*> DrawQueue;

};

[/source]


Functions associated with double buffering:
[source lang="cpp"]
void GraphicEngine :: CopyWindowHDC( HWND Hwnd, HDC WindowHDC)
{
// Post: Copy Window HDC to Buffer canvas. This function is done
once, when
// the 1st WM_PAINT message is sent when the window is
created. It also is
// called again if the window is resized/minimised etc.


GetClientRect( Hwnd, &ClientRect );

BufferCanvas = CreateCompatibleDC( WindowHDC );
hBlt = CreateCompatibleBitmap( WindowHDC, ClientRect.right,
ClientRect.bottom );
hMCBmp = SelectObject( BufferCanvas, hBlt );

BitBlt(BufferCanvas, ClientRect.left, ClientRect.top,
ClientRect.right,
ClientRect.bottom, WindowHDC, 0, 0, SRCCOPY );


}


bool GraphicEngine :: ExecuteDrawLogic( HDC WindowHDC )
{
// Post: Draw all 'Dirty' Objects onto window using Double
Buffering (avoids
// flicker affect).

hMCBmp = SelectObject( BufferCanvas, hBlt );

// Draw objects onto Buffer Canvas
while ( !DrawQueue.empty() )
{
DrawQueue.front()-> EraseSelf( BufferCanvas );
DrawQueue.front()-> DrawSelf( BufferCanvas );
DrawQueue.pop();
}


// Copy BufferCanvas HDC to WindowCanvas HDC
BitBlt( WindowHDC, ClientRect.left, ClientRect.top,
ClientRect.right,
ClientRect.bottom, BufferCanvas, 0, 0, SRCCOPY );

}


int GraphicEngine :: AddToDrawQueue( Object *Obj )
{
// Post: Add Object to Graphic Engine's draw queue. At the next
clock step
// the Graphic Engine will call this objects' DrawSelf()
function

// TODO: Arrange/Add Objects in queue according to depth eg an
airplane should
// be drawn last coz its higher

DrawQueue.push( Obj );
}

[/source]
From: Leo Davidson on
On Jun 8, 3:11 am, Sascha <nill...(a)yahoo.com> wrote:
> I have made a simple 2d Game engine in Win32 C++. I use double
> buffering to draw the objects onto the client HDC. But I think I maybe
> drawing too many times to a HDC causing an error or something?

I suspect your code is leaking GDI objects/handles and that's why
things stop working.

Open Task Manager and turn on the GDI Objects column to see if the
count is ridiculously high or ever-increasing.

It could also be some other kind of bug, but there's definitely no
limit on the number of times you can draw to a device context (else
almost every app in the world would stop being able to update its
window after a short time since almost all apps ultimately put stuff
on the screen via GDI).
From: Ulrich Eckhardt on
Sascha wrote:
> I have the executable that really simply shows my problem so I
> really encourage you to download it instead of having to read all
> the below.

I hope nobody is foolish enough to follow that request or at least runs it
in a sandbox. Otherwise, downloading random executables from unknown
persons is a ticket to the next botnet drama. And even if that executable
is completely harmless, I wouldn't ask others to download it, exactly for
that reason.


> class GraphicEngine
> {
> public:
> GraphicEngine( Engine2d *ParentEng, HWND Hwnd );
> ~GraphicEngine();
> void StoreSiblingEngines( SystemEngine *SystemEng,
> InputEngine *InputEng,
> AudioEngine *AudioEng );
> void SetHwnd( HWND Hwnd );
> void CopyWindowHDC( HWND Hwnd, HDC WindowHDC );
> void Clear();
> int AddToDrawQueue( Object *Obj );
> bool ExecuteDrawLogic( HDC WindowHDC );
>
> private:
>
> HWND hwnd;
> RECT ClientRect;
> HDC BufferCanvas;
> HBITMAP hBlt;
> HGDIOBJ hMCBmp;
> queue <Object*> DrawQueue;
> };

Several points here:
1. Your GraphicEngine class is both copyable and assignable, those functions
are compiler-generated. You probably don't want that, so you should prevent
it. Check the C++ FAQ at parashift's.
2. Who owns all those objects you pass handles or pointers to around? Which
of these can be NULL? You can and should use C++ references, because those
implicitly say that the parameter can't be left out.

> BufferCanvas = CreateCompatibleDC( WindowHDC );
> hBlt = CreateCompatibleBitmap( WindowHDC, ClientRect.right,
> ClientRect.bottom );
> hMCBmp = SelectObject( BufferCanvas, hBlt );
>
> BitBlt(BufferCanvas, ClientRect.left, ClientRect.top,
> ClientRect.right, ClientRect.bottom,
> WindowHDC, 0, 0, SRCCOPY );

Where are you releasing the resources you allocated here (DC, bitmap)? If
you allocate more and more of those, that resource leak will cause further
allocations to fails, which you completely ignore here. Check for errors,
and if it's only that you output a message to stderr and exit or something
like that. Also, what do you need hMCBmp for after leaving this function?
In other words, why do you store this in a membervariable?

Start with error checking, I guess you will then see where your program
fails. Then, think about ownership and proper allocation/deallocation of
resources, that will then probably fix your program.

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932

From: Heck on
On Tue, 08 Jun 2010 09:31:29 +0200, Ulrich Eckhardt
<eckhardt(a)satorlaser.com> wrote:

>Sascha wrote:
>> I have the executable that really simply shows my problem so I
>> really encourage you to download it instead of having to read all
>> the below.
>
>I hope nobody is foolish enough to follow that request or at least runs it
>in a sandbox. Otherwise, downloading random executables from unknown
>persons is a ticket to the next botnet drama. And even if that executable
>is completely harmless, I wouldn't ask others to download it, exactly for
>that reason.

I think he's relatively young and inexperienced. And trusting.
>[b]...[/b] PS how do you add links in this forum?

Try alt.religion.kibology.

Or am I the gullible one?