107 lines
3.0 KiB
Python
107 lines
3.0 KiB
Python
|
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().
|
||
|
"""
|
||
|
|
||
|
# check if this is run from the doctester
|
||
|
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()
|