e-fs.info

画像描画クラス


画像読込みをクラス化

画像表示 2Dゲームでは、画像をたくさん使う。
なので、画像読込み自体をクラス化させ汎用的に使う。

そうすると、画像を簡単に表示できる

対応している画像拡張子はBMPのみです
classが入ってくるが、1ファイルになっている

実行サンプル

使い方

#pragma comment(lib,"msimg32.lib")    // TransparentBltに必要
#include <wingdi.h>
#include <string>

class Graphic{
private:
    HDC m_graphichdc;
    HDC m_hdc;
    HANDLE m_hbmp;
    BITMAP m_bitmap;

public:
    Graphic();
    Graphic(HDC hdc,std::string filename);
    ~Graphic();

    void Create(HDC hdc,std::string filename);
    bool TrDraw(HDC hdc,int x,int y,int width = 0,int height = 0,int px = 0,int py = 0,UINT color = RGB(255,255,255));
    bool TrDraw(int x,int y,int width = 0,int height = 0,int px = 0,int py = 0,UINT color = RGB(255,255,255));
    bool Draw(HDC hdc,int x,int y,int width = 0,int height = 0,int px = 0,int py = 0);
    bool Draw(int x,int y,int width = 0,int height = 0,int px = 0,int py = 0);
    void SetHDC(HDC hdc){ m_hdc = hdc;}
    HDC GetGraphicHDC(){ return m_graphichdc;}
    BITMAP GetBitmap(){ return m_bitmap;}
};

Graphic::Graphic(){}

Graphic::Graphic(HDC hdc,std::string filename){
    Create(hdc,filename);
}

Graphic::~Graphic(){
    ReleaseDC(g_hwnd,m_graphichdc);
    ReleaseDC(g_hwnd,m_hdc);
    DeleteObject(m_hbmp);
}

void Graphic::Create(HDC hdc,std::string filename){
    m_hdc  = hdc;
    m_hbmp = LoadImage(GetModuleHandle(NULL),filename.c_str(),IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    m_graphichdc = CreateCompatibleDC(m_hdc);
    SelectObject(m_graphichdc,m_hbmp);
    GetObject(m_hbmp,sizeof(HBITMAP),&m_bitmap);
}

bool Graphic::TrDraw(HDC hdc,int x,int y,int width,int height,int px,int py,UINT color){
    if(width == 0){
        TransparentBlt(hdc,x,y,m_bitmap.bmWidth,m_bitmap.bmHeight,m_graphichdc,px,py,m_bitmap.bmWidth,m_bitmap.bmHeight,color);
    }else{
        TransparentBlt(hdc,x,y,width,height,m_graphichdc,px,py,width,height,color);
    }
    return true;
}

bool Graphic::TrDraw(int x,int y,int width,int height,int px,int py,UINT color){
    TrDraw(m_hdc,x,y,width,height,px,py,color);
    return true;
}

bool Graphic::Draw(HDC hdc,int x,int y,int width,int height,int px,int py){
    if(width == 0){
        BitBlt(hdc,x,y,m_bitmap.bmWidth,m_bitmap.bmHeight,m_graphichdc,px,py,SRCCOPY);
    }else{
        BitBlt(hdc,x,y,width,height,m_graphichdc,px,py,SRCCOPY);
    }
    return true;
}

bool Graphic::Draw(int x,int y,int width,int height,int px,int py){
    Draw(m_hdc,x,y,width,height,px,py);
    return true;
}

具体的な使い方
Graphic sekitori;
sekitori.Create(hdc,"ファイルの名前.bmp");

sekitori.Draw(hdc, x, y, width, height, px, py);
Draw関数の第4、第5引数は画像の大きさ
Draw関数の第6、第7引数は画像内のx,y(複数の絵がファイルに描かれていた時などに使う)

プログラム

#include <windows.h>
#include <windowsx.h>

#pragma comment(lib,"msimg32.lib")// TransparentBltに必要
#include <wingdi.h>
#include <string>

HWND g_hwnd;
const int  WINX        = 320;
const int  WINY        = 240;
const char TITLE[]    = "Win06";
const int  nFramesPerSecond = 30;

class Graphic{
private:
    HDC m_graphichdc;
    HDC m_hdc;
    HANDLE m_hbmp;
    BITMAP m_bitmap;

public:
    Graphic();
    Graphic(HDC hdc,std::string filename);
    ~Graphic();

    void Create(HDC hdc,std::string filename);
    bool TrDraw(HDC hdc,int x,int y,int width = 0,int height = 0,int px = 0,int py = 0,UINT color = RGB(255,255,255));
    bool TrDraw(int x,int y,int width = 0,int height = 0,int px = 0,int py = 0,UINT color = RGB(255,255,255));
    bool Draw(HDC hdc,int x,int y,int width = 0,int height = 0,int px = 0,int py = 0);
    bool Draw(int x,int y,int width = 0,int height = 0,int px = 0,int py = 0);
    void SetHDC(HDC hdc){ m_hdc = hdc;}
    HDC GetGraphicHDC(){ return m_graphichdc;}
    BITMAP GetBitmap(){ return m_bitmap;}
};

Graphic::Graphic(){}

Graphic::Graphic(HDC hdc,std::string filename){
    Create(hdc,filename);
}

Graphic::~Graphic(){
    ReleaseDC(g_hwnd,m_graphichdc);
    ReleaseDC(g_hwnd,m_hdc);
    DeleteObject(m_hbmp);
}

void Graphic::Create(HDC hdc,std::string filename){
    m_hdc  = hdc;
    m_hbmp = LoadImage(GetModuleHandle(NULL),filename.c_str(),IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    m_graphichdc = CreateCompatibleDC(m_hdc);
    SelectObject(m_graphichdc,m_hbmp);
    GetObject(m_hbmp,sizeof(HBITMAP),&m_bitmap);
}

bool Graphic::TrDraw(HDC hdc,int x,int y,int width,int height,int px,int py,UINT color){
    if(width == 0){
        TransparentBlt(hdc,x,y,m_bitmap.bmWidth,m_bitmap.bmHeight,m_graphichdc,px,py,m_bitmap.bmWidth,m_bitmap.bmHeight,color);
    }else{
        TransparentBlt(hdc,x,y,width,height,m_graphichdc,px,py,width,height,color);
    }
    return true;
}

bool Graphic::TrDraw(int x,int y,int width,int height,int px,int py,UINT color){
    TrDraw(m_hdc,x,y,width,height,px,py,color);
    return true;
}

bool Graphic::Draw(HDC hdc,int x,int y,int width,int height,int px,int py){
    if(width == 0){
        BitBlt(hdc,x,y,m_bitmap.bmWidth,m_bitmap.bmHeight,m_graphichdc,px,py,SRCCOPY);
    }else{
        BitBlt(hdc,x,y,width,height,m_graphichdc,px,py,SRCCOPY);
    }
    return true;
}

bool Graphic::Draw(int x,int y,int width,int height,int px,int py){
    Draw(m_hdc,x,y,width,height,px,py);
    return true;
}

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
bool Query(LONGLONG&,DWORD&);
void Release(HDC&,HWND&,char*);
void Mainloop(HDC hdc,const int frame);
bool Start(HDC hdc);
bool End(HDC hdc);



HDC Back_Init_Surface(HWND hwnd)
{
    HDC hdc,BackDC;
    HBITMAP hBackBMP;

    hdc=GetDC(hwnd);
    BackDC=CreateCompatibleDC(hdc);
    hBackBMP=CreateCompatibleBitmap(hdc,WINX,WINY);
    SelectObject(BackDC,hBackBMP);
    PatBlt(BackDC,0,0,WINX,WINY,WHITENESS);
    DeleteObject(hBackBMP);
    ReleaseDC(hwnd,hdc);

    return BackDC;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR lpCmdLine,int nCmdShow)
{
    MSG msg;
    WNDCLASSEX wc;
    HWND hwnd;

    ZeroMemory(&wc,sizeof(WNDCLASSEX));

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style        = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc    = WndProc;
    wc.lpszMenuName = NULL;
    wc.hInstance    = hInstance;
    wc.hIcon        = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_SHARED);
    wc.hIconSm        = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_SHARED);
    wc.hCursor        = (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(IDC_ARROW),IMAGE_CURSOR,0,0,LR_DEFAULTCOLOR | LR_SHARED);
    wc.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszClassName= TITLE;

    if(!RegisterClassEx(&wc))return FALSE;

    // ウィンドウのスタイル
    // WS_OVERLAPPEDWINDOW = 大抵のやつを有効にしろ
    // & ~WS_THICKFRAME = WS_OVERLAPPEDWINDOWからサイズ変更を無効に
    // & ~WS_MAXIMIZEBOX = WS_OVERLAPPEDWINDOWから最大化を無効に
    const DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;

    // ウィンドウを作る!
    hwnd = CreateWindowEx(0,TITLE,TITLE,dwStyle,
        GetSystemMetrics(SM_CXSCREEN)/2 - WINX/2,    // 真ん中に表示
        GetSystemMetrics(SM_CYSCREEN)/2 - WINY/2,    // 真ん中に表示
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,NULL,hInstance,NULL);

    if(!hwnd)return FALSE;

    g_hwnd = hwnd;

    //----- ウィンドウサイズをWINX WINY の大きさに。------
    RECT window_rect;
    SetRect(&window_rect,0,0,WINX,WINY);
    AdjustWindowRectEx(&window_rect,GetWindowLong(hwnd,GWL_STYLE),GetMenu(hwnd) != NULL,GetWindowLong(hwnd,GWL_EXSTYLE));
    const int nWidth  = window_rect.right  - window_rect.left;
    const int nHeight = window_rect.bottom - window_rect.top;
    SetWindowPos(hwnd,NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
    //----- WINX WINY の大きさに。E -----

    // ちらつきが起こるのでダブルバッファ
    HDC BackDC = Back_Init_Surface(hwnd);
    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);
    
    HDC hdc=GetDC(hwnd);

    //----- QueryPerformance準備 -----//
    LONGLONG llCurrentTime,llNextTime;
    DWORD dwTimeCount;
    if(!Query(llNextTime,dwTimeCount))
        Release(hdc,hwnd,"QueryPerformanceの失敗");
    //----- QueryPerformance準備 E -----//

    int frame = 0;    // 開始時からの合計フレーム数
    bool active;    // ウィンドウはアクティブ?
    
    // ループ前の準備
    Start(BackDC);

    for(;;){
        active = (hwnd == GetActiveWindow()) ? (IsIconic(hwnd)? true : false) : true;
        if(active || PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){
            if(!GetMessage(&msg,(HWND)NULL,0,0))break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }else{
            // nFramesPerSecondで決められたFPSに固定
            QueryPerformanceCounter((LARGE_INTEGER *)&llCurrentTime);
            if (llCurrentTime > llNextTime){
                // 白で塗りつぶし
                PatBlt(BackDC,0,0,WINX,WINY,WHITENESS);
                if(!active){Mainloop(BackDC,frame);}
                // メインの画面に描画
                BitBlt(hdc,0,0,WINX,WINY,BackDC,0,0,SRCCOPY);
                llNextTime += dwTimeCount;
                if(llNextTime < llCurrentTime)llNextTime = llCurrentTime + dwTimeCount;
            }
        }
        frame++;
    }

    // 破棄などの処理
    End(BackDC);
    ReleaseDC(hwnd,hdc);

    return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
    switch(msg){
        case WM_KEYDOWN:
            if(wParam != VK_ESCAPE){return 0;}
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            break;
    }
    return (DefWindowProc(hwnd,msg,wParam,lParam));
}

void Release(HDC &hdc,HWND &hwnd,char *str)
{
    MessageBox(hwnd,str,"失敗",MB_OK | MB_ICONSTOP);
    if(!hdc)ReleaseDC(hwnd,hdc);
    PostQuitMessage(0);
}

bool Query(LONGLONG &llNextTime,DWORD &dwTimeCount){

    LONGLONG llPerformanceCounter;
    if(!QueryPerformanceFrequency((LARGE_INTEGER *)&llPerformanceCounter))return false;
    dwTimeCount = (DWORD)(llPerformanceCounter / nFramesPerSecond);
    if(!QueryPerformanceCounter((LARGE_INTEGER *)&llNextTime))return false;

    return true;
}

void FPS_Show(HDC hdc,int x,int y)
{
    static DWORD dwTime = GetTickCount();
    static int count = 0;
    static char str[50] = "0FPS";

    count++;

    // 一秒間を測る
    if(GetTickCount() - dwTime >= 1000){
        wsprintf(str,"%dFPS",count);
        count = 0;
        dwTime = GetTickCount();
    }
    TextOut(hdc,x,y,str,lstrlen(str));
}

static int x=20,y=50;
static const int speed = 2;
static Graphic sekitori;

bool Start(HDC hdc){

    // 画像を読み込む
    sekitori.Create(hdc,"Graphic/sekitori1.bmp");

    return true;
}

// メインループ
void Mainloop(HDC hdc,const int frame){
    if(GetKeyState(VK_UP   ) & 0x80)y -= speed;
    if(GetKeyState(VK_DOWN ) & 0x80)y += speed;
    if(GetKeyState(VK_RIGHT) & 0x80)x += speed;
    if(GetKeyState(VK_LEFT ) & 0x80)x -= speed;

    sekitori.Draw(hdc,x,y,48,48,0,0);

    // FPSを表示
    FPS_Show(hdc,0,0);
}

bool End(HDC hdc){
    return true;
}