Archived

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

Orpheum

Unnecessary Device Context Overhead

Recommended Posts

I found a solution to my torn images with bitblt, but the solution is unacceptable. I am trying to store all the windows variables in the main class so I can just pop them in whenever I need them. I was initializing them in the constructor like so:
GDITile::GDITile(HWND hwnd)
{
   hWnd = hwnd;
   hdc = GetDC(hWnd);
   memDC = CreateCompatibleDC(hdc);
}
 
The way I fixed my torn images bug was to move the hdc and memDC lines to the render function. That places a lot more overhead on that function than I want. It is much nicer to get that shit outta the way once, than to call it every frame! Does anyone know a way around this?? My engine is already static in WndProc, and I cant make any of the above varaibles static because they need function calls to initialize them, which all stem from initializing hWnd - which is done in the constructor.

Share this post


Link to post
Share on other sites
You''re still not giving a whole lot of info...

Just a question though, are you sure that the getDC() and CreateCompatibleDC() functions are in-fact not returning a NULL value (indication of an error)?

Jumpster





Semper Fi

Share this post


Link to post
Share on other sites
Yes, everything is working fine, I just want to initialize the DC''s one time, not every time I want to blt. I can only assume the reason for the problems is that when WndProc goes out of scope, the variables get hosed. That is why I tried to make every thing static, but it didn''t work. I''m no Win32 guru so I''m looking for methods people have come up with to initialize their hdc and memoryDC once, and not have to do it every time you want to paint.

Share this post


Link to post
Share on other sites
And thats why you don''t see too many games written using GDI.

But seeing as you''re doing it this way, and the above''s not too helpful, try using getdc() at the beginning of the rendering loop, and storing the dc for each tile graphic in their class at load-time. (Win32 can have as many dc''s as memory permits).

OR, you could just store each tile on a big, long, bitmap, and use some maths to get the correct tile for the blt,

e.g.
BitBlt(
ScreenX, ScreenY, TileWidth, TileHeight, BitmapDC, //dest.
0, TileHeight * TileID, Flags); //source

but you get the idea.

That way you''re only getting a dc once per rendering loop, as opposed to the amount of tiles that you''re rendering.

Just an idea.



Waassaap!!

Share this post


Link to post
Share on other sites
Hmm... I didn't realize I was being so vague, but I guess my perspective is a little more informed. Here's all the code you can use:

        
GDITile::GDITile(HWND hwnd, int iResX, int iResY)
:iTileSizeX(32), iTileSizeY(32)
{
bMapLoaded = false;
szMapName = '\0';
iMapSizeX = 0;
iMapSizeY = 0;
iMapVisX = 0;
iMapVisY = 0;
World = '\0';

for(int i = 0; i < 256; i++)
bTileLoaded = false;

m_iResX = iResX;
m_iResY = iResY;

hWnd = hwnd;
//Want to call these once, here in the constructor
// hdc = GetDC(hWnd);
// memDC = CreateCompatibleDC(hdc);
}


void GDITile::RenderWorld(void)
{
//dont want to call these two every frame

hdc = GetDC(hWnd);
memDC = CreateCompatibleDC(hdc);

int tempX = 0;
int tempY = 0;

for(tempY; tempY < (m_iResY / iTileSizeY); tempY++)
{
for(tempX; tempX < (m_iResX / iTileSizeX); tempX++)
{
SelectObject(memDC, TileCache[World[(iMapVisX + tempX) % iMapSizeY].iTileIndex[0]]);

if(tempX == 0 && tempY == 0)
BitBlt(hdc, tempX, tempY, iTileSizeX, iTileSizeY, memDC, 0, 0, SRCCOPY);

else if(tempX == 0)
BitBlt(hdc, tempX, (tempY * iTileSizeY), iTileSizeX, iTileSizeY, memDC, 0, 0, SRCCOPY);

else if(tempY == 0)
BitBlt(hdc, (tempX * iTileSizeX), tempY, iTileSizeX, iTileSizeY, memDC, 0, 0, SRCCOPY);

else
BitBlt(hdc, (tempX * iTileSizeX), (tempY * iTileSizeY), iTileSizeX, iTileSizeY, memDC, 0, 0, SRCCOPY);
}

tempX = 0;
}
//would also like to call this once, in the destructor
DeleteDC(memDC);

return;
}



I also wanted to say this is v1 of the rendering engine, I havent put in page flipping, or even configured it to use more than 1 tile per grid point, it is just a test to see if the damn thing even worked... and also, Im just doing this engine for Win32 experience, so I can see whats possible with it. I plan on getting into DX next year.

Edited by - Orpheum on October 8, 2000 8:10:24 PM

Share this post


Link to post
Share on other sites
I wrote a tile-based engine for Windows GDI once, and it worked very well. Dude, why don''t you just save the DC as a global variable and clean it up when the program exits? Unless I am missing something, it really is that simple... that''s what I did.

Share this post


Link to post
Share on other sites
Let me add a few more thoughts to this. What I did was instead of storing a HBITMAP for each tile (which it appears you are doing in TileCache[x].iTileIndex), I stored each one as a DC.
Sure, you've got to load the bitmap and get a handle to it at first, but then I used SelectObject() to put each bitmap right into it's own DC (using CreateCompatibleDC like you did), all done once during the initialization of the program. Then in the renderer, you just blit to your window's DC right from each tile's DC.



Edited by - Steel on October 8, 2000 11:13:40 PM

Share this post


Link to post
Share on other sites
Steel - So what you''re saying is that when you load your map, you create a separate DC for each bitmap, and then when you needed to blt them, just copy each DC to hdc + xoffset + yoffset(windows one)? How do you keep track of where each bitmap is at? Did you just create an array of DC''s? What I did was to give each grid point a tile index # (i plan to support 3 tile index''s per grid point, but that will come later), and when the tiles are being loaded, tile #3 gets loaded into (HBITMAP) TileCache[3].

Share this post


Link to post
Share on other sites
quote:
Original post by Orpheum

Steel - So what you're saying is that when you load your map, you create a separate DC for each bitmap, and then when you needed to blt them, just copy each DC to hdc + xoffset + yoffset(windows one)? How do you keep track of where each bitmap is at? Did you just create an array of DC's?

That's exactly what I did.
quote:
What I did was to give each grid point a tile index # (i plan to support 3 tile index's per grid point, but that will come later), and when the tiles are being loaded, tile #3 gets loaded into (HBITMAP) TileCache[3].

Yep, pretty much the same idea. My array wasn't an array of HBITMAPS or DCs though, rather it was an array of data structures with a DC type as a member (in addition to other "fields"). For example:
struct TILETYPE
{
char cWalkability;
char cOpacity;
HDC hdcImage;
};


Then I create an array of this structure, load my bitmaps from a file, and "select" each bitmap handle into the .hdcImage member of a specific array element, delete the handle (but not the DC of course), and I can continue to reference each tile by it's index!

TILETYPE Tile[100];

// load data from a file into each array element.
// Here's just the "hdc" part for Tile[n]:

HBITMAP hbmImage;
HDC hdcImage;
hbmImage = LoadImage(0, sImagePath, IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION || LR_LOADFROMFILE);
hdcImage = CreateCompatibleDC(0) // Passing zero, or NULL, makes
// a DC compatible with the current screen
SelectObject(hdcImage, hbmImage);
DeleteObject(hbmImage);
Tile[n].hdcImage = hdcImage;


You can then blit from Tile[n].hdcImage. It's much faster. Then at the end of the program, you call DeleteObject() on the .hdcImage memeber of every element of your array. HDCs just hold a number that somehow identifies objects that Windows manage. It's not a pointer, though in a way it works like one since it's used by Windows as a sort of "index" into a table of junk Windows manages. But technically, an HDC is just a long integer.

int GameShutDown()
{
// MAX_TILES is defined as your highest array element
for (n = 0; n <= MAX_TILES; n++)
{
DeleteObject(Tile[n].hdcImage);
}

// do other clean up
}


Hope that helps! BTW, I learned the same you are now: I decided to learn doing things using the Windows GDI first. In some small cases it can be more complex, but once I mastered DCs and such, I was able to concentrate on just learning more about game programming in general. I learned DirectX later (and still learning). In retrospect, I'm glad I took that route. I ended up know more about the Win32 API and Window's interal makeup better than many others, and the knowledge is of course very useful!

Edited by - Steel on October 9, 2000 5:47:31 PM

Share this post


Link to post
Share on other sites
Steel - seeing as you did the same thing I''m trying to, I was wondering how you setup your game loop. I have a few ideas, but it seems like it is going to be quite the headache once my engine gets to the point that I would call it a game. Did you use PeekMessage()? Any insights you care the share are appreciated.

Share this post


Link to post
Share on other sites