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__
Example #2
0
    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
Example #3
0
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
Example #4
0
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
Example #5
0
    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
Example #6
0
    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
Example #9
0
# 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()
Example #10
0
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)
Example #11
0
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__
Example #12
0
    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
Example #13
0
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()
Example #14
0
# 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()
Example #15
0
    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)
Example #16
0
    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)
Example #17
0
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()