Hi all,
I've modified the background thread code by Zach Pincus trying to keep
code intrusion to a minimum. There are mainly two modifications:
First, the pyglet thread is now the main thread and the shell
emulation is done in a second thread using IPython.
Second, I tried to use class decorators (python 2.6 at least) and
function decorators to keep things light.
If you want to use it in you own code, just add the "proxy" decorator
in front of your window definition and to any function that deals with
OpenGL. I do not master class decoration deeply and I'm not so sure
about that part. It seems to work but any call to the super method
does not work for some reason.
Furthermore, from within the shell, all GL functions are already
proxied.
Here is the code, hope (it works) and it is useful.
-----
import sys
import types
import traceback
import threading
import collections
import IPython.ipapi
import pyglet
from pyglet.gl import *
#
-------------------------------------------------------------------------
call
def call (function, args, kwargs, output=None):
''' WARNING: This can be only called from the OpenGL thread '''
try:
result = function(*args, **kwargs)
except:
traceback.print_exc()
result = None
if output:
output(result)
#
-------------------------------------------------------------------------
post
def post (function, args, kwargs, output):
''' Post a function call on the queue. '''
_lock.acquire()
_queue.append((function, args, kwargs, output))
_lock.release()
# ----------------------------------------------
__decorate_function_with_result
def __decorate_function_with_result(function):
''' Internal decorator for function that needs to get result '''
class container(object):
def __init__(self):
self.value = None
self.filled = False
def __call__(self, value=None):
self.value = value
self.filled = True
class proxy(object):
def __call__(self, *args, **kwargs):
output = container()
post(function, args, kwargs, output)
while not output.filled: pass
return output.value
return proxy()
# -------------------------------------------
__decorate_function_without_result
def __decorate_function_without_result(function):
''' Internal decorator for function that does not nedd to get
result '''
class proxy(object):
def __call__(self, *args, **kwargs):
post(function, args, kwargs, None)
return proxy()
# -------------------------------------------------------------
__decorate_class
def __decorate_class(klass):
class proxy(object):
''' Internal decorator for class '''
__protected__ = set(['__init__',
'__getattribute__',
'__setattr__',
'__proxy__'])
def __init__(self, *args, **kwargs):
object.__setattr__(self, '__proxy__', None)
output = lambda result: object.__setattr__(self,
'__proxy__', result)
post(klass, args, kwargs, output)
def __getattribute__(self, name):
if name in proxy.__protected__:
return object.__getattribute__(self, name)
proxy_ref = self.__proxy__
value = getattr(proxy_ref, name)
if isinstance(value, types.MethodType):
return proxy_function(value)
else:
return value
def __setattr__(self, name, value):
proxy_ref = self.__proxy__
if hasattr(proxy_ref, name):
call(setattr, (proxy_ref, name, value), {})
else:
object.__setattr__(self, name, value)
return proxy
# -------------------------------------------------------------- proxy
decorator
def proxy(obj):
''' '''
if type(obj) is bool:
def wrap(function):
if isinstance(function, types.FunctionType):
if obj:
return __decorate_function_with_result(function)
else:
return __decorate_function_without_result
(function)
elif isinstance(function,types.TypeType):
return __decorate_class(function)
else:
raise NotImplementedError('Cannot make proxy for
%s.'%str(obj))
return wrap
else:
if isinstance(obj, types.FunctionType):
return __decorate_function_without_result(obj)
elif isinstance(obj,types.TypeType):
return __decorate_class(obj)
else:
raise NotImplementedError('Cannot make proxy for %s.'%str
(obj))
#
----------------------------------------------------------------------
process
def process(dt):
''' '''
if not len(_queue): return
_lock.acquire()
function, args, kwargs, output = _queue.popleft()
call (function, args, kwargs, output)
_lock.release()
# ----------------------------------------------------------------
session_start
def session_start():
''' '''
pyglet.clock.schedule_interval(process, 1/60.)
namespace = globals().copy()
for key in namespace.keys():
if callable(namespace[key]) and key[:2] == 'gl':
namespace[key] = __decorate_function_with_result(namespace
[key])
IPython.ipapi.launch_new_instance(namespace)
pyglet.app.exit()
_lock = threading.Lock()
_queue = collections.deque()
#
-----------------------------------------------------------------------
Window
@proxy
class Window(pyglet.window.Window):
def __init__(self, *args, **kwargs):
self.label = pyglet.text.Label('Hello, world',
font_name='Times New Roman',
font_size=36,
anchor_x='center',
anchor_y='center')
pyglet.window.Window.__init__(self,*args, **kwargs)
def on_resize(self, width, height):
pyglet.window.Window.on_resize(self, width, height)
self.label.x = self.width//2
self.label.y = self.height//2
def on_draw(self):
self.clear()
self.label.draw()
@proxy
def clear(r,g,b,a):
glClearColor(r,g,b,a)
@proxy(True) # True means we want to get function result
def viewport():
viewport = (GLint*4)()
glGetIntegerv(GL_VIEWPORT, viewport)
return viewport[0],viewport[1],viewport[2],viewport[3]
@proxy
def set_text(window, text):
window.label.text = text
session = threading.Thread(target=session_start)
session.start()
while session.isAlive(): pyglet.app.run()
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"pyglet-users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/pyglet-users?hl=en
-~----------~----~----~----~------~----~------~--~---