无法启动并运行我的第一个Windows opengl窗口

时间:2018-04-03 13:03:58

标签: c++ windows winapi opengl

我正在尝试启动一个将在Windows 10和我们的OpenGL上运行的应用程序。我能够在屏幕上显示一个窗口,但在初始化OpenGL后,我无法在窗口中显示颜色。我试图不使用像GLFW这样的第三方库。

我目前的代码如下:

#include <Windows.h>
#include <gl/gl.h>
#include <cassert>

#define local_persist static
#define local_func static
#define global_variable static

namespace Win64
{
    local_func void
    ProcessPendingMessages()
    {
        MSG Message;
        while(GetMessageA(&Message, 0, 0, 0))
        {
            switch(Message.message)
            {
                case WM_QUIT:
                {
                } break;

                case WM_SYSKEYDOWN:
                case WM_SYSKEYUP:
                case WM_KEYDOWN:
                case WM_KEYUP:
                {
                    uint32 VKCode = (uint32)Message.wParam;

                    if(VKCode == 'W')
                    {
                    }
                    else if(VKCode == 'A')
                    {
                    }
                    else if(VKCode == 'S')
                    {
                    }
                    else if(VKCode == 'D')
                    {
                    }
                    else if(VKCode == 'Q')
                    {
                    }
                    else if(VKCode == 'E')
                    {
                    }
                    else if(VKCode == VK_UP)
                    {
                    }
                    else if(VKCode == VK_LEFT)
                    {
                    }
                    else if(VKCode == VK_DOWN)
                    {
                    }
                    else if(VKCode == VK_RIGHT)
                    {
                    }
                    else if(VKCode == VK_ESCAPE)
                    {
                    }
                    else if(VKCode == VK_SPACE)
                    {
                    }
                }

                default:
                {
                    TranslateMessage(&Message);
                    DispatchMessageA(&Message);
                } break;
            }
        }
    };

    LRESULT CALLBACK
    ProgramWindowCallback(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam)
    {
        LRESULT Result{0};

        switch(Message)
        {
            case WM_SIZE:
            {
                OutputDebugStringA("WM_SIZE\n");
            }break;

            case WM_DESTROY:
            {
                OutputDebugStringA("WM_DESTROY\n");
            }break;

            case WM_CLOSE:
            {
                OutputDebugStringA("WM_CLOSE\n");
            }break;

            case WM_ACTIVATEAPP:
            {
                OutputDebugStringA("WM_ACTIVATEAPP\n");
            }break;

            case WM_PAINT:
            {
                PAINTSTRUCT Paint;
                RECT ClientRect;
                GetClientRect(WindowHandle, &ClientRect);

                HDC DeviceContext = BeginPaint(WindowHandle, &Paint);

                LONG Width = ClientRect.right - ClientRect.left;
                LONG Height = ClientRect.bottom - ClientRect.top;

                glViewport(0, 0, Width, Height);
                glClearColor(1.0f, 0.0f, 1.0f, 0.0f);
                glClear(GL_COLOR_BUFFER_BIT);
                SwapBuffers(DeviceContext);

                EndPaint(WindowHandle, &Paint);
            }break;

            default:
            {
                Result = DefWindowProc(WindowHandle, Message, wParam, lParam);
            }break;
        }

        return Result;
    };
}

int CALLBACK WinMain(HINSTANCE CurrentProgramInstance, HINSTANCE PrevInstance, LPSTR CommandLine, int ShowCode)
{
    WNDCLASS WindowProperties{};

    //TODO: Check if OWNDC/HREDRAW/VEDRAW matter
    WindowProperties.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
    WindowProperties.lpfnWndProc = Win64::ProgramWindowCallback;
    WindowProperties.hInstance = CurrentProgramInstance;
    WindowProperties.lpszClassName = "MemoWindowClass";

    if(RegisterClass(&WindowProperties))
    {
        HWND Window = CreateWindowEx(0, WindowProperties.lpszClassName, "Memo", WS_OVERLAPPEDWINDOW|WS_VISIBLE, 
                                     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, CurrentProgramInstance, 0);

        if(Window)
        {
            HDC WindowDeviceContext = GetDC(Window);

            { //Init OpenGL
                HGLRC OpenGLRenderingContext = wglCreateContext(WindowDeviceContext);

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

                int SuggestedPixelFormatIndex = ChoosePixelFormat(WindowDeviceContext, &DesiredPixelFormat);
                PIXELFORMATDESCRIPTOR SuggestedPixelFormat{};
                DescribePixelFormat(WindowDeviceContext, SuggestedPixelFormatIndex, sizeof(SuggestedPixelFormat), &SuggestedPixelFormat);

                if (SetPixelFormat(WindowDeviceContext, SuggestedPixelFormatIndex, &SuggestedPixelFormat))
                {
                    if (wglMakeCurrent(WindowDeviceContext, OpenGLRenderingContext))
                    {
                        //Success!
                    }
                    else
                    {
                        //Log error
                        assert(1 == 0);
                    }
                }
                else
                {
                    //Log error
                    assert(1 == 0);
                }
            }

            Win64::ProcessPendingMessages();
        }
    }

    return 0;
}

我期待glClear()清除我在glClearColor()中设置的颜色。然而,这并没有发生。我做错了什么?

2 个答案:

答案 0 :(得分:1)

wglCreateContext()之前移动调用wglMakeCurrent的行,并在设置像素格式(SetPixelFormat()调用)之后移动。

if (SetPixelFormat(WindowDeviceContext, SuggestedPixelFormatIndex, &SuggestedPixelFormat))
{
    HGLRC OpenGLRenderingContext = wglCreateContext(WindowDeviceContext);
    if (wglMakeCurrent(WindowDeviceContext, OpenGLRenderingContext))
    //...

Creating a Rendering Context and Making It Current

OpenGL Win32 Tutorial Sample Code

答案 1 :(得分:0)

我不知道这是不是问题,但是在许多OpenGL样本中有一个可怕的反模式,它使用CS_OWNDC创建一个窗口类,然后假设在程序启动时调用wglMakeCurrent一次是安全的,并且再也不会

从窗口类中省略CS_OWNDC样式是远远的,更安全,只需使用wglMakeCurrent将所有入口点包装到OpenGl调用中进行设置和清理。

模式是,你想用OpenGL做一些事情,所以你适当地调用GetDC / BeginPaint得到一个窗口DC,然后你调用wglMakeCurrent传递dc和gl rc句柄,做你的OpenGL调用,然后就在你之前调用ReleaseDC / EndPaint,再次调用wglMakeCurrent传递NULL,NULL。

遵循这个基本建议,您可以在一个线程上安全地创建多个open gl窗口实例,并且您不必担心某些第三方代码可能会创建并临时创建其自己的GL上下文。