Popo Heche
Popo Heche

Reputation: 75

Create Modern OpenGL context using WGL?

I'm trying to create an OpenGL context (Modern Version) using Windows functions.

Basically the code is just:

  1. Create window class
  2. Register the class
  3. create a Window
  4. choose PIXELFORMATDESCRIPTOR & set it
  5. Create a legacy OpenGL context
  6. Make context current
  7. glewInit()
  8. Create new window
  9. Create a modern pixel format attrib array
  10. Set the format
  11. Create modern OpenGL context
  12. Make context current

After this I try to draw a square (using a VAO & VBO).

The result is: the Windows window works, the glClear(GL_COLOR_BUFFER_BIT) works, but the square is not drawn (display() function).

If I use an OpenGL 2.0 context, it draws the square (using a VAO & VBO as before), so the problem must be on the init of OpenGL 3.2.

Where am I going wrong?

Here is the code:

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

Upvotes: 3

Views: 5316

Answers (1)

BDL
BDL

Reputation: 22168

The problem is not in the context creation code alone, but in the combination of the used OpenGL version and the drawing code.

When requesting an OpenGL context as it is done in the question, there are several attributes that can be set. The relevant one here is the WGL_CONTEXT_PROFILE_MASK_ARB (which is not set). The extension description states:

The default value for WGL_CONTEXT_PROFILE_MASK_ARB is WGL_CONTEXT_CORE_PROFILE_BIT_ARB. [...] If the requested OpenGL version is less than 3.2, WGL_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality of the context is determined solely by the requested version.

This means that the code in the question requests a OpenGL 3.2 Core Profile in the not working version a 3.1 (compatibility) profile in the other case.

In a core profile, the use of GL_QUADS as mode for glDrawArrays is deprecated and cannot be used. Due to this, the quad isn't rendered. Note, that you would have found the problem ways faster if you would check for OpenGL errors (glGetError) in your code since it would have reported a GL_INVALID_ENUM for the draw command.

There are two ways how the problem can be solved:

  • Stop drawing quads and draw triangles instead (GL_TRIANGLES). This is the recommended way.
  • Explicitly request a OpenGL 3.2 compatibility profile by adding a WGL_CONTEXT_PROFILE_MASK_ARB with the value WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB. But note, that this might cause problems in the future because mixing old OpenGL code with modern OpenGL can lead to problems.

Upvotes: 2

Related Questions