使用GLFW渲染和WinAPI来处理消息

时间:2011-09-20 16:44:38

标签: c++ winapi opengl glfw

我想使用OpenGL库GLFW来渲染窗口,但也希望使用WinAPi来创建控件和处理事件。有没有办法做到这一点? 我尝试搜索(谷歌搜索)“使用glfw和winapi”,但没有产生任何结果。 我找到的唯一一个我想要的页面是this,但由于GLFW_WINPAR不存在,页面似乎已经过时了。有没有办法做我想要的,或者我必须使用“Vanilla”OpenGL。

1 个答案:

答案 0 :(得分:5)

如果您打算使用本机Win32 API,那么使用GLFW并没有多大好处。 GLFW的重点是隐藏下面的系统API。

单独使用Win32创建一个OpenGL窗口并不那么难:

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

namespace viewwnd
{
    HWND    hWnd;
    HDC     hDC;
    HGLRC   hRC;
};

namespace render
{
    int win_width;
    int win_height;
}

typedef HGLRC (*wglprocCreateContextAttribsARB)(HDC, HGLRC, const int *);
typedef BOOL (*wglprocChoosePixelFormatARB)(HDC, const int *, const FLOAT *, UINT,int *,UINT *);

#define VIEWCLASS   "ViewWnd"
#define VIEWSTYLE   WS_VISIBLE|WS_POPUP|WS_MAXIMIZE

BOOL OpenGLWindowCreate()
{
    srand((unsigned)time(NULL));
    using namespace viewwnd;
    {
        WNDCLASS wc;
        memset(&wc,0,sizeof(wc));
        wc.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
        wc.lpfnWndProc = ViewProc;
        wc.hInstance = GetModuleHandle(NULL);
        wc.lpszClassName = VIEWCLASS;
        RegisterClass(&wc);
    }

    /* Create a temporaray context to get address of wgl extensions. */

    HWND hTmpWnd= CreateWindowEx(   WS_EX_APPWINDOW,
                    VIEWCLASS,
                    "Simple",
                    VIEWSTYLE,
                    0,0,0,0,
                    NULL,NULL,
                    hInstance,
                    NULL);
    if(!hTmpWnd)
        return FALSE;

    HDC hTempDC = GetDC(hTempWnd);
    if(!hTempDC) {
        DestroyWindow(hTempWnd);
        return FALSE;
    }

    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd,0,sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 24;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int iPF;
    if( (!(iPF = ChoosePixelFormat(hTempDC, &pfd)) || !SetPixelFormat(hTempDC, iPF, &pfd)) ||

        (!(hTempRC = wglCreateContext(hTempDC)) || !wglMakeCurrent(hTempDC,hTempRC)) ) {
        ReleaseDC(hTempDC);
        DestroyWindow(hTempWnd);
        return FALSE;
    }

    /* Like all extensions in Win32, the function pointers returned by wglGetProcAddress are tied
     * to the render context they were obtained with. Since this is a temporary context, we
     * place those function pointers in automatic storage of the window and context creation function. */
    wglprocCreateContextAttribsARB wglCreateContextAttribsARB = (wglprocCreateContextAttribsARB) wglGetProcAddress("wglCreateContextAttribsARB");
    wglprocChoosePixelFormatARB wglChoosePixelFormatARB = (wglprocChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");

    if( wglChoosePixelFormatARB && wglCreateContextAttribsARB ) {
        /* good we have access to extended pixelformat and context attributes */
        hWnd = CreateWindowEx(  WS_EX_APPWINDOW,
                    VIEWCLASS,
                    "Simple",
                    VIEWSTYLE,
                    0,0,0,0,
                    NULL,NULL,
                    hInstance,
                    NULL);

        if(!hWnd) {
            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(hTempRC);
            ReleaseDC(hTempDC);
            DestroyWindow(hTempWnd);

            return FALSE;
        }

        hDC = GetDC(hWnd);
        if(!hDC) {
                DestroyWindow(hWnd);

            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(hTempRC);
            ReleaseDC(hTempDC);
            DestroyWindow(hTempWnd);

            return FALSE;
        }

        int attribs[] = {
            WGL_DRAW_TO_WINDOW_ARB, TRUE,
            WGL_DOUBLE_BUFFER_ARB, TRUE,
            WGL_SUPPORT_OPENGL_ARB, TRUE, 
            WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
            WGL_COLOR_BITS_ARB, 24,
            WGL_RED_BITS_ARB, 8,
            WGL_GREEN_BITS_ARB, 8,
            WGL_BLUE_BITS_ARB, 8,
            WGL_DEPTH_BITS_ARB, 24,
            WGL_STENCIL_BITS_ARB, 8,
            0, 0
        };
        UINT num_formats_choosen;
        BOOL choose_pf_success = wglChoosePixelFormatARB(
            hDC, 
            attribs, 
            NULL,
            1,
            &iPF,
            &num_formats_choosen);

        /* now this is a kludge; we need to pass something in the PIXELFORMATDESCRIPTOR 
         * to SetPixelFormat; it will be ignored, mostly. OTOH we want to send something
         * sane, we're nice people after all - it doesn't hurt if this fails. */
        DescribePixelFormat(hDC, iPF, sizeof(pfd), &pfd);

        if(!( choose_pf_success && 
              num_formats_choosen >= 1 && 
              SetPixelFormat(hDC, iPF, &pfd) )) {
            ReleaseDC(hDC);
            DestroyWindow(hWnd);

            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(hTempRC);
            ReleaseDC(hTempDC);
            DestroyWindow(hTempWnd);

            return FALSE;
        }

        /* we request a OpenGL-3 compatibility profile */
            int context_attribs[] = {
            WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
            WGL_CONTEXT_MINOR_VERSION_ARB, 0,
            WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB | WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
            0, 0
        };
        hRC = wglCreateContextAttribARB(hDC, NULL, context_attribs);
        if(!hRC) {
            ReleaseDC(hDC);
            DestroyWindow(hWnd);

            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(hTempRC);
            ReleaseDC(hTempDC);
            DestroyWindow(hTempWnd);
            return FALSE;
        }
        wglMakeCurrent(hDC, hRC);

        /* now that we've created the proper window, DC and RC
         * we can delete the temporaries */
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(hTempRC);
        ReleaseDC(hTempDC);
        DestroyWindow(hTempWnd);

    } else {
        /* extended pixelformats and context attributes not supported
         * => use temporary window and context as the proper ones */
        hWnd = hTempWnd;
        hDC = hTempDC;
        hRC = hTempRC;
    }

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    return TRUE;
}

void OnOpenGLWindowDestroy()
{
    using namespace viewwnd;
    wglMakeCurrent(NULL,NULL);
    wglDeleteContext(hRC);
    ReleaseDC(hWnd,hDC);
    UnregisterClass(VIEWCLASS, GetModuleHandle(NULL));
    PostQuitMessage(0);
}

LRESULT CALLBACK ViewProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    using namespace viewwnd;
    switch(uMsg)
    {
    case WM_DESTROY:
        OnOpenGLWindowDestroy();
        break;
    case WM_PAINT:
        display();
        break;
    case WM_SIZE:
        reshape(LOWORD(lParam),HIWORD(lParam));
        break;
    default:
        break;
    }
    return DefWindowProc(hWnd,uMsg,wParam,lParam);
}


void reshape(int w,int h)
{
    win_width = w;
    win_height = h;
}

void display()
{
    using namespace viewwnd;
    using namespace render;

    glViewport(0, 0, win_width, win_heighth);

    glClearColor(0., 0., 0., 1.);
    glClearDepth(1.);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45,ratio,0.1,100);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    SwapBuffers(hDC);
}