def __init__(clock=None, framerate=None, backend=None): """ Initialize the main loop Parameters ---------- clock : Clock clock to use to run the app (gives the elementary tick) framerate : int frames per second backend : python module Backend module """ global __clock__ options = parser.get_options() if options.debug: log.setLevel(logging.DEBUG) if framerate is None: framerate = options.framerate if framerate > 0: log.info("Running at %d frames/second" % framerate) else: log.info("Running at full speed") if clock is None: __clock__ = _clock.get_default() else: __clock__ = clock __clock__.set_fps_limit(framerate) # OpenGL Initialization gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glEnable(gl.GL_VERTEX_PROGRAM_POINT_SIZE) gl.glEnable(gl.GL_POINT_SPRITE) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) # Initialize timers for all windows for window in backend.windows(): window._clock = __clock__ # Start timers for i in range(len(window._timer_stack)): handler, interval = window._timer_stack[i] __clock__.schedule_interval(handler, interval) # Dispatch init event window.dispatch_event('on_init') # Dispatch an initial resize event window.dispatch_event('on_resize', window._width, window._height) return __clock__
def __init__(self, size=(800,600), position=(0,0), anchor=(0,0), aspect=None): """ Create a new viewport with requested size and position. Parameters ---------- size: tuple as ([int,float], [int,float]) Requested size. May be absolute (pixel) or relative to the parent (percent). Positive or negative values are accepted. position: tuple as ([int,float], [int,float]) Requested position. May be absolute (pixel) or relative to the parent (percent). Positive or negative values are accepted. anchor: tuple as ([int,float], [int,float]) or string Anchor point for positioning. May be absolute (pixel) or relative (percent). Positive or negative values are accepted. aspect: float Aspect (width/height) to be enforced. """ self._parent = None self._children = [] self._active_viewports = [] self._dispatcher = ViewportDispatcher() # Aspect ratio (width/height) self._aspect = aspect if aspect: log.info("Enforcing viewport aspect ratio (%g)" % aspect) # Anchor point for placement self._anchor = anchor # Requested size & position (may be honored or not, depending on parent) # (relative or absolute coordinates) self._requested_size = size self._requested_position = position # Clipped size & position (used for glScissor) # (absolute coordinates) self._scissor_size = size self._scissor_position = position # Viewport size & position (used for glViewport) # (absolute coordinates) self._viewport_size = size self._viewport_position = position # Wheter viewport is active (cursor is inside) self._active = False # Viewport id self._id = Viewport._idcount Viewport._idcount += 1
def _fetch_file(filename): """ Fetch a font file from a remote data server Available servers: * https://github.com/glumpy/glumpy-font/raw/master/Fonts * https://github.com/glumpy/glumpy-data/raw/master/Data """ local_directory = os.path.dirname(__file__) or '.' local_file = os.path.join(local_directory, filename) if os.path.isfile(local_file): return local_file extension = os.path.basename(filename).split('.')[-1] # Font server if extension in ['ttf', 'otf']: server = "https://github.com/glumpy/glumpy-font/raw/master/Fonts" # Data server else: server = "https://github.com/glumpy/glumpy-data/raw/master/Data" filename = os.path.basename(filename) remote = os.path.join(server, filename) # Build url request log.info('Requesting "%s" from remote server' % filename) try: response = request.urlopen(remote) except: log.warning('Data not available on remote server') return None # Fetch symlink data (font location) symlink = response.read().decode() remote = os.path.join(server, symlink) response = request.urlopen(remote) # Fetch data size = response.headers['Content-Length'].strip() log.info('Fetching data (%s bytes) to "%s"' % (size, local_file)) with open(local_file, 'wb') as fp: fp.write(response.read()) return local_file
def __init__(self, size=(800, 600), position=(0, 0), anchor=(0, 0), aspect=None): """ Create a new viewport with requested size and position. Parameters ---------- """ self._parent = None self._children = [] self._active_viewports = [] self._dispatcher = ViewportDispatcher() # Aspect ratio (width/height) self._aspect = aspect if aspect: log.info("Enforcing viewport aspect ratio (%g)" % aspect) # Anchor point for placement self._anchor = anchor # Requested size & position (may be honored or not, depending on parent) # (relative or absolute coordinates) self._requested_size = size self._requested_position = position # Clipped size & position (used for glScissor) # (absolute coordinates) self._scissor_size = size self._scissor_position = position # Viewport size & position (used for glViewport) # (absolute coordinates) self._viewport_size = size self._viewport_position = position # Wheter viewport is active (cursor is inside) self._active = False # Viewport id self._id = Viewport._idcount Viewport._idcount += 1
def __init__(self, size=(800,600), position=(0,0), anchor=(0,0), aspect=None): """ Create a new viewport with requested size and position. Parameters ---------- """ self._parent = None self._children = [] self._active_viewports = [] self._dispatcher = ViewportDispatcher() # Aspect ratio (width/height) self._aspect = aspect if aspect: log.info("Enforcing viewport aspect ratio (%g)" % aspect) # Anchor point for placement self._anchor = anchor # Requested size & position (may be honored or not, depending on parent) # (relative or absolute coordinates) self._requested_size = size self._requested_position = position # Clipped size & position (used for glScissor) # (absolute coordinates) self._scissor_size = size self._scissor_position = position # Viewport size & position (used for glViewport) # (absolute coordinates) self._viewport_size = size self._viewport_position = position # Wheter viewport is active (cursor is inside) self._active = False # Viewport id self._id = Viewport._idcount Viewport._idcount += 1
def run(clock=None, framerate=None, interactive=None, duration=sys.maxsize, framecount=sys.maxsize): """ Run the main loop Parameters ---------- clock : Clock clock to use to run the app (gives the elementary tick) framerate : int frames per second duration : float Duration after which the app will be stopped framecount : int Number of frame to display before stopping. """ global __running__ clock = __init__(clock=clock, framerate=framerate, backend=__backend__) options = parser.get_options() if interactive is None: interactive = options.interactive if interactive: # Set interactive python session os.environ['PYTHONINSPECT'] = '1' import readline readline.parse_and_bind("tab: complete") def run(): while not stdin_ready(): __backend__.process(clock.tick()) return 0 inputhook_manager.set_inputhook(run) else: __running__ = True def run(duration, framecount): count = len(__backend__.windows()) while count and duration > 0 and framecount > 0 and __running__: dt = clock.tick() duration -= dt framecount -= 1 count = __backend__.process(dt) if options.record: from .movie import record # Obtain the name of the script that is being run name = os.path.basename(sys.argv[0]) # Replace .py extension with .mp4 filename = re.sub('.py$', '.mp4', name) log.info("Recording movie in '%s'" % filename) with record(window=__backend__.windows()[0], filename=filename, fps=60): run(duration, framecount) else: run(duration, framecount)
def __new__(cls, *args, **kwargs): global __backend__ all = list(backends.__backends__) options = parser.get_options() # No backend was specified # Check for command line argument then pick a default one if possible if __backend__ is None: if options.backend != all[0]: all = [ options.backend, ] + all for name in all: backend = use(name) if backend and backend.available(): __backend__ = backend break # No backend available, there's nothing we can do if __backend__ is None: log.critical("No suitable backend found") raise NotImplementedError config = configuration.get_default() if "config" not in kwargs.keys(): kwargs['config'] = config # Get command line size # if options.size: # size = options.size.split(",") # kwargs['width'] = int(size[0]) # kwargs['height'] = int(size[1]) # else: # kwargs['width'] = kwargs.get('width', 512) # kwargs['height'] = kwargs.get('height', 512) # Get command line position # if options.position: # position = options.position.split(",") # #kwargs['x'] = kwargs.get('x', int(position[0])) # #kwargs['y'] = kwargs.get('y', int(position[1])) # else: # pass # #kwargs['x'] = kwargs.get('x', 0) # #kwargs['y'] = kwargs.get('y', 0) # Create the backend window window = __backend__.Window(*args, **kwargs) window._backend = __backend__ config = configuration.gl_get_configuration() window._config = config log.info("Using %s (%s %d.%d)" % (__backend__.name(), config.api, config.major_version, config.minor_version)) # Display fps options if options.display_fps: @window.timer(1.0) def timer(elapsed): print("Estimated FPS: %f" % fps()) return window
# Distributed under the (new) BSD License. # ----------------------------------------------------------------------------- from glumpy import app from glumpy.log import log from glumpy.graphics.text import FontManager from glumpy.graphics.collections import GlyphCollection from glumpy.transforms import Position, OrthographicProjection, Viewport window = app.Window(width=1200, height=800, color=(1, 1, 1, 1)) @window.event def on_draw(dt): window.clear() labels.draw() labels = GlyphCollection('agg', transform=OrthographicProjection(Position())) text = "The quick brown fox jumps over the lazy dog" x, y, z = 2, window.height, 0 log.info("Caching texture fonts") for i in range(6, 54, 2): font = FontManager.get("OpenSans-Regular.ttf", size=i, mode='agg') y -= i * 1.1 labels.append(text, font, origin=(x, y, z), anchor_x="left") window.attach(labels["transform"]) window.attach(labels["viewport"]) app.run()
def run(clock=None, framerate=None, interactive=None, duration = sys.maxsize, framecount = sys.maxsize): """ Run the main loop Parameters ---------- clock : Clock clock to use to run the app (gives the elementary tick) framerate : int frames per second duration : float Duration after which the app will be stopped framecount : int Number of frame to display before stopping. """ global __running__ clock = __init__(clock=clock, framerate=framerate, backend=__backend__) options = parser.get_options() if interactive is None: interactive = options.interactive if interactive: # Set interactive python session os.environ['PYTHONINSPECT'] = '1' import readline readline.parse_and_bind("tab: complete") def run(): while not stdin_ready(): __backend__.process(clock.tick()) return 0 inputhook_manager.set_inputhook(run) else: __running__ = True def run(duration, framecount): count = len(__backend__.windows()) while count and duration > 0 and framecount > 0 and __running__: dt = clock.tick() duration -= dt framecount -= 1 count = __backend__.process(dt) if options.record: from .movie import record # Obtain the name of the script that is being run name = os.path.basename(sys.argv[0]) # Replace .py extension with .mp4 filename=re.sub('.py$', '.mp4', name) log.info("Recording movie in '%s'" % filename) with record(window=__backend__.windows()[0], filename=filename, fps=60): run(duration, framecount) else: run(duration, framecount)
def __init__(clock=None, framerate=None, backend=None): """ Initialize the main loop Parameters ---------- clock : Clock clock to use to run the app (gives the elementary tick) framerate : int frames per second backend : python module Backend module """ global __clock__ options = parser.get_options() if options.debug: log.setLevel(logging.DEBUG) if framerate is None: framerate = options.framerate if framerate > 0: log.info("Running at %d frames/second" % framerate) else: log.info("Running at full speed") if clock is None: __clock__ = _clock.get_default() else: __clock__ = clock __clock__.set_fps_limit(framerate) # OpenGL Initialization for window in backend.windows(): window.activate() gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1) gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1) gl.glEnable(gl.GL_VERTEX_PROGRAM_POINT_SIZE) gl.glEnable(gl.GL_POINT_SPRITE) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) # Initialize timers for all windows for window in backend.windows(): window._clock = __clock__ # Start timers for i in range(len(window._timer_stack)): handler, interval = window._timer_stack[i] __clock__.schedule_interval(handler, interval) # Activate window window.activate() # Dispatch init event window.dispatch_event('on_init') # Dispatch an initial resize event window.dispatch_event('on_resize', window._width, window._height) return __clock__
def __new__(cls, *args, **kwargs): global __backend__ all = list(backends.__backends__) options = parser.get_options() # No backend was specified # Check for command line argument then pick a default one if possible if __backend__ is None: if options.backend != all[0]: all = [options.backend,] + all for name in all: backend = use(name) if backend and backend.available(): __backend__ = backend break # No backend available, there's nothing we can do if __backend__ is None: log.critical("No suitable backend found") raise NotImplementedError config = configuration.get_default() if "config" not in kwargs.keys(): kwargs['config'] = config # Get command line size # if options.size: # size = options.size.split(",") # kwargs['width'] = int(size[0]) # kwargs['height'] = int(size[1]) # else: # kwargs['width'] = kwargs.get('width', 512) # kwargs['height'] = kwargs.get('height', 512) # Get command line position # if options.position: # position = options.position.split(",") # #kwargs['x'] = kwargs.get('x', int(position[0])) # #kwargs['y'] = kwargs.get('y', int(position[1])) # else: # pass # #kwargs['x'] = kwargs.get('x', 0) # #kwargs['y'] = kwargs.get('y', 0) # Create the backend window window = __backend__.Window(*args, **kwargs) window._backend = __backend__ config = configuration.gl_get_configuration() window._config = config log.info("Using %s (%s %d.%d)" % (__backend__.name(), config.api, config.major_version, config.minor_version)) # Display fps options if options.display_fps: @window.timer(1.0) def timer(elapsed): print("Estimated FPS: %f"% fps()) return window
def run(clock=None, framerate=None, interactive=None, duration=sys.maxint, framecount=sys.maxint): """ Run the main loop Parameters ---------- clock : Clock clock to use to run the app (gives the elementary tick) framerate : int frames per second duration : float Duration after which the app will be stopped framecount : int Number of frame to display before stopping. """ global __running__ clock = __init__(clock=clock, framerate=framerate, backend=__backend__) options = parser.get_options() if interactive is None: interactive = options.interactive writer = None if options.record: from glumpy.ext.ffmpeg_writer import FFMPEG_VideoWriter framerate = 60 window = __backend__.windows()[0] width, height = window.width, window.height filename = "movie.mp4" writer = FFMPEG_VideoWriter(filename, (width, height), fps=framerate) fbuffer = np.zeros((height, width, 3), dtype=np.uint8) data = fbuffer.copy() log.info("Recording movie in '%s'" % filename) if interactive: # Set interactive python session os.environ['PYTHONINSPECT'] = '1' import readline readline.parse_and_bind("tab: complete") def run(): while not stdin_ready(): __backend__.process(clock.tick()) return 0 inputhook_manager.set_inputhook(run) else: __running__ = True count = len(__backend__.windows()) while count and duration > 0 and framecount > 0 and __running__: dt = clock.tick() duration -= dt framecount -= 1 count = __backend__.process(dt) # Record one frame (if there is writer available) if writer is not None: gl.glReadPixels(0, 0, window.width, window.height, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, fbuffer) data[...] = fbuffer[::-1, :, :] writer.write_frame(data) if writer is not None: writer.close()
# Distributed under the (new) BSD License. # ----------------------------------------------------------------------------- from glumpy import app from glumpy.log import log from glumpy.graphics.text import FontManager from glumpy.graphics.collections import GlyphCollection from glumpy.transforms import Position, OrthographicProjection, Viewport window = app.Window(width=1200, height=800, color=(1, 1, 1, 1)) @window.event def on_draw(dt): window.clear() labels.draw() labels = GlyphCollection("agg", transform=OrthographicProjection(Position())) text = "The quick brown fox jumps over the lazy dog" x, y, z = 2, window.height, 0 log.info("Caching texture fonts") for i in range(6, 54, 2): font = FontManager.get("OpenSans-Regular.ttf", size=i, mode="agg") y -= i * 1.1 labels.append(text, font, origin=(x, y, z), anchor_x="left") window.attach(labels["transform"]) window.attach(labels["viewport"]) app.run()
def __init__( self, width=512, height=512, title=None, visible=True, aspect=None, decoration=True, fullscreen=False, config=None, context=None, color=(0,0,0,1)): window.Window.__init__(self, width=width, height=height, title=title, visible=visible, aspect=aspect, decoration=decoration, fullscreen=fullscreen, config=config, context=context, color=color) # Whether hidpi is active self._hidpi = False def on_error(error, message): log.warning(message) glfw.glfwSetErrorCallback(on_error) glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, True) glfw.glfwWindowHint(glfw.GLFW_DECORATED, True) glfw.glfwWindowHint(glfw.GLFW_VISIBLE, True) if not decoration: glfw.glfwWindowHint(glfw.GLFW_DECORATED, False) if not visible: glfw.glfwWindowHint(glfw.GLFW_VISIBLE, False) if config is None: config = configuration.Configuration() set_configuration(config) self._native_window = glfw.glfwCreateWindow( self._width, self._height, self._title, None, None) if not self._native_window: log.critical("Window creation failed") __exit__() sys.exit() glfw.glfwMakeContextCurrent(self._native_window) glfw.glfwSwapInterval(0) # OSX: check framebuffer size / window size. On retina display, they # can be different so we try to correct window size such as having # the framebuffer size of the right size w,h = glfw.glfwGetFramebufferSize(self._native_window) if w != width or h!= height: width, height = width//2, height//2 glfw.glfwSetWindowSize(self._native_window, width, height) log.info("HiDPI detected, fixing window size") self._hidpi = True def on_framebuffer_resize(win, width, height): self._width, self._height = width, height self.dispatch_event('on_resize', width, height) glfw.glfwSetFramebufferSizeCallback(self._native_window, on_framebuffer_resize) # def on_resize(win, width, height): # self._width, self._height = width, height # self.dispatch_event('on_resize', width, height) # glfw.glfwSetWindowSizeCallback(self._native_window, on_resize) def on_cursor_enter(win, entered): if entered: self.dispatch_event('on_enter') else: self.dispatch_event('on_leave') glfw.glfwSetCursorEnterCallback(self._native_window, on_cursor_enter) def on_window_close(win): self.close() glfw.glfwSetWindowCloseCallback(self._native_window, on_window_close) def on_keyboard(win, key, scancode, action, mods): symbol = self._keyboard_translate(key) modifiers = self._modifiers_translate(mods) if action in[glfw.GLFW_PRESS,glfw.GLFW_REPEAT]: self.dispatch_event('on_key_press', symbol, modifiers) else: self.dispatch_event('on_key_release', symbol, modifiers) glfw.glfwSetKeyCallback(self._native_window, on_keyboard) def on_character(win, character): self.dispatch_event('on_character', u"%c" % character) glfw.glfwSetCharCallback(self._native_window, on_character) def on_mouse_button(win, button, action, mods): x,y = glfw.glfwGetCursorPos(win) if self._hidpi: x, y = 2*x, 2*y button = __mouse_map__.get(button, window.mouse.UNKNOWN) if action == glfw.GLFW_RELEASE: self._button = window.mouse.NONE self._mouse_x = x self._mouse_y = y self.dispatch_event('on_mouse_release', x, y, button) elif action == glfw.GLFW_PRESS: self._button = button self._mouse_x = x self._mouse_y = y self.dispatch_event('on_mouse_press', x, y, button) glfw.glfwSetMouseButtonCallback(self._native_window, on_mouse_button) def on_mouse_motion(win, x, y): if self._hidpi: x, y = 2*x, 2*y dx = x - self._mouse_x dy = y - self._mouse_y self._mouse_x = x self._mouse_y = y if self._button != window.mouse.NONE: self.dispatch_event('on_mouse_drag', x, y, dx, dy, self._button) else: self.dispatch_event('on_mouse_motion', x, y, dx, dy) glfw.glfwSetCursorPosCallback(self._native_window, on_mouse_motion) def on_scroll(win, xoffset, yoffset): x,y = glfw.glfwGetCursorPos(win) if self._hidpi: x, y = 2*x, 2*y self.dispatch_event('on_mouse_scroll', x, y, xoffset, yoffset) glfw.glfwSetScrollCallback( self._native_window, on_scroll ) self._width, self._height = self.get_size() __windows__.append(self)
def __init__(self, width=512, height=512, title=None, visible=True, aspect=None, decoration=True, fullscreen=False, config=None, context=None, color=(0, 0, 0, 1), vsync=False): window.Window.__init__(self, width=width, height=height, title=title, visible=visible, aspect=aspect, decoration=decoration, fullscreen=fullscreen, config=config, context=context, color=color) # Whether hidpi is active self._hidpi = False def on_error(error, message): log.warning(message) glfw.glfwSetErrorCallback(on_error) glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, True) glfw.glfwWindowHint(glfw.GLFW_DECORATED, True) glfw.glfwWindowHint(glfw.GLFW_VISIBLE, True) if not decoration: glfw.glfwWindowHint(glfw.GLFW_DECORATED, False) if not visible: glfw.glfwWindowHint(glfw.GLFW_VISIBLE, False) if config is None: config = configuration.Configuration() set_configuration(config) self._native_window = glfw.glfwCreateWindow(self._width, self._height, self._title, None, None) if not self._native_window: log.critical("Window creation failed") __exit__() sys.exit() glfw.glfwMakeContextCurrent(self._native_window) glfw.glfwSwapInterval(1 if vsync else 0) # OSX: check framebuffer size / window size. On retina display, they # can be different so we try to correct window size such as having # the framebuffer size of the right size w, h = glfw.glfwGetFramebufferSize(self._native_window) if w != width or h != height: width, height = width // 2, height // 2 glfw.glfwSetWindowSize(self._native_window, width, height) log.info("HiDPI detected, fixing window size") self._hidpi = True def on_framebuffer_resize(win, width, height): self._width, self._height = width, height self.dispatch_event('on_resize', width, height) glfw.glfwSetFramebufferSizeCallback(self._native_window, on_framebuffer_resize) # def on_resize(win, width, height): # self._width, self._height = width, height # self.dispatch_event('on_resize', width, height) # glfw.glfwSetWindowSizeCallback(self._native_window, on_resize) def on_cursor_enter(win, entered): if entered: self.dispatch_event('on_enter') else: self.dispatch_event('on_leave') glfw.glfwSetCursorEnterCallback(self._native_window, on_cursor_enter) def on_window_close(win): self.close() glfw.glfwSetWindowCloseCallback(self._native_window, on_window_close) def on_keyboard(win, key, scancode, action, mods): symbol = self._keyboard_translate(key) modifiers = self._modifiers_translate(mods) if action in [glfw.GLFW_PRESS, glfw.GLFW_REPEAT]: self.dispatch_event('on_key_press', symbol, modifiers) else: self.dispatch_event('on_key_release', symbol, modifiers) glfw.glfwSetKeyCallback(self._native_window, on_keyboard) def on_character(win, character): self.dispatch_event('on_character', u"%c" % character) glfw.glfwSetCharCallback(self._native_window, on_character) def on_mouse_button(win, button, action, mods): x, y = glfw.glfwGetCursorPos(win) if self._hidpi: x, y = 2 * x, 2 * y button = __mouse_map__.get(button, window.mouse.UNKNOWN) if action == glfw.GLFW_RELEASE: self._button = window.mouse.NONE self._mouse_x = x self._mouse_y = y self.dispatch_event('on_mouse_release', x, y, button) elif action == glfw.GLFW_PRESS: self._button = button self._mouse_x = x self._mouse_y = y self.dispatch_event('on_mouse_press', x, y, button) glfw.glfwSetMouseButtonCallback(self._native_window, on_mouse_button) def on_mouse_motion(win, x, y): if self._hidpi: x, y = 2 * x, 2 * y dx = x - self._mouse_x dy = y - self._mouse_y self._mouse_x = x self._mouse_y = y if self._button != window.mouse.NONE: self.dispatch_event('on_mouse_drag', x, y, dx, dy, self._button) else: self.dispatch_event('on_mouse_motion', x, y, dx, dy) glfw.glfwSetCursorPosCallback(self._native_window, on_mouse_motion) def on_scroll(win, xoffset, yoffset): x, y = glfw.glfwGetCursorPos(win) if self._hidpi: x, y = 2 * x, 2 * y self.dispatch_event('on_mouse_scroll', x, y, xoffset, yoffset) glfw.glfwSetScrollCallback(self._native_window, on_scroll) self._width, self._height = self.get_size() __windows__.append(self)
def run(clock=None, framerate=None, interactive=None, duration = sys.maxint, framecount = sys.maxint): """ Run the main loop Parameters ---------- clock : Clock clock to use to run the app (gives the elementary tick) framerate : int frames per second duration : float Duration after which the app will be stopped framecount : int Number of frame to display before stopping. """ global __running__ clock = __init__(clock=clock, framerate=framerate, backend=__backend__) options = parser.get_options() if interactive is None: interactive = options.interactive writer = None if options.record: from glumpy.ext.ffmpeg_writer import FFMPEG_VideoWriter framerate = 60 window = __backend__.windows()[0] width, height = window.width, window.height filename = "movie.mp4" writer = FFMPEG_VideoWriter(filename, (width, height), fps=framerate) fbuffer = np.zeros((height, width, 3), dtype=np.uint8) data = fbuffer.copy() log.info("Recording movie in '%s'" % filename) if interactive: # Set interactive python session os.environ['PYTHONINSPECT'] = '1' import readline readline.parse_and_bind("tab: complete") def run(): while not stdin_ready(): __backend__.process(clock.tick()) return 0 inputhook_manager.set_inputhook(run) else: __running__ = True count = len(__backend__.windows()) while count and duration > 0 and framecount > 0 and __running__: dt = clock.tick() duration -= dt framecount -= 1 count = __backend__.process(dt) # Record one frame (if there is writer available) if writer is not None: gl.glReadPixels(0, 0, window.width, window.height, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, fbuffer) data[...] = fbuffer[::-1,:,:] writer.write_frame(data) if writer is not None: writer.close()