ソフトウェア開発 Win32プログラミング

Win32/OpenGL 2D

戻る


Win32 APIでOpenGLを使って、描画を試してみた。

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>

static const TCHAR g_szCaption[] = TEXT("Win32/OpenGL 2D");
static const TCHAR g_szClassName[] = TEXT("Win32 Template");
 
#define FPS 50
#define FRAME_RATE (1000 / FPS)
 
#define WIDTH  300
#define HEIGHT 300
 
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")

HINSTANCE g_hInstance;
HWND g_hMainWnd;
 
PIXELFORMATDESCRIPTOR g_pfd =
{
    sizeof(PIXELFORMATDESCRIPTOR),   // size
    1,                      // version number
    PFD_DRAW_TO_BITMAP |    // draw to bitmap
    PFD_SUPPORT_OPENGL,     // support OpenGL
    PFD_TYPE_RGBA,          // RGBA type
    24,                     // 24-bit color depth
    0, 0, 0, 0, 0, 0,       // color bits ignored
    0,                      // no alpha buffer
    0,                      // shift bit ignored
    0,                      // no accumulation buffer
    0, 0, 0, 0,             // accum bits ignored
    32,                     // 32-bit z-buffer
    0,                      // no stencil buffer
    0,                      // no auxiliary buffer
    PFD_MAIN_PLANE,         // main layer
    0,                      // reserved
    0, 0, 0                 // layer masks ignored
};
 
BITMAPINFO g_bi = {
    {
        sizeof(BITMAPINFOHEADER), // size
        WIDTH, HEIGHT,      // width and height
        1,                  // planes
        24,                 // bits
        BI_RGB,             // compression
        0, 0, 0, 0, 0
    }
};
 
HBITMAP g_hbm;
LPVOID g_pvBits;
HDC g_hdc;
HGLRC g_hglrc;
HGDIOBJ g_hbmOld;
 
INT OnCreate(HWND hWnd)
{
    g_hbm = CreateDIBSection(NULL, &g_bi, DIB_RGB_COLORS, &g_pvBits,
        NULL, 0);
    if (g_hbm == NULL)
    {
        MessageBox(NULL, TEXT("NG1"), NULL, 0);
        return -1;
    }
    g_hdc = CreateCompatibleDC(NULL);
    if (g_hdc == NULL)
    {
        DeleteObject(g_hbm);
        MessageBox(NULL, TEXT("NG2"), NULL, 0);
        return -1;
    }
 
    g_hbmOld = SelectObject(g_hdc, g_hbm);
 
    INT iPixelFormat = ChoosePixelFormat(g_hdc, &g_pfd);
    SetPixelFormat(g_hdc, iPixelFormat, &g_pfd);
 
    g_hglrc = wglCreateContext(g_hdc);
    if (g_hglrc == NULL)
    {
        SelectObject(g_hdc, g_hbmOld);
        DeleteObject(g_hbm);
        MessageBox(NULL, TEXT("NG3"), NULL, 0);
        return -1;
    }
    return 0;
}
 
VOID OnDestroy(HWND hWnd)
{
    SelectObject(g_hdc, g_hbmOld);
    wglMakeCurrent(NULL, NULL);
    DeleteDC(g_hdc);
    wglDeleteContext(g_hglrc);
    DeleteObject(g_hbm);
    PostQuitMessage(0);
}
 
LRESULT CALLBACK
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CREATE:
        return OnCreate(hWnd);
 
    case WM_DESTROY:
        OnDestroy(hWnd);
        break;
 
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}
 
VOID Draw(HWND hWnd, DWORD dwTimeDiff)
{
    static FLOAT theta = 0.0f;
    wglMakeCurrent(g_hdc, g_hglrc);
 
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
 
    glShadeModel(GL_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
 
    glPushMatrix();
        gluOrtho2D(0, WIDTH, HEIGHT, 0); // top-down
        //gluOrtho2D(0, WIDTH, 0, HEIGHT); // bottom-up
        glBegin(GL_LINES);
            glColor3f(1.0f, 0.0f, 0.0f);    // red
            glVertex2i(0, 0);
            glColor3f(0.0f, 1.0f, 0.0f);    // green
            glVertex2i(WIDTH, HEIGHT);
        glEnd();
        INT c = 10;
        glBegin(GL_LINES);
            glColor3f(0.0f, 0.0f, 1.0f);    // blue
            glVertex2i(c, c);
            glVertex2i(WIDTH - c, c);
            glVertex2i(WIDTH - c, c);
            glVertex2i(WIDTH - c, HEIGHT - c);
            glVertex2i(WIDTH - c, HEIGHT - c);
            glVertex2i(c, HEIGHT - c);  
            glVertex2i(c, HEIGHT - c);  
            glVertex2i(c, c);
        glEnd();
    glPopMatrix();
    glPushMatrix();
        glRotatef(theta, 0.0f, 0.0f, 1.0f);
        glBegin(GL_TRIANGLES);
            glColor4f(1.0f, 0.0f, 0.0f, 0.75f); // red
            glVertex2f(0.0f, 1.0f);
            glColor4f(0.0f, 1.0f, 0.0f, 0.75f); // green
            glVertex2f(0.87f, -0.5f);
            glColor4f(0.0f, 0.0f, 1.0f, 0.75f); // blue
            glVertex2f(-0.87f, -0.5f);
        glEnd();
    glPopMatrix();
 
    CHAR sz[64];
    wsprintf(sz, TEXT("%ldFPS"), 1000 / (FRAME_RATE + dwTimeDiff));
    RECT rc = {0, 0, 100, 100};
    SetBkMode(g_hdc, OPAQUE);
    DrawText(g_hdc, sz, -1, &rc, DT_NOCLIP | DT_NOPREFIX);
 
    HDC hdc = GetDC(hWnd);
    BitBlt(hdc, 0, 0, WIDTH, HEIGHT, g_hdc, 0, 0, SRCCOPY);
    ReleaseDC(hWnd, hdc);
 
    theta += 1.0f;
}
 
INT WINAPI WinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    LPSTR       pszCmdLine,
    INT         nCmdShow)
{
    WNDCLASSEX wcx;
    MSG msg;
    BOOL f;
 
    g_hInstance = hInstance;
    wcx.cbSize          = sizeof(WNDCLASSEX);
    wcx.style           = 0;
    wcx.lpfnWndProc     = WindowProc;
    wcx.cbClsExtra      = 0;
    wcx.cbWndExtra      = 0;
    wcx.hInstance       = hInstance;
    wcx.hIcon           = LoadIcon(NULL, IDI_APPLICATION);
    wcx.hCursor         = LoadCursor(NULL, IDC_ARROW);
    wcx.hbrBackground   = (HBRUSH)(COLOR_3DFACE + 1);
    wcx.lpszMenuName    = NULL;
    wcx.lpszClassName   = g_szClassName;
    wcx.hIconSm         = (HICON)LoadImage(NULL, IDI_APPLICATION,
        IMAGE_ICON, 
        GetSystemMetrics(SM_CXSMICON), 
        GetSystemMetrics(SM_CYSMICON), 0);
    if (!RegisterClassEx(&wcx))
        return 1;
 
    DWORD style = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;
    RECT rc;
    rc.left = rc.top = 0;
    rc.right = WIDTH;
    rc.bottom = HEIGHT;
    AdjustWindowRect(&rc, style, FALSE);
    SIZE siz;
    siz.cx = rc.right - rc.left;
    siz.cy = rc.bottom - rc.top;
 
    g_hMainWnd = CreateWindow(g_szClassName, g_szCaption, 
        style, CW_USEDEFAULT, 0, siz.cx, siz.cy,
        NULL, NULL, hInstance, NULL);
    if (g_hMainWnd == NULL)
        return 2;
 
    ShowWindow(g_hMainWnd, nCmdShow);
    UpdateWindow(g_hMainWnd);
 
    ::timeBeginPeriod(1);
    DWORD dwTime, dwNextTime = ::timeGetTime() + FRAME_RATE;
    for(;;)
    {
        if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
        {
            f = ::GetMessage(&msg, NULL, 0, 0);
            if (!f || f == -1)
                break;
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
        else
        {
            dwTime = ::timeGetTime();
            if (dwTime < dwNextTime)
            {
                ::Sleep(1);
                continue;
            }
            Draw(g_hMainWnd, dwTime - dwNextTime);
            dwNextTime = dwTime + FRAME_RATE;
        }
    }
    ::timeEndPeriod(1);
    return (INT)msg.wParam;
}

このコードでは、ウィンドウに直接描画するのではなく、ビットマップに一度描いてから、ウィンドウに転送している。多分、その方が応用が利くと思われる。

Win32でOpenGLを使うには、最初にChoosePixelFormatとSetPixelFormatでピクセルフォーマットというものを設定しなければいけない。それから、描画する前に、wglMakeCurrentで描画したいコンテキストを選ぶ必要がある。

描画を行っているDraw関数を見てほしい。まず最初にwglMakeCurrentを呼ぶ。その後、glClearColorとglClear関数で消去する。glShadeModelでなめらかに描画されるように設定する。glEnable(GL_BLEND);とglBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);でアルファブレンドが行われるように設定する。 gluOrtho2D(0, WIDTH, HEIGHT, 0);は、座標系を設定している。glBeginで次に描画する図形を設定した上で実際の描画を開始し、glEndで終了する。glColor*は色の設定、glVertex*は頂点の設定を行っている。

glBegin(GL_TRIANGLES);で描画した三角形が半透明になっているのが確認できる。

ソース: ogl2d.zip


戻る

©片山博文MZ
katayama.hirofumi.mz@gmail.com

inserted by FC2 system