Appendix: Migrating to pyglet 1.1

pyglet 1.1 introduces new features for rendering high performance graphics and text, is more convenient to use, and integrates better with the operating system. Some of the existing interfaces have also been redesigned slightly to conform with standard Python practice or to fix design flaws.

Compatibility and deprecation

pyglet 1.1 is backward compatible with pyglet 1.0. Any application that uses only public and documented methods of pyglet 1.0 will continue to work unchanged in pyglet 1.1. If you encounter an issue where this is not the case, please consider it a bug in pyglet and file an issue report.

Some methods have been marked deprecated in pyglet 1.1. These methods continue to work, but have been superceded by newer methods that are either more efficient or have a better design. The API reference has a complete list of deprecated methods; the main changes are described in the next section.

  • Continue to use deprecated methods if your application needs to work with pyglet 1.0 as well as pyglet 1.1.
  • New applications should not use deprecated methods.

Deprecated methods will continue to be supported in all minor revisions of pyglet 1.x. A pyglet 2.0 release will no longer support these methods.

Deprecated methods

The following minor changes have been made for design or efficiency reasons. Applications which no longer need to support pyglet 1.0 should make the appropriate changes to ensure the deprecated methods are not called.

The dispatch_events method on Player and the equivalent function on the pyglet.media module should no longer be called. In pyglet 1.1, media objects schedule an update function on pyglet.clock at an appropriate interval. New applications using media are required to call pyglet.clock.tick periodically.

The AbstractImage properties texture, image_data, and so on have been replaced with equivalent methods get_texture, get_image_data, etc.

The ImageData properties data, format and pitch, which together were used to extract pixel data from an image, have been replaced with a single function get_data. The format and pitch properties should now be used only to determine the current format and pitch of the image.

The get_current_context function has been replaced with a global variable, current_context, for efficiency.

New features replacing standard practice

pyglet 1.1 introduces new features that make it easier to program with, so the standard practice as followed in many of the pyglet example programs has changed.

Importing pyglet

In pyglet 1.0, it was necessary to explicitly import each submodule required by the application; for example:

from pyglet import font
from pyglet import image
from pyglet import window

pyglet now lazily loads submodules on demand, so an application can get away with importing just pyglet. This is especially handy for modules that are typically only used once in an application, and frees up the names font, image, window and so on for the application developer. For example:

window = pyglet.window.Window()

Application event loop

Every application using pyglet 1.0 provides its own event loop, such as:

while not window.has_exit:
    dt = clock.tick()
    update(dt)

    window.dispatch_events()
    window.clear()
    draw()
    window.flip()

Besides being somewhat repetitious to type, this type of event loop is difficult to extend with more windows, and exausts all available system resources, even if the application is not doing anything.

The new pyglet.app module provides an application event loop that is less demanding of the CPU yet more responsive to user events. A complete application that opens an empty window can be written with:

window = pyglet.window.Window()

@window.event
def on_draw():
    window.clear()

pyglet.app.run()

Note the new on_draw() event, which makes it easy to specify different drawing functions for each window. The pyglet.app event loop takes care of dispatching events, ticking the clock, calling the draw function and flipping the window buffer.

Update functions can be scheduled on the clock. To have an update function be called as often as possible, use clock.schedule (this effectively degenerates into the older dispatch_events practice of thrashing the CPU):

def update(dt):
    pass
clock.schedule(update)

Usually applications can update at a less frequent interval. For example, a game that is designed to run at 60Hz can use clock.schedule_interval:

def update(dt):
    pass
clock.schedule_interval(update, 1/60.0)

This also removes the need for clock.set_fps_limit.

Besides the advantages already listed, windows managed by the event loop will not block while being resized or moved; and the menu bar on OS X can be interacted with without blocking the application.

It is highly recommended that all applications use the event loop. The loop can be extended if you need to add additional hooks or integrate with another package. Applications continuing to use dispatch_events() gain no advantage, but suffer from poorer response, increased CPU usage and artifacts during window resizing and moving.

See The application event loop for more details.

Loading resources

Locating resources such as images, sound and video files, data files and fonts is difficult to do correctly across all platforms, considering the effects of a changing working directory and various distribution packages such as setuptools, py2exe and py2app.

The new pyglet.resource module implements the correct logic for all these cases, making it simple to load resources that belong to a specific module or the application as a whole. A resource path can be set that is indexed once, and can include filesystem directories, Python module paths and ZIP files.

For example, suppose your application ships with a logo.png that needs to be loaded on startup. In pyglet 1.0 you might have written:

import os.path
from pyglet import image

script_dir = os.path.dirname(__file__)
logo_filename = os.path.join(script_dir, 'logo.png')
logo = image.load(logo_filename)

In pyglet 1.1, you can write:

logo = pyglet.resource.image('logo.png')

And will actually work in more scenarios (such as within a setuptools egg file, py2exe and py2app).

The resource module efficiently packs multiple small images into larger textures, so there is less need for artists to create sprite sheets themselves for efficient rendering. Images and textures are also cached automatically.

See Application resources for more details.

New graphics features

The pyglet.graphics module is a low-level abstraction of OpenGL vertex arrays and buffer objects. It is intended for use by developers who are already very familiar with OpenGL and are after the best performance possible. pyglet uses this module internally to implement its new sprite module and the new text rendering module. The Graphics chapter describes this module in detail.

The pyglet.sprite module provide a fast, easy way to display 2D graphics on screen. Sprites can be moved, rotated, scaled and made translucent. Using the batch features of the new graphics API, multiple sprites can be drawn in one go very quickly. See Sprites for details.

The pyglet.image.load_animation function can load animated GIF images. These are returned as an Animation, which exposes the individual image frames and timings. Animations can also be played directly on a sprite in place of an image. The Animations chapter describes how to use them.

The pyglet.image.atlas module packs multiple images into larger textures for efficient rendering. The pyglet.resource module uses this module for small images automatically, but you can use it directly even if you’re not making use of pyglet.resource. See Texture bins and atlases for details.

Images now have anchor_x and anchor_y attributes, which specify a point from which the image should be drawn. The sprite module also uses the anchor point as the center of rotation.

Textures have a get_transform method for retrieving a TextureRegion that refers to the same texture data in video memory, but with optional horizontal or vertical flipping, or 90-degree rotation.

New text features

The pyglet.text module can render formatted text efficiently. A new class Label supercedes the old pyglet.font.Text class (which is now actually implemented in terms of Label()). The “Hello, World” application can now be written:

window = pyglet.window.Window()
label = pyglet.text.Label('Hello, world',
                          font_name='Times New Roman',
                          font_size=36,
                          x=window.width//2, y=window.height//2,
                          halign='center', valign='center')

@window.event
def on_draw():
    window.clear()
    label.draw()

pyglet.app.run()

You can also display multiple fonts and styles within one label, with HTMLLabel:

label = pyglet.text.HTMLLabel('<b>Hello</b>, <font color=red>world!</font>')

More advanced uses of the new text module permit applications to efficiently display large, scrolling, formatted documents (for example, HTML files with embedded images), and to allow the user to interactively edit text as in a WYSIWYG text editor.

Other new features

EventDispatcher now has a remove_handlers method which provides finer control over the event stack than pop_handlers().

The @event decorator has been fixed so that it no longer overrides existing event handlers on the object, which fixes the common problem of handling the on_resize() event. For example, the following now works without any surprises (in pyglet 1.0 this would override the default handler, which sets up a default, necessary viewport and projection):

@window.event
def on_resize(width, height):
    pass

A variant of clock.schedule_interval, clock.schedule_interval_soft has been added. This is for functions that need to be called periodically at a given interval, but do not need to schedule the period immediately. Soft interval scheduling is used by the pyglet.media module to distribute the work of decoding video and audio data over time, rather than stalling the CPU periodically. Games could use soft interval scheduling to spread the regular computational requirements of multiple agents out over time.

In pyglet 1.0, font.load attempted to match the font resolution (DPI) with the operating system’s typical behaviour. For example, on Linux and Mac OS X the default DPI was typically set at 72, and on Windows at 96. While this would be useful for writing a word processor, it adds a burden on the application developer to ensure their fonts work at arbitrary resolutions. In pyglet 1.1 the default DPI is set at 96 across all platforms. It can still be overridden explicitly by the application if desired.

Video sources in pyglet.media can now be stepped through frame-by-frame: individual image frames can be extracted without needing to play back the video in realtime.

For a complete list of new features and bug fixes, see the CHANGELOG distributed with the source distribution.