🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Win32 GDI - Need help Adding a bitmap to this example

Started by
37 comments, last by aston2 4 years, 2 months ago

8Observer8 said:

@rafaelsantana could you build your game from the video above to EXE and attach it in an achieve?

I'll do it this weekend but I have to build a good base map first.

Advertisement

Hello Endurion and Airbatz..

I copy source code of this GDI win32 api examples and code compile and run fine .

I am using mingW with Falcon++ IDE.

I have question, i want to add new sprite, and i add it with LoadImage() func and sprite become visible with BitBlt…then i add arrow keys under WM_KEYDOWN ..but when i

pressing keys nothing heappend, i also check key respond with MessageBox and it looks that WM_KEYDOWN is somehow ignored…nothing …any help here ?

this is the code :

case WM_COMMAND:
    	{
           // SHOULD REALLY USE GetAsyncKeyState for game, but simplified here
           switch (wParam)
           {
           case VK_LEFT:
               spriteX=spriteX-4;
                MessageBox( hwnd, "KEY LEFT PRESSED!", "KEY_LEFT", MB_OK | MB_ICONEXCLAMATION );
               break;
           case VK_RIGHT:
               spriteX=spriteX+4;
               break;
           case VK_UP:
               spriteY=spriteY-4;
               break;
           case VK_DOWN:
               spriteY=spriteY+4;
               break;

A) The snippet you pasted shows WM_COMMAND, not WM_KEYDOWN

B) WM_KEYDOWN is posted when the key is pushed down, WM_KEYUP once the key is released. You have to remember the key state somewhere, and check it periodically in your Update code (you do have something like this?)

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Hi Endurion

Sorry i mix up keydown and wm_command..

Most of time i am using basic compiler called o2 which is also native compiler.

So i don't have much experience with C compilers but all api looking same:

here is whole code:

#define WIN32_LEAN_AND_MEAN
#define TIMER_VELOCITY 1
#define TIMER_ANIMATE  2

#include <windows.h>
#include <stdlib.h>
//#include "resource.h"

HICON hMyIcon;
HBITMAP graphics[4];
HBITMAP g_hbmMask = NULL;
HDC hdcBuffer;
HBITMAP hbmBuffer;
int spriteX = 320, spriteY = 400;

typedef struct SpriteAnimation
{
  int xpos; 
  int ypos; 
  int frames; 
  int x_velocity; 
  int counter; 
  int direction; 

}SAKURA;
 SAKURA g_spriteInfo;

HBITMAP CreateBitmapMask( HBITMAP hbmColour, COLORREF crTransparent )
{
  HDC hdcMem, hdcMem2;
  HBITMAP hbmMask;
  BITMAP bm;

  GetObject( hbmColour, sizeof( BITMAP ), &bm );
  hbmMask = CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL );

  hdcMem = CreateCompatibleDC( 0 );
  hdcMem2 = CreateCompatibleDC( 0 );

  SelectObject( hdcMem, hbmColour );
  SelectObject( hdcMem2, hbmMask );

  SetBkColor( hdcMem, crTransparent );

  BitBlt( hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY );
  BitBlt( hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT );

  DeleteDC( hdcMem );
  DeleteDC( hdcMem2 );

  return hbmMask;
}

void DrawScene( HDC hdc, RECT* prc )
{
  HDC hdcBuffer         = CreateCompatibleDC( hdc );
  HBITMAP hbmBuffer     = CreateCompatibleBitmap( hdc, prc->right, prc->bottom );
  HBITMAP hbmOldBuffer  = (HBITMAP)SelectObject( hdcBuffer, hbmBuffer );
  HDC hdcMem            = CreateCompatibleDC( hdc );

  BitBlt(hdcBuffer, g_spriteInfo.xpos, g_spriteInfo.ypos, 32, 32, hdcMem, 4*(g_spriteInfo.frames%1), 0, SRCAND); //the sprite G
 // BitBlt(hdcBuffer, spriteX, spriteY, 32, 32, hdcMem, 1, 0, SRCAND); //the sprite ship
  
  SelectObject(hdcMem,graphics[1]); // sprG
  BitBlt(hdcBuffer, g_spriteInfo.xpos, g_spriteInfo.ypos, 32, 32, hdcMem, 4*(g_spriteInfo.frames%1), 0, SRCPAINT); //spr G
  
  SelectObject(hdcMem,graphics[3]); // ship
  BitBlt(hdcBuffer, spriteX, spriteY, 32, 32, hdcMem, 0, 0, SRCPAINT); //ship

  SelectObject(hdcMem,graphics[1]);
  BitBlt( hdc, 0, 0, prc->right, prc->bottom, hdcBuffer, 0, 0, SRCCOPY );
  
 // SelectObject(hdcMem,graphics[3]); //ship
  //BitBlt( hdc, spriteX, spriteY, 32, 32 , hdcBuffer, 0, 0, SRCCOPY ); //ship
  

  SelectObject( hdcMem, hbmBuffer );
  DeleteDC( hdcMem );

  SelectObject( hdcBuffer, hbmOldBuffer );
  DeleteDC( hdcBuffer );
  DeleteObject( hbmBuffer );
}

void AnimateSprite( RECT* prc )
{
g_spriteInfo.frames+=TIMER_ANIMATE;
}

void UpdateSpritePosition( RECT* prc )
{
  g_spriteInfo.ypos += TIMER_VELOCITY; 
  g_spriteInfo.counter++;

		if(g_spriteInfo.counter == 8)
		{
			if(g_spriteInfo.direction == 0 )
                {
                g_spriteInfo.x_velocity = 2; 
                g_spriteInfo.direction = 1; 
                }

			else if (g_spriteInfo.direction == 1) 
                {
                g_spriteInfo.x_velocity = -2; 
                g_spriteInfo.direction = 0; 
			}
			g_spriteInfo.counter = 0; 
		}
		g_spriteInfo.xpos += g_spriteInfo.x_velocity;

if ( g_spriteInfo.ypos > 460 ) //when the sprite goes beyond the bottom of the window 
  {
     g_spriteInfo.ypos = -7; //re-set the position of the sprite to be above the top of the window
     g_spriteInfo.xpos = abs(rand()*400/RAND_MAX); //randomize the x position of the sprite
  }
   if (spriteX > 640) // if out pf window
    {
	   spriteX == 0;	
    }	

  
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
  switch ( msg )
  {
    case WM_CREATE:
      {
        BITMAP bm;
        SelectObject(hdcBuffer, hbmBuffer);
        graphics[1] = LoadImageA( 0, "C:\\man.bmp", 0, 32,32,16 );
        graphics[3] = LoadImageA( 0, "C:\\ship.bmp", 0, 32,32,16 );
   
        graphics[0] = CreateBitmapMask( graphics[1], RGB( 0, 0, 0 ) );
        graphics[2] = CreateBitmapMask( graphics[3], RGB( 0, 0, 0 ) );

        GetObject( graphics, sizeof( bm ), &bm );

        ZeroMemory( &g_spriteInfo, sizeof( g_spriteInfo ) );
        g_spriteInfo.xpos = abs(rand()*405/RAND_MAX+10); //randomize starting x position
        g_spriteInfo.direction = 0;

        SetTimer( hwnd, TIMER_VELOCITY, 1, NULL );
        SetTimer( hwnd, TIMER_ANIMATE, 2, NULL );
      }
      return 0;

    case WM_COMMAND:
    	{
           // SHOULD REALLY USE GetAsyncKeyState for game, but simplified here
           switch (wParam)
           {
           case 0xCB :
               spriteX=spriteX-4;
                MessageBox( hwnd, "KEY LEFT PRESSED!", "KEY_LEFT", MB_OK | MB_ICONEXCLAMATION );
               break;
           case VK_RIGHT:
               spriteX=spriteX+4;
               break;
           case VK_UP:
               spriteY=spriteY-4;
               break;
           case VK_DOWN:
               spriteY=spriteY+4;
               break;
           }	
      //return 0;--------------------------------------------------------
		}
    case WM_CLOSE:
      DestroyWindow( hwnd );
      return 0;

    case WM_PAINT:
      {
        RECT rcClient;
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint( hwnd, &ps );
        GetClientRect( hwnd, &rcClient );

        DrawScene( hdc, &rcClient );

        EndPaint( hwnd, &ps );
      }
      return 0;
//--------------------------------------------------------------------------
    case WM_TIMER:
      {
        RECT rcClient;
        GetClientRect( hwnd, &rcClient );

    switch(wParam)
      {
      case TIMER_VELOCITY:
        UpdateSpritePosition( &rcClient );
        //spriteX = spriteX+1;
        break;

      case TIMER_ANIMATE:
        AnimateSprite( &rcClient );
        break;
      }
        InvalidateRect( hwnd, NULL, 0 );
      }
      return 0;
      
      case WM_ERASEBKGND:
      return 1;

    case WM_DESTROY:
      KillTimer( hwnd, TIMER_VELOCITY );
      KillTimer( hwnd, TIMER_ANIMATE );
      DeleteObject( graphics );
      DeleteObject( g_hbmMask );

      PostQuitMessage( 0 );
      return 0;
  }
  return DefWindowProc( hwnd, msg, wParam, lParam );
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
  hMyIcon = LoadIconW( hInstance, "\myicon.ico");
  WNDCLASSEX wc = {0};
  HWND hwnd;
  MSG Msg;

  wc.cbSize = sizeof( WNDCLASSEX );
  wc.style = 0;
  wc.lpfnWndProc = WndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = hMyIcon;
  wc.hIconSm = NULL;
  wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  wc.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
  wc.lpszMenuName = NULL;
  wc.lpszClassName = TEXT( "Buttons" );

  RegisterClassEx( &wc );

  hwnd = CreateWindowEx( 0, TEXT("Buttons"), "Movin Ghost",
    WS_OVERLAPPED | WS_SYSMENU |WS_VISIBLE |WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL );

  ShowWindow( hwnd, nCmdShow );
  UpdateWindow( hwnd );

  while ( GetMessage( &Msg, NULL, 0, 0 ) > 0 )
  {
    TranslateMessage( &Msg );
    DispatchMessage( &Msg );
  }
  return Msg.wParam;
}

[quote]HDC hdcBuffer = CreateCompatibleDC(hdc); HBITMAP hbmBuffer = CreateCompatibleBitmap(hdc, prc->right, prc->bottom);
[/quote]

Don't create a new bitmap and new DC everytime you paint. Cache these values and re-use them!

enum Bool { True, False, FileNotFound };

Don't create a new bitmap and new DC everytime you paint. Cache these values and re-use them!

OK thanks ..

but do you can help with code ,how to do that ?

aston2 said:

Don't create a new bitmap and new DC everytime you paint. Cache these values and re-use them!

Didn't I already tell him this? O.o

Yes i just post quoted text…

I need some code because i don't know how?

Make them global. Only create them if they are the INVALID_HANDLE_VALUE.

/*globally*/
HDC hdcBuffer = (HDC)INVALID_HANDLE_VALUE;
HBITMAP hbmBuffer = (HBITMAP)INVALID_HANDLE_VALUE;

void DrawScene(HDC hdc, LPRECT prc)
{
  if (hdcBuffer == (HDC)INVALID_HANDLE_VALUE) {
    hdcBuffer = CreateCompatibleDC( hdc );
  }
  if (hbmBuffer == (HBITMAP)INVALID_HANDLE_VALUE) {
    hbmBuffer = CreateCompatibleBitmap( hdc, prc->right, prc->bottom );
  }
  …
}

Note that, if your window changes client rect size, you need to re-create the bitmap. You could, for example, call DeleteObject(hbmBuffer) and set hbmBuffer to INVALID_HANDLE_VALUE in the WM_SIZE message handler.

Finally, it turns out that a better way of running a message pump than using a TIMER is to call InvalidateRect(window, &clientRect) on the window after you call EndPaint(). This will make sure there is always a WM_PAINT message waiting to be drawn, but the rules for message priority is that all other messages have higher priority than WM_PAINT, so user input will still get delivered. Then you want to update simulation right before WM_PAINT if enough time has passed, rather than using WM_TIMER for that.

enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement