PDA

View Full Version : Win32 API Question


Fuzake
30th May 2006, 08:51 AM
:D Hello, world! I am a new member who is an aspiring game programmer. I am using C++ to program video games right now, but I have a problem... The sprites (2D objects) won't display on screen. Here is the most likely problem.

- My resource files are incorrect. Here's an example...

Resource.h
{
#define IDB_WALKLEFT 2000
//Rest of images
}
Resource.rc
{
#include "Resource.h"
IDB_WALKLEFT BITMAP "WalkLeft.gif"
//Rest of images
}

And I don't completely understand BitBlt(). The book I bought to learn about Windows programming (Sam's Teach Yourself Game Programming In 24 Hours) doesn't tell you how it works. It only shows you one way to use it. Could someone tell me if my resource files are wrong and what BitBlt() does and how to use it?

Thanks

Fuzake :cool:

roger
30th May 2006, 09:16 AM
Your resource files look fine.

another possible problem: you are not loading the bitmap correctly.
CBitmap foo;
foo.LoadBitmap (IDB_FOO);

Why don't you post your entire bit of code to blit a bmp to the screen. Basically bitblt copies a bitmap to another bitmap. you can't blit directly to a screen resource. Instead, select the bitmap into a device context, and then blits that device context into the screen.

For example, here is some real code I just wrote and tested. In production code the 'foo' local object would be made a class member, and only loaded once. The save/restore DC is overkill in this tiny example, but I tend to use this style as my default, so I don't have to remember to correctly release resources every time I make a code change.



void CChildView::OnPaint()
{
CPaintDC dc(this);

CDC memDC;
CBitmap foo;
foo.LoadBitmap (IDB_BITMAP1);

memDC.CreateCompatibleDC (&dc);
int save = memDC.SaveDC ();

memDC.SelectObject (&foo);
dc.BitBlt (100, 120, 48, 48, &memDC, 0, 0, SRCCOPY);
memDC.RestoreDC (save);
}

Fuzake
30th May 2006, 11:29 AM
Hmm. Well, I've never heard of CBitmpap or CDC. This is C++ code, right? I may have to use this. Yeah, I do load it into a device context and then blit the DC. Maybe I didn't make that clear. Thanks.

...Um, you won't sue me if I do use that, right?... I will fight you if you say you will! YAAAA!!! :catfight:

roger
30th May 2006, 11:48 AM
Sorry, that is MFC code. But pretty much all these calls have equivalent win32 API calls.

to wit:


case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
HBITMAP foo = LoadBitmap (hInst, MAKEINTRESOURCE(IDB_BITMAP1));
HDC memDC = CreateCompatibleDC (hdc);

int save = SaveDC (memDC);

SelectObject (memDC, foo);

BitBlt (hdc, 100, 120, 48, 48, memDC, 0, 0, SRCCOPY);

RestoreDC (memDC, save);
EndPaint(hWnd, &ps);
DeleteObject (foo);
}
break;

roger
30th May 2006, 11:52 AM
p.s. this will overwrite the full 48x48 square with the new bitmap. If your sprites need to have transparent sections, which is pretty much a given for a 2D game, you are going to have to be a bit more clever. But let's get you drawing bitmaps first, before tackling that problem.

Fuzake
30th May 2006, 01:14 PM
w00t!!! I just found an example how to do it on the computer! Even though your first reply was in MFC, it was pretty close... And your last one is about the same as the code I just found. Man, was my loading method off. :eye-poppi: Thanks, man.

I know how to make the images transparent. Just go to Paint, save them in GIF format, and specify a transparent background color under Attributes. Any other pointers you could give me on images?

roger
30th May 2006, 01:36 PM
Any other pointers Nothing comes to mind offhand, but I pretty much do 2D and 3D graphics for a living, so feel free to ask questions as they come up.

Probably the next issue you will face is making your sprites move around without "blinking". If you naively redraw the screen each time they move, the image will flicker, because it takes time for the computer to draw the image, and you sort of see it happen as it draws. So what you do is create a bitmap, draw the new screen to that, and then blit the bitmap onto the screen. Blitting goes much faster than GDI draw commands, so the result is flickerless animation.

Here's a helper class to do all of that for you:


#ifndef MemoryHDC_h
#define MemoryHDC_h

// This class facilitates drawing to the screen without flashing
// caused by updates. It creates a memory mapped HDC, which you draw
// to. When ~MemoryHDC is called it BitBlts the data to the screen.
// SOO, this class must be constructed and destroyed locally.
//
// Everything is inline so there should be little performance loss
// when optimizations are invoked.

class MemoryDC
{
public:
// wnd : handle to window
// hdc : handle to drawing dc.
// bound : optional, region to redraw. The entire
// client region of hwnd will be redrawn
// if this parameter is NULL.
MemoryDC (HWND wnd, HDC hdc, RECT* bound) :
cwnd (wnd),
ScreenDC (hdc)
{
RECT ClientRect;
GetClientRect (wnd, &ClientRect);
int Width = ClientRect.right - ClientRect.left;
int Height = ClientRect.bottom - ClientRect.top;
if (bound)
rgn = *bound;
else
rgn = ClientRect;


// build a memory DC which we will write to instead of the
// screen. This allows us to avoid flickering.

memDC = CreateCompatibleDC (ScreenDC);
hbmp = CreateCompatibleBitmap (ScreenDC, Width, Height);
Oldhbmp = SelectObject (memDC, hbmp);
}


~MemoryDC ()
{
// Now render the memDC to the screen
BitBlt (ScreenDC, rgn.left, rgn.top, rgn.right-rgn.left, rgn.bottom-rgn.top, memDC, rgn.left, rgn.top, SRCCOPY);

// and delete the resource now we are done with them.
SelectObject (memDC, Oldhbmp);
DeleteObject (hbmp);
DeleteDC (memDC);
}


HDC MemDC() {return memDC;}

private:
RECT rgn;

HDC memDC;
HGDIOBJ Oldhbmp;
HDC ScreenDC;
HBITMAP hbmp;
HWND cwnd;
};

#endif

russell_morris
30th May 2006, 03:24 PM
w00t!!! I just found an example how to do it on the computer! Even though your first reply was in MFC, it was pretty close... And your last one is about the same as the code I just found. Man, was my loading method off. :eye-poppi: Thanks, man.

I know how to make the images transparent. Just go to Paint, save them in GIF format, and specify a transparent background color under Attributes. Any other pointers you could give me on images?

I think part of your problem may be that you're using Windows GDI's ::LoadBitmap() function to attempt to load a .gif file from resources. I haven't done down-and-dirty GDI programming since '98, but I'm willing to bet that ::LoadBitmap is only able to make sense out of .bmp format images, not GIFs. Check the return value from your ::LoadBitmap() call - I'm willing to bet it's NULL.

With regards to transparency, you'll need to pick a color in the image that will end up 'transparent'. Make sure this color is ONLY used on parts of the images that must be transparent (a common color for this is bright pink, RGB (255,0,255), but it can be any color of your choosing). Once you've saved that .bmp and loaded it via ::LoadBitmap(), draw it with ::TransparentBlt() instead of BitBlt().

If you want to get really fancy and have alpha-blending support (i.e. per-pixel partial transparency), save your images as 32-bpp bitmaps with an alpha channel, and draw them using ::AlphaBlend().

It sounds like you're somewhat new to Windows programming. I'd suggest poking around at the CodeProject (http://www.codeproject.com), looking through their articles and tutorials on Win32 programming. For instance, there's an entire section devoted to working with Bitmaps (http://codeproject.com/bitmap/), and another one devoted to just Windows GDI (http://codeproject.com/gdi/) in general. Don't be afraid to ask questions you may have, or ask for help, in their various programming forums.

Fuzake
31st May 2006, 09:32 AM
I have tried to use TransparentBlt() before. However, it doesn't work. Is this function only available to Visual C++ users? Cuz I'm using Bloodshed Dev.

Roger: I do use double-buffered animation; that's simple. I do it like this:

Code:
void GameStart()
{
//Assume all variables not declared here are declared in the header file
_hOffscreenDC = CreateCompatibleDC(hwnd);
_hOffscreenBitmap = CreateCompatibleBitmap(hwnd, _pGame->GetWidth(),
_pGame->GetHeight());
SelectObject(_hOffscreenDC, _hOffscreenBitmap);
//Rest of code
}

Then I just paint to the offscreen and blit that to the main screen. Voila! No flicker. Do you have to include a certain file or library in your code to use TransparentBlt()? That's my biggest problem. And you're right, it can't use .gif files. That could be my problem. Thanks, guys. Any other stuff I should know? Any and all tips are greatly appreciated. :idea:

roger
31st May 2006, 09:45 AM
TransparentBlt is declared in wingdi.h and you must link in Msimg32.lib in VC++. Are you able to compile your code, but not link it?

Note that TransparentBlt() has a known memory leak in 95 & 98. The alternative is to write your own routine, which is what I was hinting at earlier. It's actually pretty easy.

roger
31st May 2006, 09:47 AM
Example using TransparentBlt. I paint the background black, and use white as my transparent color:

case WM_PAINT: {
hdc = BeginPaint(hWnd, &ps);
HBITMAP foo = LoadBitmap (hInst, MAKEINTRESOURCE (IDB_BITMAP1));
HDC memDC = CreateCompatibleDC (hdc);

int save = SaveDC (memDC);
int savedc = SaveDC (hdc);
SelectObject (hdc, GetStockObject (BLACK_BRUSH));
Rectangle (hdc, 0, 0, 500, 500);
SelectObject (memDC, foo);

// BitBlt (hdc, 100, 120, 48, 48, memDC, 0, 0, SRCCOPY);
TransparentBlt (hdc, 100, 120, 48, 48, memDC, 0, 0, 48, 48, RGB (255, 255, 255));
RestoreDC (memDC, save);
RestoreDC (hdc, savedc);
EndPaint(hWnd, &ps);
DeleteObject (foo);
}
break;

russell_morris
31st May 2006, 10:00 AM
I have tried to use TransparentBlt() before. However, it doesn't work. Is this function only available to Visual C++ users? Cuz I'm using Bloodshed Dev.


No - it's a standard Win32 API, so it'll be available to C, C++, and any other programming language that can call C-style functions.

When you say that it didn't work, do you mean that you got a compiler error, or that ::TransparentBlt() didn't draw anything? What version of Windows are you using? Have you used a .bmp instead of a .gif in your resources yet?

Humphreys
1st June 2006, 07:38 AM
Transparency isn't as simple as just setting "transparent" on the gif's attributes. It's a bit of a pain in the ass, actually, especially with detailed graphics.

Windows API programming, MFC or not, is generally appalling with graphics. I'd STRONGLY recommend not using it for games, but instead using a multi-buffered graphics API like Fastgraph (http://www.fastgraph.com/), or DirectX.

Fuzake
1st June 2006, 07:55 AM
Well, thanks for your advice everyone. I am using Windows 98.

When you say that it didn't work, do you mean that you got a compiler error, or that ::TransparentBlt() didn't draw anything? What version of Windows are you using? Have you used a .bmp instead of a .gif in your resources yet?

Okay, I'll answer your questions in order...

1) Compiler error, i.e. "TransparentBlt() undeclared" or something along those lines.

2) 98, as above.

3) Yes. I just haven't gotten around the above TransparentBlt() error.

I already link to Msimg32.lib; I didn't know I had to include "Wingdi.h" for it to work. That's probably it! Weehee... yeah... now it's not gonna work cuz I jinxed myself.:boggled:

Fuzake
1st June 2006, 07:56 AM
Oh yeah. Hate to double-post, but there is no way I can download anything because my connection is crappy and literally takes three hours just to load RuneScape... I'm stuck with Win32. Thanks anyway, Humphreys.

roger
1st June 2006, 08:12 AM
I already link to Msimg32.lib; I didn't know I had to include "Wingdi.h" for it to work. That's probably it! Weehee... yeah... now it's not gonna work cuz I jinxed myself.:boggled:Well, I have no idea where Bloodsheed declares it, if it declares it at all. In windows windgi.h is included when you include "windows.h" - you don't need to explicitly include wingdi.

If you need to find where something is declared, a grep is always helpful. Grep all the .h files in the compiler directory for the declaration of TransparentBlt. Often you can get away with #including that file, though sometimes include files require certain other include files to be included first, but don't include them. This drives me crazy with the windows include files shipped with microsoft. Basically it requires some detective work, but eventually you can get it right.

roger
1st June 2006, 09:03 AM
p.s. a quick google on transparentblt and Dev-C++ indicates that this is a common problem with that package. Yay, I say, because now you get to understand how transparent bmps are done, rather than rely on a magic API call that does it for you. :D

Banbury
2nd June 2006, 03:52 AM
Why reinvent the wheel. There are about a gazillion game engines out there for sprite painting.
SpriteCraft (http://spritecraft.teggo.com/) is really easy to use for example.

Darat
2nd June 2006, 04:08 AM
Why reinvent the wheel. There are about a gazillion game engines out there for sprite painting.
SpriteCraft (http://spritecraft.teggo.com/) is really easy to use for example.

It's good fun and a great way to learn about the fundamentals.

Fuzake
6th June 2006, 07:17 AM
Yeah... um. As I have said before, downloading is out... No SpriteCraft for me... I'm stuck with Win32. Crap; now you've made me sad. Thanks anyway... I wish I had a better connection. I would use it if I could. :o

roger
6th June 2006, 07:46 AM
It's a 1mb download. Surely you can download 1mb.

Fuzake
7th June 2006, 08:43 AM
Got it! I have SpriteCraft. But... the example code is in VB, which I only know a little of, and the actual C++ code is not only in Visual C++, but way beyond my level of experience. So what I'm going to do is take that as an example thing and create my own game engine. Maybe there's an "Advanced C++ For Dummies" out there that I should check out. Or maybe even "Advanced Game/Windows Programming For Dummies". Yeaaahh...:rolleyes:

roger
7th June 2006, 08:53 AM
I think that is a good idea - glean what you can from that package, and write your own. If you want to create great games, you need to roll your own anyway - using somebody else's package means you will be a year or two behind the curve, always catching up, never being original. That's a bit overstated, but largely true.

CodeGuru (http://forums.randi.org/www.codeguru.com) is another site with a lot of tutorials. The GDI and graphics sections are very applicable. For example, in the bitmap section is an article (http://www.codeguru.com/cpp/g-m/bitmap/article.php/c1753/)on making transparent bitmaps. Be warned - the code quality in these is quite variable. Don't take everything as gospel.

Fuzake
12th June 2006, 08:45 AM
Thanks! I am working on the SpriteCraft-based engine now. The particle system looks to be the hardest part because I have never (successfully) used OpenGL before.

rockoon
13th June 2006, 05:41 AM
Beware of using TransparentBlt() on Win95 and Win98 machines, as it has a well known resource leak on those operating systems when unpatched.

Fuzake
13th June 2006, 08:08 AM
Yep. But, um, looking back at your posts, I don't know what the heck a Grep is. Can anyone explain? And I am using a 98, which might be it... I have already encountered this suggestion from the guys on RPG-Dev.net and RPGDX.net.

roger
13th June 2006, 09:09 AM
grep searches for text within a file. It is a unix utility, but there are many windows variants. In Windows Explorer, the find function allows you to search inside of files. grep is much more powerful, and worth knowing about, but for this purpose the windows search facility is fine.

But, as I pointed out, your compiler does not support TransparentBlt, so you can't use it anyway.

Fuzake
14th June 2006, 09:37 AM
Okay. I'll do that. Since my compiler doesn't support TransparentBlt(), I'll have to use OpenGL. This could be a problem.

roger
14th June 2006, 09:41 AM
No, since your compiler doesn't support TransparentBlt(), you just need to write your own TransparentBlt routine. :) I provided a link above on how to do that.

Fuzake
15th June 2006, 12:00 PM
Which one?

Almo
21st June 2006, 01:05 PM
BTW: grep rules. It whomps major ass. But: a friend of mine said:

grep is as powerful as it is unfriendly.

:)