• Quick note - the problem with Youtube videos not embedding on the forum appears to have been fixed, thanks to ZiprHead. If you do still see problems let me know.

Win32 API Question

Fuzake

Student
Joined
May 30, 2006
Messages
28
: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:
 
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.


Code:
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);
}
 
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:
 
Sorry, that is MFC code. But pretty much all these calls have equivalent win32 API calls.

to wit:

Code:
   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;
 
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.
 
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?
 
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:

Code:
#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
 
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, looking through their articles and tutorials on Win32 programming. For instance, there's an entire section devoted to working with Bitmaps, and another one devoted to just Windows GDI in general. Don't be afraid to ask questions you may have, or ask for help, in their various programming forums.
 
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:
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:
 
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.
 
Example using TransparentBlt. I paint the background black, and use white as my transparent color:

Code:
   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;
 
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?
 
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.
 
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:
 
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.
 
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.
 
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
 
Why reinvent the wheel. There are about a gazillion game engines out there for sprite painting.
SpriteCraft is really easy to use for example.
 
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
 

Back
Top Bottom