◆GLUTを使わずに頑張る(1) 2004.5.5(ガキんちょの日)


私はGLUTライブラリが大好きでWin32 APIがめんどくさいと思っているのであまりやりたくはなかったのですが、現時点ではGLUTの動作がなんとなくアヤシイ※ので、GLUTを使わずに書いてみようと思います。

※WinXPでは全く問題は見つかってないけど、Win2000でおかしな動きが多少見られます。たとえばウィンドウサイズを変えた場合にプログラムが終了してしまったり、[×]をクリックして閉じると見た目は終了しているがプロセスに残っている時がある。何が原因なのかははっきりしないけど、主にphobos(std.c.windows.windows)の問題のような気がします。

dmdのサンプルに、winsamp.dというファイルがあったのでそれをいじってみました。


/* Compile with:
 *  dmd wgl01 opengl32.lib glu32.lib gdi32.lib wgl01.def
 */

import std.c.windows.windows;
import std.c.stdio;
import gl.gl;
import gl.glu;

import gdi32;

extern(Windows)
int WindowProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    static HGLRC hRC;
    PAINTSTRUCT ps;
    GLdouble aspect;
    GLsizei width, height;

    switch (uMsg)
    {
        case WM_CREATE:
            hRC = InitGL( hWnd );
            break;
        case WM_SIZE:
            hDC = GetDC(hWnd);
            wglMakeCurrent(hDC, hRC);
            width = (GLsizei)LOWORD(lParam);
            height = (GLsizei)HIWORD(lParam);
            aspect = (GLdouble)width/height;
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluPerspective(30.0, aspect, 1.0, 10.0);
            glViewport(0, 0, width, height);
            wglMakeCurrent(cast(HWND) null, cast(HGLRC) null);
            ReleaseDC(hWnd, hDC);
            break;
        case WM_ERASEBKGND:
            return TRUE;//いちいち消すなっちゅうの
        case WM_PAINT:
            hDC = BeginPaint(hWnd, &ps);        
            wglMakeCurrent(hDC, hRC);
            DrawScene();
            SwapBuffers(hDC);
            wglMakeCurrent(cast(HWND) null, cast(HGLRC) null);
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            wglDeleteContext(hRC);
            PostQuitMessage(0);
        break;

        default:
        break;
    }
    return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}

int doit()
{
    HINSTANCE hInst = GetModuleHandleA(null);
    WNDCLASS wc;
    wc.lpszClassName = "DWndClass";
    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = &WindowProc;
    wc.hInstance = hInst;
    wc.hIcon = LoadIconA(cast(HINSTANCE) null, IDI_APPLICATION);
    wc.hCursor = LoadCursorA(cast(HINSTANCE) null, IDC_ARROW);
    wc.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1);
    wc.lpszMenuName = null;
    wc.cbClsExtra = wc.cbWndExtra = 0;
    assert(RegisterClassA(&wc));
    
    HWND hWnd, btnClick, btnDontClick;
    hWnd = CreateWindowA("DWndClass", "OpenGL test1", 
//      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
    WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, HWND_DESKTOP,
        cast(HMENU) null, hInst, null);
    assert(hWnd);
    
    MSG msg;
    while (GetMessageA(&msg, cast(HWND) null, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    
    return 1;
}


HGLRC InitGL(HWND hWnd)
{
    static PIXELFORMATDESCRIPTOR pfd = {
            40, //sizeof(PIXELFORMATDESCRIPTOR),
            1,
            PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER |PFD_TYPE_RGBA,
            24,
            0, 0, 0,
            0, 0, 0,
            0, 0,
            0, 0, 0, 0, 0,
            32,
            0,
            0,
            PFD_MAIN_PLANE,
            0,
            0,
            0,
            0
    };

    int pixelFormatID;
    HDC hDC;
    HGLRC hRC;

    hDC = GetDC(hWnd);
    pixelFormatID = ChoosePixelFormat(hDC, &pfd);
    SetPixelFormat(hDC, pixelFormatID, &pfd);
    hRC = wglCreateContext(hDC);
    ReleaseDC(hWnd, hDC);

    return hRC;
}

void DrawScene(){
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -5.0);

    glBegin(GL_POLYGON);
    glColor3f(0.0, 0.0, 1.0);
    glVertex3f(1.0, 1.0, 0.0);
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f(-1.0, 1.0, 0.0);
    glColor3f(1.0, 0.0, 0.0);
    glVertex3f(-1.0, -1.0, 0.0);
    glColor3f(1.0, 1.0, 1.0);
    glVertex3f(1.0, -1.0, 0.0);
    glColor3f(0.0, 0.0, 1.0);
    glVertex3f(1.0, 1.0, 0.0);
    glEnd();
}

/**********************************************************/

/* Note the similarity of this code to the console D startup
 * code in \dmd\src\phobos\dmain2.d
 * You'll also need a .def file with at least the following in it:
 *  EXETYPE NT
 *  SUBSYSTEM WINDOWS
 */

extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleUnitTests();

extern (Windows)
int WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    int result;

    gc_init();          // initialize garbage collector
    _minit();           // initialize module constructor table

    try
    {
    _moduleCtor();      // call module constructors
    _moduleUnitTests(); // run unit tests (optional)

    result = doit();    // insert user code here
    }

    catch (Object o)        // catch any uncaught exceptions
    {
    MessageBoxA(null, (char *)o.toString(), "Error",
            MB_OK | MB_ICONEXCLAMATION);
    result = 0;     // failed
    }

    gc_term();          // run finalizers; terminate garbage collector
    return result;
}

あ、そうそう。今のところstd.c.windows.windowsが不完全なので、その場しのぎのgdi32.dというファイルを作ってます。簡単に言うと、このプログラムで呼ばれるwglXxxとかSwapBuffers等の関数が宣言されていないので、使われそうな所だけ書き出しました。ソースに直接書き込んでもよいのだけど、無駄に長くなるので分けてます。上のソースと一緒にしておきますのでここからダウンロードしてください。(makefileもオマケ)

展開したフォルダ内で"make"とすれば大丈夫なハズ。
ダメならdmd wgl01 opengl32.lib glu32.lib gdi32.lib wgl01.defと入力してチョ。
makefileってなんじゃいって人はここを読むべし。

実行するとこんなかんじになります。

わりと簡単♪



トップに戻る 前に戻る 次に進む