using an existing GL context ?

45 views
Skip to first unread message

dumebi bidume

unread,
Sep 30, 2015, 9:13:19 AM9/30/15
to pyglet-users
hello,

I would like to use pyglet code within a GUI application, currently I'm trying to achieve that by setting pyglet context, based on some old thread about this…

I'm using pyglet 1.2 and trying to use glglue with a glut window to test this but I'm not able to make it work.

Is there a reasonable way to get pyglet using an already created context ?
thanks

Ryexander

unread,
Oct 1, 2015, 6:35:26 AM10/1/15
to pyglet-users
you have to trick Pyglet into thinking that a context exists and use OpenGL internal context switching. I've gotten this working in wx but the process should work with other context providders

The real impotent bits I'll highlight here:

import pyglet
# this line is very important, we're tricking pyglet into thinking there is a context avalible
# but we can't make it work with the shadow window that alows sharing of
# object between contexts
pyglet.options['shadow_window'] = False
# now that that is set we can import gl and get on our way
from pyglet import gl

This sequence must take place in this order. The shadow_window option must be set to false before pyglet.gl is ever imported in the application..

Then the next step is creating a fake context opbject for pyglet to use. Up to version 1.1.4 this was easy, New pyglet however requires a bit more work

if pyglet.version > "1.1.4":
    pygletcontext = PygletContext()
else:
    pygletcontext = gl.Context()
pygletcontext.set_current()

Do this BEFORE  you do any work with your context like setting the blend func etc.
If you have multiple contexts you want to work with in your GUI application then keep your  pygletcontext object handy you'll need to use the GUI's method of setting the current context as well as the .set_current() of the fake context to get pyglet drawing in the right context.

Here is the class I cobbled together to trick pyglet < 1.1.4 It's mostly a copy paste of the pyglet source for pyglet.gl.context the important bit is after the #implement workarounds comment

class PygletWXContext(gl.Context):
    def __init__(self, config=None, context_share=None):
        self.config = config
        self.context_share = context_share
        self.canvas = None
        if context_share:
            self.object_space = context_share.object_space
        else:
            self.object_space = gl.ObjectSpace()
    def attach(self, canvas=None):
        pass
    def detach(self):
        pass
    def set_current(self):
        # XXX not per-thread
        gl.current_context = self
        # XXX
        gl.gl_info.set_active_context()
        gl.glu_info.set_active_context()
        # Implement workarounds
        if not self._info:
            self._info = gl.gl_info.GLInfo()
            self._info.set_active_context()
            for attr, check in self._workaround_checks:
                setattr(self, attr, check(self._info))
        # Release textures and buffers on this context scheduled for deletion.
        # Note that the garbage collector may introduce a race condition,
        # so operate on a copy of the textures/buffers and remove the deleted
        # items using list slicing (which is an atomic operation)
        if self.object_space._doomed_textures:
            textures = self.object_space._doomed_textures[:]
            textures = (gl.GLuint * len(textures))(*textures)
            gl.glDeleteTextures(len(textures), textures)
            self.object_space._doomed_textures[0:len(textures)] = []
        if self.object_space._doomed_buffers:
            buffers = self.object_space._doomed_buffers[:]
            buffers = (gl.GLuint * len(buffers))(*buffers)
            gl.glDeleteBuffers(len(buffers), buffers)
            self.object_space._doomed_buffers[0:len(buffers)] = []

And that should be it. so long as you set teh current context correctly every time you begin work with a new context you don't need pyglet to manage it. The down side of pyglet not managing the context is that object can not be reused. (at least I couldn't figure out how to make it work when I tried a few years ago. perhaps the internals are different now and it can be done.)

dumebi bidume

unread,
Oct 5, 2015, 5:57:25 AM10/5/15
to pyglet-users
It seems to work for me, at least with a trivial glut test:

from OpenGL.GL import *
import pyglet
pyglet.options['shadow_window'] = False
from pyglet import gl

class PygletContext(gl.Context):
 
class Controller(object):
    def __init__(self):
        self.test = False

    def onResize(self, w, h):
        glViewport(0, 0, w, h)

    […]

    def onUpdate(self, d):
        print 'onUpdate', d

    def draw(self):
        if self.test == False:
            self.ctx = PygletContext()
            self.ctx.set_current()
            self.label = pyglet.text.Label('Hello, world',
                          font_name='Times New Roman',
                          font_size=36,
                          x=500, y=500,
                          anchor_x='center', anchor_y='center')
            self.test = True 

                  #glglue sample (PyOpenGL + glut) 
        glClearColor(0.9, 0.5, 0.0, 0.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glBegin(GL_TRIANGLES)
        glVertex(-1.0,-1.0)
        glVertex( 1.0,-1.0)
        glVertex( 0.0, 1.0)
        glEnd()
   
                  # pyglet test here 
        gl.glMatrixMode( gl.GL_PROJECTION )
        gl.glLoadIdentity()
        gl.glMatrixMode( gl.GL_MODELVIEW )
        gl.glLoadIdentity()
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glClear( gl.GL_COLOR_BUFFER_BIT )
        gl.glClearColor(0/255, 0/255, 0/255, 0)
        gl.glOrtho(0, 1000, 0, 1000, 1, -1 )
        gl.glBegin(gl.GL_TRIANGLES)
        gl.glColor4f(1.,0.,1.,0.3)
        gl.glVertex2f(0.0,0.0)
        gl.glVertex2f(500.,500.)
        gl.glVertex2f(1000., 0.)
        gl.glEnd()
        self.label.draw()

        glFlush()

if __name__=="__main__":
    controller=Controller()
    import glglue.glut
    glglue.glut.mainloop(controller, width=640, height=480, title="sample")
 
It also solved an issue with pyglet windowing on windows 7 (did not try other Windows versions…) with Intel chipset graphics, I was unable to open a simple window with pyglet on every PC without a "real" graphic card… After some debugging I guess it was a win32 issue, but only with some workstations having an Intel chipset (several versions), while the OpenGL stuffs seemed to run…

Thank you very much for your help.
I think there should be a section in pyglet documentation about how to use a custom OpenGL context, even if pyglet is intended to be library free this is very useful in some cases. I could not fix it without your hacking sample…
When you want to make an OpenGL application in Python without dealing with tricky stuffs like OpenGL "batch" programming, then pyglet contains just what you need.

Ryexander

unread,
Oct 6, 2015, 6:11:37 AM10/6/15
to pyglet-users
Glad to help, Took me several hours of reading pyglet's code to figure out how to bypass it's internal contexts. again with this setup I've attached pyglet to multiple contexts in the same window and even child windows in the same application. so long as you set the current context properly before every draw your good to go. Good luck with your project.


On Wednesday, September 30, 2015 at 7:13:19 AM UTC-6, dumebi bidume wrote:
Reply all
Reply to author
Forward
0 new messages