Help end child hunger
Jul 102012
 

I’ve been working for some time with wxWidgets. The only thing I’ve missed, regarding OpenGL, is the ability to define my own OpenGL context, in particular Core profile and Debug contexts.

To be able to set a context we, or the toolkit we’re using, must use the wglCreateContextAttribsARB function, as defined in the WGL_ARB_create_context extension. As it happens, wxWidgets uses wglCreateContext, hence no OpenGL context can be explicitly defined using the provided source code for the current release (2.9.4).

As OpenGL context setting is not yet in the roadmap for future releases of wxWidgets, nor is it in its Todo List, I’m sharing a solution for this issue.

The solution is for the Windows platform, but other platforms should be as easy to change as well.

Note: I make no claim regarding the quality of the solution, it worked for me, and that’s all I claim. If anyone knows of a better way of doing this comments are most welcome, as they may prove useful for other readers (and me as well 🙂 ).

What I want is the possibility to specify the context attributes as a parameter when calling the wxGLcanvasconstructor.

The solution involves changing two files in the standard distribution: glcanvas.cpp and glcanvas.h.

For the Windows platform, these files can be located in (starting from the root of your installation):

  • glcanvas.h : include/wx/msw
  • glcanvas.cpp : src/msw

glcanvas.h

In wxGLContext class add a public static variable to store the context attribute list:

static const int* m_glContextAttribs;

This var will store the attrib list, and it will be set in the wxGLCanvas constructor. Later, in wxGLContext constructor it will be used to set the required context.

In the wxGLCanvas class, we must modify the constructor and Create method so that they’ll receive an extra parameter, the context attribute list.

wxGLCanvas(wxWindow *parent,
		wxWindowID id = wxID_ANY,
		const int *attribList = NULL,
		const int *contextAttribs = NULL,
		const wxPoint& pos = wxDefaultPosition,
		const wxSize& size = wxDefaultSize,
		long style = 0,
		const wxString& name = wxGLCanvasName,
		const wxPalette& palette = wxNullPalette);

bool Create(wxWindow *parent,
		wxWindowID id = wxID_ANY,
		const wxPoint& pos = wxDefaultPosition,
		const wxSize& size = wxDefaultSize,
		long style = 0,
		const wxString& name = wxGLCanvasName,
		const int *attribList = NULL,
		const int *contextAttribs = NULL,
		const wxPalette& palette = wxNullPalette);

glcanvas.cpp

In this file we must first add some definitions to be able to use the wglCreateContextAttribsARB function.

I placed the following two lines just before the wxGLContext constructor:

extern HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList);
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);

It is also necessary to initialize the static variable m_glContextAttribs:

const int* wxGLContext::m_glContextAttribs = NULL;

Setting it to NULL by default it will provide the default context.

The wxGLContext constructor must be rewritten as follows:

wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext* other)
{

	if (m_glContextAttribs == NULL) {

	    m_glContext = wglCreateContext(win->GetHDC()); 
	}
	else {

		HGLRC hTempRC = wglCreateContext(win->GetHDC()); 
		wglMakeCurrent(win->GetHDC(), hTempRC);
		PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB");
		wglMakeCurrent(win->GetHDC(), NULL);
		wglDeleteContext(hTempRC);

		m_glContext = wglCreateContextAttribsARB(win->GetHDC(), 0, m_glContextAttribs);
	}

    wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") );

    if ( other )
    {
        if ( !wglShareLists(other->m_glContext, m_glContext) )
        {
            wxLogLastError(wxT("wglShareLists"));
        }
    }
}

Moving on the wxGLCanvas class, in the same file, we need to change two methods: the constructor and one of the Create methods.

The constructor receives an extra argument, the context attribute list contextAttribs, and calls the Create, also with the extra argument.

wxGLCanvas::wxGLCanvas(wxWindow *parent,
		wxWindowID id,
		const int *attribList,
		const int *contextAttribs,
		const wxPoint& pos,
		const wxSize& size,
		long style,
		const wxString& name,
		const wxPalette& palette)
{
    Init();
    (void)Create(parent, id, pos, size, style, name, attribList, contextAttribs, palette);
}

Changes to the Creat method, from wxGLCanvas class are few, only the attribute list, to receive the extra argument, and a call to initialize the argument list static variable, m_glContextAttribs, we declared for the wxGLContext class. The remaining of the method stays as is.

bool wxGLCanvas::Create(wxWindow *parent,
		wxWindowID id,
		const wxPoint& pos,
		const wxSize& size,
		long style,
		const wxString& name,
		const int *attribList,
		const int *contextAttribs,
		const wxPalette& palette)
{

	wxGLContext::m_glContextAttribs = contextAttribs;

        ...
}

That’s it! Now, from our application, when calling the wxGLCanvas constructor, we just need to add the context attribute list after the attribute list for the pixel format.

  2 Responses to “Working with Core OpenGL in WX Wigets”

  1. I still need to recompile the library with these changes right?
    It does not seem to work ;_;

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: