|
from pyglet.window import Window |
|
from pyglet.clock import Clock |
|
|
|
from threading import Thread, Lock |
|
|
|
gl_lock = Lock() |
|
|
|
|
|
class ManagedWindow(Window): |
|
""" |
|
A pyglet window with an event loop which executes automatically |
|
in a separate thread. Behavior is added by creating a subclass |
|
which overrides setup, update, and/or draw. |
|
""" |
|
fps_limit = 30 |
|
default_win_args = {"width": 600, |
|
"height": 500, |
|
"vsync": False, |
|
"resizable": True} |
|
|
|
def __init__(self, **win_args): |
|
""" |
|
It is best not to override this function in the child |
|
class, unless you need to take additional arguments. |
|
Do any OpenGL initialization calls in setup(). |
|
""" |
|
|
|
|
|
if win_args.get('runfromdoctester', False): |
|
return |
|
|
|
self.win_args = dict(self.default_win_args, **win_args) |
|
self.Thread = Thread(target=self.__event_loop__) |
|
self.Thread.start() |
|
|
|
def __event_loop__(self, **win_args): |
|
""" |
|
The event loop thread function. Do not override or call |
|
directly (it is called by __init__). |
|
""" |
|
gl_lock.acquire() |
|
try: |
|
try: |
|
super().__init__(**self.win_args) |
|
self.switch_to() |
|
self.setup() |
|
except Exception as e: |
|
print("Window initialization failed: %s" % (str(e))) |
|
self.has_exit = True |
|
finally: |
|
gl_lock.release() |
|
|
|
clock = Clock() |
|
clock.fps_limit = self.fps_limit |
|
while not self.has_exit: |
|
dt = clock.tick() |
|
gl_lock.acquire() |
|
try: |
|
try: |
|
self.switch_to() |
|
self.dispatch_events() |
|
self.clear() |
|
self.update(dt) |
|
self.draw() |
|
self.flip() |
|
except Exception as e: |
|
print("Uncaught exception in event loop: %s" % str(e)) |
|
self.has_exit = True |
|
finally: |
|
gl_lock.release() |
|
super().close() |
|
|
|
def close(self): |
|
""" |
|
Closes the window. |
|
""" |
|
self.has_exit = True |
|
|
|
def setup(self): |
|
""" |
|
Called once before the event loop begins. |
|
Override this method in a child class. This |
|
is the best place to put things like OpenGL |
|
initialization calls. |
|
""" |
|
pass |
|
|
|
def update(self, dt): |
|
""" |
|
Called before draw during each iteration of |
|
the event loop. dt is the elapsed time in |
|
seconds since the last update. OpenGL rendering |
|
calls are best put in draw() rather than here. |
|
""" |
|
pass |
|
|
|
def draw(self): |
|
""" |
|
Called after update during each iteration of |
|
the event loop. Put OpenGL rendering calls |
|
here. |
|
""" |
|
pass |
|
|
|
if __name__ == '__main__': |
|
ManagedWindow() |
|
|