Question

I'm trying to create an OpenGL context inside a Win32 window for a library I'm writing. I've boiled it down to a small example which will compile to help debug it. For some reason, it never chooses a pixel format properly. Here's the code:

#include <iostream>
#include <windows.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/wglew.h>

HWND handle;
HDC deviceContext;
HGLRC context;
int resolutionX = 1280;
int resolutionY = 720;
std::string title = "Test Window";

LRESULT CALLBACK eventCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

int main()
{
    // Register the window class
    WNDCLASSA windowClass;
    windowClass.style         = 0;
    windowClass.lpfnWndProc   = &eventCallback;
    windowClass.cbClsExtra    = 0;
    windowClass.cbWndExtra    = 0;
    windowClass.hInstance     = GetModuleHandle(nullptr);
    windowClass.hIcon         = nullptr;
    windowClass.hCursor       = nullptr;
    windowClass.hbrBackground = nullptr;
    windowClass.lpszMenuName  = nullptr;
    windowClass.lpszClassName = "Test_Window";
    RegisterClassA(&windowClass);

    // Compute position and size
    HDC screenDC = GetDC(nullptr);
    int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast<int>(resolutionX)) / 2;
    int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(resolutionY)) / 2;
    int width = resolutionX;
    int height = resolutionY;
    ReleaseDC(nullptr, screenDC);

    // Set window style
    DWORD win32Style = WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_SYSMENU;

    // In windowed mode, adjust width and height so that window will have the requested client area
    RECT rectangle = {0, 0, width, height};
    AdjustWindowRect(&rectangle, win32Style, false);
    width = rectangle.right - rectangle.left;
    height = rectangle.bottom - rectangle.top;


    // Create the window
    handle = CreateWindowA("Test_Window", title.c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(nullptr), nullptr);
    if(handle == NULL)
    {
        std::cout << "Failed to create window" << std::endl;
        return 1;
    }

    // Setup a pixel format descriptor from the rendering settings
    PIXELFORMATDESCRIPTOR descriptor;
    ZeroMemory(&descriptor, sizeof(descriptor));
    descriptor.nSize        = sizeof(descriptor);
    descriptor.nVersion     = 1;
    descriptor.iLayerType   = PFD_MAIN_PLANE;
    descriptor.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    descriptor.iPixelType   = PFD_TYPE_RGBA;
    descriptor.cColorBits   = static_cast<BYTE>(32);
    descriptor.cDepthBits   = static_cast<BYTE>(24);
    descriptor.cStencilBits = static_cast<BYTE>(8);
    descriptor.cAlphaBits   = 8;

    // Get the pixel format that best matches our requirements
    int bestFormat = ChoosePixelFormat(deviceContext, &descriptor);
    if(bestFormat == 0)
    {
        std::cout << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
        return 1;
    }

    // Extract the depth and stencil bits from the chosen format
    PIXELFORMATDESCRIPTOR actualFormat;
    actualFormat.nSize    = sizeof(actualFormat);
    actualFormat.nVersion = 1;
    DescribePixelFormat(deviceContext, bestFormat, sizeof(actualFormat), &actualFormat);

    // Set the chosen pixel format
    if(!SetPixelFormat(deviceContext, bestFormat, &actualFormat))
    {
        std::cout << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
        return 1;
    }

    PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
    if(wglCreateContextAttribsARB)
    {
        int attributes[] =
        {
            WGL_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(3),
            WGL_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(0),
            WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
            0, 0
        };

        context = wglCreateContextAttribsARB(deviceContext, nullptr, attributes);
    }

    if(!context)
    {
        context = wglCreateContext(deviceContext);

        if(!context)
        {
            std::cout << "Failed to create the OpenGL context" << std::endl;
            return 1;
        }
    }

    // Destroy the OpenGL context
    wglMakeCurrent(nullptr, nullptr);
    wglDeleteContext(context);

    // Destroy the device context
    ReleaseDC(handle, deviceContext);

    // Destroy the window handle
    DestroyWindow(handle);

    // Unregister the window
    UnregisterClassA("Test_Window", GetModuleHandle(nullptr));

    std::cout << "Window created" << std::endl;

    return 0;
}

LRESULT CALLBACK eventCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // Associate handle and Window instance when the creation message is received
    if(message == WM_CREATE)
    {
        LONG_PTR window = (LONG_PTR)reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams;

        // Set as the "user data" parameter of the window
        SetWindowLongPtr(hwnd, GWLP_USERDATA, window);
    }

    return DefWindowProcA(hwnd, message, wParam, lParam);
}
Was it helpful?

Solution

You never initialize deviceContext, which means that it will have a garbage value. If you call GetLastError after trying ChoosePixelFormat, I imagine that you'll find that it's telling you that you have an invalid handle.

OTHER TIPS

wglGetProcAddress needs a valid OpenGL context being created and bound to yield a sensible result. Which means that in order to use wglCreateContextAttribsARB you first have to create an intermediary helper OpenGL context that gives you access to that function.

Update

As it happens I recently wrote some small helper to deal with this. Available under the terms of the MIT license at https://github.com/datenwolf/wglarb

Try to add this on the initialization of pixel format descriptor:

descriptor.cRedBits            = 8;
descriptor.cGreenBits          = 8;
descriptor.cBlueBits           = 8;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top