简体   繁体   中英

OpenGL -> wglCreateContext, wglMakeCurrent in WndProc's WM_CREATE makes rendering fail

OS: Windows 7, 64 bit Visual Studio 2010, debug, 32 bit

I'm trying out a simple Windows program to start working with openGL: all the program should do is clear the color buffer with glClear(GL_COLOR_BUFFER_BIT).

In the tutorials I found on the web, I find that people are creating and setting the openGL context during the creation of the window (and thus during the treatment of the WM_CREATE message). Somehow, I find that this doesn't work for my code and I don't seem to be able to figure it out. So if anyone could point me in the right direction.

Please find hereafter the code how I expect that it should work based on tutorials:

#include <windows.h>
#include <GL\glew.h>
#include <GL\wglew.h>

#include "Application.h"

HWND ghMainWnd = 0;

bool InitWindowsApp(HINSTANCE instanceHandle, int show);

int Run();

LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

HDC hDC;
HGLRC hGLRC;
HPALETTE hPalette;

void SetupPixelFormat()
{
    PIXELFORMATDESCRIPTOR pfd = {};
    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cAlphaBits = 8;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int pixelFormat = ChoosePixelFormat(hDC, &pfd);
    if(pixelFormat == 0)
    {
        MessageBox(ghMainWnd, L"ChoosePixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    if(!SetPixelFormat(hDC, pixelFormat, &pfd))
    {
        MessageBox(ghMainWnd, L"SetPixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }
}

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
    if(!InitWindowsApp(hInstance, nShowCmd))
        return 0;

    return Run();
}

bool InitWindowsApp(HINSTANCE instanceHandle, int show)
{
    WNDCLASS wc;
    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instanceHandle;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"BasicWndClass";

    if(!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass failed", 0, 0);
        return false;
    }

    ghMainWnd = CreateWindow(
        L"BasicWndClass",
        L"BasicWindowsApp",
        WS_OVERLAPPEDWINDOW, 
        0,
        0,
        600,
        600,
        0,
        0,
        instanceHandle,
        0);

    if(ghMainWnd == 0)
    {   
        MessageBox(0, L"CreateWindow failed", 0, 0);
        return false;
    }

    ShowWindow(ghMainWnd, show);
    UpdateWindow(ghMainWnd);

    return true;

}

int Run()
{
    MSG msg = {0};

    Application *pApp = new Application();
    pApp->Init();

    while(msg.message != WM_QUIT)
    {
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //Do Other stuff
            pApp->Draw();
            SwapBuffers(hDC);
        }
    }

    if(pApp)
    {
        delete pApp;
        pApp = nullptr;
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch(msg)
    {
    case WM_CREATE:

        hDC = GetDC(ghMainWnd);

        SetupPixelFormat();

        hGLRC = wglCreateContext(hDC);
        if(!hGLRC)
        {
            MessageBox(ghMainWnd, L"wglCreateContext() failed", L"Error", MB_ICONERROR | MB_OK);
            exit(1);
        }

        if(!wglMakeCurrent(hDC, hGLRC))
        {
            MessageBox(ghMainWnd, L"wglMakeCurrent() failed", L"Error", MB_ICONERROR | MB_OK);
            exit(1);
        }

        glViewport(0, 0, 600, 600);
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

        return 0;

    case WM_LBUTTONDOWN:

        return 0;

    case WM_KEYDOWN:
        if(wParam == VK_ESCAPE)
            DestroyWindow(ghMainWnd);

        return 0;

    case WM_DESTROY:
        if(hGLRC)
        {
            wglMakeCurrent(nullptr, nullptr);
            wglDeleteContext(hGLRC);
        }

        ReleaseDC(ghMainWnd, hDC);

        PostQuitMessage(0);

        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

Below, I found a "hack" to make it work: I basically move the opengl context creation into the InitWindowsApp() function... But why does the code above doesn't work?

#include <windows.h>
#include <GL\glew.h>
#include <GL\wglew.h>

#include "Application.h"

HWND ghMainWnd = 0;

bool InitWindowsApp(HINSTANCE instanceHandle, int show);

int Run();

LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

HDC hDC;
HGLRC hGLRC;
HPALETTE hPalette;

void SetupPixelFormat()
{
    PIXELFORMATDESCRIPTOR pfd = {};
    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cAlphaBits = 8;
    pfd.cDepthBits = 32;
    pfd.iLayerType = PFD_MAIN_PLANE;

    int pixelFormat = ChoosePixelFormat(hDC, &pfd);
    if(pixelFormat == 0)
    {
        MessageBox(ghMainWnd, L"ChoosePixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    if(!SetPixelFormat(hDC, pixelFormat, &pfd))
    {
        MessageBox(ghMainWnd, L"SetPixelFormat() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }
}

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
    if(!InitWindowsApp(hInstance, nShowCmd))
        return 0;

    return Run();
}

bool InitWindowsApp(HINSTANCE instanceHandle, int show)
{
    WNDCLASS wc;
    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = instanceHandle;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"BasicWndClass";

    if(!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass failed", 0, 0);
        return false;
    }

    ghMainWnd = CreateWindow(
        L"BasicWndClass",
        L"BasicWindowsApp",
        WS_OVERLAPPEDWINDOW, 
        0,
        0,
        600,
        600,
        0,
        0,
        instanceHandle,
        0);

    if(ghMainWnd == 0)
    {   
        MessageBox(0, L"CreateWindow failed", 0, 0);
        return false;
    }

    ShowWindow(ghMainWnd, show);
    UpdateWindow(ghMainWnd);

    hDC = GetDC(ghMainWnd);

    SetupPixelFormat();

    hGLRC = wglCreateContext(hDC);
    if(!hGLRC)
    {
        MessageBox(ghMainWnd, L"wglCreateContext() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    if(!wglMakeCurrent(hDC, hGLRC))
    {
        MessageBox(ghMainWnd, L"wglMakeCurrent() failed", L"Error", MB_ICONERROR | MB_OK);
        exit(1);
    }

    glViewport(0, 0, 600, 600);
    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

    return true;

}

int Run()
{
    MSG msg = {0};

    Application *pApp = new Application();
    pApp->Init();

    while(msg.message != WM_QUIT)
    {
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            //Do Other stuff
            pApp->Draw();
            SwapBuffers(hDC);
        }
    }

    if(pApp)
    {
        delete pApp;
        pApp = nullptr;
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch(msg)
    {
    case WM_CREATE:

        return 0;

    case WM_LBUTTONDOWN:

        return 0;

    case WM_KEYDOWN:
        if(wParam == VK_ESCAPE)
            DestroyWindow(ghMainWnd);

        return 0;

    case WM_DESTROY:
        if(hGLRC)
        {
            wglMakeCurrent(nullptr, nullptr);
            wglDeleteContext(hGLRC);
        }

        ReleaseDC(ghMainWnd, hDC);

        PostQuitMessage(0);

        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

When WM_CREATE arrives, your ghMainWnd is still NULL (the message is sent before the CreateWindow call returns). Instead, use the hWnd parameter of the message in your GetDC call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM