It does seem like it is due to the OpenGL canvas drawing over the top of the UI.
I did some more digging but couldn’t not find a way to make the canvas display behind the UI but I did find a bit of a workaround.
This post mentions that mixing opengl and wx is not advised but mentioned a workaround to make it work. FAQ: wxWidgets and OpenGL - wxWidgets Discussion Forum
The penultimate question reads:
Q. Can I mix OGL and wx controls?
A. Normally, not. The OS and the GPU will fight for the window.
But you can render to a not-shown buffer (GL_BACK, or better a FBO ) without SwapBuffers, then read the picture by glReadPixels, and set it as a background of the window.
I have implemented this in wxpython and it mostly works on the mac but I am having issues with it not updating.
Each frame instead of calling canvas.SwapBuffers()
I am calling canvas.Refresh()
which triggers the paint event. The paint function looks like this. It gets the image from the renderer and sets it as the background image.
def _on_paint(self, evt):
if sys.platform != "win32":
dc = wx.PaintDC(self)
size = self.GetClientSize()
width = size.width * self.GetContentScaleFactor()
height = size.height * self.GetContentScaleFactor()
img = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
btmap = wx.Image(width, height, img).Scale(size.width, size.height).Mirror(False).ConvertToBitmap()
dc.DrawBitmap(btmap, 0, 0)
All of this works as expected. The rendered image is displayed behind the UI and the canvas can be interacted with.
The issue is that the image only changes when the window is moved or resized or programs are switched between. Interestingly after doing this it will draw the next hadful of frames correctly and then go back into its frozen state. The same also applies to the UI itself.
A few more things to mention. If a dialog is opened and moved around the screen the section around it will update correctly. If instead of calling Refresh
you call Hide
and then Show
it animates correctly but as expected you can’t interact with the canvas for more than a frame.
TLDR: I have mostly gotten what I want working. The rendered image is behind the UI but Refresh
is not updating the screen. It requires a forced redraw by tabbing between programs to get the display to update.