"""Example 2: white triangle on orange background with debugging enabled Set up a window with OpenGL context and rendering one white triangle on an orange background using shaders. But this time check for errors and enable debugging log. """ import ctypes import sdl2 #import OpenGL #OpenGL.FULL_LOGGING = True from OpenGL import GL, constant from OpenGL.GL.ARB import debug_output from OpenGL.extensions import alternate glGetDebugMessageLog = alternate( 'glGetDebugMessageLog', GL.glGetDebugMessageLog, debug_output.glGetDebugMessageLogARB) # the size specifications of some debug_output tokens seem to be missing so # we add them manually even though it does not seem to be a nice way to do it GL.glget.GL_GET_SIZES[debug_output.GL_MAX_DEBUG_MESSAGE_LENGTH_ARB] = (1,) GL.glget.GL_GET_SIZES[debug_output.GL_DEBUG_LOGGED_MESSAGES_ARB] = (1,) def get_constant(value, namespace): """Get symbolic constant. value - the (integer) token value to look for namespace - the module object to search in """ for var in dir(namespace): attr = getattr(namespace, var) if isinstance(attr, constant.Constant) and attr == value: return var return value def get_debug_output(): """Get the contents of the OpenGL debug log as a string.""" # details for the available log messages msgmaxlen = GL.glGetInteger(debug_output.GL_MAX_DEBUG_MESSAGE_LENGTH_ARB) msgcount = GL.glGetInteger(debug_output.GL_DEBUG_LOGGED_MESSAGES_ARB) # ctypes arrays to receive the log data msgsources = (ctypes.c_uint32 * msgcount)() msgtypes = (ctypes.c_uint32 * msgcount)() msgids = (ctypes.c_uint32 * msgcount)() msgseverities = (ctypes.c_uint32 * msgcount)() msglengths = (ctypes.c_uint32 * msgcount)() msglog = (ctypes.c_char * (msgmaxlen * msgcount))() glGetDebugMessageLog(msgcount, msgmaxlen, msgsources, msgtypes, msgids, msgseverities, msglengths, msglog) offset = 0 logdata = zip(msgsources, msgtypes, msgids, msgseverities, msglengths) for msgsource, msgtype, msgid, msgseverity, msglen in logdata: msgtext = msglog.raw[offset:offset + msglen].decode("ASCII") offset += msglen msgsource = get_constant(msgsource, debug_output) msgtype = get_constant(msgtype, debug_output) msgseverity = get_constant(msgseverity, debug_output) return("SOURCE: {0}\nTYPE: {1}\nID: {2}\nSEVERITY: {3}\n" "MESSAGE: {4}".format(msgsource, msgtype, msgid, msgseverity, msgtext)) return "" def run(): if sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) != 0: print(sdl2.SDL_GetError()) return sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, 3) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MINOR_VERSION, 2) sdl2.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_FLAGS, sdl2.SDL_GL_CONTEXT_DEBUG_FLAG) window = sdl2.SDL_CreateWindow( b"Example 1", sdl2.SDL_WINDOWPOS_UNDEFINED, sdl2.SDL_WINDOWPOS_UNDEFINED, 640, 480, sdl2.SDL_WINDOW_OPENGL) context = sdl2.SDL_GL_CreateContext(window) # get Vertex Array Object name vao = GL.glGenVertexArrays(1) # set this new VAO to the active one GL.glBindVertexArray(vao) # vertex data for one triangle triangle_vertices = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5] # convert to ctypes c_float array triangle_array = ((ctypes.c_float * len(triangle_vertices)) (*triangle_vertices)) # get a VBO name from the graphics card vbo = GL.glGenBuffers(1) # bind our vbo name to the GL_ARRAY_BUFFER target GL.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo) # move the vertex data to a new data store associated with our vbo GL.glBufferData(GL.GL_ARRAY_BUFFER, ctypes.sizeof(triangle_array), triangle_array, GL.GL_STATIC_DRAW) # vertex shader vertexShaderProgramm = """#version 100 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); }""" vertexShader = GL.glCreateShader(GL.GL_VERTEX_SHADER) GL.glShaderSource(vertexShader, vertexShaderProgramm) GL.glCompileShader(vertexShader) # print the current debug log print(get_debug_output()) compilestatus = GL.glGetShaderiv(vertexShader, GL.GL_COMPILE_STATUS) if compilestatus != GL.GL_TRUE: raise RuntimeError(GL.glGetShaderInfoLog(vertexShader) .decode('ASCII')) # fragment shader fragmentShaderProgramm = """#version 100 out vec4 outColor; void main() { outColor = vec4(1.0, 1.0, 1.0, 1.0); }""" fragmentShader = GL.glCreateShader(GL.GL_FRAGMENT_SHADER) GL.glShaderSource(fragmentShader, fragmentShaderProgramm) GL.glCompileShader(fragmentShader) compilestatus = GL.glGetShaderiv(fragmentShader, GL.GL_COMPILE_STATUS) if compilestatus != GL.GL_TRUE: raise RuntimeError(GL.glGetShaderInfoLog(fragmentShader) .decode('ASCII')) # shader program shaderProgram = GL.glCreateProgram() GL.glAttachShader(shaderProgram, vertexShader) GL.glAttachShader(shaderProgram, fragmentShader) # color output buffer assignment GL.glBindFragDataLocation(shaderProgram, 0, b"outColor") # link the program GL.glLinkProgram(shaderProgram) linkstatus = GL.glGetProgramiv(shaderProgram, GL.GL_LINK_STATUS) if linkstatus != GL.GL_TRUE: raise RuntimeError(GL.glGetProgramInfoLog(shaderProgram) .decode('ASCII')) # validate program GL.glValidateProgram(shaderProgram) validatestatus = GL.glGetProgramiv(shaderProgram, GL.GL_VALIDATE_STATUS) if validatestatus != GL.GL_TRUE: raise RuntimeError(GL.glGetProgramInfoLog(shaderProgram) .decode('ASCII')) # activate the program GL.glUseProgram(shaderProgram) # specify the layout of our vertex data posAttrib = GL.glGetAttribLocation(shaderProgram, b"position") GL.glEnableVertexAttribArray(posAttrib) GL.glVertexAttribPointer(posAttrib, 2, GL.GL_FLOAT, False, 0, ctypes.c_voidp(0)) # do the actual drawing GL.glClearColor(1.0, 0.5, 0.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT) GL.glDrawArrays(GL.GL_TRIANGLES, 0, int(len(triangle_vertices) / 2)) # show the back buffer sdl2.SDL_GL_SwapWindow(window) # wait for somebody to close the window event = sdl2.SDL_Event() while sdl2.SDL_WaitEvent(ctypes.byref(event)): if event.type == sdl2.SDL_QUIT: break # cleanup GL.glDisableVertexAttribArray(posAttrib) GL.glDeleteProgram(shaderProgram) GL.glDeleteShader(fragmentShader) GL.glDeleteShader(vertexShader) GL.glDeleteBuffers(1, [vbo]) GL.glDeleteVertexArrays(1, [vao]) sdl2.SDL_GL_DeleteContext(context) sdl2.SDL_Quit() if __name__ == "__main__": run()