I am trying to learn OpenGL
and want to use wx
for the GUI window an all. I have setup a demo application to test it out, but I’m having a sight problem. I cannot get the context to be set current. I’m using Linux with GTK
back-end. I have read somewhere that I need to set the context in wx.EVT_SIZE
. Here is the full demo project.
import wx
from wx import glcanvas
from OpenGL.GL import *
from pathlib import Path
import numpy as np
class GL():
def ParseShader(self, filepath):
return Path(filepath).read_text()
def CompileShader(self, type, source):
id = glCreateShader(type)
src = source
glShaderSource(id, 1, src , None)
glCompileShader(id)
result = 0
glGetShaderiv(id, GL_COMPILE_STATUS, result)
if result == GL_FALSE:
length = 0
glGetShaderiv(id, GL_INFO_LOG_LENGTH, length)
message[length]
glGetShaderInfoLog(id, length, length, message)
print(f"Failed to compile {'vertex' if GL_VERTEX_SHADER else 'fragment'} shader")
print(message)
glDeleteShader(id)
return None
return id
def CreateShader(self, vertexShader, fragmentShader):
program = glCreateProgram()
vs = self.CompileShader(GL_VERTEX_SHADER, vertexShader)
fs = self.CompileShader(GL_FRAGMENT_SHADER, fragmentShader)
glAttachShader(program, vs)
glAttachShader(program, fs)
glLinkProgram(program)
glValidateProgram(program)
glDeleteShader(vs)
glDeleteShader(fs)
return program
class GLCanvas(glcanvas.GLCanvas):
def __init__(self, parent):
glcanvas.GLCanvas.__init__(self, parent, -1, size=(200, 200))
self.gl = GL()
self.context = glcanvas.GLContext(self)
if not self.context.IsOK():
wx.LogDebug("Error! Could not create context")
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnDraw)
def OnSize(self, event):
size = event.GetSize()
self.SetViewport(0, 0, size.x, size.y)
if not self.context:
return
if not self.IsShownOnScreen():
return
if not self.SetCurrent(self.context):
wx.LogDebug("Error 1! Unable to set the context")
return
if not self.context.SetCurrent(self):
wx.LogDebug("Error 2! Unable to set the context")
return
wx.LogDebug("Canvas is ready and Context is set as current.")
def OnDraw(self, event):
glClearColor(0.4, 0.2, 0.8, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
self.SwapBuffers()
def SetViewport(self, x, y, w, h):
glViewport(x, y, w, h)
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="GL_Demo", size=(800, 600))
wx.LogDebug(f"[wxPython Version]: {wx.version()}")
panel = wx.Panel(self)
self.canvas = GLCanvas(panel)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas, wx.SizerFlags(1).Expand())
panel.SetSizer(sizer)
class App(wx.App):
def OnInit(self):
frame = MainFrame()
frame.Show()
return True
if __name__ == '__main__':
app = App()
app.MainLoop()
This does draw a bluish/purple color window, but when I change the OnDraw function to draw from a vert and frag shader file,
def OnDraw(self, event):
positions = np.array([
-0.5, -0.5, # 0
0.5, -0.5, # 1
0.5, 0.5, # 2
-0.5, 0.5 # 3
], dtype=np.float32)
indices = np.array([
0, 1, 2,
2, 3, 0
], dtype=np.float32)
vertex_array_object = glGenVertexArrays(1)
glBindVertexArray(vertex_array_object)
vertex_buffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer)
glBufferData(GL_ARRAY_BUFFER, positions.nbytes, positions, GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, None)
glEnableVertexAttribArray(0)
index_buffer = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
vertexShader = self.gl.ParseShader("res/shaders/basic.vert")
fragmentShader = self.gl.ParseShader("res/shaders/basic.frag")
shader = self.gl.CreateShader(vertexShader, fragmentShader)
location = glGetUniformLocation(shader, "u_Color")
glUseProgram(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
glUseProgram(shader)
glUniform4f(location, 0.0, 0.3, 0.02, 1.0)
glBindVertexArray(vertex_array_object)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
self.SwapBuffers()
I get this error,
❯ python main.py
00:35:37: Debug: Canvas is ready and Context is set as current.
Traceback (most recent call last):
File "/home/apoorv/repos/python-projects/wxpython/wxGL/main.py", line 102, in OnDraw
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, None)
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/latebind.py", line 63, in __call__
return self.wrapperFunction( self.baseFunction, *args, **named )
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/GL/VERSION/GL_2_0.py", line 469, in glVertexAttribPointer
contextdata.setValue( key, array )
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/contextdata.py", line 58, in setValue
context = getContext( context )
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/contextdata.py", line 40, in getContext
raise error.Error(
OpenGL.error.Error: Attempt to retrieve context when no valid context
Traceback (most recent call last):
File "/home/apoorv/repos/python-projects/wxpython/wxGL/main.py", line 102, in OnDraw
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, None)
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/latebind.py", line 63, in __call__
return self.wrapperFunction( self.baseFunction, *args, **named )
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/GL/VERSION/GL_2_0.py", line 469, in glVertexAttribPointer
contextdata.setValue( key, array )
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/contextdata.py", line 58, in setValue
context = getContext( context )
File "/home/apoorv/.local/lib/python3.9/site-packages/OpenGL/contextdata.py", line 40, in getContext
raise error.Error(
OpenGL.error.Error: Attempt to retrieve context when no valid context
Here is the vert shader file,
#version 330 core
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
};
Here is the frag shader file,
#version 330 core
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main()
{
color = u_Color;
};
What am I doing wrong?