Jump to content
  • Advertisement
Sign in to follow this  

HBITMAP - How do I do tiles with a bitmap?

This topic is 3716 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've had occasions of using HBITMAP to do an overlay for an application, but they used solely the entire image, to cover the window. My question is basically, how do I access the individual tile inside the image? Any snippets that can be provided or insight in the direction to follow? Thanks. Quinn

Share this post


Link to post
Share on other sites
Advertisement
If you know how to draw a bitmap to a region of the window you already have most of what it takes to tile it. When tiling a bitmap you basically just draw it multiple times and each time you draw it you shift the location of where you're drawing it. The functions you'll need to use are GetObject(), to know the size of the HBITMAP, and BitBlt() (or similar) to actually draw the bitmap.

The basic algorithm is to start at (0, 0) in the destination and blit your image. Then move W pixels to the right, where W is the width of the bitmap, and blit your image again. Do this until you reach the end of the line then move down by H pixels, where H is the height of the bitmap, and back to the start of the row.

Share this post


Link to post
Share on other sites
Well, I was aware of using BitBlt and GetObject, but my concern, is that it would entail loading several instances of the HBitmap object, wouldn't it?

For example, if I have a struct TILE, that consists of an HBitmap - when you load the data in, that will end up with having multiple instances of the same bitmap loading up, the entire image! over the course of your data structure of tiles.

TILE MAP[MAP_WIDTH][MAP_HEIGHT] for example.

In WM_PAINT:


...
for (int x = 0; x < MAP_WIDTH; x++)
for (int y = 0; y < MAP_HEIGHT; y++)
{
RECT rSource = { (x * TILE_WIDTH),
(y * TILE_HEIGHT),
(x * TILE_WIDTH + TILE_WIDTH),
(y * TILE_HEIGHT + TILE_HEIGHT)};

hDCMem = CreateCompatibleDC(hdc);
SelectObject(hDCMem, MAP[x][y].hTile);
BitBlt(hdc, rSource.left, rSource.top, rSource.right, rSource.bottom, hDCMem,rSource.left, rSource.top , SRCCOPY);
}



In WinMain


for (int x = 0; x < MAP_WIDTH; x++)
for (int y = 0; y < MAP_HEIGHT; y++)
{
MAP[x][y].hTile = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1));
MAP[x][y].bBlocked = false;
}



It displays my tiles fine, but isn't there a more efficient way to do it, that I may be overlooking?

Share this post


Link to post
Share on other sites
Firstly, you shouldn't be creating a DC every time you need to paint, and you don't seem to be calling DeleteDC, which is a resource leak. You should create the DC at init time, not at render time.
I might be wrong about this, but the way I've always done this is to have one HDC per HBITMAP, so the HBITMAP is always selected into the HDC. Again, I might be wrong, I'm not sure if that's the correct way, or if you should only have one HDC and change the bitmap that's selected into it.

The way I'd handle this, is to have a vector of HBITMAPs, one HBITMAP for each unique image. Then instead of using MAP[x][y].hTile, you'd have an index into the std::vector of bitmaps, and use that. So it's like a look up table.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
I might be wrong about this, but the way I've always done this is to have one HDC per HBITMAP, so the HBITMAP is always selected into the HDC. Again, I might be wrong, I'm not sure if that's the correct way, or if you should only have one HDC and change the bitmap that's selected into it.

Since the GDI functions almost all work on DCs, these are the correct ways to do this. If I have just one bitmap or if I have many bitmaps that persist for a long time I give them each a DC. If there are several bitmaps that are used occasionally I have one DC and use that to switch between them.

Share this post


Link to post
Share on other sites
In regards to the DeleteDC(), its already there, I just pasted a snippet into the source box, that didn't include it. So, I need to create MAP_WIDTH * MAP_HEIGHT DC's now too? Isn't that a little much? So, just add a DC to my struct, and throw them in the call?

Share this post


Link to post
Share on other sites
You shouldn't need to have each and every tile in it's own HBITMAP, because BitBlit/StretchBlit both support source coordinates so you can just select a region from the source bitmap and copy that into your frame buffer.

I think that was your original question, right? How do you select a single tile from an image comprised of many tiles, like a tile-sheet?

Share this post


Link to post
Share on other sites
Then its easy enough, in your BitBlit call, just set the source X/Y to the upper-left corner of the desired tile -- exactly the same as you do to set the location of the destination blit. For BitBlit, the width and height of the source and destination are the same, so one is implicit. For StretchBlit, the width and height of the source rect can be different than the destination rect, so both must be explicitly provided.

For more information, look at the BitBlit and StretchBlit documentation on MSDN.

Share this post


Link to post
Share on other sites
RECT rSource = { (x * TILE_WIDTH),
(y * TILE_HEIGHT),
(x * TILE_WIDTH + TILE_WIDTH),
(y * TILE_HEIGHT + TILE_HEIGHT)};

hDCMem = CreateCompatibleDC(hdc);
SelectObject(hDCMem, MAP[x][y].hTile);
BitBlt(hdc, rSource.left, rSource.top, rSource.right, rSource.bottom, hDCMem,rSource.left, rSource.top , SRCCOPY);
}



isn't that exactly what I was doing? lol.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!