OpenGL上下文创建永远不会选择像素格式

时间:2014-03-27 15:46:52

标签: c++ opengl glew

我正在尝试在Win32窗口中为我正在编写的库创建一个OpenGL上下文。我把它归结为一个小例子,它将编译以帮助调试它。出于某种原因,它从不正确地选择像素格式。这是代码:

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

3 个答案:

答案 0 :(得分:2)

您永远不会初始化deviceContext,这意味着它将具有垃圾值。如果你在尝试ChoosePixelFormat后调用GetLastError,我想你会发现它告诉你你的句柄无效。

答案 1 :(得分:2)

wglGetProcAddress需要创建有效的OpenGL上下文并绑定以产生合理的结果。这意味着为了使用wglCreateContextAttribsARB,您首先必须创建一个中间帮助程序OpenGL上下文,以便您访问该函数。

更新

碰巧我最近写了一些小助手来解决这个问题。根据{{​​3}}

的MIT许可条款提供

答案 2 :(得分:0)

尝试在像素格式描述符的初始化上添加它:

descriptor.cRedBits            = 8;
descriptor.cGreenBits          = 8;
descriptor.cBlueBits           = 8;