QT OpenGL canvas with pyglet.gl issues

502 views
Skip to first unread message

Crispin Wellington

unread,
Mar 25, 2009, 9:50:41 PM3/25/09
to pyglet-users
Hi there people,

So I started down the road to building a QT4.5 compatible pyglet
widget. I thought the first step would be to just get pyglet.gl OpenGL
calls working on a Qt OpenGL context.

What I found, at least under Mac OSX leopard, is that the calls
"work", but somehow, for some reason, importing pyglet.gl freezes the
QT app window. The app still works, and the buttons and QT events
inside the window still work, but you cannot drag the window, maximize
it, close it, or resize it. There is something strange happening the
minute the pyglet.gl namespace gets imported. In fact, if you import
pyglet.gl and then import OpenGL, to overwrite the pyglet GL call
namespace with the PyOpenGL namespace, the freeze still happens.

OK. heres some test code so you can see for yourself. To run using the
PyOpenGL API go "python test.py", and to run using the pyglet.gl api,
go "PYGLET=1 python test.py"

So now testing under OSX, the display DOES render, I get no error, and
the window is locked.
Testing under linux, the pyglet.gl does NOT render, but the window IS
draggable. It does spit out an error on linux that it doesn't on OSX.
The traceback on linux is

Traceback (most recent call last):
File "test.py", line 45, in paintGL
glClear(GL_COLOR_BUFFER_BIT)
File "/var/lib/python-support/python2.5/pyglet/gl/lib.py", line 83,
in errcheck
raise GLException('No GL context; create a Window first')
pyglet.gl.lib.GLException: No GL context; create a Window first

Anyone have any ideas how to "unlock" the window on OSX and use the
pyglet.gl calls? Or how to get the GL drawing on linux?

---------------------------------------------------
#!/usr/bin/env python

import sys, math, os
from PyQt4 import QtGui, QtCore, QtOpenGL

if 'PYGLET' in os.environ:
from pyglet.gl import *

def glmult(l):
return glMultMatrixf( (GLfloat * len(l))(*l) )

else:
from OpenGL.GL import *

def glmult(l):
return glMultMatrixf( l )

class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
QtOpenGL.QGLWidget.__init__(self, parent)

def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 0.0)
glShadeModel(GL_FLAT)

def lookAt(self,ex,ey,ez,cx,cy,cz,ux,uy,uz):
F = [cx-ex, cy-ey, cz-ez]
Fmag = math.sqrt(sum([a*a for a in F]))
fnorm = [a/Fmag for a in F]

Up = [ux,uy,uz]
Upmag = math.sqrt(sum([a*a for a in Up]))
upnorm = [a/Upmag for a in Up]

def cross(v1,v2):
return [v1[1]*v2[2] - v1[2]*v2[1], v1[2]*v2[0] - v1[0]*v2[2],
v1[0]*v2[1] - v1[1]*v2[0]]

s = cross( fnorm, upnorm )
u = cross( s, fnorm )

glmult([ s[0], s[1], s[2], 0, u[0], u[1], u[2], 0, -fnorm[0],
-fnorm[1], -fnorm[2], 0, 0, 0, 0, 1 ])
glTranslated(-ex, -ey, -ez)

def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT)

glColor3f(1.0,1.0,1.0)
glLoadIdentity()
self.lookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
glScalef(1.0, 2.0, 1.0)
glBegin(GL_TRIANGLES)
glNormal3f(1,0,0)
glVertex3f(1,0,0)
glVertex3f(0,1,0)
glVertex3f(1,1,0)
glEnd()
glFlush()

def resizeGL(self, height, width):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0)
glMatrixMode(GL_MODELVIEW)

def mousePressEvent(self, event):
print "mousePressEvent:",event.pos()

def mouseMoveEvent(self, event):
print "mouseMoveEvent:",event.pos()

class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)

self.resize(350, 400)
self.setWindowTitle('Main Window')

self.gl = glwidget = GLWidget()
self.setCentralWidget(glwidget)

exit = QtGui.QAction(QtGui.QIcon(), 'Exit', self)
exit.setShortcut('Ctrl+Q')
exit.setStatusTip('Exit application')
self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))

self.statusBar()

toolbar = self.addToolBar('Exit')
toolbar.addAction(exit)

def idle(self):
pass

# QT app
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()

sys.exit(app.exec_())

---------------------------------------------------


Kind Regards

Crispin

Bruce Smith

unread,
Mar 26, 2009, 12:18:30 AM3/26/09
to pyglet-users
On Mar 25, 6:50 pm, Crispin Wellington <retrogradeor...@gmail.com>
wrote:
> ... first step would be to just get pyglet.gl OpenGL
> calls working on a Qt OpenGL context.
>
> What I found, at least under Mac OSX leopard, is that the calls
> "work", but somehow, for some reason, importing pyglet.gl freezes the
> QT app window. ...
>
> So now testing under OSX, the display DOES render, I get no error, and
> the window is locked.
> Testing under linux, the pyglet.gl does NOT render, but the window IS
> draggable. It does spit out an error on linux that it doesn't on OSX.
> The traceback on linux is
>
> Traceback (most recent call last):
>   File "test.py", line 45, in paintGL
>     glClear(GL_COLOR_BUFFER_BIT)
>   File "/var/lib/python-support/python2.5/pyglet/gl/lib.py", line 83,
> in errcheck
>     raise GLException('No GL context; create a Window first')
> pyglet.gl.lib.GLException: No GL context; create a Window first
>
> Anyone have any ideas how to "unlock" the window on OSX and use the
> pyglet.gl calls? Or how to get the GL drawing on linux?

I get the same error (Intel Mac OS 10.5). I have a (vague) theory
about the cause of all the behaviors you list above: Importing
pyglet.gl (I speculate) doesn't only define symbols, it also does
something to (or using) your current GL context. (Rather than, for
example, requiring you to call an init function and not doing that
stuff until you call that function.) If so, then the behaviors you
describe are consistent with Linux not having any GL context current
when pyglet.gl is imported (which it complains about), but with Mac
having the *wrong* context current -- perhaps one related to being
able to drag the window, thus the freeze. (I.e. either Qt or the Mac
window manager is using OpenGL to drag the window, and has left that
context current when your program starts.)

(It's certain that the context you want (the one owned by the
QGLWidget) can't be current yet, during that import, since it doesn't
even exist yet.)

I've been involved in some Qt OpenGL programming, and seen similar
bugs, for example when we did anything to an OpenGL context outside of
paintGL (e.g. in a mouse event handler) and forgot to first call
makeCurrent on the QGLWidget whose context we wanted to affect. In
that case too, we found different bugs on Linux and Mac.

Based on this theory, I tried fixing this in your example code by just
delaying the import of pyglet.gl until the desired GL context is known
to be current (which is first true inside initializeGL, I think), but
I couldn't get it to work. The problems might be trivial, related to
doing import * inside a function (SyntaxWarning in python 2.5) -- it
might be easier if you did explicit imports rather than import *.

A better fix, if this theory is right, would be to be able to set a
flag which causes pyglet.gl to defer all initialization which depends
on having an OpenGL context current, until a specific function is
called (and ideally to let it be called more than once, in case of non-
resource-sharing contexts, but that's much more work if any global
variables are involved -- they'd need to become attributes of a class
associated with each context -- so for now we can only hope for a
singleton context, just one that doesn't have to exist when your
program starts).

I.e. your program would look like this:

pyglet_gl_no_implicit_init = True

import pyglet.gl # affected by that flag

.....

def initializeGL(self):

pyglet.gl.ok_now_you_can_do_that_init_stuff_that_requires_the_right_GL_context
()
.....

(But I couldn't easily find the right place in pyglet.gl.__init__ or
one of its submodules to do this.)

(I must emphasize that this theory and proposed fix is purely
speculative -- the real issue could be something completely
different.)

- Bruce Smith

Crispin Wellington

unread,
Mar 26, 2009, 12:22:52 AM3/26/09
to pyglet...@googlegroups.com
I haven't finished reading you're whole email, but just quickly, I did
try an explicit import...

from pyglet.gl import glTranlated, GL_.... etc. etc.

but it did the same locking...

Crispin

Bruce Smith

unread,
Mar 26, 2009, 12:23:22 AM3/26/09
to pyglet-users
Oops, at least part of my theory (prior mail) doesn't fit your
evidence: the Linux traceback comes during paintGL, not during the
initial import of pyglet.gl as I had assumed.

Crispin Wellington

unread,
Mar 26, 2009, 12:50:11 AM3/26/09
to pyglet...@googlegroups.com
Woops. I keep forgetting to mail the list...

For the specific import replace the PYGLET part of the header with

--------------------------------------------
if 'PYGLET' in os.environ:
from pyglet.gl import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
from pyglet.gl import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
from pyglet.gl import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
from pyglet.gl import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
return glMultMatrixf( (GLfloat * len(l))(*l) )
----------------------------------------


Regards

Crispin

Bruce Smith

unread,
Mar 26, 2009, 1:11:48 AM3/26/09
to pyglet-users
On Mar 25, 9:50 pm, Crispin Wellington <retrogradeor...@gmail.com>
wrote:
> Woops. I keep forgetting to mail the list...
>
> For the specific import replace the PYGLET part of the header with
>
> --------------------------------------------
> if 'PYGLET' in os.environ:
>        from pyglet.gl import glMultMatrixf, glClearColor,
> glShadeModel, glTranslated, glClear
>        from pyglet.gl import glColor3f, glLoadIdentity, glScalef,
> glVertex3f, glNormal3f
>        from pyglet.gl import glBegin, glEnd, glFlush, GLfloat,
> glViewport, glMatrixMode, glFrustum
>        from pyglet.gl import GL_TRIANGLES, GL_FLAT,
> GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW
>
>        def glmult(l):
>                return glMultMatrixf( (GLfloat * len(l))(*l) )

I used the above, and tried delaying the pyglet.gl import in a cleaner
way. (Diff -c with your original example is below.)

This convinces me that my original theory is not what's happening
here. With the pyglet.gl imports deferred until the GL context is
current, there is no behavior difference related to dragging the
window. (Something else I did caused the rendering to not show up
until you resize the window. I can't guess what caused that.)

(FYI I also swapped the args of resizeGL to fix a bug.)

Other speculations: maybe pyglet does something which locks the
window, which it normally undoes somehow when it first shows a window
of its own? Maybe it does something which tells the OS window manager
that this Qt window is not the right one to receive some sort of
events? (I think I better stop speculating and wait for the experts to
weigh in.)

- Bruce

P.S. Here's what I tried, relative to your original example code:

*** crispin_qt-ORIG.py 2009-03-25 20:47:23.000000000 -0700
--- crispin_qt.py 2009-03-25 21:56:53.000000000 -0700
***************
*** 1,29 ****
#!/usr/bin/env python

import sys, math, os
- from PyQt4 import QtGui, QtCore, QtOpenGL

! if 'PYGLET' in os.environ:
! from pyglet.gl import *

def glmult(l):
! return glMultMatrixf( (GLfloat * len(l))(*l) )

! else:
! from OpenGL.GL import *

def glmult(l):
return glMultMatrixf( l )

class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
QtOpenGL.QGLWidget.__init__(self, parent)

def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 0.0)
glShadeModel(GL_FLAT)

def lookAt(self,ex,ey,ez,cx,cy,cz,ux,uy,uz):
F = [cx-ex, cy-ey, cz-ez]
Fmag = math.sqrt(sum([a*a for a in F]))
fnorm = [a/Fmag for a in F]
--- 1,59 ----
#!/usr/bin/env python

import sys, math, os

! glMultMatrixf, glClearColor, glShadeModel, glTranslated, glClear =
0,0,0,0,0
! glColor3f, glLoadIdentity, glScalef, glVertex3f, glNormal3f =
0,0,0,0,0
! glBegin, glEnd, glFlush, GLfloat, glViewport, glMatrixMode,
glFrustum = 0,0,0,0,0,0,0
! GL_TRIANGLES, GL_FLAT, GL_COLOR_BUFFER_BIT, GL_PROJECTION,
GL_MODELVIEW = 0,0,0,0,0
!
! glmult = 0
!
! def _import_gl():
! global glMultMatrixf, glClearColor, glShadeModel, glTranslated,
glClear
! global glColor3f, glLoadIdentity, glScalef, glVertex3f,
glNormal3f
! global glBegin, glEnd, glFlush, GLfloat, glViewport,
glMatrixMode, glFrustum
! global GL_TRIANGLES, GL_FLAT, GL_COLOR_BUFFER_BIT,
GL_PROJECTION, GL_MODELVIEW
! global glmult
!
! if 'PYGLET' in os.environ:
! ## from pyglet.gl import *
!
! from pyglet.gl import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
! from pyglet.gl import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
! from pyglet.gl import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
! from pyglet.gl import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
! return glMultMatrixf( (GLfloat * len(l))(*l) )
!
! ## pwin = pyglet.window.Window(resizable=True)

! else:
! ## from OpenGL.GL import *
! from OpenGL.GL import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
! from OpenGL.GL import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
! from OpenGL.GL import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
! from OpenGL.GL import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
return glMultMatrixf( l )

+
+ from PyQt4 import QtGui, QtCore, QtOpenGL
+
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
QtOpenGL.QGLWidget.__init__(self, parent)

def initializeGL(self):
+ _import_gl()
+ self.resizeGL(self.width(), self.height()) #
probably not needed
glClearColor(0.0, 0.0, 0.0, 0.0)
glShadeModel(GL_FLAT)

def lookAt(self,ex,ey,ez,cx,cy,cz,ux,uy,uz):
+ _import_gl()
F = [cx-ex, cy-ey, cz-ez]
Fmag = math.sqrt(sum([a*a for a in F]))
fnorm = [a/Fmag for a in F]
***************
*** 44,49 ****
--- 74,80 ----
glTranslated(-ex, -ey, -ez)

def paintGL(self):
+ _import_gl()
glClear(GL_COLOR_BUFFER_BIT)

glColor3f(1.0,1.0,1.0)
***************
*** 58,64 ****
glEnd()
glFlush()

! def resizeGL(self, height, width):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
--- 89,96 ----
glEnd()
glFlush()

! def resizeGL(self, width, height): # bugfix, swapped args
! _import_gl()

Bruce Smith

unread,
Mar 26, 2009, 1:45:43 AM3/26/09
to pyglet-users
BTW, changing part of my modified version of your example as follows,
I can confirm your earlier statement that importing pyglet.gl has a
side effect (locking the window re dragging) which is not mediated by
its redefinition of all the gl*/GL* globals:

def _import_gl_raw(use_pyglet):
global glMultMatrixf, glClearColor, glShadeModel, glTranslated,
glClear
global glColor3f, glLoadIdentity, glScalef, glVertex3f, glNormal3f
global glBegin, glEnd, glFlush, GLfloat, glViewport, glMatrixMode,
glFrustum
global GL_TRIANGLES, GL_FLAT, GL_COLOR_BUFFER_BIT, GL_PROJECTION,
GL_MODELVIEW
global glmult

if use_pyglet:
## from pyglet.gl import *

from pyglet.gl import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
from pyglet.gl import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
from pyglet.gl import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
from pyglet.gl import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
return glMultMatrixf( (GLfloat * len(l))(*l) )

## pwin = pyglet.window.Window(resizable=True)

else:
## from OpenGL.GL import *
from OpenGL.GL import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
from OpenGL.GL import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
from OpenGL.GL import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
from OpenGL.GL import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
return glMultMatrixf( l )

def _import_gl():
_import_gl_raw( 'PYGLET' in os.environ) # do the import pyglet.gl
_import_gl_raw( False) # then change the globals gl*/GL* back to
what they were (bug still present on my Mac)

- Bruce

Crispin Wellington

unread,
Mar 26, 2009, 9:42:50 AM3/26/09
to pyglet...@googlegroups.com
I found the culprit.

In pyglet/gl/__init__.py, right at the very end there is this devilish
looking piece of code.
----------------------
# Import pyglet.window now if it isn't currently being imported (this creates
# the shadow window).
if (not _is_epydoc and
'pyglet.window' not in _sys.modules and
_pyglet.options['shadow_window']):
# trickery is for circular import
_pyglet.gl = _sys.modules[__name__]
import pyglet.window
----------------------
It seems to be caused by a bug here. If you remove this, the osx
version begins to behave the same way as the linux version, It ceases
to draw the scene and throws an exception like the linux one.

pyglet.gl.lib.GLException: No GL context; create a Window first

Does anyone know what is this "shadow window" this code is referring
to? Needless to say, this snippet of code as it stands prevents being
able to use pyglet gl with QT without adverse effects.

Regards

Crispin Wellington

Bruce Smith

unread,
Mar 26, 2009, 12:46:09 PM3/26/09
to pyglet-users
On Mar 26, 6:42 am, Crispin Wellington <retrogradeor...@gmail.com>
wrote:
> ...
> Does anyone know what is this "shadow window" this code is referring
> to? Needless to say, this snippet of code as it stands prevents being
> able to use pyglet gl with QT without adverse effects.

There is some documentation for it in pyglet/__init__.py:

#: Global dict of pyglet options. To change an option from its
default, you
#: must import ``pyglet`` before any sub-packages. For example::
#:
#: import pyglet
#: pyglet.options['debug_gl'] = False
#:
#: The default options can be overridden from the OS environment...
#:
#: The non-development options are:
#: ....
#: shadow_window
#: By default, pyglet creates a hidden window with a GL context
when
#: pyglet.gl is imported. This allows resources to be loaded
before
#: the application window is created, and permits GL objects to be
#: shared between windows even after they've been closed. You can
#: disable the creation of the shadow window by setting this
option to
#: False. Recommended for advanced devlopers only.
#:
#: **Since:** pyglet 1.1

So, maybe it will be sufficient to modify this option before importing
pyglet.gl, then run equivalent code (not sure what will be needed)
before first using pyglet on the QGLWidget GL context.

Looking for uses of shadow_window in the pyglet code:

in gl.base.Context.destroy, it looks like it wants to switch back to
that "shadow GL context" whenever destroying one of its own... more
generally, that class looks designed to wrap a GL context so pyglet
can use it -- maybe you'll need another way of creating one, to wrap
an existing context?

Looking in the documentation, it's also mentioned in

pyglet-1.1.2-docs/doc/html/programming_guide/
creating_an_opengl_context.html

but skimming that, I don't see anything about using a context and
window created outside of pyglet.

Glancing at the APIs in pyglet-1.1.2-docs/doc/html/api/index.html, it
sure looks general enough to support multiple contexts, some sharing
resources and some not, potentially from multiple sources (e.g. some
Qt windows and some pyglet windows), but I still don't notice anything
explicit about using contexts from non-pyglet sources. IIRC, that is a
documented general limitation of pyglet, so maybe new code for
creating a subclass or sibling class of Context would be needed to do
that properly....

And I finally glanced at experimental/wxtest.py, but didn't study it
closely (I don't have or know wxWindows). But it looks like it's
mainly worried about *creating* a GL context in a different way,
whereas all we want to do here is *use* an existing one, which ought
to be easier.

I think at this point it makes sense to wait for Alex or Richard to
weigh in....

- Bruce

Bruce Smith

unread,
Mar 26, 2009, 1:32:29 PM3/26/09
to pyglet-users
I wrote:
> I think at this point it makes sense to wait for Alex or Richard to
> weigh in....

I still think that makes sense, but a little hacking around couldn't
hurt... and I did get your program to work (see below). However, I
think to make this approach work with more of pyglet's functionality
beyond pure rendering, much more work would be needed.

Making it work required two things (starting from the last version I
posted earlier -- I don't know if that version's delayed import is
still needed, but probably not):

1. just before first importing anything from pyglet:
import pyglet
pyglet.options['shadow_window'] = False
# this prevents the window-drag-locking effect of
import pyglet.gl,
# when _import_gl calls _import_gl_raw once with True
then once with False.

2. use python -O, to turn off pyglet's debugging code, which is what
raised the exception you reported, because it keeps track of begins/
ends in the gl context, but in this case pyglet doesn't know the gl
context so it thinks it's missing. (See errcheck* and
decorate_function in pyglet.gl.lib.)
This could alternatively be turned off using a change to
pyglet.options.

I will post the working version below, and leave it to you to clean it
up -- at that point I think it would make a good example, at least for
contrib or experimental.

But I'm guessing it's an incomplete solution, since I presume other
pyglet functions (besides gl debugging support) will also suffer from
not knowing the gl context and thinking it's missing (I didn't look
for other uses of the pyglet.gl.current_context global which records
it, and which is None in this case). Fixing that requires making a
Context or related object and assigning it there, and then the more
you asked pyglet to do anything with this, the more "realistic" this
object would need to be. For example, to make display lists or
textures or batches, I presume pyglet wants to record something in
this context's ObjectSpace (about shared GL resources); maybe it wants
to query the context for bit depth for some reason; etc. I'm just
guessing, but it goes to enough trouble to do this for its own
contexts (e.g. pyglet/gl/agl.py) that I'd be surprised if it doesn't
need any of that info for a "foreign" GL context (from Qt).

- Bruce

=====

here's the messy code that finally worked, when run like this:

% env PYGLET=1 python -O crispin_qt.py

(BTW, my contributions to this are trivial and are in the public
domain.)

#!/usr/bin/env python

import sys, math, os

glMultMatrixf, glClearColor, glShadeModel, glTranslated, glClear =
0,0,0,0,0 # 0 is easier to type lots of than None
glColor3f, glLoadIdentity, glScalef, glVertex3f, glNormal3f =
0,0,0,0,0
glBegin, glEnd, glFlush, GLfloat, glViewport, glMatrixMode, glFrustum
= 0,0,0,0,0,0,0
GL_TRIANGLES, GL_FLAT, GL_COLOR_BUFFER_BIT, GL_PROJECTION,
GL_MODELVIEW = 0,0,0,0,0

glmult = 0
_already_imported_pyglet = False

def _import_gl_raw(use_pyglet):
global glMultMatrixf, glClearColor, glShadeModel, glTranslated,
glClear
global glColor3f, glLoadIdentity, glScalef, glVertex3f, glNormal3f
global glBegin, glEnd, glFlush, GLfloat, glViewport, glMatrixMode,
glFrustum
global GL_TRIANGLES, GL_FLAT, GL_COLOR_BUFFER_BIT, GL_PROJECTION,
GL_MODELVIEW
global glmult, _already_imported_pyglet

if use_pyglet:

if not _already_imported_pyglet:
_already_imported_pyglet = True
print "using pyglet"
import pyglet
pyglet.options['shadow_window'] = False
# this prevents the window-drag-locking effect of
import pyglet.gl,
# when _import_gl calls _import_gl_raw once with True
then once with False.
## from pyglet.gl import *

from pyglet.gl import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
from pyglet.gl import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
from pyglet.gl import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
from pyglet.gl import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
return glMultMatrixf( (GLfloat * len(l))(*l) )

else:
## from OpenGL.GL import *
from OpenGL.GL import glMultMatrixf, glClearColor,
glShadeModel, glTranslated, glClear
from OpenGL.GL import glColor3f, glLoadIdentity, glScalef,
glVertex3f, glNormal3f
from OpenGL.GL import glBegin, glEnd, glFlush, GLfloat,
glViewport, glMatrixMode, glFrustum
from OpenGL.GL import GL_TRIANGLES, GL_FLAT,
GL_COLOR_BUFFER_BIT, GL_PROJECTION, GL_MODELVIEW

def glmult(l):
return glMultMatrixf( l )

def _import_gl():
_import_gl_raw( 'PYGLET' in os.environ) # do the import pyglet.gl
## _import_gl_raw( False) # then change the globals gl*/GL* back
to what they were (bug still present on my Mac)

from PyQt4 import QtGui, QtCore, QtOpenGL

class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
QtOpenGL.QGLWidget.__init__(self, parent)

def initializeGL(self):
_import_gl()
self.resizeGL(self.width(), self.height()) # probably
not needed
glClearColor(0.0, 0.0, 0.0, 0.0)
glShadeModel(GL_FLAT)

def lookAt(self,ex,ey,ez,cx,cy,cz,ux,uy,uz):
_import_gl()
F = [cx-ex, cy-ey, cz-ez]
Fmag = math.sqrt(sum([a*a for a in F]))
fnorm = [a/Fmag for a in F]

Up = [ux,uy,uz]
Upmag = math.sqrt(sum([a*a for a in Up]))
upnorm = [a/Upmag for a in Up]

def cross(v1,v2):
return [v1[1]*v2[2] - v1[2]*v2[1], v1[2]*v2[0]
- v1[0]*v2[2],
v1[0]*v2[1] - v1[1]*v2[0]]

s = cross( fnorm, upnorm )
u = cross( s, fnorm )

glmult([ s[0], s[1], s[2], 0, u[0], u[1], u[2], 0, -
fnorm[0],
-fnorm[1], -fnorm[2], 0, 0, 0, 0, 1 ])
glTranslated(-ex, -ey, -ez)

def paintGL(self):
_import_gl()
glClear(GL_COLOR_BUFFER_BIT)

glColor3f(1.0,1.0,1.0)
glLoadIdentity()
self.lookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0)
glScalef(1.0, 2.0, 1.0)
glBegin(GL_TRIANGLES)
glNormal3f(1,0,0)
glVertex3f(1,0,0)
glVertex3f(0,1,0)
glVertex3f(1,1,0)
glEnd()
glFlush()

def resizeGL(self, width, height): # bugfix, swapped args
_import_gl()
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()

Alex Holkner

unread,
Mar 26, 2009, 4:23:22 PM3/26/09
to pyglet...@googlegroups.com
On Fri, Mar 27, 2009 at 3:46 AM, Bruce Smith <ore...@gmail.com> wrote:

> I think at this point it makes sense to wait for Alex or Richard to
> weigh in....

Ok. I'm pretty sure other developers have successfully done this with
either Qt or wxWidgets in the past, and discovered all the relevant
hacks required. It's worth searching the group archives.

Anyway, there are three possible ways you might want to get pyglet
rendering into another toolkit's window.

1. Let the toolkit create the OpenGL context, and trick pyglet into
using that context without creating its own.

2. Let the toolkit create the platform window, and trick pyglet into
creating a context for that window.

3. Let the toolkit create a container for the window, and trick pyglet
into creating a child window with a GL context within that container.

It sounds like you want (1), and it's probably the easiest. The main
issue is getting pyglet to believe there is already a valid context
bound. Disable the shadow window, because you won't be needing it.
Then set a mock context object for pyglet.gl._current_context (you'll
have to write the class for this mock object yourself).

FWIW, (2) is what the wxtest.py code attempts to do. It has the
benefit of allowing you to use pyglet's context configuration, and get
OpenGL 2.1 contexts with multisampling, etc.

(3) would let you use pyglet's event handlers for the GL window, but
would probably only be possible on Windows (just set WS_CHILD style
and parent it to the container's hwnd).

These are all very much hacks because integration with other toolkits
was never a design goal of pyglet (in the original discussions Richard
and I shared, I don't think it was even brought up as a possibility!).
I made some headway into refactoring the context, window and a new
canvas class in pyglet-1.2dev (SVN trunk), but this is not in a
releasable state.

Alex.

Bruce Smith

unread,
Mar 26, 2009, 5:15:16 PM3/26/09
to pyglet...@googlegroups.com


On Thu, Mar 26, 2009 at 1:23 PM, Alex Holkner <alex.h...@gmail.com> wrote:
...

1. Let the toolkit create the OpenGL context, and trick pyglet into
using that context without creating its own.
...

It sounds like you want (1), and it's probably the easiest.  The main
issue is getting pyglet to believe there is already a valid context
bound.  Disable the shadow window, because you won't be needing it.
Then set a mock context object for pyglet.gl._current_context (you'll
have to write the class for this mock object yourself).

Right, this is what Crispin wanted and what I got halfway working (with debug_gl disabled rather than the mock context).

If we end up with a clean version of this kind of example, where is the best place to put it so the next developers don't have to search the archives again?

These are all very much hacks because integration with other toolkits
was never a design goal of pyglet (in the original discussions Richard
and I shared, I don't think it was even brought up as a possibility!).

I don't blame you -- I find all the other toolkits bulky and ugly, and am glad to get away from them. (And I find pyglet's code/API a beauty and a joy by comparison.) But for existing projects that use the other toolkits, or when their fancy features are required for some reason, I can also see usefulness in giving them Pyglet's rendering support (especially if its Batches, Groups, and images could work there). (A project I was involved with using Python, Qt and OpenGL (nanoengineer-1.sourceforge.net) recently put some effort into making something like Batches, but less general and slower.)

==

Another use case would simply be to let pyglet windows and other-toolkit windows coexist in the same application, but with no interaction or relation between them. I just tried "Bruce the presentation tool" and I think it did something like this, since it put up a Tk file chooser to get going. But this was entirely "serial" rather than "parallel" -- I guess it would be harder to support both windowing toolkits at once, since the two "event loops" would have to coexist. But for letting a pyglet program access a file chooser or color picker from the OS, it might be easy enough and useful (since we can stand suspending pyglet while the specialized dialog is up). (So my question about where to put examples of this kind of thing, if we write any, applies to this too.)

==

 I made some headway into refactoring the context, window and a new
canvas class in pyglet-1.2dev (SVN trunk), but this is not in a
releasable state.

Is this what I see in the svn trunk right now? I assumed that was essentially identical to the 1.1.3 release.

- Bruce

Alex Holkner

unread,
Mar 26, 2009, 5:30:22 PM3/26/09
to pyglet...@googlegroups.com


On 27/03/2009, at 8:15 AM, Bruce Smith <ore...@gmail.com> wrote:



On Thu, Mar 26, 2009 at 1:23 PM, Alex Holkner <alex.h...@gmail.com> wrote:
...
1. Let the toolkit create the OpenGL context, and trick pyglet into
using that context without creating its own.
...
It sounds like you want (1), and it's probably the easiest.  The main
issue is getting pyglet to believe there is already a valid context
bound.  Disable the shadow window, because you won't be needing it.
Then set a mock context object for pyglet.gl._current_context (you'll
have to write the class for this mock object yourself).

Right, this is what Crispin wanted and what I got halfway working (with debug_gl disabled rather than the mock context).

If we end up with a clean version of this kind of example, where is the best place to put it so the next developers don't have to search the archives again?


We used to have community pages for this sort of thing, but we were forced to close them due to spam. We don't have anything comparable at the moment.

These are all very much hacks because integration with other toolkits
was never a design goal of pyglet (in the original discussions Richard
and I shared, I don't think it was even brought up as a possibility!).



Another use case would simply be to let pyglet windows and other-toolkit windows coexist in the same application, but with no interaction or relation between them. I just tried "Bruce the presentation tool" and I think it did something like this, since it put up a Tk file chooser to get going. But this was entirely "serial" rather than "parallel" -- I guess it would be harder to support both windowing toolkits at once, since the two "event loops" would have to coexist. But for letting a pyglet program access a file chooser or color picker from the OS, it might be easy enough and useful (since we can stand suspending pyglet while the specialized dialog is up). (So my question about where to put examples of this kind of thing, if we write any, applies to this too.)


Actually in these cases it would be much simpler to expose the platform's dialogs as additional pyglet features.

==

 I made some headway into refactoring the context, window and a new
canvas class in pyglet-1.2dev (SVN trunk), but this is not in a
releasable state.

Is this what I see in the svn trunk right now? I assumed that was essentially identical to the 1.1.3 release.

The 1.1.3 release is from the pyglet-1.1-maintenance branch. The trunk contains an ambitious refactoring of pyglet that attempts to retain backward compatibility while supporting some new features that weren't possible in the old design. It's unlikely to be released, however.

Alex.




Casey Duncan

unread,
Mar 26, 2009, 5:58:32 PM3/26/09
to pyglet...@googlegroups.com

Are the ambitions of the features begun in the trunk documented
anywhere? I'm inclined to help, but I only have the vaguest notion as
to what is needed.

I'd hate to see the project start to die on the vine due to lack of
available developer time.

-Casey

Tristam MacDonald

unread,
Mar 26, 2009, 5:59:19 PM3/26/09
to pyglet...@googlegroups.com
On Thu, Mar 26, 2009 at 5:30 PM, Alex Holkner <alex.h...@gmail.com> wrote:


On 27/03/2009, at 8:15 AM, Bruce Smith <ore...@gmail.com> wrote:
If we end up with a clean version of this kind of example, where is the best place to put it so the next developers don't have to search the archives again?
We used to have community pages for this sort of thing, but we were forced to close them due to spam. We don't have anything comparable at the moment.

How about a Wiki page on the google code site?
 
--
Tristam MacDonald
http://swiftcoder.wordpress.com/

Bruce Smith

unread,
Mar 26, 2009, 7:46:50 PM3/26/09
to pyglet-users
On Mar 26, 2:30 pm, Alex Holkner <alex.holk...@gmail.com> wrote:

> We used to have community pages for this sort of thing,

Do you mean these? http://groups.google.com/group/pyglet-users/web

> but we were  
> forced to close them due to spam. We don't have anything comparable at  
> the moment.

Don't the googlecode wiki, and the google groups Pages above, have
effective CAPTCHA systems?

If not, could you individually approve people (revocably) to let them
add things to places like that?

> Actually in these cases it would be much simpler to expose the  
> platform's dialogs as additional pyglet features.

That would be great... but if you don't have time to do that yourself,
will you consider patches which do it for individual platforms, though
with an API intended to be implementable on all platforms?

But for community development purposes, rather than patches, letting
these grow up as example code in some sort of experimental area,
before being proposed for pyglet proper, seems best... if there's no
better idea, how about a new googlecode project "pyglet-examples" for
which you'd approve any reasonable person as a developer?

> >  I made some headway into refactoring the context, window and a new
> > canvas class in pyglet-1.2dev (SVN trunk), but this is not in a
> > releasable state.
>
> > Is this what I see in the svn trunk right now? I assumed that was  
> > essentially identical to the 1.1.3 release.
>
> The 1.1.3 release is from the pyglet-1.1-maintenance branch. The trunk  
> contains an ambitious refactoring of pyglet that attempts to retain  
> backward compatibility while supporting some new features that weren't  
> possible in the old design. It's unlikely to be released, however.

Several points about that:

- it probably means that my recent mail about breakage in experimental
and contrib should be disregarded, or at least understood to only
apply to the trunk

- you ought to update (IMHO) the following text on http://www.pyglet.org/contribute.html:

The subversion repository houses the source trunk, documentation,
examples and development tools. You can browse the repository or check
out a working copy using an SVN client:

svn checkout http://pyglet.googlecode.com/svn/trunk/ pyglet

to warn potential contributors (of bug reports, tests, and patches)
that the trunk is experimental, and give the command for checking out
the 1.1 maintenance branch as a preferred alternative for most of us
(if I understand you correctly)

- it doesn't seem like a good situation to allow to last. Was the
refactoring misguided in hindsight, or is it just taking too long to
finish, relative to the time you have? If the latter, is it feasible
for some of your many users to help out?

If it will be abandoned (or even just take forever to finish), it
seems better to put the refactoring in a branch and make sure the
trunk represents the intended continuing line of development.

- Bruce

(These are all just suggestions, given humbly, to avoid potential
confusion.)
Reply all
Reply to author
Forward
0 new messages