Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 975
I Phantasm I Avatar asked Jun 09 '11 03:06

I Phantasm I


1 Answers

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.

like image 106
Ben Voigt Avatar answered Oct 07 '22 21:10

Ben Voigt