Search code examples
winapiopenglwindow

Win32 opengl Window creation


What is the best way to set up a window in win32 that has OpenGl(and glsl if the needs extra code to work) integrated into it?

I have done some research and found numerous ways of accomplishing this task i was wondering what the best way is or what way you like the most if the best way doesn't have an answer.

I have looked at nehe`s design and also the one supplied by the OpenGl super bible which both have completely different ways of accomplishing it (also the super bibles one gives me errors :().

any help would be appreciated including tutorials etc.

thanks


Solution

  • All your "different ways" aren't so different. You have to:

    • create your window (in the usual Win32 way, with RegisterClass(Ex) and CreateWindow(Ex))
    • create a GDI device context corresponding to your window (GetDC)
    • pick a pixel format which is supported by the display (optional DescribePixelFormat, then ChoosePixelFormat)
    • create your OpenGL context (wglCreateContext)
    • (optional, but required to use GLSL) link OpenGL extension functions (GLee or GLEW helpers, or glGetString(GL_EXTENSIONS) then wglGetProcAddress)
    • (optional) create an OpenGL 3.x context, free the compatibility context (wglCreateContextAttribs)
    • make the context active (wglMakeCurrent)
    • start using OpenGL (set up shader programs, load textures, draw stuff, etc.)

    An excerpt of code showing these steps in action (not suitable for copy+paste, a bunch of RAII wrappers are used):

    bool Context::attach( HWND hwnd )
    {
        PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd), 1 };
        if (!m_dc) {
            scoped_window_hdc(hwnd).swap(m_dc);
    
            pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_SUPPORT_COMPOSITION | PFD_DOUBLEBUFFER;
            pfd.iPixelType = PFD_TYPE_RGBA;
            pfd.cColorBits = 32;
            pfd.cAlphaBits = 8;
            pfd.iLayerType = PFD_MAIN_PLANE;
            auto format_index = ::ChoosePixelFormat(m_dc.get(), &pfd);
            if (!format_index)
                return false;
    
            if (!::SetPixelFormat(m_dc.get(), format_index, &pfd))
                return false;
        }
    
        auto active_format_index = ::GetPixelFormat(m_dc.get());
        if (!active_format_index)
            return false;
    
        if (!::DescribePixelFormat(m_dc.get(), active_format_index, sizeof pfd, &pfd))
            return false;
    
        if ((pfd.dwFlags & PFD_SUPPORT_OPENGL) != PFD_SUPPORT_OPENGL)
            return false;
    
        m_render_thread = ::CreateThread(NULL, 0, &RenderThreadProc, this, 0, NULL);
        return m_render_thread != NULL;
    }
    
    DWORD WINAPI Context::RenderThreadProc( LPVOID param )
    {
        Context* const ctx = static_cast<Context*>(param);
        HDC dc = ctx->m_dc.get();
    
        SIZE canvas_size;
        ctx->m_dc.check_resize(&canvas_size);
    
        scoped_hglrc glrc(wglCreateContext(dc));
    
        if (!glrc)
            return EXIT_FAILURE;
    
        if (!glrc.make_current(dc))
            return EXIT_FAILURE;
    
        if (ctx->m_major_version > 2 && GLEE_WGL_ARB_create_context) {
            int const create_attribs[] = {
                WGL_CONTEXT_MAJOR_VERSION_ARB, ctx->m_major_version,
                WGL_CONTEXT_MINOR_VERSION_ARB, ctx->m_minor_version,
                0
            };
            scoped_hglrc advrc(wglCreateContextAttribsARB(dc, 0, create_attribs));
    
            if (advrc) {
                if (!advrc.make_current(dc))
                    return EXIT_FAILURE;
                advrc.swap(glrc);
            }
        }
    
        {
            const char* ver = reinterpret_cast<const char*>(glGetString(GL_VERSION));
            if (ver) {
                OutputDebugStringA("GL_VERSION = \"");
                OutputDebugStringA(ver);
                OutputDebugStringA("\"\n");
            }
        }
    
        glDisable(GL_DITHER);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
        glClearColor(0.f, 0.f, 0.f, 1.f);
        if (GLEE_WGL_EXT_swap_control)
            wglSwapIntervalEXT(1);
    
        GLuint vao;
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
    
        while (!::InterlockedExchange(&ctx->m_stop_render, 0)) {
            ctx->process_queued_tasks();
    
            if (ctx->m_dc.check_resize(&canvas_size)) {
                glViewport(0, 0, canvas_size.cx, canvas_size.cy);
                ctx->process_on_resize();
            }
            glClear(GL_COLOR_BUFFER_BIT);
    
            glBindVertexArray(vao);
    
            ctx->process_on_render();
    
            BOOL swapped = ::SwapBuffers(dc);
            if (!swapped)
                std::cout << "::SwapBuffers failure, GetLastError() returns " << std::hex << ::GetLastError() << std::endl;
        }
    
        ctx->m_program_db.clear();
    
        return EXIT_SUCCESS;
    }
    

    It also doesn't cover window creation, it enables OpenGL on an existing window.