【问题标题】:Using GLFW to render and WinAPI to handle messages使用 GLFW 渲染和 WinAPI 处理消息
【发布时间】:2011-11-21 06:26:18
【问题描述】:

我想使用 OpenGL 库 GLFW 来渲染窗口,但也想使用 WinAPi 创建控件和处理事件。有没有办法做到这一点? 我尝试搜索(谷歌搜索)“使用 glfw 和 winapi”,但没有产生任何结果。 我发现的唯一符合我要求的页面是this,但该页面似乎已经过时,因为 GLFW_WINPAR 不存在。有什么方法可以做我想做的事,还是我必须使用“Vanilla”OpenGL。

【问题讨论】:

  • 也愿意使用 glut 库来代替 glfw。

标签: c++ winapi opengl glfw


【解决方案1】:

如果您还打算使用本机 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);
}

【讨论】:

  • 您可能需要更新它以至少使用 wglChoosePixelFormatARB,如果不是 wglCreateContextAttribsARB。没有前者,您甚至无法进行多重采样,而没有后者,您将无法获得核心上下文。
  • @Nicol Bolas:你当然是对的。坦率地说,我只是从大约 10 年前写的一些(过时的)教程中复制并粘贴了这个。会调整的。
  • 所以没有办法通过 glfw 实际使用按钮和标签等控件?
  • @viraj:您可以使用 OpenGL 绘制它们。有许多基于 OpenGL 的 GUI 库。使用 OpenGL 绘制整个 GUI 的复杂应用程序的一个示例是 Blender,但是 GUI 系统被深度集成到其中,即没有独立的库。不过值得一看参考。
  • @viraj:然而,更大的问题是:你为什么要使用原生的、神秘的 Win32 API?只要您不开发工具包,我就没有理由这样做。为什么不简单地使用支持 OpenGL 的成熟、现代、广泛使用的工具包,例如 Qt?
猜你喜欢
  • 2013-01-14
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2020-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多