使用WGL创建现代OpenGL上下文?

时间:2017-10-09 21:39:40

标签: c++ winapi opengl wgl

我尝试使用Windows函数创建OpenGL上下文(现代版)。

基本上代码只是:

  1. 创建窗口类
  2. 注册课程
  3. 创建一个窗口
  4. 选择PIXELFORMATDESCRIPTOR&设置它
  5. 创建旧版OpenGL上下文
  6. 使上下文更新
  7. glewInit()
  8. 创建新窗口
  9. 创建现代像素格式attrib数组
  10. 设置格式
  11. 创建现代OpenGL上下文
  12. 使上下文更新
  13. 在此之后我尝试画一个正方形(使用VAO和VBO)。

    结果是: Windows 窗口正常工作,glClear(GL_COLOR_BUFFER_BIT)正常工作,但未绘制正方形(display()函数)。

    如果我使用OpenGL 2.0上下文,它会绘制正方形(使用VAO和VBO),因此问题必须出在OpenGL 3.2的初始化。

    我哪里错了?

    以下是代码:

    #include <iostream>
    #include <GL/glew.h>
    #include <GL/wglew.h>
    #include <windows.h>
    #include <string>
    using namespace std;
    
    bool progRun = false;
    
    void display(){
       glUseProgram(shaderProg);
       glBindVertexArray(vao[0]);
       glDrawArrays(GL_QUADS, 0,4);
    }
    
    string errorStr = "none";
    
    PIXELFORMATDESCRIPTOR pfd;
    
    HGLRC hrc; // vars to init glew
    HDC hdc;
    HWND hwnd;
    
    HGLRC hrc1; //vars for the real window
    HDC hdc1;
    HWND hwnd1;
    
    LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); // window event hadler prototype
    
    //-------------------- INIT OPENGL
    int initOpengl(
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpCmdLine,
        int       nCmdShow
    )
    {
        //---- fake Window
        WNDCLASSEX wcex;
        wcex.cbSize = sizeof( WNDCLASSEX );
        wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
        wcex.lpfnWndProc = WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = hInstance;
        wcex.hIcon = LoadIcon( NULL, IDI_APPLICATION );
        wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
        wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
        wcex.lpszMenuName = NULL;
        wcex.lpszClassName = "coco";
        wcex.hIconSm = NULL;
    
        if( !RegisterClassEx( &wcex ) )
        {
            errorStr = "RegisterClassEx";
            return 0;
        }
        hwnd = CreateWindow(
            "coco",
            "dddd",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            500, 500,
            NULL,
            NULL,
            hInstance,
            NULL
        );
    
        hdc = GetDC( hwnd );
    
        memset( &pfd, 0, sizeof( PIXELFORMATDESCRIPTOR ) );
        pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR );
        pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 32;
        pfd.cDepthBits = 32;
        pfd.iLayerType = PFD_MAIN_PLANE;
    
        int nPixelFormat = ChoosePixelFormat( hdc, &pfd );
    
        SetPixelFormat( hdc, nPixelFormat, &pfd );
    
        hrc = wglCreateContext( hdc );
    
        wglMakeCurrent( hdc, hrc );
    
        glewExperimental = true;
        glewInit();
    
        //---------------For the real window
        if( wglewIsSupported( "WGL_ARB_create_context" ) == 1 )
        {
            wglMakeCurrent( NULL, NULL );
            wglDeleteContext( hrc );
            ReleaseDC( hwnd, hdc );
            DestroyWindow( hwnd );
    
            hwnd1 = CreateWindow(
                "coco",
                "ddddd",
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                500, 500,
                NULL,
                NULL,
                hInstance,
                NULL
            );
    
            hdc1 = GetDC( hwnd1 );
    
            const int iPixelFormatAttribList[] = {
                WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
                WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
                WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
                WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
                WGL_COLOR_BITS_ARB, 32,
                WGL_DEPTH_BITS_ARB, 24,
                WGL_STENCIL_BITS_ARB, 8,
                0 // End of attributes list
            };
            int attributes[] = {
                WGL_CONTEXT_MAJOR_VERSION_ARB, 3
                , WGL_CONTEXT_MINOR_VERSION_ARB, 2
                , WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
                , 0
            };
    
            int nPixelFormat = 0;
            UINT iNumFormats = 0;
    
            wglChoosePixelFormatARB( hdc1, iPixelFormatAttribList, NULL, 1, &nPixelFormat, (UINT*)&iNumFormats );
    
            SetPixelFormat( hdc1, nPixelFormat, &pfd );
    
            hrc1 = wglCreateContextAttribsARB( hdc1, 0, attributes );
    
            wglMakeCurrent( NULL, NULL );
            wglMakeCurrent( hdc1, hrc1 );
        }
        else
        {
            errorStr = "WGL_ARB_create_context";
            return 0;
        }
        return true;
    }
    
    
    // MAIN -----
    
    int CALLBACK WinMain(
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpCmdLine,
        int       nCmdShow
    )
    {
        initOpengl( hInstance, hPrevInstance, lpCmdLine, nCmdShow );
    
        ShowWindow( hwnd1, SW_SHOW );
    
        glClearColor( 1, 0, 0, 1 );
    
        MSG msg;
        progRun = true;
    
        while( progRun )
        {
            if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
            {
                TranslateMessage( &msg );
                DispatchMessage( &msg );
            }
    
            glClear( GL_COLOR_BUFFER_BIT );
            glViewport( 0, 0, 500, 500 );
            display();
    
            SwapBuffers( hdc1 );
        }
    
        return 0;
    }
    
    LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
    {
        return DefWindowProc( hWnd, message, wParam, lParam );
    }
    

1 个答案:

答案 0 :(得分:2)

问题不仅在上下文创建代码中,而在于使用的OpenGL版本和绘图代码的组合。

在问题中完成请求OpenGL上下文时,可以设置几个属性。这里的相关内容是WGL_CONTEXT_PROFILE_MASK_ARB(未设置)。 extension description州:

  

WGL_CONTEXT_PROFILE_MASK_ARB的默认值为WGL_CONTEXT_CORE_PROFILE_BIT_ARB。 [...]如果请求的OpenGL版本低于3.2,       忽略WGL_CONTEXT_PROFILE_MASK_ARB和功能       上下文仅由所请求的版本决定。

这意味着问题中的代码在另一种情况下请求不工作版本中的OpenGL 3.2 Core Profile 3.1(兼容性)配置文件。

在核心配置文件中,GL_QUADS作为glDrawArrays模式的使用已弃用,无法使用。因此,不渲染四边形。请注意,如果您在代码中检查OpenGL错误(glGetError),您会发现问题的方式更快,因为它会为draw命令报告GL_INVALID_ENUM

有两种方法可以解决问题:

  • 停止绘制四边形并绘制三角形(GL_TRIANGLES)。这是推荐的方式。
  • 通过添加值WGL_CONTEXT_PROFILE_MASK_ARB的{​​{1}},明确请求OpenGL 3.2兼容性配置文件。但请注意,这可能会在未来引起问题,因为将旧的OpenGL代码与现代OpenGL混合会导致问题。