Использование GLFW для рендеринга и WinAPI для обработки сообщений - PullRequest
1 голос
/ 20 сентября 2011

Я хочу использовать библиотеку OpenGL, GLFW, для рендеринга окна, но также хочу использовать WinAPi для создания элементов управления и обработки событий.Есть какой-либо способ сделать это ?Я пытался искать (прибегая к помощи) «использование glfw и winapi», но это не дало никаких результатов.Единственная найденная мной страница, которая сделала то, что я хотела, была эта , но страница, кажется, устарела, поскольку GLFW_WINPAR не существует.Есть ли способ сделать то, что я хочу, или я должен использовать «Vanilla» OpenGL.

1 Ответ

5 голосов
/ 20 сентября 2011

Использование GLFW не принесет особой пользы, если вы намереваетесь использовать и собственный Win32 API. Весь смысл GLFW в том, чтобы скрыть системные API, приведенные ниже.

Создание окна OpenGL с использованием только Win32 совсем не сложно:

#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);
}
...