pyglet Documentation¶
pyglet is a cross-platform windowing and multimedia library for Python, intended for developing games and other visually rich applications. It supports windowing, user interface event handling, game controllers and joysticks, OpenGL graphics, loading images and videos, and playing sounds and music. pyglet works on Windows, OS X and Linux.
Some of the features of pyglet are:
- No external dependencies or installation requirements. For most application and game requirements, pyglet needs nothing else besides Python, simplifying distribution and installation.
- Take advantage of multiple windows and multi-monitor desktops. pyglet allows you to use as many windows as you need, and is fully aware of multi-monitor setups for use with fullscreen games and applications.
- Load images, sound, music and video in almost any format. pyglet has built-in support for common audio and image formats, and can optionally use ffmpeg to load almost any other compressed audio or video files.
- pyglet is provided under the BSD open-source license, allowing you to use it for both commercial and other open-source projects with very little restriction.
Please join our Discord server, or join us on the mailing list!
If this is your first time reading about pyglet, we suggest you start at Writing a pyglet application.
Installation¶
Note
These instructions apply to pyglet 1.5.
pyglet is a pure python library, so no special steps are required for
installation. You can install it in a variety of ways, or simply copy the
pyglet folder directly into your project. If you’re unsure what to do,
the recommended method is to install it into your local site-packages
directory. pyglet is available on PyPI.
and can be installed like any other Python library via pip:
pip install pyglet --user
You can also clone the repository using git and install from source:
git clone https://github.com/pyglet/pyglet.git
cd pyglet
git checkout pyglet-1.5-maintenance
python setup.py install --user
To play compressed audio and video files (anything except for WAV), you will need FFmpeg.
Running the examples¶
The source code archives include examples. Archives are available on Github:
unzip pyglet-x.x.x.zip
cd pyglet-x.x.x
python examples/hello_world.py
As mentioned above, you can also clone the repository using Git:
git clone https://github.com/pyglet/pyglet.git
cd pyglet
git checkout pyglet-1.5-maintenance
python examples/hello_world.py
Writing a pyglet application¶
Getting started with a new library or framework can be daunting, especially when presented with a large amount of reference material to read. This chapter gives a very quick introduction to pyglet without going into too much detail.
Hello, World¶
We’ll begin with the requisite “Hello, World” introduction. This program will open a window with some text in it and wait to be closed. You can find the entire program in the examples/programming_guide/hello_world.py file.
Begin by importing the pyglet
package:
import pyglet
Create a pyglet.window.Window
by calling its default constructor.
The window will be visible as soon as it’s created, and will have reasonable
default values for all its parameters:
window = pyglet.window.Window()
To display the text, we’ll create a Label
. Keyword
arguments are used to set the font, position and anchorage of the label:
label = pyglet.text.Label('Hello, world',
font_name='Times New Roman',
font_size=36,
x=window.width//2, y=window.height//2,
anchor_x='center', anchor_y='center')
An on_draw()
event is dispatched to the window
to give it a chance to redraw its contents. pyglet provides several ways to
attach event handlers to objects; a simple way is to use a decorator:
@window.event
def on_draw():
window.clear()
label.draw()
Within the on_draw()
handler the window is cleared
to the default background color (black), and the label is drawn.
Finally, call:
pyglet.app.run()
This will enter pyglet’s default event loop, and let pyglet respond to
application events such as the mouse and keyboard.
Your event handlers will now be called as required, and the
run()
method will return only when all application
windows have been closed.
If you are coming from another library, you may be used to writing your own event loop. This is possible to do with pyglet as well, but it is generally discouraged; see The application event loop for details.
Image viewer¶
Most games and applications will need to load and display images on the screen. In this example we’ll load an image from the application’s directory and display it within the window:
import pyglet
window = pyglet.window.Window()
image = pyglet.resource.image('kitten.jpg')
@window.event
def on_draw():
window.clear()
image.blit(0, 0)
pyglet.app.run()
We used the image()
function of pyglet.resource
to load the image, which automatically locates the file relative to the source
file (rather than the working directory). To load an image not bundled with
the application (for example, specified on the command line), you would use
pyglet.image.load()
.
The blit()
method draws the image. The
arguments (0, 0)
tell pyglet to draw the image at pixel coordinates 0,
0 in the window (the lower-left corner).
The complete code for this example is located in examples/programming_guide/image_viewer.py.
Handling mouse and keyboard events¶
So far the only event used is the on_draw()
event. To react to keyboard and mouse events, it’s necessary to write and
attach event handlers for these events as well:
import pyglet
window = pyglet.window.Window()
@window.event
def on_key_press(symbol, modifiers):
print('A key was pressed')
@window.event
def on_draw():
window.clear()
pyglet.app.run()
Keyboard events have two parameters: the virtual key symbol that was
pressed, and a bitwise combination of any modifiers that are present (for
example, the CTRL
and SHIFT
keys).
The key symbols are defined in pyglet.window.key
:
from pyglet.window import key
@window.event
def on_key_press(symbol, modifiers):
if symbol == key.A:
print('The "A" key was pressed.')
elif symbol == key.LEFT:
print('The left arrow key was pressed.')
elif symbol == key.ENTER:
print('The enter key was pressed.')
See the pyglet.window.key
documentation for a complete list
of key symbols.
Mouse events are handled in a similar way:
from pyglet.window import mouse
@window.event
def on_mouse_press(x, y, button, modifiers):
if button == mouse.LEFT:
print('The left mouse button was pressed.')
The x
and y
parameters give the position of the mouse when the button
was pressed, relative to the lower-left corner of the window.
There are more than 20 event types that you can handle on a window. An easy way to find the event names and parameters you need is to add the following lines to your program:
event_logger = pyglet.window.event.WindowEventLogger()
window.push_handlers(event_logger)
This will cause all events received on the window to be printed to the console.
An example program using keyboard and mouse events is in examples/programming_guide/events.py
Playing sounds and music¶
pyglet makes it easy to play and mix multiple sounds together. The following example plays an MP3 file [1]:
import pyglet
music = pyglet.resource.media('music.mp3')
music.play()
pyglet.app.run()
As with the image loading example presented earlier,
media()
locates the sound file in the application’s
directory (not the working directory). If you know the actual filesystem path
(either relative or absolute), use pyglet.media.load()
.
By default, audio is streamed when playing. This works well for longer music
tracks. Short sounds, such as a gunfire shot used in a game, should instead be
fully decoded in memory before they are used. This allows them to play more
immediately and incur less of a CPU performance penalty. It also allows playing
the same sound repeatedly without reloading it.
Specify streaming=False
in this case:
sound = pyglet.resource.media('shot.wav', streaming=False)
sound.play()
The examples/media_player.py example demonstrates playback of streaming audio and video using pyglet. The examples/noisy/noisy.py example demonstrates playing many short audio samples simultaneously, as in a game.
[1] | MP3 and other compressed audio formats require FFmpeg to be installed. Uncompressed WAV files can be played without FFmpeg. |
Where to next?¶
The examples above have shown you how to display something on the screen, and perform a few basic tasks. You’re probably left with a lot of questions about these examples, but don’t worry. The remainder of this programming guide goes into greater technical detail on many of pyglet’s features. If you’re an experienced developer, you can probably dive right into the sections that interest you.
For new users, it might be daunting to read through everything all at once. If you feel overwhelmed, we recommend browsing through the beginnings of each chapter, and then having a look at a more in-depth example project. You can find an example of a 2D game in the In-depth game example section.
To write advanced 3D applications or achieve optimal performance in your 2D applications, you’ll need to work with OpenGL directly. If you only want to work with OpenGL primitives, but want something slightly higher-level, have a look at the Graphics module.
There are numerous examples of pyglet applications in the examples/
directory of the documentation and source distributions. If you get
stuck, or have any questions, join us on the mailing list or Discord!
Windowing¶
A Window
in pyglet corresponds to a top-level
window provided by the operating system. Windows can be floating
(overlapped with other application windows) or fullscreen.
Creating a window¶
If the Window
constructor is called with no
arguments, defaults will be assumed for all parameters:
window = pyglet.window.Window()
The default parameters used are:
- The window will have a size of 640x480, and not be resizable.
- A default context will be created using template config described in OpenGL configuration options.
- The window caption will be the name of the executing Python script
(i.e.,
sys.argv[0]
).
Windows are visible as soon as they are created, unless you give the
visible=False
argument to the constructor. The following
example shows how to create and display a window in two steps:
window = pyglet.window.Window(visible=False)
# ... perform some additional initialisation
window.set_visible()
Context configuration¶
The context of a window cannot be changed once created. There are several ways to control the context that is created:
Supply an already-created
Context
using thecontext
argument:context = config.create_context(share) window = pyglet.window.Window(context=context)
Supply a complete
Config
obtained from aScreen
using theconfig
argument. The context will be created from this config and will share object space with the most recently created existing context:config = screen.get_best_config(template) window = pyglet.window.Window(config=config)
Supply a template
Config
using theconfig
argument. The context will use the best config obtained from the default screen of the default display:config = gl.Config(double_buffer=True) window = pyglet.window.Window(config=config)
Specify a
Screen
using thescreen
argument. The context will use a config created from default template configuration and this screen:screen = display.get_screens()[screen_number] window = pyglet.window.Window(screen=screen)
Specify a
Display
using thedisplay
argument. The default screen on this display will be used to obtain a context using the default template configuration:display = platform.get_display(display_name) window = pyglet.window.Window(display=display)
If a template Config
is given, a
Screen
or Display
may also be specified; however any other combination of parameters
overconstrains the configuration and some parameters will be ignored.
Fullscreen windows¶
If the fullscreen=True
argument is given to the window constructor, the
window will draw to an entire screen rather than a floating window. No window
border or controls will be shown, so you must ensure you provide some other
means to exit the application.
By default, the default screen on the default display will be used, however you can optionally specify another screen to use instead. For example, the following code creates a fullscreen window on the secondary screen:
screens = display.get_screens()
window = pyglet.window.Window(fullscreen=True, screen=screens[1])
There is no way to create a fullscreen window that spans more than one window (for example, if you wanted to create an immersive 3D environment across multiple monitors). Instead, you should create a separate fullscreen window for each screen and attach identical event handlers to all windows.
Windows can be toggled in and out of fullscreen mode with the
set_fullscreen()
method. For example, to return to windowed mode from fullscreen:
window.set_fullscreen(False)
The previous window size and location, if any, will attempt to be restored, however the operating system does not always permit this, and the window may have relocated.
Size and position¶
This section applies only to windows that are not fullscreen. Fullscreen windows always have the width and height of the screen they fill.
You can specify the size of a window as the first two arguments to the window constructor. In the following example, a window is created with a width of 1280 pixels and a height of 720 pixels:
window = pyglet.window.Window(1280, 720)
The “size” of a window refers to the drawable space within it, excluding any additional borders or title bar drawn by the operating system.
You can allow the user to resize your window by specifying resizable=True
in the constructor. If you do this, you may also want to handle the
on_resize()
event:
window = pyglet.window.Window(resizable=True)
@window.event
def on_resize(width, height):
print('The window was resized to %dx%d' % (width, height))
You can specify a minimum and maximum size that the window can be resized to
by the user with the set_minimum_size()
and
set_maximum_size()
methods:
window.set_minimum_size(320, 200)
window.set_maximum_size(1024, 768)
The window can also be resized programatically (even if the window is not
user-resizable) with the set_size()
method:
window.set_size(1280, 720)
The window will initially be positioned by the operating system. Typically,
it will use its own algorithm to locate the window in a place that does not
block other application windows, or cascades with them. You can manually
adjust the position of the window using the
get_location()
and
set_location()
methods:
x, y = window.get_location()
window.set_location(x + 20, y + 20)
Note that unlike the usual coordinate system in pyglet, the window location is relative to the top-left corner of the desktop, as shown in the following diagram:

The position and size of the window relative to the desktop.
Appearance¶
Window style¶
Non-fullscreen windows can be created in one of four styles: default, dialog, tool or borderless. Examples of the appearances of each of these styles under Windows and Mac OS X 10.4 are shown below.
Style Windows Mac OS X WINDOW_STYLE_DEFAULT
![]()
![]()
WINDOW_STYLE_DIALOG
![]()
![]()
WINDOW_STYLE_TOOL
![]()
![]()
WINDOW_STYLE_TRANSPARENT
![]()
<Not Implemented> WINDOW_STYLE_OVERLAY
![]()
<Not Implemented>
Non-resizable variants of these window styles may appear slightly different (for example, the maximize button will either be disabled or absent).
Besides the change in appearance, the window styles affect how the window behaves. For example, tool windows do not usually appear in the task bar and cannot receive keyboard focus. Dialog windows cannot be minimized. Overlay’s require custom sizing and moving of the respective window. the appropriate window style for your windows means your application will behave correctly for the platform on which it is running, however that behaviour may not be consistent across Windows, Linux and Mac OS X.
The appearance and behaviour of windows in Linux will vary greatly depending on the distribution, window manager and user preferences.
Borderless windows (WINDOW_STYLE_BORDERLESS
)
are not decorated by the operating system at all, and have no way to be resized
or moved around the desktop. These are useful for implementing splash screens
or custom window borders.
You can specify the style of the window in the
Window
constructor.
Once created, the window style cannot be altered:
window = pyglet.window.Window(style=pyglet.window.Window.WINDOW_STYLE_DIALOG)
Caption¶
The window’s caption appears in its title bar and task bar icon (on Windows
and some Linux window managers). You can set the caption during window
creation or at any later time using the
set_caption()
method:
window = pyglet.window.Window(caption='Initial caption')
window.set_caption('A different caption')
Icon¶
The window icon appears in the title bar and task bar icon on Windows and Linux, and in the dock icon on Mac OS X. Dialog and tool windows do not necessarily show their icon.
Windows, Mac OS X and the Linux window managers each have their own preferred icon sizes:
- Windows XP
- A 16x16 icon for the title bar and task bar.
- A 32x32 icon for the Alt+Tab switcher.
- Mac OS X
- Any number of icons of resolutions 16x16, 24x24, 32x32, 48x48, 72x72 and 128x128. The actual image displayed will be interpolated to the correct size from those provided.
- Linux
- No constraints, however most window managers will use a 16x16 and a 32x32 icon in the same way as Windows XP.
The set_icon()
method allows you to set any
number of images as the icon.
pyglet will select the most appropriate ones to use and apply them to
the window. If an alternate size is required but not provided, pyglet will
scale the image to the correct size using a simple interpolation algorithm.
The following example provides both a 16x16 and a 32x32 image as the window icon:
window = pyglet.window.Window()
icon1 = pyglet.image.load('16x16.png')
icon2 = pyglet.image.load('32x32.png')
window.set_icon(icon1, icon2)
You can use images in any format supported by pyglet, however it is recommended to use a format that supports alpha transparency such as PNG. Windows .ico files are supported only on Windows, so their use is discouraged. Mac OS X .icons files are not supported at all.
Note that the icon that you set at runtime need not have anything to do with the application icon, which must be encoded specially in the application binary (see Self-contained executables).
Visibility¶
Windows have several states of visibility. Already shown is the
visible
property which shows or hides
the window.
Windows can be minimized, which is equivalent to hiding them except that
they still appear on the taskbar (or are minimised to the dock, on OS X).
The user can minimize a window by clicking the appropriate button in the
title bar.
You can also programmatically minimize a window using the
minimize
method (there is also a
corresponding maximize
method).
When a window is made visible the on_show()
event is triggered. When it is hidden the
on_hide()
event is triggered.
On Windows and Linux these events
will only occur when you manually change the visibility of the window or when
the window is minimized or restored. On Mac OS X the user can also hide or
show the window (affecting visibility) using the Command+H shortcut.
Subclassing Window¶
A useful pattern in pyglet is to subclass Window
for
each type of window you will display, or as your main application class. There
are several benefits:
- You can load font and other resources from the constructor, ensuring the OpenGL context has already been created.
- You can add event handlers simply by defining them on the class. The
on_resize()
event will be called as soon as the window is created (this doesn’t usually happen, as you must create the window before you can attach event handlers). - There is reduced need for global variables, as you can maintain application state on the window.
The following example shows the same “Hello World” application as presented
in Writing a pyglet application, using a subclass of Window
:
class HelloWorldWindow(pyglet.window.Window):
def __init__(self):
super(HelloWorldWindow, self).__init__()
self.label = pyglet.text.Label('Hello, world!')
def on_draw(self):
self.clear()
self.label.draw()
if __name__ == '__main__':
window = HelloWorldWindow()
pyglet.app.run()
This example program is located in
examples/programming_guide/window_subclass.py
.
Windows and OpenGL contexts¶
Every window in pyglet has an associated OpenGL context. Specifying the configuration of this context has already been covered in Creating a window. Drawing into the OpenGL context is the only way to draw into the window’s client area.
Double-buffering¶
If the window is double-buffered (i.e., the configuration specified
double_buffer=True
, the default), OpenGL commands are applied to a hidden
back buffer. This back buffer can be brought to the front using the flip
method. The previous front buffer then becomes the hidden back buffer
we render to in the next frame. If you are using the standard pyglet.app.run
or pyglet.app.EventLoop
event loop, this is taken care of
automatically after each on_draw()
event.
If the window is not double-buffered, the
flip()
operation is unnecessary,
and you should remember only to call pyglet.gl.glFlush()
to
ensure buffered commands are executed.
Vertical retrace synchronisation¶
Double-buffering eliminates one cause of flickering: the user is unable to see the image as it is painted, only the final rendering. However, it does introduce another source of flicker known as “tearing”.
Tearing becomes apparent when displaying fast-moving objects in an animation. The buffer flip occurs while the video display is still reading data from the framebuffer, causing the top half of the display to show the previous frame while the bottom half shows the updated frame. If you are updating the framebuffer particularly quickly you may notice three or more such “tears” in the display.
pyglet provides a way to avoid tearing by synchronising buffer flips to the
video refresh rate. This is enabled by default, but can be set or unset
manually at any time with the vsync
(vertical
retrace synchronisation)
property. A window is created with vsync initially disabled in the following
example:
window = pyglet.window.Window(vsync=False)
It is usually desirable to leave vsync enabled, as it results in flicker-free animation. There are some use-cases where you may want to disable it, for example:
- Profiling an application. Measuring the time taken to perform an operation will be affected by the time spent waiting for the video device to refresh, which can throw off results. You should disable vsync if you are measuring the performance of your application.
- If you cannot afford for your application to block. If your application run loop needs to quickly poll a hardware device, for example, you may want to avoid blocking with vsync.
Note that some older video cards do not support the required extensions to implement vsync; this will appear as a warning on the console but is otherwise ignored.
Working with the keyboard¶
pyglet has support for low-level keyboard input suitable for games as well as locale- and device-independent Unicode text entry.
Keyboard input requires a window which has focus. The operating system usually decides which application window has keyboard focus. Typically this window appears above all others and may be decorated differently, though this is platform-specific (for example, Unix window managers sometimes couple keyboard focus with the mouse pointer).
You can request keyboard focus for a window with the
activate()
method, but you should not rely
on this – it may simply provide a visual cue to the user indicating that
the window requires user input, without actually getting focus.
Windows created with the
WINDOW_STYLE_BORDERLESS
or
WINDOW_STYLE_TOOL
style cannot receive keyboard focus.
It is not possible to use pyglet’s keyboard or text events without a window;
consider using Python built-in functions such as input
instead.
Keyboard events¶
The on_key_press()
and
on_key_release()
events are fired when
any key on the keyboard is pressed or released, respectively. These events
are not affected by “key repeat” – once a key is pressed there are no more
events for that key until it is released.
Both events are parameterised by the same arguments:
def on_key_press(symbol, modifiers):
pass
def on_key_release(symbol, modifiers):
pass
Defined key symbols¶
The symbol argument is an integer that represents a “virtual” key code. It does not correspond to any particular numbering scheme; in particular the symbol is not an ASCII character code.
pyglet has key symbols that are hardware and platform independent
for many types of keyboard. These are defined in
pyglet.window.key
as constants. For example, the Latin-1
alphabet is simply the letter itself:
key.A
key.B
key.C
...
The numeric keys have an underscore to make them valid identifiers:
key._1
key._2
key._3
...
Various control and directional keys are identified by name:
key.ENTER or key.RETURN
key.SPACE
key.BACKSPACE
key.DELETE
key.MINUS
key.EQUAL
key.BACKSLASH
key.LEFT
key.RIGHT
key.UP
key.DOWN
key.HOME
key.END
key.PAGEUP
key.PAGEDOWN
key.F1
key.F2
...
Keys on the number pad have separate symbols:
key.NUM_1
key.NUM_2
...
key.NUM_EQUAL
key.NUM_DIVIDE
key.NUM_MULTIPLY
key.NUM_SUBTRACT
key.NUM_ADD
key.NUM_DECIMAL
key.NUM_ENTER
Some modifier keys have separate symbols for their left and right sides (however they cannot all be distinguished on all platforms, including Mac OS X):
key.LCTRL
key.RCTRL
key.LSHIFT
key.RSHIFT
...
Key symbols are independent of any modifiers being held down. For example, lower-case and upper-case letters both generate the A symbol. This is also true of the number keypad.
Modifiers¶
The modifiers that are held down when the event is generated are combined in a
bitwise fashion and provided in the modifiers
parameter. The modifier
constants defined in pyglet.window.key
are:
MOD_SHIFT
MOD_CTRL
MOD_ALT Not available on Mac OS X
MOD_WINDOWS Available on Windows only
MOD_COMMAND Available on Mac OS X only
MOD_OPTION Available on Mac OS X only
MOD_CAPSLOCK
MOD_NUMLOCK
MOD_SCROLLLOCK
MOD_ACCEL Equivalent to MOD_CTRL, or MOD_COMMAND on Mac OS X.
For example, to test if the shift key is held down:
if modifiers & MOD_SHIFT:
pass
Unlike the corresponding key symbols, it is not possible to determine whether the left or right modifier is held down (though you could emulate this behaviour by keeping track of the key states yourself).
User-defined key symbols¶
pyglet does not define key symbols for every keyboard ever made. For example, non-Latin languages will have many keys not recognised by pyglet (however, their Unicode representations will still be valid, see Text and motion events). Even English keyboards often have additional so-called “OEM” keys added by the manufacturer, which might be labelled “Media”, “Volume” or “Shopping”, for example.
In these cases pyglet will create a key symbol at runtime based on the hardware scancode of the key. This is guaranteed to be unique for that model of keyboard, but may not be consistent across other keyboards with the same labelled key.
The best way to use these keys is to record what the user presses after a prompt, and then check for that same key symbol. Many commercial games have similar functionality in allowing players to set up their own key bindings.
Remembering key state¶
pyglet provides the convenience class
KeyStateHandler
for storing the
current keyboard state. This can be pushed onto the event handler stack of
any window and subsequently queried as a dict:
from pyglet.window import key
window = pyglet.window.Window()
keys = key.KeyStateHandler()
window.push_handlers(keys)
# Check if the spacebar is currently pressed:
if keys[key.SPACE]:
pass
Text and motion events¶
pyglet decouples the keys that the user presses from the Unicode text that is input. There are several benefits to this:
- The complex task of mapping modifiers and key symbols to Unicode characters is taken care of automatically and correctly.
- Key repeat is applied to keys held down according to the user’s operating system preferences.
- Dead keys and compose keys are automatically interpreted to produce diacritic marks or combining characters.
- Keyboard input can be routed via an input palette, for example to input characters from Asian languages.
- Text input can come from other user-defined sources, such as handwriting or voice recognition.
The actual source of input (i.e., which keys were pressed, or what input method was used) should be considered outside of the scope of the application – the operating system provides the necessary services.
When text is entered into a window, the
on_text()
event is fired:
def on_text(text):
pass
The only parameter provided is a Unicode string. For keyboard input this will usually be one character long, however more complex input methods such as an input palette may provide an entire word or phrase at once.
You should always use the on_text()
event when you need to determine a string from a sequence of keystrokes.
Conversely, you never use on_text()
when you
require keys to be pressed (for example, to control the movement of the player
in a game).
Motion events¶
In addition to entering text, users press keys on the keyboard to navigate around text widgets according to well-ingrained conventions. For example, pressing the left arrow key moves the cursor one character to the left.
While you might be tempted to use the
on_key_press()
event to capture these
events, there are a couple of problems:
- Key repeat events are not generated for
on_key_press()
, yet users expect that holding down the left arrow key will eventually move the character to the beginning of the line. - Different operating systems have different conventions for the behaviour of keys. For example, on Windows it is customary for the Home key to move the cursor to the beginning of the line, whereas on Mac OS X the same key moves to the beginning of the document.
pyglet windows provide the on_text_motion()
event, which takes care of these problems by abstracting away the key presses
and providing your application only with the intended cursor motion:
def on_text_motion(motion):
pass
motion is an integer which is a constant defined in
pyglet.window.key
. The following table shows the defined text motions
and their keyboard mapping on each operating system.
Constant Behaviour Windows/Linux Mac OS X MOTION_UP
Move the cursor up Up Up MOTION_DOWN
Move the cursor down Down Down MOTION_LEFT
Move the cursor left Left Left MOTION_RIGHT
Move the cursor right Right Right MOTION_PREVIOUS_WORD
Move the cursor to the previous word Ctrl + Left Option + Left MOTION_NEXT_WORD
Move the cursor to the next word Ctrl + Right Option + Right MOTION_BEGINNING_OF_LINE
Move the cursor to the beginning of the current line Home Command + Left MOTION_END_OF_LINE
Move the cursor to the end of the current line End Command + Right MOTION_PREVIOUS_PAGE
Move to the previous page Page Up Page Up MOTION_NEXT_PAGE
Move to the next page Page Down Page Down MOTION_BEGINNING_OF_FILE
Move to the beginning of the document Ctrl + Home Home MOTION_END_OF_FILE
Move to the end of the document Ctrl + End End MOTION_BACKSPACE
Delete the previous character Backspace Backspace MOTION_DELETE
Delete the next character, or the current character Delete Delete
Keyboard exclusivity¶
Some keystrokes or key combinations normally bypass applications and are handled by the operating system. Some examples are Alt+Tab (Command+Tab on Mac OS X) to switch applications and the keys mapped to Expose on Mac OS X.
You can disable these hot keys and have them behave as ordinary keystrokes for your application. This can be useful if you are developing a kiosk application which should not be closed, or a game in which it is possible for a user to accidentally press one of these keys.
To enable this mode, call
set_exclusive_keyboard()
for the window on
which it should apply. On Mac OS X the dock and menu bar will slide out of
view while exclusive keyboard is activated.
The following restrictions apply on Windows:
- Most keys are not disabled: a user can still switch away from your application using Ctrl+Escape, Alt+Escape, the Windows key or Ctrl+Alt+Delete. Only the Alt+Tab combination is disabled.
The following restrictions apply on Mac OS X:
- The power key is not disabled.
Use of this function is not recommended for general release applications or games as it violates user-interface conventions.
Working with the mouse¶
All pyglet windows can receive input from a 3 button mouse with a 2 dimensional scroll wheel. The mouse pointer is typically drawn by the operating system, but you can override this and request either a different cursor shape or provide your own image or animation.
Mouse events¶
All mouse events are dispatched by the window which receives the event from the operating system. Typically this is the window over which the mouse cursor is, however mouse exclusivity and drag operations mean this is not always the case.
The coordinate space for the mouse pointer’s location is relative to the bottom-left corner of the window, with increasing Y values approaching the top of the screen (note that this is “upside-down” compared with many other windowing toolkits, but is consistent with the default OpenGL projection in pyglet).

The coordinate space for the mouse pointer.
The most basic mouse event is on_mouse_motion()
which is dispatched every time the mouse moves:
def on_mouse_motion(x, y, dx, dy):
pass
The x and y parameters give the coordinates of the mouse pointer, relative to the bottom-left corner of the window.
The event is dispatched every time the operating system registers a mouse
movement. This is not necessarily once for every pixel moved – the operating
system typically samples the mouse at a fixed frequency, and it is easy to
move the mouse faster than this. Conversely, if your application is not
processing events fast enough you may find that several queued-up mouse events
are dispatched in a single dispatch_events()
call. There is no need to concern yourself with either of these issues;
the latter rarely causes problems, and the former can not be avoided.
Many games are not concerned with the actual position of the mouse cursor, and only need to know in which direction the mouse has moved. For example, the mouse in a first-person game typically controls the direction the player looks, but the mouse pointer itself is not displayed.
The dx and dy parameters are for this purpose: they give the distance the mouse travelled along each axis to get to its present position. This can be computed naively by storing the previous x and y parameters after every mouse event, but besides being tiresome to code, it does not take into account the effects of other obscuring windows. It is best to use the dx and dy parameters instead.
The following events are dispatched when a mouse button is pressed or released, or the mouse is moved while any button is held down:
def on_mouse_press(x, y, button, modifiers):
pass
def on_mouse_release(x, y, button, modifiers):
pass
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
pass
The x, y, dx and dy parameters are as for the
on_mouse_motion()
event.
The press and release events do not require dx and dy parameters as they
would be zero in this case. The modifiers parameter is as for the keyboard
events, see Working with the keyboard.
The button parameter signifies which mouse button was pressed, and is one of the following constants:
pyglet.window.mouse.LEFT
pyglet.window.mouse.MIDDLE
pyglet.window.mouse.RIGHT
The buttons parameter in on_mouse_drag()
is a bitwise combination of all the mouse buttons currently held down.
For example, to test if the user is performing a drag gesture with the
left button:
from pyglet.window import mouse
def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
if buttons & mouse.LEFT:
pass
When the user begins a drag operation (i.e., pressing and holding a mouse
button and then moving the mouse), the window in which they began the drag
will continue to receive the on_mouse_drag()
event as long as the button is held down.
This is true even if the mouse leaves the window.
You generally do not need to handle this specially: it is a convention
among all operating systems that dragging is a gesture rather than a direct
manipulation of the user interface widget.
There are events for when the mouse enters or leaves a window:
def on_mouse_enter(x, y):
pass
def on_mouse_leave(x, y):
pass
The coordinates for on_mouse_leave()
will
lie outside of your window. These events are not dispatched while a drag
operation is taking place.
The mouse scroll wheel generates the
on_mouse_scroll()
event:
def on_mouse_scroll(x, y, scroll_x, scroll_y):
pass
The scroll_y parameter gives the number of “clicks” the wheel moved, with positive numbers indicating the wheel was pushed forward. The scroll_x parameter is 0 for most mice, however some new mice such as the Apple Mighty Mouse use a ball instead of a wheel; the scroll_x parameter gives the horizontal movement in this case. The scale of these numbers is not known; it is typically set by the user in their operating system preferences.
Changing the mouse cursor¶
The mouse cursor can be set to one of the operating system cursors, a custom
image, or hidden completely. The change to the cursor will be applicable only
to the window you make the change to. To hide the mouse cursor, call
set_mouse_visible()
:
win = pyglet.window.Window()
win.set_mouse_visible(False)
This can be useful if the mouse would obscure text that the user is typing. If you are hiding the mouse cursor for use in a game environment, consider making the mouse exclusive instead; see Mouse exclusivity, below.
Use set_mouse_cursor()
to change the appearance
of the mouse cursor. A mouse cursor is an instance of
MouseCursor
. You can obtain the operating
system-defined cursors with
get_system_mouse_cursor()
:
cursor = win.get_system_mouse_cursor(win.CURSOR_HELP)
win.set_mouse_cursor(cursor)
The cursors that pyglet defines are listed below, along with their typical appearance on Windows and Mac OS X. The pointer image on Linux is dependent on the window manager.
Constant Windows XP Mac OS X CURSOR_DEFAULT ![]()
![]()
CURSOR_CROSSHAIR ![]()
![]()
CURSOR_HAND ![]()
![]()
CURSOR_HELP ![]()
![]()
CURSOR_NO ![]()
![]()
CURSOR_SIZE ![]()
![]()
CURSOR_SIZE_DOWN ![]()
![]()
CURSOR_SIZE_DOWN_LEFT ![]()
![]()
CURSOR_SIZE_DOWN_RIGHT ![]()
![]()
CURSOR_SIZE_LEFT ![]()
![]()
CURSOR_SIZE_LEFT_RIGHT ![]()
![]()
CURSOR_SIZE_RIGHT ![]()
![]()
CURSOR_SIZE_UP ![]()
![]()
CURSOR_SIZE_UP_DOWN ![]()
![]()
CURSOR_SIZE_UP_LEFT ![]()
![]()
CURSOR_SIZE_UP_RIGHT ![]()
![]()
CURSOR_TEXT ![]()
![]()
CURSOR_WAIT ![]()
![]()
CURSOR_WAIT_ARROW ![]()
![]()
Alternatively, you can use your own image as the mouse cursor. Use
pyglet.image.load()
to load the image, then create an
ImageMouseCursor
with
the image and “hot-spot” of the cursor. The hot-spot is the point of the
image that corresponds to the actual pointer location on screen, for example,
the point of the arrow:
image = pyglet.image.load('cursor.png')
cursor = pyglet.window.ImageMouseCursor(image, 16, 8)
win.set_mouse_cursor(cursor)
You can even render a mouse cursor directly with OpenGL. You could draw a
3-dimensional cursor, or a particle trail, for example. To do this, subclass
MouseCursor
and implement your own draw method.
The draw method will be called with the default pyglet window projection,
even if you are using another projection in the rest of your application.
Mouse exclusivity¶
It is possible to take complete control of the mouse for your own application, preventing it being used to activate other applications. This is most useful for immersive games such as first-person shooters.
When you enable mouse-exclusive mode, the mouse cursor is no longer available. It is not merely hidden – no amount of mouse movement will make it leave your application. Because there is no longer a mouse cursor, the x and y parameters of the mouse events are meaningless; you should use only the dx and dy parameters to determine how the mouse was moved.
Activate mouse exclusive mode with
set_exclusive_mouse()
:
win = pyglet.window.Window()
win.set_exclusive_mouse(True)
You should activate mouse exclusive mode even if your window is full-screen: it will prevent the window “hitting” the edges of the screen, and behave correctly in multi-monitor setups (a common problem with commercial full-screen games is that the mouse is only hidden, meaning it can accidentally travel onto the other monitor where applications are still visible).
Note that on Linux setting exclusive mouse also disables Alt+Tab and other hotkeys for switching applications. No workaround for this has yet been discovered.
Working with other input devices¶
Pyglet’s input
module allows you to accept input
from any USB human interface device (HID). High level interfaces
are provided for working with joysticks and with the Apple Remote.
Using joysticks¶
Before using a joystick, you must find it and open it. To get a list
of all joystick devices currently connected to your computer, call
pyglet.input.get_joysticks()
:
joysticks = pyglet.input.get_joysticks()
Then choose a joystick from the list and call Joystick.open to open the device:
if joysticks:
joystick = joysticks[0]
joystick.open()
The current position of the joystick is recorded in its ‘x’ and ‘y’ attributes, both of which are normalized to values within the range of -1 to 1. For the x-axis, x = -1 means the joystick is pushed all the way to the left and x = 1 means the joystick is pushed to the right. For the y-axis, a value of y = -1 means that the joystick is pushed up and a value of y = 1 means that the joystick is pushed down.
If your joystick has two analog controllers, the position of the second controller is typically given by z and rz, where z is the horizontal axis position and rz is the vertical axis position.
The state of the joystick buttons is contained in the buttons attribute as a list of boolean values. A True value indicates that the corresponding button is being pressed. While buttons may be labeled A, B, X, or Y on the physical joystick, they are simply referred to by their index when accessing the buttons list. There is no easy way to know which button index corresponds to which physical button on the device without testing the particular joystick, so it is a good idea to let users change button assignments.
Each open joystick dispatches events when the joystick changes state.
For buttons, there is the on_joybutton_press()
event which is sent whenever any of the joystick’s buttons are pressed:
def on_joybutton_press(joystick, button):
pass
and the on_joybutton_release()
event which is
sent whenever any of the joystick’s buttons are released:
def on_joybutton_release(joystick, button):
pass
The Joystick
parameter is the
Joystick
instance whose buttons changed state
(useful if you have multiple joysticks connected).
The button parameter signifies which button changed and is simply an
integer value, the index of the corresponding button in the buttons
list.
For most games, it is probably best to examine the current position of
the joystick directly by using the x and y attributes. However if
you want to receive notifications whenever these values change you
should handle the on_joyaxis_motion()
event:
def on_joyaxis_motion(joystick, axis, value):
pass
The Joystick
parameter again tells you which
joystick device changed. The axis parameter is string such as
“x”, “y”, or “rx” telling you which axis changed value. And value
gives the current normalized value of the axis, ranging between -1 and 1.
If the joystick has a hat switch, you may examine its current value by looking at the hat_x and hat_y attributes. For both, the values are either -1, 0, or 1. Note that hat_y will output 1 in the up position and -1 in the down position, which is the opposite of the y-axis control.
To be notified when the hat switch changes value, handle the
on_joyhat_motion()
event:
def on_joyhat_motion(joystick, hat_x, hat_y):
pass
The hat_x and hat_y parameters give the same values as the joystick’s hat_x and hat_y attributes.
A good way to use the joystick event handlers might be to define them within a controller class and then call:
joystick.push_handlers(my_controller)
Please note that you need a running application event loop for the joystick button an axis values to be properly updated. See the The application event loop section for more details on how to start an event loop.
Using the Apple Remote¶
The Apple Remote is a small infrared remote originally distributed with the iMac. The remote has six buttons, which are accessed with the names left, right, up, down, menu, and select. Additionally when certain buttons are held down, they act as virtual buttons. These are named left_hold, right_hold, menu_hold, and select_hold.
To use the remote, first call get_apple_remote()
:
remote = pyglet.input.get_apple_remote()
Then open it:
if remote:
remote.open(window, exclusive=True)
The remote is opened in exclusive mode so that while we are using the remote in our program, pressing the buttons does not activate Front Row, or change the volume, etc. on the computer.
The following event handlers tell you when a button on the remote has been either pressed or released:
def on_button_press(button):
pass
def on_button_release(button):
pass
The button parameter indicates which button changed and is a string equal to one of the ten button names defined above: “up”, “down”, “left”, “left_hold”, “right”, “right_hold”, “select”, “select_hold”, “menu”, or “menu_hold”.
To use the remote, you may define code for the event handlers in some controller class and then call:
remote.push_handlers(my_controller)
Graphics¶
At the lowest level, pyglet uses OpenGL to draw graphics in program windows.
The OpenGL interface is exposed via the pyglet.gl
module
(see The OpenGL interface).
Using the OpenGL interface directly, however, can be difficult to do
efficiently. The pyglet.graphics
module provides a simpler means
for drawing graphics that uses vertex arrays and vertex buffer objects
internally to deliver better performance.
Drawing primitives¶
The pyglet.graphics
module draws the OpenGL primitive objects by
a mode denoted by the constants
pyglet.gl.GL_POINTS
pyglet.gl.GL_LINES
pyglet.gl.GL_LINE_LOOP
pyglet.gl.GL_LINE_STRIP
pyglet.gl.GL_TRIANGLES
pyglet.gl.GL_TRIANGLE_STRIP
pyglet.gl.GL_TRIANGLE_FAN
pyglet.gl.GL_QUADS
pyglet.gl.GL_QUAD_STRIP
pyglet.gl.GL_POLYGON
See the OpenGL Programming Guide for a description of each of mode.
Each primitive is made up of one or more vertices. Each vertex is specified with either 2, 3 or 4 components (for 2D, 3D, or non-homogeneous coordinates). The data type of each component can be either int or float.
Use pyglet.graphics.draw()
to directly draw a primitive.
The following example draws two points at coordinates (10, 15) and (30, 35):
pyglet.graphics.draw(2, pyglet.gl.GL_POINTS,
('v2i', (10, 15, 30, 35))
)
The first and second arguments to the function give the number of vertices to draw and the primitive mode, respectively. The third argument is a “data item”, and gives the actual vertex data.
However, because of the way the graphics API renders multiple primitives with
shared state, GL_POLYGON
, GL_LINE_LOOP
and GL_TRIANGLE_FAN
cannot
be used — the results are undefined.
Alternatively, the NV_primitive_restart
extension can be used if it is
present. This also permits use of GL_POLYGON
, GL_LINE_LOOP
and
GL_TRIANGLE_FAN
. Unfortunately the extension is not provided by older
video drivers, and requires indexed vertex lists.
Because vertex data can be supplied in several forms, a “format string” is
required. In this case, the format string is "v2i"
, meaning the vertex
position data has two components (2D) and int type.
The following example has the same effect as the previous one, but uses floating point data and 3 components per vertex:
pyglet.graphics.draw(2, pyglet.gl.GL_POINTS,
('v3f', (10.0, 15.0, 0.0, 30.0, 35.0, 0.0))
)
Vertices can also be drawn out of order and more than once by using the
pyglet.graphics.draw_indexed()
function. This requires a list of
integers giving the indices into the vertex data. The following example
draws the same two points as above, but indexes the vertices (sequentially):
pyglet.graphics.draw_indexed(2, pyglet.gl.GL_POINTS,
[0, 1],
('v2i', (10, 15, 30, 35))
)
This second example is more typical; two adjacent triangles are drawn, and the shared vertices are reused with indexing:
pyglet.graphics.draw_indexed(4, pyglet.gl.GL_TRIANGLES,
[0, 1, 2, 0, 2, 3],
('v2i', (100, 100,
150, 100,
150, 150,
100, 150))
)
Note that the first argument gives the number of vertices in the data, not the number of indices (which is implicit on the length of the index list given in the third argument).
When using GL_LINE_STRIP
, GL_TRIANGLE_STRIP
or GL_QUAD_STRIP
care
must be taken to insert degenerate vertices at the beginning and end of each
vertex list. For example, given the vertex list:
A, B, C, D
the correct vertex list to provide the vertex list is:
A, A, B, C, D, D
Vertex attributes¶
Besides the required vertex position, vertices can have several other numeric attributes. Each is specified in the format string with a letter, the number of components and the data type.
Each of the attributes is described in the table below with the set of valid
format strings written as a regular expression (for example, "v[234][if]"
means "v2f"
, "v3i"
, "v4f"
, etc. are all valid formats).
Some attributes have a “recommended” format string, which is the most efficient form for the video driver as it requires less conversion.
Attribute Formats Recommended Vertex position "v[234][sifd]"
"v[234]f"
Color "c[34][bBsSiIfd]"
"c[34]B"
Edge flag "e1[bB]"
Fog coordinate "f[1234][bBsSiIfd]"
Normal "n3[bsifd]"
"n3f"
Secondary color "s[34][bBsSiIfd]"
"s[34]B"
Texture coordinate "[0-31]?t[234][sifd]"
"[0-31]?t[234]f"
Generic attribute "[0-15]g(n)?[1234][bBsSiIfd]"
The possible data types that can be specified in the format string are described below.
Format Type Python type "b"
Signed byte int "B"
Unsigned byte int "s"
Signed short int "S"
Unsigned short int "i"
Signed int int "I"
Unsigned int int "f"
Single precision float float "d"
Double precision float float
The following attributes are normalised to the range [0, 1]
. The value is
used as-is if the data type is floating-point. If the data type is byte,
short or int, the value is divided by the maximum value representable by that
type. For example, unsigned bytes are divided by 255 to get the normalised
value.
- Color
- Secondary color
- Generic attributes with the
"n"
format given.
Texture coordinate attributes may optionally be preceded by a texture unit
number. If unspecified, texture unit 0 (GL_TEXTURE0
) is implied. It is
the application’s responsibility to ensure that the OpenGL version is adequate
and that the specified texture unit is within the maximum allowed by the
implementation.
Up to 16 generic attributes can be specified per vertex, and can be used by shader programs for any purpose (they are ignored in the fixed-function pipeline). For the other attributes, consult the OpenGL programming guide for details on their effects.
When using the pyglet.graphics.draw and related functions, attribute data is specified alongside the vertex position data. The following example reproduces the two points from the previous page, except that the first point is blue and the second green:
pyglet.graphics.draw(2, pyglet.gl.GL_POINTS,
('v2i', (10, 15, 30, 35)),
('c3B', (0, 0, 255, 0, 255, 0))
)
It is an error to provide more than one set of data for any attribute, or to mismatch the size of the initial data with the number of vertices specified in the first argument.
Vertex lists¶
There is a significant overhead in using pyglet.graphics.draw()
and
pyglet.graphics.draw_indexed()
due to pyglet interpreting and
formatting the vertex data for the video device. Usually the data drawn in
each frame (of an animation) is identical or very similar to the previous
frame, so this overhead is unnecessarily repeated.
A VertexList
is a list of vertices
and their attributes, stored in an efficient manner that’s suitable for
direct upload to the video card. On newer video cards (supporting
OpenGL 1.5 or later) the data is actually stored in video memory.
Create a VertexList
for a set of
attributes and initial data with pyglet.graphics.vertex_list()
.
The following example creates a vertex list with the two coloured points
used in the previous page:
vertex_list = pyglet.graphics.vertex_list(2,
('v2i', (10, 15, 30, 35)),
('c3B', (0, 0, 255, 0, 255, 0))
)
To draw the vertex list, call its draw()
method:
vertex_list.draw(pyglet.gl.GL_POINTS)
Note that the primitive mode is given to the draw method, not the vertex list
constructor. Otherwise the pyglet.graphics.vertex_list()
function
takes the same arguments as pyglet.graphics.draw
, including
any number of vertex attributes.
Because vertex lists can reside in video memory, it is necessary to call the delete method to release video resources if the vertex list isn’t going to be used any more (there’s no need to do this if you’re just exiting the process).
Updating vertex data¶
The data in a vertex list can be modified. Each vertex attribute (including
the vertex position) appears as an attribute on the
VertexList
object.
The attribute names are given in the following table.
Vertex attribute Object attribute Vertex position vertices
Color colors
Edge flag edge_flags
Fog coordinate fog_coords
Normal normals
Secondary color secondary_colors
Texture coordinate tex_coords
[1]Generic attribute Inaccessible
In the following example, the vertex positions of the vertex list are updated
by replacing the vertices
attribute:
vertex_list.vertices = [20, 25, 40, 45]
The attributes can also be selectively updated in-place:
vertex_list.vertices[:2] = [30, 35]
Similarly, the color attribute of the vertex can be updated:
vertex_list.colors[:3] = [255, 0, 0]
For large vertex lists, updating only the modified vertices can have a perfomance benefit, especially on newer graphics cards.
Attempting to set the attribute list to a different size will cause an error (not necessarily immediately, either). To resize the vertex list, call VertexList.resize with the new vertex count. Be sure to fill in any newly uninitialised data after resizing the vertex list.
Since vertex lists are mutable, you may not necessarily want to initialise
them with any particular data. You can specify just the format string in
place of the (format, data)
tuple in the data arguments vertex_list
function. The following example creates a vertex list of 1024 vertices with
positional, color, texture coordinate and normal attributes:
vertex_list = pyglet.graphics.vertex_list(1024, 'v3f', 'c4B', 't2f', 'n3f')
Data usage¶
By default, pyglet assumes vertex data will be updated less often than it is drawn, but more often than just during initialisation. You can override this assumption for each attribute by affixing a usage specification onto the end of the format string, detailed in the following table:
Usage Description "/static"
Data is never or rarely modified after initialisation "/dynamic"
Data is occasionally modified (default) "/stream"
Data is updated every frame
In the following example a vertex list is created in which the positional data is expected to change every frame, but the color data is expected to remain relatively constant:
vertex_list = pyglet.graphics.vertex_list(1024, 'v3f/stream', 'c4B/static')
The usage specification affects how pyglet lays out vertex data in memory,
whether or not it’s stored on the video card, and is used as a hint to OpenGL.
Specifying a usage does not affect what operations are possible with a vertex
list (a static
attribute can still be modified), and may only have
performance benefits on some hardware.
Indexed vertex lists¶
IndexedVertexList
performs the same
role as VertexList
, but for indexed
vertices. Use pyglet.graphics.vertex_list_indexed()
to construct an
indexed vertex list, and update the
indices
sequence to
change the indices.
[1] | Only texture coordinates for texture unit 0 are accessible through this attribute. |
Batched rendering¶
For optimal OpenGL performance, you should render as many vertex lists as
possible in a single draw
call. Internally, pyglet uses
VertexDomain
and
IndexedVertexDomain
to keep vertex
lists that share the same attribute formats in adjacent areas of memory.
The entire domain of vertex lists can then be drawn at once, without calling
draw()
on each individual
list.
It is quite difficult and tedious to write an application that manages vertex domains itself, though. In addition to maintaining a vertex domain for each set of attribute formats, domains must also be separated by primitive mode and required OpenGL state.
The Batch
class implements this functionality,
grouping related vertex lists together and sorting by OpenGL state
automatically. A batch is created with no arguments:
batch = pyglet.graphics.Batch()
Vertex lists can now be created with the add()
and add_indexed()
methods instead of
pyglet.graphics.vertex_list()
and
pyglet.graphics.vertex_list_indexed()
functions. Unlike the module
functions, these methods accept a mode
parameter (the primitive mode)
and a group
parameter (described below).
The two coloured points from previous pages can be added to a batch as a single vertex list with:
vertex_list = batch.add(2, pyglet.gl.GL_POINTS, None,
('v2i', (10, 15, 30, 35)),
('c3B', (0, 0, 255, 0, 255, 0))
)
The resulting vertex_list can be modified as described in the previous
section. However, instead of calling VertexList.draw
to draw it, call
Batch.draw()
to draw all vertex lists contained in the batch at once:
batch.draw()
For batches containing many vertex lists this gives a significant performance improvement over drawing individual vertex lists.
To remove a vertex list from a batch, call VertexList.delete()
. If you
don’t need to modify or delete vertex lists after adding them to the batch,
you can simply ignore the return value of the
add()
and
add_indexed()
methods.
Setting the OpenGL state¶
In order to achieve many effects in OpenGL one or more global state parameters must be set. For example, to enable and bind a texture requires:
from pyglet.gl import *
glEnable(texture.target)
glBindTexture(texture.target, texture.id)
before drawing vertex lists, and then:
glDisable(texture.target)
afterwards to avoid interfering with later drawing commands.
With a Group
these state changes can be
encapsulated and associated with the vertex lists they affect.
Subclass Group
and override the Group.set_state
and Group.unset_state methods to perform the required state changes:
class CustomGroup(pyglet.graphics.Group):
def set_state(self):
glEnable(texture.target)
glBindTexture(texture.target, texture.id)
def unset_state(self):
glDisable(texture.target)
An instance of this group can now be attached to vertex lists in the batch:
custom_group = CustomGroup()
vertex_list = batch.add(2, pyglet.gl.GL_POINTS, custom_group,
('v2i', (10, 15, 30, 35)),
('c3B', (0, 0, 255, 0, 255, 0))
)
The Batch
ensures that the appropriate
set_state
and unset_state
methods are called before and after
the vertex lists that use them.
Hierarchical state¶
Groups have a parent attribute that allows them to be implicitly organised
in a tree structure. If groups B and C have parent A, then the
order of set_state
and unset_state
calls for vertex lists in a batch
will be:
A.set_state()
# Draw A vertices
B.set_state()
# Draw B vertices
B.unset_state()
C.set_state()
# Draw C vertices
C.unset_state()
A.unset_state()
This is useful to group state changes into as few calls as possible. For example, if you have a number of vertex lists that all need texturing enabled, but have different bound textures, you could enable and disable texturing in the parent group and bind each texture in the child groups. The following example demonstrates this:
class TextureEnableGroup(pyglet.graphics.Group):
def set_state(self):
glEnable(GL_TEXTURE_2D)
def unset_state(self):
glDisable(GL_TEXTURE_2D)
texture_enable_group = TextureEnableGroup()
class TextureBindGroup(pyglet.graphics.Group):
def __init__(self, texture):
super(TextureBindGroup, self).__init__(parent=texture_enable_group)
assert texture.target = GL_TEXTURE_2D
self.texture = texture
def set_state(self):
glBindTexture(GL_TEXTURE_2D, self.texture.id)
# No unset_state method required.
def __eq__(self, other):
return (self.__class__ is other.__class__ and
self.texture.id == other.texture.id and
self.texture.target == other.texture.target and
self.parent == other.parent)
def __hash__(self):
return hash((self.texture.id, self.texture.target))
batch.add(4, GL_QUADS, TextureBindGroup(texture1), 'v2f', 't2f')
batch.add(4, GL_QUADS, TextureBindGroup(texture2), 'v2f', 't2f')
batch.add(4, GL_QUADS, TextureBindGroup(texture1), 'v2f', 't2f')
Note the use of an __eq__
method on the group to allow
Batch
to merge the two TextureBindGroup
identical instances.
Sorting vertex lists¶
VertexDomain
does not attempt
to keep vertex lists in any particular order. So, any vertex lists sharing
the same primitive mode, attribute formats and group will be drawn in an
arbitrary order. However, Batch
will sort
Group
objects sharing the same parent by
their __cmp__
method. This allows groups to be ordered.
The OrderedGroup
class is a convenience
group that does not set any OpenGL state, but is parameterised by an
integer giving its draw order. In the following example a number of
vertex lists are grouped into a “background” group that is drawn before
the vertex lists in the “foreground” group:
background = pyglet.graphics.OrderedGroup(0)
foreground = pyglet.graphics.OrderedGroup(1)
batch.add(4, GL_QUADS, foreground, 'v2f')
batch.add(4, GL_QUADS, background, 'v2f')
batch.add(4, GL_QUADS, foreground, 'v2f')
batch.add(4, GL_QUADS, background, 'v2f', 'c4B')
By combining hierarchical groups with ordered groups it is possible to
describe an entire scene within a single Batch
,
which then renders it as efficiently as possible.
Batches and groups in other modules¶
The Sprite
, Label
and
TextLayout
classes all accept batch
and
group
parameters in their constructors. This allows you to add any of
these higher-level pyglet drawables into arbitrary places in your rendering
code.
For example, multiple sprites can be grouped into a single batch and then
drawn at once, instead of calling Sprite.draw()
on each one individually:
batch = pyglet.graphics.Batch()
sprites = [pyglet.sprite.Sprite(image, batch=batch) for i in range(100)]
batch.draw()
The group
parameter can be used to set the drawing order (and hence which
objects overlap others) within a single batch, as described on the previous
page.
In general you should batch all drawing objects into as few batches as
possible, and use groups to manage the draw order and other OpenGL state
changes for optimal performance. If you are creating your own drawable
classes, consider adding batch
and group
parameters in a similar way.
Shapes¶
The shapes
module is a simplified option for creating
and manipulating colored shapes. This includes rectangles, circles, and
lines. Shapes can be resized, positioned, and rotated where applicable,
and their color and opacity can be changed. All shapes are implemented
using OpenGL primitives, so they can be drawn efficiently with Batched rendering.
In the following examples Batch will be ommitted for brevity, but in
general you always want to use Batched rendering for performance.
For drawing more complex shapes, see the Graphics module.
Creating a Shape¶
Various shapes can be constructed with a specific position, size, and color:
circle = shapes.Circle(x=100, y=150, radius=100, color=(50, 225, 30))
square = shapes.Rectangle(x=200, y=200, width=200, height=200, color=(55, 55, 255))
You can also change the color, or set the opacity after creation. The opacity can can be set on a scale of 0-255, for various levels of transparency:
circle.opacity = 120
The size of Shapes can also be adjusted after creation:
square.width = 200
circle.radius = 99
Anchor Points¶
Similar to images in pyglet, the “anchor point” of a Shape can be set. This relates to the center of the shape on the x and y axis. For Circles, the default anchor point is the center of the circle. For Rectangles, it is the bottom left corner. Depending on how you need to position your Shapes, this can be changed. For Rectangles this is especially useful if you will rotate it, since Shapes will rotate around the anchor point. In this example, a Rectangle is created, and the anchor point is then set to the center:
rectangle = shapes.Rectangle(x=400, y=400, width=100, height=50)
rectangle.anchor_x = 50
rectangle.anchor_y = 25
# or, set at the same time:
rectangle.anchor_position = 50, 25
# The rectangle is then rotated around it's anchor point:
rectangle.rotation = 45
If you plan to create a large number of shapes, you can optionally set the default anchor points:
shapes.Rectangle._anchor_x = 100
shapes.Rectangle._anchor_y = 50
Displaying text¶
pyglet provides the font
module for efficiently rendering
high-quality antialiased Unicode glyphs. pyglet can use any installed font
on the operating system, or you can provide your own font with your
application.
Please note that not all font formats are supported, see Supported font formats
Text rendering is performed with the text
module, which
can display word-wrapped formatted text. There is also support for
interactive editing of text on-screen with a caret.
Simple text rendering¶
The following complete example creates a window that displays “Hello, World” centered vertically and horizontally:
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,
anchor_x='center', anchor_y='center')
@window.event
def on_draw():
window.clear()
label.draw()
pyglet.app.run()
The example demonstrates the most common uses of text rendering:
- The font name and size are specified directly in the constructor. Additional parameters exist for setting the bold and italic styles and the color of the text.
- The position of the text is given by the
x
andy
coordinates. The meaning of these coordinates is given by theanchor_x
andanchor_y
parameters. - The actual drawing of the text to the screen is done with the
pyglet.text.Label.draw()
method. Labels can also be added to a graphics batch; see Batched rendering for details.
The HTMLLabel()
class is used similarly, but accepts
an HTML formatted string instead of parameters describing the style.
This allows the label to display text with mixed style:
label = pyglet.text.HTMLLabel(
'<font face="Times New Roman" size="4">Hello, <i>world</i></font>',
x=window.width//2, y=window.height//2,
anchor_x='center', anchor_y='center')
See Formatted text for details on the subset of HTML that is supported.
The document/layout model¶
The Label()
class demonstrated above presents a
simplified interface to pyglet’s complete text rendering capabilities.
The underlying TextLayout()
and
AbstractDocument
classes provide a
“model/view” interface to all of pyglet’s text features.
Documents¶
A document is the “model” part of the architecture, and describes the
content and style of the text to be displayed. There are two concrete
document classes: UnformattedDocument
and FormattedDocument
.
UnformattedDocument
models a document
containing text in just one style, whereas
FormattedDocument
allows the style to
change within the text.
An empty, unstyled document can be created by constructing either of the
classes directly. Usually you will want to initialise the document with some
text, however. The decode_text()
,
decode_attributed()
and
decode_html()
functions return a document given a
source string. For decode_text()
,
this is simply a plain text string, and the return value is an
UnformattedDocument
:
document = pyglet.text.decode_text('Hello, world.')
decode_attributed()
and
decode_html()
are described in detail in the next
section.
The text of a document can be modified directly as a property on the object:
document.text = 'Goodbye, cruel world.'
However, if small changes are being made to the document it can be more
efficient (when coupled with an appropriate layout; see below) to use the
delete_text()
and
insert_text()
methods instead.
Layouts¶
The actual layout and rendering of a document is performed by the
TextLayout()
classes.
This split exists to reduce the complexity of the code, and to allow
a single document to be displayed in multiple layouts simultaneously (in other
words, many layouts can display one document).
Each of the TextLayout()
classes perform layout
in the same way, but represent a trade-off in efficiency of update against
efficiency of drawing and memory usage.
The base TextLayout()
class uses little memory,
and shares its graphics group with other
TextLayout()
instances in the same batch
(see Batched rendering). When the text or style of the document
is modified, or the layout constraints change (for example, the width of the
layout changes), the entire text layout is recalculated.
This is a potentially expensive operation, especially for long documents.
This makes TextLayout()
suitable
for relatively short or unchanging documents.
ScrollableTextLayout
is a small extension to
TextLayout()
that clips the
text to a specified view rectangle, and allows text to be scrolled within that
rectangle without performing the layout calculuation again. Because of this
clipping rectangle the graphics group cannot be shared with other text
layouts, so for ideal performance
ScrollableTextLayout
should be used only
if this behaviour is required.
IncrementalTextLayout
uses a more sophisticated
layout algorithm that performs less work for small changes to documents.
For example, if a document is being edited by the user, only the immediately
affected lines of text are recalculated when a character is typed or deleted.
IncrementalTextLayout
also performs view rectangle culling, reducing the amount of layout and
rendering required when the document is larger than the view.
IncrementalTextLayout
should be used for
large documents or documents that change rapidly.
All the layout classes can be constructed given a document and display dimensions:
layout = pyglet.text.layout.TextLayout(document, width, height)
Additional arguments to the constructor allow the specification of a graphics batch and group (recommended if many layouts are to be rendered), and the optional multiline and wrap_lines flags.
- multiline
- To honor newlines in the document you will need to set this to
True
. If you do not then newlines will be rendered as plain spaces. - wrap_lines
- If you expect that your document lines will be wider than the display width
then pyglet can automatically wrap them to fit the width by setting this
option to
True
.
Like labels, layouts are positioned through their x, y,
anchor_x and anchor_y properties.
Note that unlike AbstractImage
, the anchor
properties accept a string such as "bottom"
or "center"
instead of a
numeric displacement.
Formatted text¶
The FormattedDocument
class maintains
style information for individual characters in the text, rather than a
single style for the whole document.
Styles can be accessed and modified by name, for example:
# Get the font name used at character index 0
font_name = document.get_style('font_name', 0)
# Set the font name and size for the first 5 characters
document.set_style(0, 5, dict(font_name='Arial', font_size=12))
Internally, character styles are run-length encoded over the document text; so longer documents with few style changes do not use excessive memory.
From the document’s point of view, there are no predefined style names: it
simply maps names and character ranges to arbitrary Python values.
It is the TextLayout
classes that interpret
this style information; for example, by selecting a different font based on the
font_name
style. Unrecognised style names are ignored by the layout
– you can use this knowledge to store additional data alongside the
document text (for example, a URL behind a hyperlink).
Character styles¶
The following character styles are recognised by all
TextLayout()
classes.
Where an attribute is marked “as a distance” the value is assumed to be
in pixels if given as an int or float, otherwise a string of the form
"0u"
is required, where 0
is the distance and u
is the unit; one
of "px"
(pixels), "pt"
(points), "pc"
(picas), "cm"
(centimeters), "mm"
(millimeters) or "in"
(inches). For example,
"14pt"
is the distance covering 14 points, which at the default DPI of 96
is 18 pixels.
font_name
- Font family name, as given to
pyglet.font.load()
. font_size
- Font size, in points.
bold
- Boolean.
italic
- Boolean.
underline
- 4-tuple of ints in range (0, 255) giving RGBA underline color, or None (default) for no underline.
kerning
- Additional space to insert between glyphs, as a distance. Defaults to 0.
baseline
- Offset of glyph baseline from line baseline, as a distance. Positive values give a superscript, negative values give a subscript. Defaults to 0.
color
- 4-tuple of ints in range (0, 255) giving RGBA text color
background_color
- 4-tuple of ints in range (0, 255) giving RGBA text background color; or
None
for no background fill.
Paragraph styles¶
Although FormattedDocument
does not
distinguish between character- and paragraph-level styles,
TextLayout()
interprets the following styles
only at the paragraph level. You should take care to set these styles for
complete paragraphs only, for example, by using
set_paragraph_style()
.
These styles are ignored for layouts without the multiline
flag set.
align
"left"
(default),"center"
or"right"
.indent
- Additional horizontal space to insert before the first glyph of the first line of a paragraph, as a distance.
leading
- Additional space to insert between consecutive lines within a paragraph, as a distance. Defaults to 0.
line_spacing
- Distance between consecutive baselines in a paragraph, as a distance.
Defaults to
None
, which automatically calculates the tightest line spacing for each line based on the maximum font ascent and descent. margin_left
- Left paragraph margin, as a distance.
margin_right
- Right paragraph margin, as a distance.
margin_top
- Margin above paragraph, as a distance.
margin_bottom
- Margin below paragraph, as a distance. Adjacent margins do not collapse.
tab_stops
- List of horizontal tab stops, as distances, measured from the left edge of the text layout. Defaults to the empty list. When the tab stops are exhausted, they implicitly continue at 50 pixel intervals.
wrap
- Boolean. If True (the default), text wraps within the width of the layout.
For the purposes of these attributes, paragraphs are split by the newline character (U+0010) or the paragraph break character (U+2029). Line breaks within a paragraph can be forced with character U+2028.
Tabs¶
A tab character in pyglet text is interpreted as ‘move to the next tab stop’. Tab stops are specified in pixels, not in some font unit; by default there is a tab stop every 50 pixels and because of that a tab can look too small for big fonts or too big for small fonts.
Additionally, when rendering text with tabs using a monospace font, character boxes may not align vertically.
To avoid these visualization issues the simpler solution is to convert the tabs to spaces before sending a string to a pyglet text-related class.
Attributed text¶
pyglet provides two formats for decoding formatted documents from plain text. These are useful for loading preprepared documents such as help screens. At this time there is no facility for saving (encoding) formatted documents.
The attributed text format is an encoding specific to pyglet that can
exactly describe any FormattedDocument
.
You must use this encoding to access all of the features of pyglet text layout.
For a more accessible, yet less featureful encoding,
see the HTML encoding, described below.
The following example shows a simple attributed text encoded document:
Chapter 1
My father's family name being Pirrip, and my Christian name Philip,
my infant tongue could make of both names nothing longer or more
explicit than Pip. So, I called myself Pip, and came to be called
Pip.
I give Pirrip as my father's family name, on the authority of his
tombstone and my sister - Mrs. Joe Gargery, who married the
blacksmith. As I never saw my father or my mother, and never saw
any likeness of either of them (for their days were long before the
days of photographs), my first fancies regarding what they were
like, were unreasonably derived from their tombstones.
Newlines are ignored, unless two are made in succession, indicating a
paragraph break. Line breaks can be forced with the \\
sequence:
This is the way the world ends \\
This is the way the world ends \\
This is the way the world ends \\
Not with a bang but a whimper.
Line breaks are also forced when the text is indented with one or more spaces or tabs, which is useful for typesetting code:
The following paragraph has hard line breaks for every line of code:
import pyglet
window = pyglet.window.Window()
pyglet.app.run()
Text can be styled using a attribute tag:
This sentence makes a {bold True}bold{bold False} statement.
The attribute tag consists of the attribute name (in this example, bold
)
followed by a Python bool, int, float, string, tuple or list.
Unlike most structured documents such as HTML, attributed text has no concept
of the “end” of a style; styles merely change within the document.
This corresponds exactly to the representation used by
FormattedDocument
internally.
Some more examples follow:
{font_name 'Times New Roman'}{font_size 28}Hello{font_size 12},
{color (255, 0, 0, 255)}world{color (0, 0, 0, 255)}!
(This example uses 28pt Times New Roman for the word “Hello”, and 12pt red text for the word “world”).
Paragraph styles can be set by prefixing the style name with a period (.). This ensures the style range exactly encompasses the paragraph:
{.margin_left "12px"}This is a block quote, as the margin is inset.
{.margin_left "24px"}This paragraph is inset yet again.
Attributed text can be loaded as a Unicode string. In addition, any character can be inserted given its Unicode code point in numeric form, either in decimal:
This text is Copyright {#169}.
or hexadecimal:
This text is Copyright {#xa9}.
The characters {
and }
can be escaped by duplicating them:
Attributed text uses many "{{" and "}}" characters.
Use the decode_attributed
function to decode attributed text into a
FormattedDocument
:
document = pyglet.text.decode_attributed('Hello, {bold True}world')
HTML¶
While attributed text gives access to all of the features of
FormattedDocument
and
TextLayout()
, it is quite verbose and difficult
produce text in. For convenience, pyglet provides an HTML 4.01 decoder that
can translate a small, commonly used subset of HTML into a
FormattedDocument
.
Note that the decoder does not preserve the structure of the HTML document – all notion of element hierarchy is lost in the translation, and only the visible style changes are preserved.
The following example uses decode_html()
to create a
FormattedDocument
from a string of HTML:
document = pyglet.text.decode_html('Hello, <b>world</b>')
The following elements are supported:
B BLOCKQUOTE BR CENTER CODE DD DIR DL EM FONT H1 H2 H3 H4 H5 H6 I IMG KBD
LI MENU OL P PRE Q SAMP STRONG SUB SUP TT U UL VAR
The style
attribute is not supported, so font sizes must be given as HTML
logical sizes in the range 1 to 7, rather than as point sizes. The
corresponding font sizes, and some other stylesheet parameters, can be
modified by subclassing HTMLDecoder.
Custom elements¶
Graphics and other visual elements can be inserted inline into a document
using insert_element()
.
For example, inline elements are used to render HTML images included with
the IMG
tag. There is currently no support for floating or
absolutely-positioned elements.
Elements must subclass InlineElement
and override the place and remove methods. These methods are called by
TextLayout()
when the element becomes
or ceases to be visible. For TextLayout()
and ScrollableTextLayout
,
this is when the element is added or removed from the document;
but for IncrementalTextLayout
the methods
are also called as the element scrolls in and out of the viewport.
The constructor of InlineElement
gives the width and height (separated into the ascent above the baseline,
and descent below the baseline) of the element.
Typically an InlineElement
subclass will
add graphics primitives to the layout’s graphics batch; though applications
may choose to simply record the position of the element and render it
separately.
The position of the element in the document text is marked with a NUL character (U+0000) placeholder. This has the effect that inserting an element into a document increases the length of the document text by one. Elements can also be styled as if they were ordinary character text, though the layout ignores any such style attributes.
User-editable text¶
While pyglet does not come with any complete GUI widgets for applications to
use, it does implement many of the features required to implement interactive
text editing. These can be used as a basis for a more complete GUI system, or
to present a simple text entry field, as demonstrated in the
examples/text_input.py
example.
IncrementalTextLayout
should always be used for
text that can be edited by the user.
This class maintains information about the placement of glyphs on screen,
and so can map window coordinates to a document position and vice-versa.
These methods are
get_position_from_point()
,
get_point_from_position()
,
get_line_from_point()
,
get_point_from_line()
,
get_line_from_position()
,
get_position_from_line()
,
get_position_on_line()
and
get_line_count()
.
The viewable rectangle of the document can be adjusted using a document
position instead of a scrollbar using the
ensure_line_visible()
and
ensure_x_visible()
methods.
IncrementalTextLayout
can display a current
text selection by temporarily overriding the foreground and background colour
of the selected text. The
selection_start
and
selection_end
properties
give the range of the selection, and
selection_color
and
selection_background_color
the colors to use (defaulting to white on blue).
The Caret
class implements an insertion caret
(cursor) for IncrementalTextLayout
.
This includes displaying the blinking caret at the correct location,
and handling keyboard, text and mouse events.
The behaviour in response to the events is very similar to the system GUIs
on Windows, Mac OS X and GTK. Using Caret
frees you from using the IncrementalTextLayout
methods described above directly.
The following example creates a document, a layout and a caret and attaches the caret to the window to listen for events:
import pyglet
window = pyglet.window.Window()
document = pyglet.text.document.FormattedDocument()
layout = pyglet.text.layout.IncrementalTextLayout(document, width, height)
caret = pyglet.text.caret.Caret(layout)
window.push_handlers(caret)
When the layout is drawn, the caret will also be drawn, so this example is nearly complete enough to display the user input. However, it is suitable for use when only one editable text layout is to be in the window. If multiple text widgets are to be shown, some mechanism is needed to dispatch events to the widget that has keyboard focus. An example of how to do this is given in the examples/text_input.py example program.
Loading system fonts¶
The layout classes automatically load fonts as required. You can also explicitly load fonts to implement your own layout algorithms.
To load a font you must know its family name. This is the name displayed in the font dialog of any application. For example, all operating systems include the Times New Roman font. You must also specify the font size to load, in points:
# Load "Times New Roman" at 16pt
times = pyglet.font.load('Times New Roman', 16)
Bold and italic variants of the font can specified with keyword parameters:
times_bold = pyglet.font.load('Times New Roman', 16, bold=True)
times_italic = pyglet.font.load('Times New Roman', 16, italic=True)
times_bold_italic = pyglet.font.load('Times New Roman', 16,
bold=True, italic=True)
For maximum compatibility on all platforms, you can specify a list of font names to load, in order of preference. For example, many users will have installed the Microsoft Web Fonts pack, which includes Verdana, but this cannot be guaranteed, so you might specify Arial or Helvetica as suitable alternatives:
sans_serif = pyglet.font.load(('Verdana', 'Helvetica', 'Arial'), 16)
Also you can check for the availability of a font using
pyglet.font.have_font()
:
# Will return True
pyglet.font.have_font('Times New Roman')
# Will return False
pyglet.font.have_font('missing-font-name')
If you do not particularly care which font is used, and just need to display some readable text, you can specify None as the family name, which will load a default sans-serif font (Helvetica on Mac OS X, Arial on Windows XP):
sans_serif = pyglet.font.load(None, 16)
Font sizes¶
When loading a font you must specify the font size it is to be rendered at, in points. Points are a somewhat historical but conventional unit used in both display and print media. There are various conflicting definitions for the actual length of a point, but pyglet uses the PostScript definition: 1 point = 1/72 inches.
Font resolution¶
The actual rendered size of the font on screen depends on the display resolution. pyglet uses a default DPI of 96 on all operating systems. Most Mac OS X applications use a DPI of 72, so the font sizes will not match up on that operating system. However, application developers can be assured that font sizes remain consistent in pyglet across platforms.
The DPI can be specified directly in the pyglet.font.load()
function, and as an argument to the TextLayout()
constructor.
Determining font size¶
Once a font is loaded at a particular size, you can query its pixel size with the attributes:
Font.ascent
Font.descent
These measurements are shown in the diagram below.

Font metrics. Note that the descent is usually negative as it descends below the baseline.
You can calculate the distance between successive lines of text as:
ascent - descent + leading
where leading is the number of pixels to insert between each line of text.
Loading custom fonts¶
You can supply a font with your application if it’s not commonly installed on the target platform. You should ensure you have a license to distribute the font – the terms are often specified within the font file itself, and can be viewed with your operating system’s font viewer.
Loading a custom font must be performed in two steps:
- Let pyglet know about the additional font or font files.
- Load the font by its family name.
For example, let’s say you have the Action Man font in a file called
action_man.ttf
. The following code will load an instance of that font:
pyglet.font.add_file('action_man.ttf')
action_man = pyglet.font.load('Action Man')
Similarly, once the font file has been added, the font name can be specified as a style on a label or layout:
label = pyglet.text.Label('Hello', font_name='Action Man')
Fonts are often distributed in separate files for each variant. Action Man
Bold would probably be distributed as a separate file called
action_man_bold.ttf
; you need to let pyglet know about this as well:
font.add_file('action_man_bold.ttf')
action_man_bold = font.load('Action Man', bold=True)
Note that even when you know the filename of the font you want to load, you
must specify the font’s family name to pyglet.font.load()
.
You need not have the file on disk to add it to pyglet; you can specify any file-like object supporting the read method. This can be useful for extracting fonts from a resource archive or over a network.
If the custom font is distributed with your application, consider using the Application resources.
Supported font formats¶
pyglet can load any font file that the operating system natively supports, but not all formats all fully supported.
The list of supported formats is shown in the table below.
Font Format Windows Mac OS X Linux (FreeType) TrueType (.ttf) X X X PostScript Type 1 (.pfm, .pfb) X X X Windows Bitmap (.fnt) X X Mac OS X Data Fork Font (.dfont) X OpenType (.otf) [1] X X11 font formats PCF, BDF, SFONT X Bitstream PFR (.pfr) X
[1] | All OpenType fonts are backward compatible with TrueType, so while the advanced OpenType features can only be rendered with Mac OS X, the files can be used on any platform. pyglet does not currently make use of the additional kerning and ligature information within OpenType fonts. In Windows a few will use the variant DEVICE_FONTTYPE and may render bad, by example inconsolata.otf, from http://levien.com/type/myfonts/inconsolata.html |
Some of the fonts found in internet may miss information for some operating systems, others may have been written with work in progress tools not fully compliant with standards. Using the font with text editors or fonts viewers can help to determine if the font is broken.
OpenGL font considerations¶
Text in pyglet is drawn using textured quads. Each font maintains a set of one or more textures, into which glyphs are uploaded as they are needed. For most applications this detail is transparent and unimportant, however some of the details of these glyph textures are described below for advanced users.
Context affinity¶
When a font is loaded, it immediately creates a texture in the current context’s object space. Subsequent textures may need to be created if there is not enough room on the first texture for all the glyphs. This is done when the glyph is first requested.
pyglet always assumes that the object space that was active when the font was loaded is the active one when any texture operations are performed. Normally this assumption is valid, as pyglet shares object spaces between all contexts by default. There are a few situations in which this will not be the case, though:
- When explicitly setting the context share during context creation.
- When multiple display devices are being used which cannot support a shared context object space.
In any of these cases, you will need to reload the font for each object space that it’s needed in. pyglet keeps a cache of fonts, but does so per-object-space, so it knows when it can reuse an existing font instance or if it needs to load it and create new textures. You will also need to ensure that an appropriate context is active when any glyphs may need to be added.
Blend state¶
The glyph textures have an internal format of GL_ALPHA
, which provides
a simple way to recolour and blend antialiased text by changing the
vertex colors. pyglet makes very few assumptions about the OpenGL state, and
will not alter it besides changing the currently bound texture.
The following blend state is used for drawing font glyphs:
from pyglet.gl import *
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_BLEND)
All glyph textures use the GL_TEXTURE_2D
target, so you should ensure that
a higher priority target such as GL_TEXTURE_3D
is not enabled before
trying to render text.
Images¶
pyglet provides functions for loading and saving images in various formats using native operating system services. If the Pillow library is installed, many additional formats can be supported. pyglet also includes built-in codecs for loading PNG and BMP without external dependencies.
Loaded images can be efficiently provided to OpenGL as a texture, and OpenGL textures and framebuffers can be retrieved as pyglet images to be saved or otherwise manipulated.
If you’ve done any game or graphics programming, you’re probably familiar with
the concept of “sprites”. pyglet also provides an efficient and comprehensive
Sprite
class, for displaying images on the screen
with an optional transform (such as scaling and rotation). If you’re planning
to do anything with images that involves movement and placement on screen,
you’ll likely want to use sprites.
Loading an image¶
Images can be loaded using the pyglet.image.load()
function:
kitten = pyglet.image.load('kitten.png')
If you are distributing your application with included images, consider
using the pyglet.resource
module (see Application resources).
Without any additional arguments, pyglet.image.load()
will
attempt to load the filename specified using any available image decoder.
This will allow you to load PNG, GIF, JPEG, BMP and DDS files,
and possibly other files as well, depending on your operating system
and additional installed modules (see the next section for details).
If the image cannot be loaded, an
ImageDecodeException
will be raised.
You can load an image from any file-like object providing a read method by specifying the file keyword parameter:
kitten_stream = open('kitten.png', 'rb')
kitten = pyglet.image.load('kitten.png', file=kitten_stream)
In this case the filename kitten.png
is optional, but gives a hint to
the decoder as to the file type (it is otherwise unused when a file object
is provided).
pyglet provides the following image decoders:
Module Class Description pyglet.image.codecs.dds
DDSImageDecoder
Reads Microsoft DirectDraw Surface files containing compressed textures pyglet.image.codecs.gdiplus
GDIPlusDecoder
Uses Windows GDI+ services to decode images. pyglet.image.codecs.gdkpixbuf2
GdkPixbuf2ImageDecoder
Uses the GTK-2.0 GDK functions to decode images. pyglet.image.codecs.pil
PILImageDecoder
Wrapper interface around PIL Image class. pyglet.image.codecs.quicktime
QuickTimeImageDecoder
Uses Mac OS X QuickTime to decode images. pyglet.image.codecs.png
PNGImageDecoder
BMP decoder written in pure Python. pyglet.image.codecs.bmp
BMPImageDecoder
BMP decoder written in pure Python.
Each of these classes registers itself with pyglet.image
with
the filename extensions it supports. The load()
function will try each image decoder with a matching file extension first,
before attempting the other decoders. Only if every image decoder fails
to load an image will ImageDecodeException
be raised (the origin of the exception will be the first decoder that
was attempted).
You can override this behaviour and specify a particular decoding instance to use. For example, in the following example the pure Python PNG decoder is always used rather than the operating system’s decoder:
from pyglet.image.codecs.png import PNGImageDecoder
kitten = pyglet.image.load('kitten.png', decoder=PNGImageDecoder())
This use is not recommended unless your application has to work around specific deficiences in an operating system decoder.
Supported image formats¶
The following table lists the image formats that can be loaded on each operating system. If Pillow is installed, any additional formats it supports can also be read. See the Pillow docs for a list of such formats.
Extension Description Windows Mac OS X Linux [5] .bmp
Windows Bitmap X X X .dds
Microsoft DirectDraw Surface [6] X X X .exif
Exif X .gif
Graphics Interchange Format X X X .jpg .jpeg
JPEG/JIFF Image X X X .jp2 .jpx
JPEG 2000 X .pcx
PC Paintbrush Bitmap Graphic X .png
Portable Network Graphic X X X .pnm
PBM Portable Any Map Graphic Bitmap X .ras
Sun raster graphic X .tga
Truevision Targa Graphic X .tif .tiff
Tagged Image File Format X X X .xbm
X11 bitmap X X .xpm
X11 icon X X
The only supported save format is PNG, unless PIL is installed, in which case any format it supports can be written.
[5] | Requires GTK 2.0 or later. |
[6] | Only S3TC compressed surfaces are supported. Depth, volume and cube textures are not supported. |
Working with images¶
The pyglet.image.load()
function returns an
AbstractImage
. The actual class of the object depends
on the decoder that was used, but all loaded imageswill have the following
attributes:
- width
- The width of the image, in pixels.
- height
- The height of the image, in pixels.
- anchor_x
- Distance of the anchor point from the left edge of the image, in pixels
- anchor_y
- Distance of the anchor point from the bottom edge of the image, in pixels
The anchor point defaults to (0, 0), though some image formats may contain an intrinsic anchor point. The anchor point is used to align the image to a point in space when drawing it.
You may only want to use a portion of the complete image. You can use the
get_region()
method to return an image
of a rectangular region of a source image:
image_part = kitten.get_region(x=10, y=10, width=100, height=100)
This returns an image with dimensions 100x100. The region extracted from kitten is aligned such that the bottom-left corner of the rectangle is 10 pixels from the left and 10 pixels from the bottom of the image.
Image regions can be used as if they were complete images. Note that changes to an image region may or may not be reflected on the source image, and changes to the source image may or may not be reflected on any region images. You should not assume either behaviour.
The AbstractImage hierarchy¶
The following sections deal with the various concrete image classes. All
images subclass AbstractImage
, which provides
the basic interface described in previous sections.

The AbstractImage
class hierarchy.
An image of any class can be converted into a Texture
or ImageData
using the
get_texture()
and
get_image_data()
methods defined on
AbstractImage
. For example, to load an image
and work with it as an OpenGL texture:
kitten = pyglet.image.load('kitten.png').get_texture()
There is no penalty for accessing one of these methods if object is already of the requested class. The following table shows how concrete classes are converted into other classes:
Original class .get_texture()
.get_image_data()
Texture
No change glGetTexImage2D
TextureRegion
No change glGetTexImage2D
, crop resulting image.ImageData
glTexImage2D
[1]No change ImageDataRegion
glTexImage2D
[1]No change CompressedImageData
glCompressedTexImage2D
[2]N/A [3] BufferImage
glCopyTexSubImage2D
[4]glReadPixels
You should try to avoid conversions which use glGetTexImage2D
or
glReadPixels
, as these can impose a substantial performance penalty by
transferring data in the “wrong” direction of the video bus, especially on
older hardware.
[1] | (1, 2) ImageData caches the texture for future use, so there is no
performance penalty for repeatedly blitting an
ImageData . |
[2] | If the required texture compression extension is not present, the
image is decompressed in memory and then supplied to OpenGL via
glTexImage2D . |
[3] | It is not currently possible to retrieve ImageData for compressed
texture images. This feature may be implemented in a future release
of pyglet. One workaround is to create a texture from the compressed
image, then read the image data from the texture; i.e.,
compressed_image.get_texture().get_image_data() . |
[4] | BufferImageMask cannot be converted to
Texture . |
Accessing or providing pixel data¶
The ImageData
class represents an image as a string
or sequence of pixel data, or as a ctypes pointer. Details such as the pitch
and component layout are also stored in the class. You can access an
ImageData
object for any image with
get_image_data()
:
kitten = pyglet.image.load('kitten.png').get_image_data()
The design of ImageData
is to allow applications
to access the detail in the format they prefer, rather than having to
understand the many formats that each operating system and OpenGL make use of.
The pitch and format properties determine how the bytes are arranged. pitch gives the number of bytes between each consecutive row. The data is assumed to run from left-to-right, bottom-to-top, unless pitch is negative, in which case it runs from left-to-right, top-to-bottom. There is no need for rows to be tightly packed; larger pitch values are often used to align each row to machine word boundaries.
The format property gives the number and order of color components. It is a string of one or more of the letters corresponding to the components in the following table:
R Red G Green B Blue A Alpha L Luminance I Intensity
For example, a format string of "RGBA"
corresponds to four bytes of
colour data, in the order red, green, blue, alpha. Note that machine
endianness has no impact on the interpretation of a format string.
The length of a format string always gives the number of bytes per pixel. So,
the minimum absolute pitch for a given image is len(kitten.format) *
kitten.width
.
To retrieve pixel data in a particular format, use the get_data method,
specifying the desired format and pitch. The following example reads tightly
packed rows in RGB
format (the alpha component, if any, will be
discarded):
kitten = kitten.get_image_data()
data = kitten.get_data('RGB', kitten.width * 3)
data always returns a string, however pixel data can be set from a ctypes array, stdlib array, list of byte data, string, or ctypes pointer. To set the image data use set_data, again specifying the format and pitch:
kitten.set_data('RGB', kitten.width * 3, data)
You can also create ImageData
directly, by providing
each of these attributes to the constructor. This is any easy way to load
textures into OpenGL from other programs or libraries.
Performance concerns¶
pyglet can use several methods to transform pixel data from one format to another. It will always try to select the most efficient means. For example, when providing texture data to OpenGL, the following possibilities are examined in order:
- Can the data be provided directly using a built-in OpenGL pixel format such
as
GL_RGB
orGL_RGBA
? - Is there an extension present that handles this pixel format?
- Can the data be transformed with a single regular expression?
- If none of the above are possible, the image will be split into separate scanlines and a regular expression replacement done on each; then the lines will be joined together again.
The following table shows which image formats can be used directly with steps 1 and 2 above, as long as the image rows are tightly packed (that is, the pitch is equal to the width times the number of components).
Format Required extensions "I"
"L"
"LA"
"R"
"G"
"B"
"A"
"RGB"
"RGBA"
"ARGB"
GL_EXT_bgra
andGL_APPLE_packed_pixels
"ABGR"
GL_EXT_abgr
"BGR"
GL_EXT_bgra
"BGRA"
GL_EXT_bgra
If the image data is not in one of these formats, a regular expression will be constructed to pull it into one. If the rows are not tightly packed, or if the image is ordered from top-to-bottom, the rows will be split before the regular expression is applied. Each of these may incur a performance penalty – you should avoid such formats for real-time texture updates if possible.
Image sequences and atlases¶
Sometimes a single image is used to hold several images. For example, a “sprite sheet” is an image that contains each animation frame required for a character sprite animation.
pyglet provides convenience classes for extracting the individual images from such a composite image as if it were a simple Python sequence. Discrete images can also be packed into one or more larger textures with texture bins and atlases.

The AbstractImageSequence class hierarchy.
Image grids¶
An “image grid” is a single image which is divided into several smaller images by drawing an imaginary grid over it. The following image shows an image used for the explosion animation in the Astraea example.

An image consisting of eight animation frames arranged in a grid.
This image has one row and eight columns. This is all the information you
need to create an ImageGrid
with:
explosion = pyglet.image.load('explosion.png')
explosion_seq = pyglet.image.ImageGrid(explosion, 1, 8)
The images within the grid can now be accessed as if they were their own images:
frame_1 = explosion_seq[0]
frame_2 = explosion_seq[1]
Images with more than one row can be accessed either as a single-dimensional sequence, or as a (row, column) tuple; as shown in the following diagram.

An image grid with several rows and columns, and the slices that can be used to access it.
Image sequences can be sliced like any other sequence in Python. For example, the following obtains the first four frames in the animation:
start_frames = explosion_seq[:4]
For efficient rendering, you should use a
TextureGrid
.
This uses a single texture for the grid, and each individual image returned
from a slice will be a TextureRegion
:
explosion_tex_seq = image.TextureGrid(explosion_seq)
Because TextureGrid
is also a
Texture
, you can use it either as individual images
or as the whole grid at once.
3D textures¶
TextureGrid
is extremely efficient for drawing many
sprites from a single texture. One problem you may encounter, however,
is bleeding between adjacent images.
When OpenGL renders a texture to the screen, by default it obtains each pixel
colour by interpolating nearby texels. You can disable this behaviour by
switching to the GL_NEAREST
interpolation mode, however you then lose the
benefits of smooth scaling, distortion, rotation and sub-pixel positioning.
You can alleviate the problem by always leaving a 1-pixel clear border around each image frame. This will not solve the problem if you are using mipmapping, however. At this stage you will need a 3D texture.
You can create a 3D texture from any sequence of images, or from an
ImageGrid
. The images must all be of the same
dimension, however they need not be powers of two (pyglet takes care of
this by returning TextureRegion
as with a regular Texture
).
In the following example, the explosion texture from above is uploaded into a 3D texture:
explosion_3d = pyglet.image.Texture3D.create_for_image_grid(explosion_seq)
You could also have stored each image as a separate file and used
pyglet.image.Texture3D.create_for_images()
to create the 3D texture.
Once created, a 3D texture behaves like any other
AbstractImageSequence
; slices return
TextureRegion
for an image plane within the texture.
Unlike a TextureGrid
, though, you cannot blit a
Texture3D
in its entirety.
Texture bins and atlases¶
Image grids are useful when the artist has good tools to construct the larger images of the appropriate format, and the contained images all have the same size. However it is often simpler to keep individual images as separate files on disk, and only combine them into larger textures at runtime for efficiency.
A TextureAtlas
is initially an empty texture,
but images of any size can be added to it at any time. The atlas takes care
of tracking the “free” areas within the texture, and of placing images at
appropriate locations within the texture to avoid overlap.
It’s possible for a TextureAtlas
to run out
of space for new images, so applications will need to either know the correct
size of the texture to allocate initally, or maintain multiple atlases as
each one fills up.
The TextureBin
class provides a simple means
to manage multiple atlases. The following example loads a list of images,
then inserts those images into a texture bin. The resulting list is a list of
TextureRegion
images that map
into the larger shared texture atlases:
images = [
pyglet.image.load('img1.png'),
pyglet.image.load('img2.png'),
# ...
]
bin = pyglet.image.atlas.TextureBin()
images = [bin.add(image) for image in images]
The pyglet.resource
module (see Application resources) uses
texture bins internally to efficiently pack images automatically.
Animations¶
While image sequences and atlases provide storage for related images, they alone are not enough to describe a complete animation.
The Animation
class manages a list of
AnimationFrame
objects, each of
which references an image and a duration (in seconds). The storage of
the images is up to the application developer: they can each be discrete, or
packed into a texture atlas, or any other technique.
An animation can be loaded directly from a GIF 89a image file with
load_animation()
(supported on Linux, Mac OS X
and Windows) or constructed manually from a list of images or an image
sequence using the class methods (in which case the timing information
will also need to be provided).
The add_to_texture_bin()
method provides
a convenient way to pack the image frames into a texture bin for efficient
access.
Individual frames can be accessed by the application for use with any kind of
rendering, or the entire animation can be used directly with a
Sprite
(see next section).
The following example loads a GIF animation and packs the images in that animation into a texture bin. A sprite is used to display the animation in the window:
animation = pyglet.image.load_animation('animation.gif')
bin = pyglet.image.atlas.TextureBin()
animation.add_to_texture_bin(bin)
sprite = pyglet.sprite.Sprite(img=animation)
window = pyglet.window.Window()
@window.event
def on_draw():
window.clear()
sprite.draw()
pyglet.app.run()
When animations are loaded with pyglet.resource
(see
Application resources) the frames are automatically packed into a texture bin.
This example program is located in examples/programming_guide/animation.py, along with a sample GIF animation file.
Buffer images¶
pyglet provides a basic representation of the framebuffer as components of the
AbstractImage
hierarchy. At this stage this
representation is based off OpenGL 1.1, and there is no support for newer
features such as framebuffer objects. Of course, this doesn’t prevent you
using framebuffer objects in your programs – pyglet.gl
provides
this functionality – just that they are not represented as
AbstractImage
types.

The BufferImage
hierarchy.
A framebuffer consists of
- One or more colour buffers, represented by
ColorBufferImage
- An optional depth buffer, represented by
DepthBufferImage
- An optional stencil buffer, with each bit represented by
BufferImageMask
- Any number of auxiliary buffers, also represented by
ColorBufferImage
You cannot create the buffer images directly; instead you must obtain
instances via the BufferManager
.
Use get_buffer_manager()
to get this singleton:
buffers = image.get_buffer_manager()
Only the back-left color buffer can be obtained (i.e., the front buffer is inaccessible, and stereo contexts are not supported by the buffer manager):
color_buffer = buffers.get_color_buffer()
This buffer can be treated like any other image. For example, you could copy
it to a texture, obtain its pixel data, save it to a file, and so on. Using
the texture
attribute is particularly
useful, as it allows you to perform multipass rendering effects without
needing a render-to-texture extension.
The depth buffer can be obtained similarly:
depth_buffer = buffers.get_depth_buffer()
When a depth buffer is converted to a texture, the class used will be a
DepthTexture
, suitable for use with shadow map
techniques.
The auxiliary buffers and stencil bits are obtained by requesting one, which will then be marked as “in-use”. This permits multiple libraries and your application to work together without clashes in stencil bits or auxiliary buffer names. For example, to obtain a free stencil bit:
mask = buffers.get_buffer_mask()
The buffer manager maintains a weak reference to the buffer mask, so that when you release all references to it, it will be returned to the pool of available masks.
Similarly, a free auxiliary buffer is obtained:
aux_buffer = buffers.get_aux_buffer()
When using the stencil or auxiliary buffers, make sure you explicitly request these when creating the window. See OpenGL configuration options for details.
Displaying images¶
Image drawing is usually done in the window’s
on_draw()
event handler.
It is possible to draw individual images directly, but usually you will
want to create a “sprite” for each appearance of the image on-screen.
Sprites¶
A Sprite is a full featured class for displaying instances of Images or Animations in the window. Image and Animation instances are mainly concerned with the image data (size, pixels, etc.), wheras Sprites also include additional properties. These include x/y location, scale, rotation, opacity, color tint, visibility, and both horizontal and vertical scaling. Multiple sprites can share the same image; for example, hundreds of bullet sprites might share the same bullet image.
A Sprite is constructed given an image or animation, and can be directly
drawn with the draw()
method:
sprite = pyglet.sprite.Sprite(img=image)
@window.event
def on_draw():
window.clear()
sprite.draw()
If created with an animation, sprites automatically handle displaying the most up-to-date frame of the animation. The following example uses a scheduled function to gradually move the Sprite across the screen:
def update(dt):
# Move 10 pixels per second
sprite.x += dt * 10
# Call update 60 times a second
pyglet.clock.schedule_interval(update, 1/60.)
If you need to draw many sprites, using a Batch
to draw them all at once is strongly recommended. This is far more efficient
than calling draw()
on each of them in a loop:
batch = pyglet.graphics.Batch()
sprites = [pyglet.sprite.Sprite(image, batch=batch),
pyglet.sprite.Sprite(image, batch=batch),
# ... ]
@window.event
def on_draw():
window.clear()
batch.draw()
When sprites are collected into a batch, no guarantee is made about the order
in which they will be drawn. If you need to ensure some sprites are drawn
before others (for example, landscape tiles might be drawn before character
sprites, which might be drawn before some particle effect sprites), use two
or more OrderedGroup
objects to specify the
draw order:
batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
foreground = pyglet.graphics.OrderedGroup(1)
sprites = [pyglet.sprite.Sprite(image, batch=batch, group=background),
pyglet.sprite.Sprite(image, batch=batch, group=background),
pyglet.sprite.Sprite(image, batch=batch, group=foreground),
pyglet.sprite.Sprite(image, batch=batch, group=foreground),
# ...]
@window.event
def on_draw():
window.clear()
batch.draw()
For best performance, you should use as few batches and groups as required. (See the Graphics section for more details on batch and group rendering). This will reduce the number of internal and OpenGL operations for drawing each frame.
In addition, try to combine your images into as few textures as possible;
for example, by loading images with pyglet.resource.image()
(see Application resources) or with Texture bins and atlases).
A common pitfall is to use the pyglet.image.load()
method to load
a large number of images. This will cause a seperate texture to be created
for each image loaded, resulting in a lot of OpenGL texture binding overhead
for each frame.
Simple image blitting¶
Drawing images directly is less efficient, but may be adequate for
simple cases. Images can be drawn into a window with the
blit()
method:
@window.event
def on_draw():
window.clear()
image.blit(x, y)
The x and y coordinates locate where to draw the anchor point of the
image. For example, to center the image at (x, y)
:
kitten.anchor_x = kitten.width // 2
kitten.anchor_y = kitten.height // 2
kitten.blit(x, y)
You can also specify an optional z component to the
blit()
method.
This has no effect unless you have changed the default projection
or enabled depth testing. In the following example, the second
image is drawn behind the first, even though it is drawn after it:
from pyglet.gl import *
glEnable(GL_DEPTH_TEST)
kitten.blit(x, y, 0)
kitten.blit(x, y, -0.5)
The default pyglet projection has a depth range of (-1, 1) – images drawn with a z value outside this range will not be visible, regardless of whether depth testing is enabled or not.
Images with an alpha channel can be blended with the existing framebuffer. To do this you need to supply OpenGL with a blend equation. The following code fragment implements the most common form of alpha blending, however other techniques are also possible:
from pyglet.gl import *
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
You would only need to call the code above once during your program, before you draw any images (this is not necessary when using only sprites).
OpenGL imaging¶
This section assumes you are familiar with texture mapping in OpenGL (for example, chapter 9 of the OpenGL Programming Guide).
To create a texture from any AbstractImage
,
call get_texture()
:
kitten = image.load('kitten.jpg')
texture = kitten.get_texture()
Textures are automatically created and used by
ImageData
when blitted. Itis useful to use
textures directly when aiming for high performance or 3D applications.
The Texture
class represents any texture object.
The target
attribute gives the
texture target (for example, GL_TEXTURE_2D
) and
id
the texturename.
For example, to bind a texture:
glBindTexture(texture.target, texture.id)
Texture dimensions¶
Implementations of OpenGL prior to 2.0 require textures to have dimensions
that are powers of two (i.e., 1, 2, 4, 8, 16, …). Because of this
restriction, pyglet will always create textures of these dimensions (there are
several non-conformant post-2.0 implementations). This could have unexpected
results for a user blitting a texture loaded from a file of non-standard
dimensions. To remedy this, pyglet returns a
TextureRegion
of the larger
texture corresponding to just the part of the texture covered by the original
image.
A TextureRegion
has an owner attribute that
references the larger texture. The following session demonstrates this:
>>> rgba = image.load('tests/image/rgba.png')
>>> rgba
<ImageData 235x257> # The image is 235x257
>>> rgba.get_texture()
<TextureRegion 235x257> # The returned texture is a region
>>> rgba.get_texture().owner
<Texture 256x512> # The owning texture has power-2 dimensions
>>>
A TextureRegion
defines a
tex_coords
attribute that gives
the texture coordinates to use for a quad mapping the whole image.
tex_coords
is a 4-tuple of 3-tuple
of floats; i.e., each texture coordinate is given in 3 dimensions.
The following code can be used to render a quad for a texture region:
texture = kitten.get_texture()
t = texture.tex_coords
w, h = texture.width, texture.height
array = (GLfloat * 32)(
t[0][0], t[0][1], t[0][2], 1.,
x, y, z, 1.,
t[1][0], t[1][1], t[1][2], 1.,
x + w, y, z, 1.,
t[2][0], t[2][1], t[2][2], 1.,
x + w, y + h, z, 1.,
t[3][0], t[3][1], t[3][2], 1.,
x, y + h, z, 1.)
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
glInterleavedArrays(GL_T4F_V4F, 0, array)
glDrawArrays(GL_QUADS, 0, 4)
glPopClientAttrib()
The blit()
method does this.
Use the pyglet.image.Texture.create()
method to create
either a texture region from a larger power-2 sized texture,
or a texture with the exact dimensions using the
GL_texture_rectangle_ARB
extension.
Texture internal format¶
pyglet automatically selects an internal format for the texture based on the source image’s format attribute. The following table describes how it is selected.
Format Internal format Any format with 3 components GL_RGB
Any format with 2 components GL_LUMINANCE_ALPHA
"A"
GL_ALPHA
"L"
GL_LUMINANCE
"I"
GL_INTENSITY
Any other format GL_RGBA
Note that this table does not imply any mapping between format components and
their OpenGL counterparts. For example, an image with format "RG"
will use
GL_LUMINANCE_ALPHA
as its internal format; the luminance channel will be
averaged from the red and green components, and the alpha channel will be
empty (maximal).
Use the pyglet.image.Texture.create()
class method to create a texture
with a specific internal format.
Texture filtering¶
By default, all textures are created with smooth (GL_LINEAR
) filtering.
In some cases you may wish to have different filtered applied. Retro style
pixel art games, for example, would require sharper textures. To achieve this,
pas GL_NEAREST
to the min_filter and mag_filter parameters when
creating a texture. It is also possible to set the default filtering by
setting the default_min_filter and default_mag_filter class attributes
on the Texture class. This will cause all textures created internally by
pyglet to use these values:
pyglet.image.Texture.default_min_filter = GL_LINEAR
pyglet.image.Texture.default_mag_filter = GL_LINEAR
Saving an image¶
Any image can be saved using the save method:
kitten.save('kitten.png')
or, specifying a file-like object:
kitten_stream = open('kitten.png', 'wb')
kitten.save('kitten.png', file=kitten_stream)
The following example shows how to grab a screenshot of your application window:
pyglet.image.get_buffer_manager().get_color_buffer().save('screenshot.png')
Note that images can only be saved in the PNG format unless the Pillow library is installed.
Sound and video¶
pyglet can play many audio and video formats. Audio is played back with either OpenAL, XAudio2, DirectSound, or Pulseaudio, permitting hardware-accelerated mixing and surround-sound 3D positioning. Video is played into OpenGL textures, and so can be easily manipulated in real-time by applications and incorporated into 3D environments.
Decoding of compressed audio and video is provided by FFmpeg v4.X, an optional component available for Linux, Windows and Mac OS X. FFmpeg needs to be installed separately.
If FFmpeg is not present, pyglet will fall back to reading uncompressed WAV files only. This may be sufficient for many applications that require only a small number of short sounds, in which case those applications need not distribute FFmpeg.
Audio drivers¶
pyglet can use OpenAL, XAudio2, DirectSound or Pulseaudio to play back audio. Only one
of these drivers can be used in an application. In most cases you won’t need
to concern yourself with choosing a driver, but you can manually select one if
desired. This must be done before the pyglet.media
module is loaded.
The available drivers depend on your operating system:
The audio driver can be set through the audio
key of the
pyglet.options
dictionary. For example:
pyglet.options['audio'] = ('openal', 'pulse', 'directsound', 'silent')
This tells pyglet to try using the OpenAL driver first, and if not available
to try Pulseaudio and DirectSound in that order. If all else fails, no driver
will be instantiated. The audio
option can be a list of any of these
strings, giving the preference order for each driver:
String Audio driver openal
OpenAL directsound
DirectSound xaudio2
XAudio2 pulse
Pulseaudio silent
No audio output
You must set the audio
option before importing pyglet.media
.
You can alternatively set it through an environment variable;
see Environment settings.
The following sections describe the requirements and limitations of each audio driver.
XAudio2¶
XAudio2 is only available on Windows Vista and above and is the replacement of DirectSound. This provides hardware accelerated audio support for newer operating systems.
Note that in some stripped down versions of Windows 10, XAudio2 may not be available until the required DLL’s are installed.
DirectSound¶
DirectSound is available only on Windows, and is installed by default. pyglet uses only DirectX 7 features. On Windows Vista, DirectSound does not support hardware audio mixing or surround sound.
OpenAL¶
OpenAL is included with Mac OS X. Windows users can download a generic driver
from openal.org, or from their sound device’s manufacturer. Most Linux
distributions will have OpenAL available in the repositories for download.
For example, Ubuntu users can apt install libopenal1
.
Pulse¶
Pulseaudio has become the standard Linux audio implementation over the past few years, and is installed by default with most modern Linux distributions. Pulseaudio does not support positional audio, and is limited to stereo. It is recommended to use OpenAL if positional audio is required.
[1] | (1, 2) OpenAL is not installed by default on Windows, nor in many Linux distributions. It can be downloaded separately from your audio device manufacturer or openal.org |
Supported media types¶
Windows and Linux both support a limited amount of compressed audio types, without the need for FFmpeg. While FFmpeg supports a large array of formats and codecs, it may be an unnecessarily large dependency when simple audio playback is needed on these operating systems.
These formats are supported natively under the following systems and codecs:
Windows Media Foundation¶
Supported on Windows operating systems.
The following are supported on Windows Vista and above:
- MP3
- WMA
- ASF
- SAMI/SMI
The following are supported on Windows 7 and above:
- 3G2/3GP/3GP2/3GP
- AAC/ADTS
- AVI
- M4A/M4V/MOV/MP4
The following is undocumented but known to work on Windows 10:
- FLAC
Please note that any video playback done through WMF is limited in codec support and is not hardware accelerated. It should only be used for simple or small videos. FFmpeg is recommended for all other purposes.
GStreamer¶
Supported on Linux operating systems that have the GStreamer installed. Please note that the associated Python packages for gobject & gst are also required. This varies by distribution, but will often already be installed along with GStreamer.
- MP3
- FLAC
- OGG
- M4A
PyOgg¶
Supported on Windows, Linux, and Mac operating systems.
PyOgg is a lightweight Python library that provides Python bindings for Opus, Vorbis, and FLAC codecs.
Pyglet now provides a wrapper to support PyOgg. Since not all operating systems can decode the same audio formats natively, it can often be a hassle to choose an audio format that is truely cross platform with a small footprint. This wrapper was created to help with that issue.
Supports the following formats:
- OGG
- FLAC
- OPUS
Refer to their installation guide found here: https://pyogg.readthedocs.io/en/latest/installation.html
FFmpeg¶
FFmpeg requires an external dependency, please see installation instructions in the next section below.
With FFmpeg, many common and less-common formats are supported. Due to the large number of combinations of audio and video codecs, options, and container formats, it is difficult to provide a complete yet useful list. Some of the supported audio formats are:
- AU
- MP2
- MP3
- OGG/Vorbis
- WAV
- WMA
Some of the supported video formats are:
- AVI
- DivX
- H.263
- H.264
- MPEG
- MPEG-2
- OGG/Theora
- Xvid
- WMV
- Webm
For a complete list, see the FFmpeg sources. Otherwise, it is probably simpler
to try playing back your target file with the media_player.py
example.
New versions of FFmpeg as they are released may support additional formats, or fix errors in the current implementation. Currently a C bindings was written with ctypes using FFmpeg v4.X. This means that this version of pyglet will support all FFmpeg binaries with the major version set to 4.
FFmpeg installation¶
You can install FFmpeg for your platform by following the instructions found in the FFmpeg download page. You must choose the shared build for the targeted OS with the architecture similar to the Python interpreter.
This means that the major version must be 4.X. All minor versions are supported. Choose the correct architecture depending on the targeted Python interpreter. If you’re shipping your project with a 32 bits interpreter, you must download the 32 bits shared binaries.
On Windows, the usual error message when the wrong architecture was downloaded is:
WindowsError: [Error 193] %1 is not a valid Win32 application
Finally make sure you download the shared builds, not the static or the dev builds.
For Mac OS and Linux, the library is usually already installed system-wide. For Windows users, it’s not recommended to install the library in one of the windows sub-folders.
Instead we recommend to use the pyglet.options
search_local_libs
:
import pyglet
pyglet.options['search_local_libs'] = True
This will allow pyglet to find the FFmpeg binaries in the lib
sub-folder
located in your running script folder.
Another solution is to manipulate the environment variable. On Windows you can add the dll location to the PATH:
os.environ["PATH"] += "path/to/ffmpeg"
For Linux and Mac OS:
os.environ["LD_LIBRARY_PATH"] += ":" + "path/to/ffmpeg"
Loading media¶
Audio and video files are loaded in the same way, using the
pyglet.media.load()
function, providing a filename:
source = pyglet.media.load('explosion.wav')
If the media file is bundled with the application, consider using the
resource
module (see Application resources).
The result of loading a media file is a
Source
object. This object provides useful
information about the type of media encoded in the file, and serves as an
opaque object used for playing back the file (described in the next section).
The load()
function will raise a
MediaException
if the format is unknown.
IOError
may also be raised if the file could not be read from disk.
Future versions of pyglet will also support reading from arbitrary file-like
objects, however a valid filename must currently be given.
The length of the media file is given by the
duration
property, which returns the media’s
length in seconds.
Audio metadata is provided in the source’s
audio_format
attribute, which is None
for
silent videos. This metadata is not generally useful to applications. See
the AudioFormat
class documentation for details.
Video metadata is provided in the source’s
video_format
attribute, which is None
for
audio files. It is recommended that this attribute is checked before
attempting play back a video file – if a movie file has a readable audio
track but unknown video format it will appear as an audio file.
You can use the video metadata, described in a
VideoFormat
object, to set up display of the video
before beginning playback. The attributes are as follows:
Attribute Description width
,height
Width and height of the video image, in pixels. sample_aspect
The aspect ratio of each video pixel.
You must take care to apply the sample aspect ratio to the video image size for display purposes. The following code determines the display size for a given video format:
def get_video_size(width, height, sample_aspect):
if sample_aspect > 1.:
return width * sample_aspect, height
elif sample_aspect < 1.:
return width, height / sample_aspect
else:
return width, height
Media files are not normally read entirely from disk; instead, they are streamed into the decoder, and then into the audio buffers and video memory only when needed. This reduces the startup time of loading a file and reduces the memory requirements of the application.
However, there are times when it is desirable to completely decode an audio file in memory first. For example, a sound that will be played many times (such as a bullet or explosion) should only be decoded once. You can instruct pyglet to completely decode an audio file into memory at load time:
explosion = pyglet.media.load('explosion.wav', streaming=False)
The resulting source is an instance of StaticSource
,
which provides the same interface as a StreamingSource
.
You can also construct a StaticSource
directly from an
already- loaded Source
:
explosion = pyglet.media.StaticSource(pyglet.media.load('explosion.wav'))
Audio Synthesis¶
In addition to loading audio files, the pyglet.media.synthesis
module is available for simple audio synthesis. There are several basic
waveforms available:
The module documentation for each will provide more information on constructing them, but at a minimum you will need to specify the duration. You will also want to set the audio frequency (most waveforms will default to 440Hz). Some waveforms, such as the FM, have additional parameters.
For shaping the waveforms, several simple envelopes are available. These envelopes affect the amplitude (volume), and can make for more natural sounding tones. You first create an envelope instance, and then pass it into the constructor of any of the above waveforms. The same envelope instance can be passed to any number of waveforms, reducing duplicate code when creating multiple sounds. If no envelope is used, all waveforms will default to the FlatEnvelope of maximum volume, which esentially has no effect on the sound. Check the module documentation of each Envelope to see which parameters are available.
An example of creating an envelope and waveforms:
adsr = pyglet.media.synthesis.ADSREnvelope(0.05, 0.2, 0.1)
saw = pyglet.media.synthesis.Sawtooth(duration=1.0, frequency=220, envelope=adsr)
fm = pyglet.media.synthesis.FM(3, carrier=440, modulator=2, mod_index=22, envelope=adsr)
The waveforms you create with the synthesis module can be played like any other loaded sound. See the next sections for more detail on playback.
Simple audio playback¶
Many applications, especially games, need to play sounds in their entirety without needing to keep track of them. For example, a sound needs to be played when the player’s space ship explodes, but this sound never needs to have its volume adjusted, or be rewound, or interrupted.
pyglet provides a simple interface for this kind of use-case. Call the
play()
method of any Source
to play it immediately and completely:
explosion = pyglet.media.load('explosion.wav', streaming=False)
explosion.play()
You can call play()
on any
Source
, not just
StaticSource
.
The return value of play()
is a
Player
, which can either be
discarded, or retained to maintain control over the sound’s playback.
Controlling playback¶
You can implement many functions common to a media player using the
Player
class. Use of this class is also necessary for video playback. There are no
parameters to its construction:
player = pyglet.media.Player()
A player will play any source that is queued on it. Any number of sources can be queued on a single player, but once queued, a source can never be dequeued (until it is removed automatically once complete). The main use of this queueing mechanism is to facilitate “gapless” transitions between playback of media files.
The queue()
method is used to queue
a media on the player - a StreamingSource
or a
StaticSource
. Either you pass one instance, or you
can also pass an iterable of sources. This provides great flexibility. For
instance, you could create a generator which takes care of the logic about
what music to play:
def my_playlist():
yield intro
while game_is_running():
yield main_theme
yield ending
player.queue(my_playlist())
When the game ends, you will still need to call on the player:
player.next_source()
The generator will pass the ending
media to the player.
A StreamingSource
can only ever be queued on one
player, and only once on that player. StaticSource
objects can be queued any number of times on any number of players. Recall
that a StaticSource
can be created by passing
streaming=False
to the pyglet.media.load()
method.
In the following example, two sounds are queued onto a player:
player.queue(source1)
player.queue(source2)
Playback begins with the player’s play()
method
is called:
player.play()
Standard controls for controlling playback are provided by these methods:
Method Description play()
Begin or resume playback of the current source. pause()
Pause playback of the current source. next_source()
Dequeue the current source and move to the next one immediately. seek()
Seek to a specific time within the current source.
Note that there is no stop method. If you do not need to resume playback,
simply pause playback and discard the player and source objects. Using the
next_source()
method does not guarantee gapless
playback.
There are several properties that describe the player’s current state:
Property Description time
The current playback position within the current source, in seconds. This is read-only (but see the seek()
method).playing
True if the player is currently playing, False if there are no sources queued or the player is paused. This is read-only (but see the pause()
andplay()
methods).source
A reference to the current source being played. This is read-only (but see the queue()
method).volume
The audio level, expressed as a float from 0 (mute) to 1 (normal volume). This can be set at any time. loop
True
if the current source should be repeated when reaching the end. If set toFalse
, playback will continue to the next queued source.
When a player reaches the end of the current source, by default it will move
immediately to the next queued source. If there are no more sources, playback
stops until another source is queued. The Player
has a loop
attribute which determines
the player behaviour when the current source reaches the end. If
loop
is False
(default) the
Player
starts to play the next queued source.
Otherwise the Player
re-plays the current source
until either loop
is set to False
or next_source()
is called.
You can change the loop
attribute at
any time, but be aware that unless sufficient time is given for the future
data to be decoded and buffered there may be a stutter or gap in playback.
If set well in advance of the end of the source (say, several seconds), there
will be no disruption.
Gapless playback¶
To play back multiple similar sources without any audible gaps,
SourceGroup
is provided.
A SourceGroup
can only contain media sources
with identical audio or video format. First create an instance of
SourceGroup
, and then add all desired additional
sources with the add()
method.
Afterwards, you can queue the SourceGroup
on a Player as if it was a single source.
Incorporating video¶
When a Player
is playing back a source with
video, use the texture
property to obtain the
video frame image. This can be used to display the current video image
syncronised with the audio track, for example:
@window.event
def on_draw():
player.texture.blit(0, 0)
The texture is an instance of pyglet.image.Texture
, with an internal
format of either GL_TEXTURE_2D
or GL_TEXTURE_RECTANGLE_ARB
. While the
texture will typically be created only once and subsequentally updated each
frame, you should make no such assumption in your application – future
versions of pyglet may use multiple texture objects.
Positional audio¶
pyglet includes features for positioning sound within a 3D space. This is particularly effective with a surround-sound setup, but is also applicable to stereo systems.
A Player
in pyglet has an associated position
in 3D space – that is, it is equivalent to an OpenAL “source”. The properties
for setting these parameters are described in more detail in the API
documentation; see for example position
and
pitch
.
A “listener” object is provided by the audio driver. To obtain the listener for the current audio driver:
pyglet.media.get_audio_driver().get_listener()
This provides similar properties such as
position
,
forward_orientation
and
up_orientation
that
describe the position of the user in 3D space.
Note that only mono sounds can be positioned. Stereo sounds will play back as normal, and only their volume and pitch properties will affect the sound.
Ticking the clock¶
If you are using pyglet’s media libraries outside of a pyglet app, you will need to use some kind of loop to tick the pyglet clock periodically (perhaps every 200ms or so), otherwise only the first small sample of media will be played:
pyglet.clock.tick()
If you wish to have a media source loop continuously (player.loop = True) you will also need to ensure Pyglet’s events are dispatched inside your loop:
pyglet.app.platform_event_loop.dispatch_posted_events()
If you are inside a pyglet app then calling pyglet.app.run() takes care of all this for you.
Application resources¶
Previous sections in this guide have described how to load images, media and text documents using pyglet. Applications also usually have the need to load other data files: for example, level descriptions in a game, internationalised strings, and so on.
Programmers are often tempted to load, for example, an image required by their application with:
image = pyglet.image.load('logo.png')
This code assumes logo.png
is in the current working directory.
Unfortunately the working directory is not necessarily the same as the
directory containing the application script files.
- Applications started from the command line can start from an arbitrary working directory.
- Applications bundled into an egg, Mac OS X package or Windows executable may have their resources inside a ZIP file.
- The application might need to change the working directory in order to work with the user’s files.
A common workaround for this is to construct a path relative to the script file instead of the working directory:
import os
script_dir = os.path.dirname(__file__)
path = os.path.join(script_dir, 'logo.png')
image = pyglet.image.load(path)
This, besides being tedious to write, still does not work for resources within ZIP files, and can be troublesome in projects that span multiple packages.
The pyglet.resource
module solves this problem elegantly:
image = pyglet.resource.image('logo.png')
The following sections describe exactly how the resources are located, and how the behaviour can be customised.
Loading resources¶
Use the pyglet.resource
module when files shipped with the
application need to be loaded. For example, instead of writing:
data_file = open('file.txt')
use:
data_file = pyglet.resource.file('file.txt')
There are also convenience functions for loading media files for pyglet. The following table shows the equivalent resource functions for the standard file functions.
File function Resource function Type open
pyglet.resource.file()
File-like object pyglet.image.load()
pyglet.resource.image()
Texture
orTextureRegion
pyglet.image.load()
pyglet.resource.texture()
Texture
pyglet.image.load_animation()
pyglet.resource.animation()
Animation
pyglet.media.load()
pyglet.resource.media()
Source
mimetype =text/plain
pyglet.resource.text()
UnformattedDocument
mimetype =text/html
pyglet.resource.html()
FormattedDocument
mimetype =text/vnd.pyglet-attributed
pyglet.resource.attributed()
FormattedDocument
pyglet.font.add_file()
pyglet.resource.add_font()
None
pyglet.resource.texture()
is for loading stand-alone textures.
This can be useful when using the texture for a 3D model, or generally
working with OpenGL directly.
pyglet.resource.image()
is optimised for loading sprite-like
images that can have their texture coordinates adjusted.
The resource module attempts to pack small images into larger texture atlases
(explained in Texture bins and atlases) for efficient rendering
(which is why the return type of this function can be
TextureRegion
).
It is also advisable to use the texture atlas classes directly if you wish
to have different achor points on multiple copies of the same image.
This is because when loading an image more than once, you will actually get
the same object back. You can still use the resource module for getting
the image location, and described in the next section.
Resource locations¶
Some resource files reference other files by name. For example, an HTML
document can contain <img src="image.png" />
elements. In this case your
application needs to locate image.png
relative to the original HTML file.
Use pyglet.resource.location()
to get a
Location
object describing the location of an
application resource. This location might be a file system
directory or a directory within a ZIP file.
The Location
object can directly open files by
name, so your application does not need to distinguish between these cases.
In the following example, a thumbnails.txt
file is assumed to contain a
list of image filenames (one per line), which are then loaded assuming the
image files are located in the same directory as the thumbnails.txt
file:
thumbnails_file = pyglet.resource.file('thumbnails.txt', 'rt')
thumbnails_location = pyglet.resource.location('thumbnails.txt')
for line in thumbnails_file:
filename = line.strip()
image_file = thumbnails_location.open(filename)
image = pyglet.image.load(filename, file=image_file)
# Do something with `image`...
This code correctly ignores other images with the same filename that might appear elsewhere on the resource path.
Specifying the resource path¶
By default, only the script home directory is searched (the directory
containing the __main__
module).
You can set pyglet.resource.path
to a list of locations to
search in order. This list is indexed, so after modifying it you will
need to call pyglet.resource.reindex()
.
Each item in the path list is either a path relative to the script home, or
the name of a Python module preceded with an “at” symbol (@
). For example,
if you would like to package all your resources in a res
directory:
pyglet.resource.path = ['res']
pyglet.resource.reindex()
Items on the path are not searched recursively, so if your resource directory itself has subdirectories, these need to be specified explicitly:
pyglet.resource.path = ['res', 'res/images', 'res/sounds', 'res/fonts']
pyglet.resource.reindex()
The entries in the resource path always use forward slash characters as path separators even when the operating systems using a different character.
Specifying module names makes it easy to group code with its resources. The
following example uses the directory containing the hypothetical
gui.skins.default
for resources:
pyglet.resource.path = ['@gui.skins.default', '.']
pyglet.resource.reindex()
Multiple loaders¶
A Loader
encapsulates a complete resource path
and cache. This lets your application cleanly separate resource loading of
different modules.
Loaders are constructed for a given search path, andnexposes the same methods
as the global pyglet.resource
module functions.
For example, if a module needs to load its own graphics but does not want to
interfere with the rest of the application’s resource loading, it would create
its own Loader
with a local search path:
loader = pyglet.resource.Loader(['@' + __name__])
image = loader.image('logo.png')
This is particularly suitable for “plugin” modules.
You can also use a Loader
instance to load a set
of resources relative to some user-specified document directory.
The following example creates a loader for a directory specified on the
command line:
import sys
home = sys.argv[1]
loader = pyglet.resource.Loader(script_home=[home])
This is the only way that absolute directories and resources not bundled with
an application should be used with pyglet.resource
.
Saving user preferences¶
Because Python applications can be distributed in several ways, including within ZIP files, it is usually not feasible to save user preferences, high score lists, and so on within the application directory (or worse, the working directory).
The pyglet.resource.get_settings_path()
function returns a directory
suitable for writing arbitrary user-centric data. The directory used follows
the operating system’s convention:
~/.config/ApplicationName/
on Linux (depends on XDG_CONFIG_HOME environment variable).$HOME\Application Settings\ApplicationName
on Windows~/Library/Application Support/ApplicationName
on Mac OS X
The returned directory name is not guaranteed to exist – it is the application’s responsibility to create it. The following example opens a high score list file for a game called “SuperGame” into the settings directory:
import os
dir = pyglet.resource.get_settings_path('SuperGame')
if not os.path.exists(dir):
os.makedirs(dir)
filename = os.path.join(dir, 'highscores.txt')
file = open(filename, 'wt')
The pyglet event framework¶
The pyglet.window
, pyglet.media
, pyglet.app
,
pyglet.text
, pyglet.input
and other modules make use
of a consistent event pattern. This provides several ways to attach event
handlers to objects. You can also reuse this pattern in your own
classes easily, by subclassing EventDispatcher
.
Throughout this documentation, an “event dispatcher” is an object that has events it needs to notify other objects about, and an “event handler” is some code that can be attached to a dispatcher.
Setting event handlers¶
An event handler is simply a function with a formal parameter list
corresponding to the event type. For example, the
pyglet.window.Window.on_resize()
event has the parameters
(width, height)
, so an event handler for this event could be written as:
def on_resize(width, height):
pass
The Window
class subclasses
EventDispatcher
, which enables it to dispatch
its own events. There are a few different ways in which event handlers
can be attached to recieve them. The simplest way is to directly attach the
event handler to the corresponding attribute on the object. This will
completely replace the default event handler:
window = pyglet.window.Window()
def on_resize(width, height):
pass
window.on_resize = on_resize
If you don’t want to replace the default event handler, but instead want to
add an additional one, pyglet provides a shortcut using the
event
decorator.
Your custom event handler will run, followed by the default event handler:
window = window.Window()
@window.event
def on_resize(width, height):
pass
or if your handler has a different name:
@window.event('on_resize')
def my_resize_handler(width, height):
pass
In some cases, replacing the default event handler may be desired.
For example, the default pyglet.window.Window.on_resize()
event
sets up a 2D orthographic OpenGL projection. If you wish to use another
OpenGL projection, such as for a 3D scene, then you will likely want
to replace this with your own custom event handler.
In most simple cases, the event
decorator is most convienent. One limitation of using the decorator,
however, is that you can only add one additional event handler.
If you want to add multiple additional event handlers, the next section
describes how to accomplish that.
As a quick note, as shown in Subclassing Window, you can also replace default event handlers by subclassing the event dispatcher and adding the event handler as a method:
class MyWindow(pyglet.window.Window):
def on_resize(self, width, height):
pass
Stacking event handlers¶
It is often convenient to attach more than one event handler for an event.
EventDispatcher
allows you to stack event handlers
upon one another, rather than replacing them outright. The event will
propagate from the top of the stack to the bottom, but can be stopped
by any handler along the way.
To push an event handler onto the stack,
use the push_handlers()
method:
def on_key_press(symbol, modifiers):
if symbol == key.SPACE:
fire_laser()
window.push_handlers(on_key_press)
One use for pushing handlers instead of setting them is to handle different
parameterisations of events in different functions. In the above example, if
the spacebar is pressed, the laser will be fired. After the event handler
returns control is passed to the next handler on the stack, which on a
Window
is a function that checks for the ESC key
and sets the has_exit
attribute if it is pressed. By pushing the event
handler instead of setting it, the application keeps the default behaviour
while adding additional functionality.
You can prevent the remaining event handlers in the stack from receiving the event by returning a true value. The following event handler, when pushed onto the window, will prevent the escape key from exiting the program:
def on_key_press(symbol, modifiers):
if symbol == key.ESCAPE:
return True
window.push_handlers(on_key_press)
You can push more than one event handler at a time, which is especially useful
when coupled with the pop_handlers()
function. In the following example, when the game starts some additional
event handlers are pushed onto the stack. When the game ends (perhaps
returning to some menu screen) the handlers are popped off in one go:
def start_game():
def on_key_press(symbol, modifiers):
print('Key pressed in game')
return True
def on_mouse_press(x, y, button, modifiers):
print('Mouse button pressed in game')
return True
window.push_handlers(on_key_press, on_mouse_press)
def end_game():
window.pop_handlers()
Note that you do not specify which handlers to pop off the stack – the entire
top “level” (consisting of all handlers specified in a single call to
push_handlers()
) is popped.
You can apply the same pattern in an object-oriented fashion by grouping
related event handlers in a single class. In the following example, a
GameEventHandler
class is defined. An instance of that class can be
pushed on and popped off of a window:
class GameEventHandler:
def on_key_press(self, symbol, modifiers):
print('Key pressed in game')
return True
def on_mouse_press(self, x, y, button, modifiers):
print('Mouse button pressed in game')
return True
game_handlers = GameEventHandler()
def start_game()
window.push_handlers(game_handlers)
def stop_game()
window.pop_handlers()
Note
In order to prevent issues with garbage collection, the
EventDispatcher
class only holds weak
references to pushed event handlers. That means the following example
will not work, because the pushed object will fall out of scope and be
collected:
dispatcher.push_handlers(MyHandlerClass())
Instead, you must make sure to keep a reference to the object before pushing it. For example:
my_handler_instance = MyHandlerClass()
dispatcher.push_handlers(my_handler_instance)
Creating your own event dispatcher¶
pyglet provides the Window
,
Player
, and other event dispatchers,
but exposes a public interface for creating and dispatching your own events.
The steps for creating an event dispatcher are:
- Subclass
EventDispatcher
- Call the
register_event_type()
class method on your subclass for each event your subclass will recognise. - Call
dispatch_event()
to create and dispatch an event as needed.
In the following example, a hypothetical GUI widget provides several events:
class ClankingWidget(pyglet.event.EventDispatcher):
def clank(self):
self.dispatch_event('on_clank')
def click(self, clicks):
self.dispatch_event('on_clicked', clicks)
def on_clank(self):
print('Default clank handler.')
ClankingWidget.register_event_type('on_clank')
ClankingWidget.register_event_type('on_clicked')
Event handlers can then be attached as described in the preceding sections:
widget = ClankingWidget()
@widget.event
def on_clank():
pass
@widget.event
def on_clicked(clicks):
pass
def override_on_clicked(clicks):
pass
widget.push_handlers(on_clicked=override_on_clicked)
The EventDispatcher
takes care of propagating the
event to all attached handlers or ignoring it if there are no handlers for
that event.
There is zero instance overhead on objects that have no event handlers
attached (the event stack is created only when required). This makes
EventDispatcher
suitable for use even on light-weight
objects that may not always have handlers. For example,
Player
is an
EventDispatcher
even though potentially hundreds
of these objects may be created and destroyed each second, and most will
not need an event handler.
Implementing the Observer pattern¶
The Observer design pattern, also known as Publisher/Subscriber, is a
simple way to decouple software components. It is used extensively in many
large software projects; for example, Java’s AWT and Swing GUI toolkits and the
Python logging
module; and is fundamental to any Model-View-Controller
architecture.
EventDispatcher
can be used to easily add
observerable components to your application. The following example recreates
the ClockTimer example from Design Patterns (pages 300-301), though
without needing the bulky Attach
, Detach
and Notify
methods:
# The subject
class ClockTimer(pyglet.event.EventDispatcher):
def tick(self):
self.dispatch_event('on_update')
ClockTimer.register_event_type('on_update')
# Abstract observer class
class Observer:
def __init__(self, subject):
subject.push_handlers(self)
# Concrete observer
class DigitalClock(Observer):
def on_update(self):
pass
# Concrete observer
class AnalogClock(Observer):
def on_update(self):
pass
timer = ClockTimer()
digital_clock = DigitalClock(timer)
analog_clock = AnalogClock(timer)
The two clock objects will be notified whenever the timer is “ticked”, though neither the timer nor the clocks needed prior knowledge of the other. During object construction any relationships between subjects and observers can be created.
Keeping track of time¶
pyglet’s clock
module allows you to schedule functions
to run periodically, or for one-shot future execution. There are also some
helpful utilities provided for calculating and displaying the application
frame rate.
Calling functions periodically¶
As discussed in the The application event loop section, pyglet applications begin execution by entering into an application event loop:
pyglet.app.run()
Once called, this function doesn’t return until the application windows have been closed. This may leave you wondering how to execute code while the application is running.
Typical applications need to execute code in only three circumstances:
- A user input event (such as a mouse movement or key press) has been generated. In this case the appropriate code can be attached as an event handler to the window.
- An animation or other time-dependent system needs to update the position or parameters of an object. We’ll call this a “periodic” event.
- A certain amount of time has passed, perhaps indicating that an operation has timed out, or that a dialog can be automatically dismissed. We’ll call this a “one-shot” event.
To have a function called periodically, for example, once every 0.1 seconds:
def update(dt):
# ...
pyglet.clock.schedule_interval(update, 0.1)
The dt, or delta time parameter gives the number of “wall clock” seconds elapsed since the last call of this function, (or the time the function was scheduled, if it’s the first period). Due to latency, load and timer inprecision, this might be slightly more or less than the requested interval. Please note that the dt parameter is always passed to scheduled functions, so be sure to expect it when writing functions even if you don’t need to use it.
Scheduling functions with a set interval is ideal for animation, physics simulation, and game state updates. pyglet ensures that the application does not consume more resources than necessary to execute the scheduled functions on time.
Rather than “limiting the frame rate”, as is common in other toolkits, simply
schedule all your update functions for no less than the minimum period your
application or game requires. For example, most games need not run at more
than 60Hz (60 times a second) for imperceptibly smooth animation, so the
interval given to schedule_interval()
would be
1/60.0
(or more).
If you are writing a benchmarking program or otherwise wish to simply run at the highest possible frequency, use schedule. This will call the function as frequently as possible (and will likely cause heavy CPU usage):
def benchmark(dt):
# ...
pyglet.clock.schedule(benchmark)
By default pyglet window buffer swaps are synchronised to the display refresh rate, so you may also want to disable vsync if you are running a benchmark.
For one-shot events, use schedule_once()
:
def dismiss_dialog(dt):
# ...
# Dismiss the dialog after 5 seconds.
pyglet.clock.schedule_once(dismiss_dialog, 5.0)
To stop a scheduled function from being called, including cancelling a
periodic function, use pyglet.clock.unschedule()
. This could be
useful if you want to start running a function on schedule when a user provides
a certain input, and then unschedule it when another input is received.
Sprite movement techniques¶
As mentioned above, every scheduled function receives a dt parameter, giving the actual “wall clock” time that passed since the previous invocation. This parameter can be used for numerical integration.
For example, a non-accelerating particle with velocity v
will travel
some distance over a change in time dt
. This distance is calculated as
v * dt
. Similarly, a particle under constant acceleration a
will have
a change in velocity of a * dt
.
The following example demonstrates a simple way to move a sprite across the screen at exactly 10 pixels per second:
sprite = pyglet.sprite.Sprite(image)
sprite.dx = 10.0
def update(dt):
sprite.x += sprite.dx * dt
pyglet.clock.schedule_interval(update, 1/60.0) # update at 60Hz
This is a robust technique for simple sprite movement, as the velocity will remain constant regardless of the speed or load of the computer.
Some examples of other common animation variables are given in the table below.
Animation parameter Distance Velocity Rotation Degrees Degrees per second Position Pixels Pixels per second Keyframes Frame number Frames per second
The frame rate¶
Game performance is often measured in terms of the number of times the display is updated every second; that is, the frames-per-second or FPS. You can determine your application’s FPS with a single function call:
pyglet.clock.get_fps()
The value returned is more useful than simply taking the reciprocal of dt from a period function, as it is averaged over a sliding window of several frames.
Displaying the frame rate¶
A simple way to profile your application performance is to display the frame
rate while it is running. Printing it to the console is not ideal as this
will have a severe impact on performance. pyglet provides the
FPSDisplay
class for displaying the frame rate
with very little effort:
fps_display = pyglet.window.FPSDisplay(window=window)
@window.event
def on_draw():
window.clear()
fps_display.draw()
By default the frame rate will be drawn in the bottom-left corner of the
window in a semi-translucent large font.
See the FPSDisplay
documentation for details
on how to customise this, or even display another clock value (such as
the current time) altogether.
User-defined clocks¶
The default clock used by pyglet uses the system clock to determine the time
(i.e., time.time()
). Separate clocks can be created, however, allowing
you to use another time source. This can be useful for implementing a
separate “game time” to the real-world time, or for synchronising to a network
time source or a sound device.
Each of the clock_*
functions are aliases for the methods on a global
instance of Clock
. You can construct or subclass
your own Clock
, which can then maintain its own
schedule and framerate calculation.
See the class documentation for more details.
Creating an OpenGL context¶
This section describes how to configure an OpenGL context. For most applications the information described here is far too low-level to be of any concern, however more advanced applications can take advantage of the complete control pyglet provides.
Displays, screens, configs and contexts¶

Flow of construction, from the abstract Canvas to a newly created Window with its Context.
Contexts and configs¶
When you draw on a window in pyglet, you are drawing to an OpenGL context.
Every window has its own context, which is created when the window is created.
You can access the window’s context via its
context
attribute.
The context is created from an OpenGL configuration (or “config”), which
describes various properties of the context such as what color format to use,
how many buffers are available, and so on. You can access the config
that was used to create a context via the context’s
config
attribute.
For example, here we create a window using the default config and examine some of its properties:
>>> import pyglet
>>> window = pyglet.window.Window()
>>> context = window.context
>>> config = context.config
>>> config.double_buffer
c_int(1)
>>> config.stereo
c_int(0)
>>> config.sample_buffers
c_int(0)
Note that the values of the config’s attributes are all ctypes instances. This is because the config was not specified by pyglet. Rather, it has been selected by pyglet from a list of configs supported by the system. You can make no guarantee that a given config is valid on a system unless it was provided to you by the system.
pyglet simplifies the process of selecting one of the system’s configs by allowing you to create a “template” config which specifies only the values you are interested in. See Simple context configuration for details.
Displays¶
The system may actually support several different sets of configs, depending on which display device is being used. For example, a computer with two video cards may not support the same configs on each card. Another example is using X11 remotely: the display device will support different configurations than the local driver. Even a single video card on the local computer may support different configs for two monitors plugged in.
In pyglet, a Display
is a collection of “screens”
attached to a single display device. On Linux, the display device corresponds
to the X11 display being used. On Windows and Mac OS X, there is only one
display (as these operating systems present multiple video cards as a single
virtual device).
The pyglet.canvas
module provides access to the display(s). Use the
get_display()
function to get the default display:
>>> display = pyglet.canvas.get_display()
Note
On X11, you can use the Display
class directly to
specify the display string to use, for example to use a remotely connected
display. The name string is in the same format as used by the DISPLAY
environment variable:
>>> display = pyglet.canvas.Display(name=':1')
If you have multiple physical screens and you’re using Xinerama, see
Screens to select the desired screen as you would for Windows
and Mac OS X. Otherwise, you can specify the screen number via the
x_screen
argument:
>>> display = pyglet.canvas.Display(name=':1', x_screen=1)
Screens¶
Once you have obtained a display, you can enumerate the screens that are connected. A screen is the physical display medium connected to the display device; for example a computer monitor, TV or projector. Most computers will have a single screen, however dual-head workstations and laptops connected to a projector are common cases where more than one screen will be present.
In the following example the screens of a dual-head workstation are listed:
>>> for screen in display.get_screens():
... print(screen)
...
XlibScreen(screen=0, x=1280, y=0, width=1280, height=1024, xinerama=1)
XlibScreen(screen=0, x=0, y=0, width=1280, height=1024, xinerama=1)
Because this workstation is running Linux, the returned screens are
XlibScreen
, a subclass of Screen
. The
screen
and xinerama
attributes are specific to Linux, but the
x
, y
,
width
and
height
attributes are present on all screens,
and describe the screen’s geometry, as shown below.

Example arrangement of screens and their reported geometry. Note that the primary display (marked “1”) is positioned on the right, according to this particular user’s preference.
There is always a “default” screen, which is the first screen returned by
get_screens()
. Depending on the operating system,
the default screen is usually the one that contains the taskbar (on Windows) or
menu bar (on OS X).
You can access this screen directly using
get_default_screen()
.
OpenGL configuration options¶
When configuring or selecting a Config
, you do so based
on the properties of that config. pyglet supports a fixed subset of the
options provided by AGL, GLX, WGL and their extensions. In particular, these
constraints are placed on all OpenGL configs:
- Buffers are always component (RGB or RGBA) color, never palette indexed.
- The “level” of a buffer is always 0 (this parameter is largely unsupported by modern OpenGL drivers anyway).
- There is no way to set the transparent color of a buffer (again, this GLX-specific option is not well supported).
- There is no support for pbuffers (equivalent functionality can be achieved much more simply and efficiently using framebuffer objects).
The visible portion of the buffer, sometimes called the color buffer, is configured with the following attributes:
buffer_size
Number of bits per sample. Common values are 24 and 32, which each dedicate 8 bits per color component. A buffer size of 16 is also possible, which usually corresponds to 5, 6, and 5 bits of red, green and blue, respectively.
Usually there is no need to set this property, as the device driver will select a buffer size compatible with the current display mode by default.
red_size
,blue_size
,green_size
,alpha_size
These each give the number of bits dedicated to their respective color component. You should avoid setting any of the red, green or blue sizes, as these are determined by the driver based on the
buffer_size
property.If you require an alpha channel in your color buffer (for example, if you are compositing in multiple passes) you should specify
alpha_size=8
to ensure that this channel is created.sample_buffers
andsamples
Configures the buffer for multisampling (MSAA), in which more than one color sample is used to determine the color of each pixel, leading to a higher quality, antialiased image.
Enable multisampling (MSAA) by setting
sample_buffers=1
, then give the number of samples per pixel to use insamples
. For example,samples=2
is the fastest, lowest-quality multisample configuration.samples=4
is still widely supported and fairly performant even on Intel HD and AMD Vega. Most modern GPUs support 2×, 4×, 8×, and 16× MSAA samples with fairly high performance.stereo
- Creates separate left and right buffers, for use with stereo hardware. Only specialised video hardware such as stereoscopic glasses will support this option. When used, you will need to manually render to each buffer, for example using glDrawBuffers.
double_buffer
Create separate front and back buffers. Without double-buffering, drawing commands are immediately visible on the screen, and the user will notice a visible flicker as the image is redrawn in front of them.
It is recommended to set
double_buffer=True
, which creates a separate hidden buffer to which drawing is performed. When the Window.flip is called, the buffers are swapped, making the new drawing visible virtually instantaneously.
In addition to the color buffer, several other buffers can optionally be created based on the values of these properties:
depth_size
- A depth buffer is usually required for 3D rendering. The typical depth size is 24 bits. Specify
0
if you do not require a depth buffer.stencil_size
- The stencil buffer is required for masking the other buffers and implementing certain volumetric shadowing algorithms. The typical stencil size is 8 bits; or specify
0
if you do not require it.accum_red_size
,accum_blue_size
,accum_green_size
,accum_alpha_size
The accumulation buffer can be used for simple antialiasing, depth-of-field, motion blur and other compositing operations. Its use nowadays is being superceded by the use of floating-point textures, however it is still a practical solution for implementing these effects on older hardware.
If you require an accumulation buffer, specify
8
for each of these attributes (the alpha component is optional, of course).aux_buffers
Each auxiliary buffer is configured the same as the colour buffer. Up to four auxiliary buffers can typically be created. Specify
0
if you do not require any auxiliary buffers.Like the accumulation buffer, auxiliary buffers are used less often nowadays as more efficient techniques such as render-to-texture are available. They are almost universally available on older hardware, though, where the newer techniques are not possible.
If you wish to work with OpenGL directly, you can request a higher level context. This is required if you wish to work with the modern OpenGL programmable pipeline. Please note, however, that pyglet currently uses legacy OpenGL functionality for many of it’s internal modules (such as the text, graphics, and sprite modules). Requesting a higher version context will currently prevent usage of these modules.
major_version
- This will be either 3 or 4, for an OpenGL 3.x or 4.x context.
minor_version
- The requested minor version of the context. In some cases, the OpenGL driver may return a higher version than requested.
forward_compatible
- Setting this to True will ask the driver to exclude legacy OpenGL features from the context. Khronos does not recommend this option.
Note
To request a higher higher version OpenGL context on Mac OSX, it is necessary
to disable the pyglet shadow context. To do this, set the pyglet option
pyglet.options['shadow_window']
to False
before creating a Window,
or importing pyglet.window
.
Simple context configuration¶
A context can only be created from a config that was provided by the system. Enumerating and comparing the attributes of all the possible configs is a complicated process, so pyglet provides a simpler interface based on “template” configs.
To get the config with the attributes you need, construct a
Config
and set only the attributes you are interested in.
You can then supply this config to the Window
constructor to create the context.
For example, to create a window with an alpha channel:
config = pyglet.gl.Config(alpha_size=8)
window = pyglet.window.Window(config=config)
It is sometimes necessary to create the context yourself, rather than letting
the Window
constructor do this for you. In this case
use get_best_config()
to obtain a “complete”
config, which you can then use to create the context:
display = pyglet.canvas.get_display()
screen = display.get_default_screen()
template = pyglet.gl.Config(alpha_size=8)
config = screen.get_best_config(template)
context = config.create_context(None)
window = pyglet.window.Window(context=context)
Note that you cannot create a context directly from a template (any
Config
you constructed yourself). The
Window
constructor performs a similar process to the
above to create the context if a template config is given.
Not all configs will be possible on all machines. The call to
get_best_config()
will raise
NoSuchConfigException
if the hardware does not
support the requested attributes. It will never return a config that does not
meet or exceed the attributes you specify in the template.
You can use this to support newer hardware features where available, but also accept a lesser config if necessary. For example, the following code creates a window with multisampling if possible, otherwise leaves multisampling off:
template = pyglet.gl.Config(sample_buffers=1, samples=4)
try:
config = screen.get_best_config(template)
except pyglet.window.NoSuchConfigException:
template = gl.Config()
config = screen.get_best_config(template)
window = pyglet.window.Window(config=config)
Selecting the best configuration¶
Allowing pyglet to select the best configuration based on a template is sufficient for most applications, however some complex programs may want to specify their own algorithm for selecting a set of OpenGL attributes.
You can enumerate a screen’s configs using the
get_matching_configs()
method. You must supply a
template as a minimum specification, but you can supply an “empty” template
(one with no attributes set) to get a list of all configurations supported by
the screen.
In the following example, all configurations with either an auxiliary buffer or an accumulation buffer are printed:
display = pyglet.canvas.get_display()
screen = display.get_default_screen()
for config in screen.get_matching_configs(gl.Config()):
if config.aux_buffers or config.accum_red_size:
print(config)
As well as supporting more complex configuration selection algorithms, enumeration allows you to efficiently find the maximum value of an attribute (for example, the maximum samples per pixel), or present a list of possible configurations to the user.
Sharing objects between contexts¶
Every window in pyglet has its own OpenGL context. Each context has its own OpenGL state, including the matrix stacks and current flags. However, contexts can optionally share their objects with one or more other contexts. Shareable objects include:
- Textures
- Display lists
- Shader programs
- Vertex and pixel buffer objects
- Framebuffer objects
There are two reasons for sharing objects. The first is to allow objects to be stored on the video card only once, even if used by more than one window. For example, you could have one window showing the actual game, with other “debug” windows showing the various objects as they are manipulated. Or, a set of widget textures required for a GUI could be shared between all the windows in an application.
The second reason is to avoid having to recreate the objects when a context needs to be recreated. For example, if the user wishes to turn on multisampling, it is necessary to recreate the context. Rather than destroy the old one and lose all the objects already created, you can
- Create the new context, sharing object space with the old context, then
- Destroy the old context. The new context retains all the old objects.
pyglet defines an ObjectSpace
: a representation of a
collection of objects used by one or more contexts. Each context has a single
object space, accessible via its
object_space
attribute.
By default, all contexts share the same object space as long as at least one context using it is “alive”. If all the contexts sharing an object space are lost or destroyed, the object space will be destroyed also. This is why it is necessary to follow the steps outlined above for retaining objects when a context is recreated.
pyglet creates a hidden “shadow” context as soon as pyglet.gl
is
imported. By default, all windows will share object space with this shadow
context, so the above steps are generally not needed. The shadow context also
allows objects such as textures to be loaded before a window is created (see
shadow_window
in pyglet.options
for further details).
When you create a Context
, you tell pyglet which other
context it will obtain an object space from. By default (when using the
Window
constructor
to create the context) the most recently created context will be used. You
can specify another context, or specify no context (to create a new object
space) in the Context
constructor.
It can be useful to keep track of which object space an object was created in.
For example, when you load a font, pyglet caches the textures used and reuses
them; but only if the font is being loaded on the same object space. The
easiest way to do this is to set your own attributes on the
ObjectSpace
object.
In the following example, an attribute is set on the object space indicating that game objects have been loaded. This way, if the context is recreated, you can check for this attribute to determine if you need to load them again:
context = pyglet.gl.current_context
object_space = context.object_space
object_space.my_game_objects_loaded = True
Avoid using attribute names on ObjectSpace
that begin with
"pyglet"
, as they may conflict with an internal module.
The OpenGL interface¶
pyglet provides an interface to OpenGL and GLU. The interface is used by all of pyglet’s higher-level API’s, so that all rendering is done efficiently by the graphics card, rather than the operating system. You can access this interface directly; using it is much like using OpenGL from C.
The interface is a “thin-wrapper” around libGL.so
on Linux,
opengl32.dll
on Windows and OpenGL.framework
on OS X. The pyglet
maintainers regenerate the interface from the latest specifications, so it is
always up-to-date with the latest version and almost all extensions.
The interface is provided by the pyglet.gl
package. To use it you will
need a good knowledge of OpenGL, C and ctypes. You may prefer to use OpenGL
without using ctypes, in which case you should investigate PyOpenGL.
PyOpenGL provides similar functionality with a more “Pythonic” interface,
and will work with pyglet without any modification.
Using OpenGL¶
Documentation of OpenGL and GLU are provided at the OpenGL website and (more comprehensively) in the OpenGL Programming SDK.
Importing the package gives access to OpenGL, GLU, and all OpenGL registered extensions. This is sufficient for all but the most advanced uses of OpenGL:
from pyglet.gl import *
All function names and constants are identical to the C counterparts. For example, the following program draws a triangle on the screen:
from pyglet.gl import *
# Direct OpenGL commands to this window.
window = pyglet.window.Window()
@window.event
def on_draw():
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
glBegin(GL_TRIANGLES)
glVertex2f(0, 0)
glVertex2f(window.width, 0)
glVertex2f(window.width, window.height)
glEnd()
pyglet.app.run()
Some OpenGL functions require an array of data. These arrays must be
constructed as ctypes
arrays of the correct type. The following example
draw the same triangle as above, but uses a vertex array instead of the
immediate-mode functions. Note the construction of the vertex array using a
one-dimensional ctypes
array of GLfloat
:
from pyglet.gl import *
window = pyglet.window.Window()
vertices = [0, 0,
window.width, 0,
window.width, window.height]
vertices_gl_array = (GLfloat * len(vertices))(*vertices)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(2, GL_FLOAT, 0, vertices_gl_array)
@window.event
def on_draw():
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
glDrawArrays(GL_TRIANGLES, 0, len(vertices) // 2)
pyglet.app.run()
Similar array constructions can be used to create data for vertex buffer objects, texture data, polygon stipple data and the map functions.
Resizing the window¶
pyglet sets up the viewport and an orthographic projection on each window
automatically. It does this in a default
on_resize()
handler defined on
Window
:
@window.event
def on_resize(width, height):
glViewport(0, 0, width, height)
glMatrixMode(gl.GL_PROJECTION)
glLoadIdentity()
glOrtho(0, width, 0, height, -1, 1)
glMatrixMode(gl.GL_MODELVIEW)
If you need to define your own projection (for example, to use a 3-dimensional perspective projection), you should override this event with your own; for example:
@window.event
def on_resize(width, height):
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(65, width / float(height), .1, 1000)
glMatrixMode(GL_MODELVIEW)
return pyglet.event.EVENT_HANDLED
Note that the on_resize()
handler is called for
a window the first time it is displayed, as well as any time it is later
resized.
Error checking¶
By default, pyglet calls glGetError
after every GL function call (except
where such a check would be invalid). If an error is reported, pyglet raises
GLException
with the result of gluErrorString
as the message.
This is very handy during development, as it catches common coding errors
early on. However, it has a significant impact on performance, and is
disabled when python is run with the -O
option.
You can also disable this error check by setting the following option before
importing pyglet.gl
or pyglet.window
:
# Disable error checking for increased performance
pyglet.options['debug_gl'] = False
from pyglet.gl import *
Setting the option after importing pyglet.gl
will have no effect. Once
disabled, there is no error-checking overhead in each GL call.
Using extension functions¶
Before using an extension function, you should check that the extension is
implemented by the current driver. Typically this is done using
glGetString(GL_EXTENSIONS)
, but pyglet has a convenience module,
pyglet.gl.gl_info that does this for you:
if pyglet.gl.gl_info.have_extension('GL_ARB_shadow'):
# ... do shadow-related code.
else:
# ... raise an exception, or use a fallback method
You can also easily check the version of OpenGL:
if pyglet.gl.gl_info.have_version(1,5):
# We can assume all OpenGL 1.5 functions are implemented.
Remember to only call the gl_info
functions after creating a window.
There is a corresponding glu_info
module for checking the version and
extensions of GLU.
nVidia often release hardware with extensions before having them registered
officially. When you import * from pyglet.gl
you import only the
registered extensions. You can import the latest nVidia extensions
with:
from pyglet.gl.glext_nv import *
Using multiple windows¶
pyglet allows you to create and display any number of windows simultaneously. Each will be created with its own OpenGL context, however all contexts will share the same texture objects, display lists, shader programs, and so on, by default [1]. Each context has its own state and framebuffers.
There is always an active context (unless there are no windows). When using
pyglet.app.run()
for the application event loop, pyglet ensures that
the correct window is the active context before dispatching the
on_draw()
or
on_resize()
events.
In other cases, you can explicitly set the active context with
pyglet.window.Window.switch_to
.
[1] | Sometimes objects and lists cannot be shared between contexts; for example, when the contexts are provided by different video devices. This will usually only occur if you explicitly select different screens driven by different devices. |
AGL, GLX and WGL¶
The OpenGL context itself is managed by an operating-system specific library: AGL on OS X, GLX under X11 and WGL on Windows. pyglet handles these details when a window is created, but you may need to use the functions directly (for example, to use pbuffers) or an extension function.
The modules are named pyglet.gl.agl
, pyglet.gl.glx
and
pyglet.gl.wgl
. You must only import the correct module for the running
operating system:
if sys.platform.startswith('linux'):
from pyglet.gl.glx import *
glxCreatePbuffer(...)
elif sys.platform == 'darwin':
from pyglet.gl.agl import *
aglCreatePbuffer(...)
Alternativally you can use pyglet.compat_platform
to support
platforms that are compatible with platforms not officially supported
by pyglet. For example FreeBSD systems will appear as linux-compat
in pyglet.compat_platform
.
There are convenience modules for querying the version and extensions of WGL
and GLX named pyglet.gl.wgl_info
and pyglet.gl.glx_info
, respectively.
AGL does not have such a module, just query the version of OS X instead.
If using GLX extensions, you can import pyglet.gl.glxext_arb
for the
registered extensions or pyglet.gl.glxext_nv
for the latest nVidia
extensions.
Similarly, if using WGL extensions, import pyglet.gl.wglext_arb
or
pyglet.gl.wglext_nv
.
The application event loop¶
In order to let pyglet process operating system events such as mouse and keyboard events, applications need to enter an application event loop. The event loop continuously checks for new events, dispatches those events, and updates the contents of all open windows.
pyglet provides an application event loop that is tuned for performance and low power usage on Windows, Linux and Mac OS X. Most applications need only call:
pyglet.app.run()
to enter the event loop after creating their initial set of windows and
attaching event handlers. The run()
function does not
return until all open windows have been closed, or until
pyglet.app.exit()
is called.
The pyglet application event loop dispatches window events (such as for mouse
and keyboard input) as they occur and dispatches the
on_draw()
event to
each window after every iteration through the loop.
To have additional code run periodically or every iteration through the loop, schedule functions on the clock (see Calling functions periodically). pyglet ensures that the loop iterates only as often as necessary to fulfill all scheduled functions and user input.
Customising the event loop¶
The pyglet event loop is encapsulated in the
EventLoop
class, which provides
several hooks that can be overridden for customising its behaviour. This is
recommended only for advanced users – typical applications and games are
unlikely to require this functionality.
To use the EventLoop
class directly, instantiate it and call run:
event_loop = pyglet.app.EventLoop()
event_loop.run()
Only one EventLoop
can be running at a time; when the
run()
method is called
the module variable pyglet.app.event_loop
is set to the running
instance. Other pyglet modules such as pyglet.window
depend on this.
Event loop events¶
You can listen for several events on the event loop instance. The most useful
of these is on_window_close()
, which is
dispatched whenever a window is closed. The default handler for this event
exits the event loop if there are no more windows. The following example
overrides this behaviour to exit the application whenever any window is
closed:
event_loop = pyglet.app.EventLoop()
@event_loop.event
def on_window_close(window):
event_loop.exit()
return pyglet.event.EVENT_HANDLED
event_loop.run()
Overriding the default idle policy¶
The pyglet.app.EventLoop.idle()
method is called every iteration of
the event loop. It is responsible for calling scheduled clock functions,
redrawing windows, and deciding how idle the application is. You can override
this method if you have specific requirements for tuning the performance
of your application; especially if it uses many windows.
The default implementation has the following algorithm:
- Call
pyglet.clock.tick()
withpoll=True
to call any scheduled functions. - Dispatch the
on_draw()
event and callflip()
on every open window. - Return the value of
pyglet.clock.get_sleep_time()
.
The return value of the get_sleep_time()
method is
the number of seconds until the event loop needs to iterate again (unless
there is an earlier user-input event); or None
if the loop can wait
for input indefinitely.
Note that this default policy causes every window to be redrawn during every user event – if you have more knowledge about which events have an effect on which windows you can improve on the performance of this method.
Dispatching events manually¶
Earlier versions of pyglet and certain other windowing toolkits such as
PyGame and SDL require the application developer to write their own event
loop. This is usually just an inconvenience compared to
pyglet.app.run()
, but can be necessary in some situations when
combining pyglet with other toolkits.
A simple event loop usually has the following form:
while True:
pyglet.clock.tick()
for window in pyglet.app.windows:
window.switch_to()
window.dispatch_events()
window.dispatch_event('on_draw')
window.flip()
The dispatch_events()
method checks the window’s
operating system event queue for user input and dispatches any events found.
The method does not wait for input – if ther are no events pending, control is
returned to the program immediately.
The call to pyglet.clock.tick()
is required for ensuring scheduled
functions are called, including the internal data pump functions for playing
sounds, animations, and video.
While it is possible to write your own event loop in this way, it is strongly discouraged for the following reasons:
- The
EventLoop
class provides plenty of hooks for most toolkits to be integrated without needing to resort to a manual event loop. - Because
EventLoop
is tuned for specific operating systems, it is more responsive to user events, and continues calling clock functions while windows are being resized, and (on Mac OS X) the menu bar is being tracked. - It is difficult to write a manual event loop that does not consume 100% CPU while still remaining responsive to user input.
The capability for writing manual event loops remains for legacy support and extreme cases where the developer knows what they are doing.
pyglet options¶
pyglet is a cross-platform games and multimedia package.
More information is available at http://www.pyglet.org
-
options
= {'advanced_font_features': False, 'audio': ('xaudio2', 'directsound', 'openal', 'pulse', 'silent'), 'com_mta': False, 'debug_font': False, 'debug_gl': True, 'debug_gl_trace': False, 'debug_gl_trace_args': False, 'debug_graphics_batch': False, 'debug_lib': False, 'debug_media': False, 'debug_texture': False, 'debug_trace': False, 'debug_trace_args': False, 'debug_trace_depth': 1, 'debug_trace_flush': True, 'debug_win32': False, 'debug_x11': False, 'dw_legacy_naming': False, 'graphics_vbo': True, 'headless': False, 'headless_device': 0, 'osx_alt_loop': False, 'search_local_libs': True, 'shadow_window': True, 'vsync': None, 'win32_disable_shaping': False, 'xlib_fullscreen_override_redirect': False, 'xsync': True}¶ Global dict of pyglet options. To change an option from its default, you must import
pyglet
before any sub-packages. For example:import pyglet pyglet.options['debug_gl'] = False
The default options can be overridden from the OS environment. The corresponding environment variable for each option key is prefaced by
PYGLET_
. For example, in Bash you can set thedebug_gl
option with:PYGLET_DEBUG_GL=True; export PYGLET_DEBUG_GL
For options requiring a tuple of values, separate each value with a comma.
The non-development options are:
- audio
A sequence of the names of audio modules to attempt to load, in order of preference. Valid driver names are:
- xaudio2, the Windows Xaudio2 audio module (Windows only)
- directsound, the Windows DirectSound audio module (Windows only)
- pulse, the PulseAudio module (Linux only)
- openal, the OpenAL audio module
- silent, no audio
- debug_lib
- If True, prints the path of each dynamic library loaded.
- debug_gl
- If True, all calls to OpenGL functions are checked afterwards for
errors using
glGetError
. This will severely impact performance, but provides useful exceptions at the point of failure. By default, this option is enabled if__debug__
is (i.e., if Python was not run with the -O option). It is disabled by default when pyglet is “frozen” within a py2exe or py2app library archive. - shadow_window
By default, pyglet creates a hidden window with a GL context when pyglet.gl is imported. This allows resources to be loaded before the application window is created, and permits GL objects to be shared between windows even after they’ve been closed. You can disable the creation of the shadow window by setting this option to False.
Some OpenGL driver implementations may not support shared OpenGL contexts and may require disabling the shadow window (and all resources must be loaded after the window using them was created). Recommended for advanced developers only.
New in version 1.1.
- vsync
- If set, the pyglet.window.Window.vsync property is ignored, and this option overrides it (to either force vsync on or off). If unset, or set to None, the pyglet.window.Window.vsync property behaves as documented.
- xsync
If set (the default), pyglet will attempt to synchronise the drawing of double-buffered windows to the border updates of the X11 window manager. This improves the appearance of the window during resize operations. This option only affects double-buffered windows on X11 servers supporting the Xsync extension with a window manager that implements the _NET_WM_SYNC_REQUEST protocol.
New in version 1.1.
- search_local_libs
If False, pyglet won’t try to search for libraries in the script directory and its lib subdirectory. This is useful to load a local library instead of the system installed version. This option is set to True by default.
New in version 1.2.
-
version
= '1.5.28'¶ The release version of this pyglet installation.
Valid only if pyglet was installed from a source or binary distribution (i.e. not cloned from Git).
Debugging tools¶
pyglet includes a number of debug paths that can be enabled during or before application startup. These were primarily developed to aid in debugging pyglet itself, however some of them may also prove useful for understanding and debugging pyglet applications.
Each debug option is a key in the pyglet.options
dictionary.
Options can be set directly on the dictionary before any other modules
are imported:
import pyglet
pyglet.options['debug_gl'] = False
They can also be set with environment variables before pyglet is imported.
The corresponding environment variable for each option is the string
PYGLET_
prefixed to the uppercase option key. For example, the
environment variable for debug_gl
is PYGLET_DEBUG_GL
. Boolean options
are set or unset with 1
and 0
values.
A summary of the debug environment variables appears in the table below.
Option Environment variable Type debug_font
PYGLET_DEBUG_FONT
bool debug_gl
PYGLET_DEBUG_GL
bool debug_gl_trace
PYGLET_DEBUG_GL_TRACE
bool debug_gl_trace_args
PYGLET_DEBUG_GL_TRACE_ARGS
bool debug_graphics_batch
PYGLET_DEBUG_GRAPHICS_BATCH
bool debug_lib
PYGLET_DEBUG_LIB
bool debug_media
PYGLET_DEBUG_MEDIA
bool debug_trace
PYGLET_DEBUG_TRACE
bool debug_trace_args
PYGLET_DEBUG_TRACE_ARGS
bool debug_trace_depth
PYGLET_DEBUG_TRACE_DEPTH
int debug_win32
PYGLET_DEBUG_WIN32
bool debug_x11
PYGLET_DEBUG_X11
bool graphics_vbo
PYGLET_GRAPHICS_VBO
bool
The debug_media
and debug_font
options are used to debug the
pyglet.media
and pyglet.font
modules, respectively.
Their behaviour is platform-dependent and useful only for pyglet developers.
The remaining debug options are detailed below.
Debugging OpenGL¶
The graphics_vbo
option enables the use of vertex buffer objects in
pyglet.graphics
(instead, only vertex arrays). This is useful when
debugging the graphics
module as well as isolating code for determining if
a video driver is faulty.
The debug_graphics_batch
option causes all
Batch
objects to dump their
rendering tree to standard output before drawing, after any change (so two
drawings of the same tree will only dump once). This is useful to debug
applications making use of Group
and
Batch
rendering.
Error checking¶
The debug_gl
option intercepts most OpenGL calls and calls glGetError
afterwards (it only does this where such a call would be legal). If an error
is reported, an exception is raised immediately.
This option is enabled by default unless the -O
flag (optimisation) is
given to Python, or the script is running from within a py2exe or py2app
package.
Tracing¶
The debug_gl_trace
option causes all OpenGL functions called to be dumped
to standard out. When combined with debug_gl_trace_args
, the arguments
given to each function are also printed (they are abbreviated if necessary to
avoid dumping large amounts of buffer data).
Tracing execution¶
The debug_trace
option enables Python-wide function tracing. This causes
every function call to be printed to standard out. Due to the large number of
function calls required just to initialise pyglet, it is recommended to
redirect standard output to a file when using this option.
The debug_trace_args
option additionally prints the arguments to each
function call.
When debug_trace_depth
is greater than 1 the caller(s) of each function
(and their arguments, if debug_trace_args
is set) are also printed. Each
caller is indented beneath the callee. The default depth is 1, specifying
that no callers are printed.
Platform-specific debugging¶
The debug_lib
option causes the path of each loaded library to be printed
to standard out. This is performed by the undocumented pyglet.lib
module,
which on Linux and Mac OS X must sometimes follow complex procedures to find
the correct library. On Windows not all libraries are loaded via this module,
so they will not be printed (however, loading Windows DLLs is sufficiently
simple that there is little need for this information).
Linux¶
X11 errors are caught by pyglet and suppressed, as there are plenty of X
servers in the wild that generate errors that can be safely ignored.
The debug_x11
option causes these errors to be dumped to standard out,
along with a traceback of the Python stack (this may or may not correspond to
the error, depending on whether or not it was reported asynchronously).
Windows¶
The debug_win32
option causes all library calls into user32.dll
,
kernel32.dll
and gdi32.dll
to be intercepted. Before each library
call SetLastError(0)
is called, and afterwards GetLastError()
is
called. Any errors discovered are written to a file named
debug_win32.log
. Note that an error is only valid if the function called
returned an error code, but the interception function does not check this.
Advanced topics¶
Environment settings¶
Options in the pyglet.options
dictionary can have defaults set
through the operating system’s environment variable. The following table
shows which environment variable is used for each option:
Environment variable pyglet.options
keyType Default value PYGLET_AUDIO
audio
List of strings directsound,openal,alsa,silent
PYGLET_DEBUG_GL
debug_gl
Boolean 1
[1]
[1] | Defaults to 1 unless Python is run with -O or from a
frozen executable. |
In-depth game example¶
This tutorial will walk you through the steps of writing a simple Asteroids clone. It is assumed that the reader is familiar with writing and running Python programs. This is not a programming tutorial, but it should hopefully be clear enough to follow even if you’re a beginner. If you get stuck, first have a look at the relevant sections of the programming guide. The full source code can also be found in the examples/game/ folder of the pyglet source directory, which you can follow along with. If anything is still not clear, let us know!
Basic graphics¶
Lets begin! The first version of our game will simply show a score of zero, a label showing the name of the program, three randomly placed asteroids, and the player’s ship. Nothing will move.
Setting up¶
First things first, make sure you have pyglet installed. Then, we will set up the folder structure for our project. Since this example game is written in stages, we will have several version folders at various stages of development. We will also have a shared resource folder with the images, called ‘resources,’ outside of the example folders. Each version folder contains a Python file called asteroid.py which runs the game, as well as a sub-folder named game where we will place additional modules; this is where most of the logic will be. Your folder structure should look like this:
game/
resources/
(images go here)
version1/
asteroid.py
game/
__init__.py
Getting a window¶
To set up a window, simply import pyglet, create a new instance of
pyglet.window.Window
, and call pyglet.app.run():
import pyglet
game_window = pyglet.window.Window(800, 600)
if __name__ == '__main__':
pyglet.app.run()
If you run the code above, you should see a window full of junk that goes away when you press Esc. (What you are seeing is raw uninitialized graphics memory).
Loading and displaying an image¶
Since our images will reside in a directory other than the example’s root directory, we need to tell pyglet where to find them:
import pyglet
pyglet.resource.path = ['../resources']
pyglet.resource.reindex()
pyglet’s pyglet.resource
module takes all of the hard work out of
finding and loading game resources such as images, sounds, etc.. All that
you need to do is tell it where to look, and reindex it. In this example
game, the resource path starts with ../ because the resources folder is
on the same level as the version1 folder. If we left it off, pyglet
would look inside version1/ for the resources/ folder.
Now that pyglet’s resource module is initialized, we can easily load the images
with the image()
function of the resource module:
player_image = pyglet.resource.image("player.png")
bullet_image = pyglet.resource.image("bullet.png")
asteroid_image = pyglet.resource.image("asteroid.png")
Centering the images¶
Pyglet will draw and position all images from their lower left corner by default. We don’t want this behavior for our images, which need to rotate around their centers. All we have to do to achieve this is to set their anchor points. Lets create a function to simplify this:
def center_image(image):
"""Sets an image's anchor point to its center"""
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2
Now we can just call center_image() on all of our loaded images:
center_image(player_image)
center_image(bullet_image)
center_image(asteroid_image)
Remember that the center_image() function must be defined before it can be called at the module level. Also, note that zero degrees points directly to the right in pyglet, so the images are all drawn with their front pointing to the right.
To access the images from asteroid.py, we need to use something like from game import resources, which we’ll get into in the next section.
Initializing objects¶
We want to put some labels at the top of the window to give the player some information about the score and the current difficulty level. Eventually, we will have a score display, the name of the level, and a row of icons representing the number of remaining lives.
Making the labels¶
To make a text label in pyglet, just initialize a pyglet.text.Label
object:
score_label = pyglet.text.Label(text="Score: 0", x=10, y=460)
level_label = pyglet.text.Label(text="My Amazing Game",
x=game_window.width//2, y=game_window.height//2, anchor_x='center')
Notice that the second label is centered using the anchor_x attribute.
Drawing the labels¶
We want pyglet to run some specific code whenever the window is drawn.
An on_draw()
event is dispatched to the window
to give it a chance to redraw its contents. pyglet provides several ways
to attach event handlers to objects; a simple way is to use a decorator:
@game_window.event
def on_draw():
# draw things here
The @game_window.event decorator lets the Window instance know that our
on_draw() function is an event handler.
The on_draw()
event is fired whenever
- you guessed it - the window needs to be redrawn. Other events include
on_mouse_press()
and
on_key_press()
.
Now we can fill the method with the functions necessary to draw our labels. Before we draw anything, we should clear the screen. After that, we can simply call each object’s draw() function:
@game_window.event
def on_draw():
game_window.clear()
level_label.draw()
score_label.draw()
Now when you run asteroid.py, you should get a window with a score of zero in the upper left corner and a centered label reading “My Amazing Game” at the top of the screen.
Making the player and asteroid sprites¶
The player should be an instance or subclass of pyglet.sprite.Sprite
,
like so:
from game import resources
...
player_ship = pyglet.sprite.Sprite(img=resources.player_image, x=400, y=300)
To get the player to draw on the screen, add a line to on_draw():
@game_window.event
def on_draw():
...
player_ship.draw()
Loading the asteroids is a little more complicated, since we’ll need to place more than one at random locations that don’t immediately collide with the player. Let’s put the loading code in a new game submodule called load.py:
import pyglet
import random
from . import resources
def asteroids(num_asteroids):
asteroids = []
for i in range(num_asteroids):
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = pyglet.sprite.Sprite(img=resources.asteroid_image,
x=asteroid_x, y=asteroid_y)
new_asteroid.rotation = random.randint(0, 360)
asteroids.append(new_asteroid)
return asteroids
All we are doing here is making a few new sprites with random positions. There’s still a problem, though - an asteroid might randomly be placed exactly where the player is, causing immediate death. To fix this issue, we’ll need to be able to tell how far away new asteroids are from the player. Here is a simple function to calculate that distance:
import math
...
def distance(point_1=(0, 0), point_2=(0, 0)):
"""Returns the distance between two points"""
return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)
To check new asteroids against the player’s position, we need to pass the player’s position into the asteroids() function and keep regenerating new coordinates until the asteroid is far enough away. pyglet sprites keep track of their position both as a tuple (Sprite.position) and as x and y attributes (Sprite.x and Sprite.y). To keep our code short, we’ll just pass the position tuple into the function:
def asteroids(num_asteroids, player_position):
asteroids = []
for i in range(num_asteroids):
asteroid_x, asteroid_y = player_position
while distance((asteroid_x, asteroid_y), player_position) < 100:
asteroid_x = random.randint(0, 800)
asteroid_y = random.randint(0, 600)
new_asteroid = pyglet.sprite.Sprite(
img=resources.asteroid_image, x=asteroid_x, y=asteroid_y)
new_asteroid.rotation = random.randint(0, 360)
asteroids.append(new_asteroid)
return asteroids
For each asteroid, it chooses random positions until it finds one away from the player, creates the sprite, and gives it a random rotation. Each asteroid is appended to a list, which is returned.
Now you can load three asteroids like this:
from game import resources, load
...
asteroids = load.asteroids(3, player_ship.position)
The asteroids variable now contains a list of sprites. Drawing them on the
screen is as simple as it was for the player’s ship - just call their
draw()
methods:
@game_window.event
def on_draw():
...
for asteroid in asteroids:
asteroid.draw()
This wraps up the first section. Your “game” doesn’t do much of anything yet, but we’ll get to that in the following sections. You may want to look over the examples/game/version1 folder in the pyglet source to review what we’ve done, and to find a functional copy.
Basic motion¶
In the second version of the example, we’ll introduce a simpler, faster way to draw all of the game objects, as well as add row of icons indicating the number of lives left. We’ll also write some code to make the player and the asteroids obey the laws of physics.
Drawing with batches¶
Calling each object’s draw() method manually can become cumbersome and
tedious if there are many different kinds of objects. It’s also very
inefficient if you need to draw a large number of objects. The pyglet
pyglet.graphics.Batch
class simplifies drawing by letting you draw
all your objects with a single function call. All you need to do is create
a batch, pass it into each object you want to draw, and call the batch’s
draw()
method.
To create a new batch, simply create an instance of pyglet.graphics.Batch
:
main_batch = pyglet.graphics.Batch()
To make an object a member of a batch, just pass the batch into its constructor as the batch keyword argument:
score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
Add the batch keyword argument to each graphical object created in asteroid.py.
To use the batch with the asteroid sprites, we’ll need to pass the batch into the game.load.asteroid() function, then just add it as a keyword argument to each new sprite. Update the function:
def asteroids(num_asteroids, player_position, batch=None):
...
new_asteroid = pyglet.sprite.Sprite(img=resources.asteroid_image,
x=asteroid_x, y=asteroid_y,
batch=batch)
And update the place where it’s called:
asteroids = load.asteroids(3, player_ship.position, main_batch)
Now you can replace those five lines of draw() calls with just one:
main_batch.draw()
Now when you run asteroid.py, it should look exactly the same.
Displaying little ship icons¶
To show how many lives the player has left, we’ll need to draw a little row of icons in the upper right corner of the screen. Since we’ll be making more than one using the same template, let’s create a function called player_lives() in the load module to generate them. The icons should look the same as the player’s ship. We could create a scaled version using an image editor, or we could just let pyglet do the scaling. I don’t know about you, but I prefer the option that requires less work.
The function for creating the icons is almost exactly the same as the one for creating asteroids. For each icon we just create a sprite, give it a position and scale, and append it to the return list:
def player_lives(num_icons, batch=None):
player_lives = []
for i in range(num_icons):
new_sprite = pyglet.sprite.Sprite(img=resources.player_image,
x=785-i*30, y=585, batch=batch)
new_sprite.scale = 0.5
player_lives.append(new_sprite)
return player_lives
The player icon is 50x50 pixels, so half that size will be 25x25. We want to put a little bit of space between each icon, so we create them at 30-pixel intervals starting from the right side of the screen and moving to the left. Note that like the asteroids() function, player_lives() takes a batch argument.
Making things move¶
The game would be pretty boring if nothing on the screen ever moved. To achieve motion, we’ll need to write our own set of classes to handle frame-by-frame movement calculations. We’ll also need to write a Player class to respond to keyboard input.
Creating the basic motion class
Since every visible object is represented by at least one Sprite, we may as well make our basic motion class a subclass of pyglet.sprite.Sprite. Another approach would be to have our class have a sprite attribute.
Create a new game submodule called physicalobject.py and declare a PhysicalObject class. The only new attributes we’ll be adding will store the object’s velocity, so the constructor will be simple:
class PhysicalObject(pyglet.sprite.Sprite):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.velocity_x, self.velocity_y = 0.0, 0.0
Each object will need to be updated every frame, so let’s write an update() method:
def update(self, dt):
self.x += self.velocity_x * dt
self.y += self.velocity_y * dt
What’s dt? It’s the “delta time”, or “time step”. Game frames are not instantaneous, and they don’t always take equal amounts of time to draw. If you’ve ever tried to play a modern game on an old machine, you know that frame rates can jump all over the place. There are a number of ways to deal with this problem, the simplest one being to just multiply all time-sensitive operations by dt. I’ll show you how this value is calculated later.
If we give objects a velocity and just let them go, they will fly off the screen before long. Since we’re making an Asteroids clone, we would rather they just wrapped around the screen. Here is a simple function that accomplishes the goal:
def check_bounds(self):
min_x = -self.image.width / 2
min_y = -self.image.height / 2
max_x = 800 + self.image.width / 2
max_y = 600 + self.image.height / 2
if self.x < min_x:
self.x = max_x
elif self.x > max_x:
self.x = min_x
if self.y < min_y:
self.y = max_y
elif self.y > max_y:
self.y = min_y
As you can see, it simply checks to see if objects are no longer visible on the screen, and if so, it moves them to the other side of the screen. To make every PhysicalObject use this behavior, add a call to self.check_bounds() at the end of update().
To make the asteroids use our new motion code, just import the physicalobject module and change the new_asteroid = … line to create a new PhysicalObject instead of a Sprite. You’ll also want to give them a random initial velocity. Here is the new, improved load.asteroids() function:
def asteroids(num_asteroids, player_position, batch=None):
...
new_asteroid = physicalobject.PhysicalObject(...)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x = random.random()*40
new_asteroid.velocity_y = random.random()*40
...
Writing the game update function¶
To call each object’s update() method every frame, we first need to have a list of those objects. For now, we can just declare it after setting up all the other objects:
game_objects = [player_ship] + asteroids
Now we can write a simple function to iterate over the list:
def update(dt):
for obj in game_objects:
obj.update(dt)
The update() function takes a dt parameter because it is still not the source of the actual time step.
Calling the update() function¶
We need to update the objects at least once per frame. What’s a frame? Well, most screens have a maximum refresh rate of 60 hertz. If we set our loop to run at exactly 60 hertz, though, the motion will look a little jerky because it won’t match the screen exactly. Instead, we can have it update twice as fast, 120 times per second, to get smooth animation.
The best way to call a function 120 times per second is to ask pyglet to do it.
The pyglet.clock
module contains a number of ways to call functions
periodically or at some specified time in the future. The one we want is
pyglet.clock.schedule_interval()
:
pyglet.clock.schedule_interval(update, 1/120.0)
Putting this line above pyglet.app.run() in the if __name__ == ‘__main__’ block tells pyglet to call update() 120 times per second. Pyglet will pass in the elapsed time, i.e. dt, as the only parameter.
Now when you run asteroid.py, you should see your formerly static asteroids drifting serenely across the screen, reappearing on the other side when they slide off the edge.
Writing the Player class¶
In addition to obeying the basic laws of physics, the player object needs to respond to keyboard input. Start by creating a game.player module, importing the appropriate modules, and subclassing PhysicalObject:
from . import physicalobject, resources
class Player(physicalobject.PhysicalObject):
def __init__(self, *args, **kwargs):
super().__init__(img=resources.player_image, *args, **kwargs)
So far, the only difference between a Player and a PhysicalObject is that a Player will always have the same image. But Player objects need a couple more attributes. Since the ship will always thrust with the same force in whatever direction it points, we’ll need to define a constant for the magnitude of that force. We should also define a constant for the ship’s rotation speed:
self.thrust = 300.0
self.rotate_speed = 200.0
Now we need to get the class to respond to user input. Pyglet uses an event-based approach to input, sending key press and key release events to registered event handlers. But we want to use a polling approach in this example, checking periodically if a key is down. One way to accomplish that is to maintain a dictionary of keys. First, we need to initialize the dictionary in the constructor:
self.keys = dict(left=False, right=False, up=False)
Then we need to write two methods, on_key_press() and on_key_release(). When pyglet checks a new event handler, it looks for these two methods, among others:
import math
from pyglet.window import key
from . import physicalobject, resources
class Player(physicalobject.PhysicalObject)
def on_key_press(self, symbol, modifiers):
if symbol == key.UP:
self.keys['up'] = True
elif symbol == key.LEFT:
self.keys['left'] = True
elif symbol == key.RIGHT:
self.keys['right'] = True
def on_key_release(self, symbol, modifiers):
if symbol == key.UP:
self.keys['up'] = False
elif symbol == key.LEFT:
self.keys['left'] = False
elif symbol == key.RIGHT:
self.keys['right'] = False
That looks pretty cumbersome. There’s a better way to do it which we’ll see later, but for now, this version serves as a good demonstration of pyglet’s event system.
The last thing we need to do is write the update() method. It follows the same behavior as a PhysicalObject plus a little extra, so we’ll need to call PhysicalObject’s update() method and then respond to input:
def update(self, dt):
super(Player, self).update(dt)
if self.keys['left']:
self.rotation -= self.rotate_speed * dt
if self.keys['right']:
self.rotation += self.rotate_speed * dt
Pretty simple so far. To rotate the player, we just add the rotation speed to the angle, multiplied by dt to account for time. Note that Sprite objects’ rotation attributes are in degrees, with clockwise as the positive direction. This means that you need to call math.degrees() or math.radians() and make the result negative whenever you use Python’s built-in math functions with the Sprite class, since those functions use radians instead of degrees, and their positive direction is counter-clockwise. The code to make the ship thrust forward uses an example of such a conversion:
if self.keys['up']:
angle_radians = -math.radians(self.rotation)
force_x = math.cos(angle_radians) * self.thrust * dt
force_y = math.sin(angle_radians) * self.thrust * dt
self.velocity_x += force_x
self.velocity_y += force_y
First, we convert the angle to radians so that math.cos() and math.sin() will get the correct values. Then we apply some simple physics to modify the ship’s X and Y velocity components and push the ship in the right direction.
We now have a complete Player class. If we add it to the game and tell pyglet that it’s an event handler, we should be good to go.
Integrating the player class¶
The first thing we need to do is make player_ship an instance of Player:
from game import player
...
player_ship = player.Player(x=400, y=300, batch=main_batch)
Now we need to tell pyglet that player_ship is an event handler. To do that, we need to push it onto the event stack with game_window.push_handlers():
game_window.push_handlers(player_ship)
That’s it! Now you should be able to run the game and move the player with the arrow keys.
Giving the player something to do¶
In any good game, there needs to be something working against the player. In the case of Asteroids, it’s the threat of collision with, well, an asteroid. Collision detection requires a lot of infrastructure in the code, so this section will focus on making it work. We’ll also clean up the player class and show some visual feedback for thrusting.
Simplifying player input¶
Right now, the Player class handles all of its own keyboard events.
It spends 13 lines of code doing nothing but setting boolean values in a
dictionary. One would think that there would be a better way, and there is:
pyglet.window.key.KeyStateHandler
. This handy class automatically
does what we have been doing manually: it tracks the state of every key on the
keyboard.
To start using it, we need to initialize it and push it onto the event stack instead of the Player class. First, let’s add it to Player‘s constructor:
self.key_handler = key.KeyStateHandler()
We also need to push the key_handler object onto the event stack. Keep pushing the player_ship object in addition to its key handler, because we’ll need it to keep handling key press and release events later:
game_window.push_handlers(player_ship.key_handler)
Since Player now relies on key_handler to read the keyboard, we need to change the update() method to use it. The only changes are in the if conditions:
if self.key_handler[key.LEFT]:
...
if self.key_handler[key.RIGHT]:
...
if self.key_handler[key.UP]:
...
Now we can remove the on_key_press() and on_key_release() methods
from the class. It’s just that simple. If you need to see a list of key
constants, you can check the API documentation under
pyglet.window.key
.
Adding an engine flame¶
Without visual feedback, it can be difficult to tell if the ship is actually thrusting forward or not, especially for an observer just watching someone else play the game. One way to provide visual feedback is to show an engine flame behind the player while the player is thrusting.
Loading the flame image¶
The player will now be made of two sprites. There’s nothing preventing us from letting a Sprite own another Sprite, so we’ll just give Player an engine_sprite attribute and update it every frame. For our purposes, this approach will be the simplest and most scalable.
To make the flame draw in the correct position, we could either do some complicated math every frame, or we could just move the image’s anchor point. First, load the image in resources.py:
engine_image = pyglet.resource.image("engine_flame.png")
To get the flame to draw behind the player, we need to move the flame image’s center of rotation to the right, past the end of the image. To do that, we just set its anchor_x and anchor_y attributes:
engine_image.anchor_x = engine_image.width * 1.5
engine_image.anchor_y = engine_image.height / 2
Now the image is ready to be used by the player class. If you’re still confused about anchor points, experiment with the values for engine_image’s anchor point when you finish this section.
Creating and drawing the flame¶
The engine sprite needs to be initialized with all the same arguments as Player, except that it needs a different image and must be initially invisible. The code for creating it belongs in Player.__init__() and is very straightforward:
self.engine_sprite = pyglet.sprite.Sprite(img=resources.engine_image, *args, **kwargs)
self.engine_sprite.visible = False
To make the engine sprite appear only while the player is thrusting, we need to add some logic to the if self.key_handler[key.UP] block in the update() method:
if self.key_handler[key.UP]:
...
self.engine_sprite.visible = True
else:
self.engine_sprite.visible = False
To make the sprite appear at the player’s position, we also need to update its position and rotation attributes:
if self.key_handler[key.UP]:
...
self.engine_sprite.rotation = self.rotation
self.engine_sprite.x = self.x
self.engine_sprite.y = self.y
self.engine_sprite.visible = True
else:
self.engine_sprite.visible = False
Cleaning up after death¶
When the player is inevitably smashed to bits by an asteroid, he will disappear from the screen. However, simply removing the Player instance from the game_objects list is not enough for it to be removed from the graphics batch. To do that, we need to call its delete() method. Normally a Sprite‘s own delete() method will work fine without modifications, but our subclass has its own child Sprite (the engine flame) which must also be deleted when the Player instance is deleted. To get both to die gracefully, we must write a simple but slightly enhanced delete() method:
def delete(self):
self.engine_sprite.delete()
super(Player, self).delete()
The Player class is now cleaned up and ready to go.
Checking For collisions¶
To make objects disappear from the screen, we’ll need to manipulate the game objects list. Every object will need to check every other object’s position against its own, and each object will have to decide whether or not it should be removed from the list. The game loop will then check for dead objects and remove them from the list.
Checking all object pairs¶
We need to check every object against every other object. The simplest method is to use nested loops. This method will be inefficient for a large number of objects, but it will work for our purposes. We can use one easy optimization and avoid checking the same pair of objects twice. Here’s the setup for the loops, which belongs in update(). It simply iterates over all object pairs without doing anything:
for i in range(len(game_objects)):
for j in range(i+1, len(game_objects)):
obj_1 = game_objects[i]
obj_2 = game_objects[j]
We’ll need a way to check if an object has already been killed. We could go over to PhysicalObject right now and put it in, but let’s keep working on the game loop and implement the method later. For now, we’ll just assume that everything in game_objects has a dead attribute which will be False until the class sets it to True, at which point it will be ignored and eventually removed from the list.
To perform the actual check, we’ll also need to call two more methods that don’t exist yet. One method will determine if the two objects actually collide, and the other method will give each object an opportunity to respond to the collision. The checking code itself is easy to understand, so I won’t bother you with further explanations:
if not obj_1.dead and not obj_2.dead:
if obj_1.collides_with(obj_2):
obj_1.handle_collision_with(obj_2)
obj_2.handle_collision_with(obj_1)
Now all that remains is for us to go through the list and remove dead objects:
for to_remove in [obj for obj in game_objects if obj.dead]:
to_remove.delete()
game_objects.remove(to_remove)
As you can see, it simply calls the object’s delete() method to remove it from any batches, then it removes it from the list. If you haven’t used list comprehensions much, the above code might look like it’s removing objects from the list while traversing it. Fortunately, the list comprehension is evaluated before the loop actually runs, so there should be no problems.
Implementing the collision functions¶
We need to add three things to the PhysicalObject class: the dead attribute, the collides_with() method, and the handle_collision_with() method. The collides_with() method will need to use the distance() function, so let’s start by moving that function into its own submodule of game, called util.py:
import pyglet, math
def distance(point_1=(0, 0), point_2=(0, 0)):
return math.sqrt(
(point_1[0] - point_2[0]) ** 2 +
(point_1[1] - point_2[1]) ** 2)
Remember to call from util import distance in load.py. Now we can write PhysicalObject.collides_with() without duplicating code:
def collides_with(self, other_object):
collision_distance = self.image.width/2 + other_object.image.width/2
actual_distance = util.distance(self.position, other_object.position)
return (actual_distance <= collision_distance)
The collision handler function is even simpler, since for now we just want every object to die as soon as it touches another object:
def handle_collision_with(self, other_object):
self.dead = True
One last thing: set self.dead = False in PhysicalObject.__init__().
And that’s it! You should be able to zip around the screen, engine blazing away. If you hit something, both you and the thing you collided with should disappear from the screen. There’s still no game, but we are clearly making progress.
Collision response¶
In this section, we’ll add bullets. This new feature will require us to start adding things to the game_objects list during the game, as well as have objects check each others’ types to make a decision about whether or not they should die.
Adding objects during play¶
How?
We handled object removal with a boolean flag. Adding objects will be a little bit more complicated. For one thing, an object can’t just say “Add me to the list!” It has to come from somewhere. For another thing, an object might want to add more than one other object at a time.
There are a few ways to solve this problem. To avoid circular references, keep our constructors nice and short, and avoid adding extra modules, we’ll have each object keep a list of new child objects to be added to game_objects. This approach will make it easy for any object in the game to spawn more objects.
Tweaking the game loop¶
The simplest way to check objects for children and add those children to the list is to add two lines of code to the game_objects loop. We haven’t implemented the new_objects attribute yet, but when we do, it will be a list of objects to add:
for obj in game_objects:
obj.update(dt)
game_objects.extend(obj.new_objects)
obj.new_objects = []
Unfortunately, this simple solution is problematic. It’s generally a bad idea to modify a list while iterating over it. The fix is to simply add new objects to a separate list, then add the objects in the separate list to game_objects after we have finished iterating over it.
Declare a to_add list just above the loop and add new objects to it instead. At the very bottom of update(), after the object removal code, add the objects in to_add to game_objects:
...collision...
to_add = []
for obj in game_objects:
obj.update(dt)
to_add.extend(obj.new_objects)
obj.new_objects = []
...removal...
game_objects.extend(to_add)
Putting the attribute in PhysicalObject¶
As mentioned before, all we have to do is declare a new_objects attribute in the PhysicalObject class:
def __init__(self, *args, **kwargs):
....
self.new_objects = []
To add a new object, all we have to do is put something in new_objects, and the main loop will see it, add it to the game_objects list, and clear new_objects.
Adding bullets¶
Writing the bullet class
For the most part, bullets act like any other PhysicalObject, but they have two differences, at least in this game: they only collide with some objects, and they disappear from the screen after a couple of seconds to prevent the player from flooding the screen with bullets.
First, make a new submodule of game called bullet.py and start a simple subclass of PhysicalObject:
import pyglet
from . import physicalobject, resources
class Bullet(physicalobject.PhysicalObject):
"""Bullets fired by the player"""
def __init__(self, *args, **kwargs):
super(Bullet, self).__init__(
resources.bullet_image, *args, **kwargs)
To get bullets to disappear after a time, we could keep track of our own age and lifespan attributes, or we could let pyglet do all the work for us. I don’t know about you, but I prefer the second option. First, we need to write a function to call at the end of a bullet’s life:
def die(self, dt):
self.dead = True
Now we need to tell pyglet to call it after half a second or so.
We can do this as soon as the object is initialized by adding a call to
pyglet.clock.schedule_once()
to the constructor:
def __init__(self, *args, **kwargs):
super(Bullet, self).__init__(resources.bullet_image, *args, **kwargs)
pyglet.clock.schedule_once(self.die, 0.5)
There’s still more work to be done on the Bullet class, but before we do any more work on the class itself, let’s get them on the screen.
Firing bullets¶
The Player class will be the only class that fires bullets, so let’s open it up, import the bullet module, and add a bullet_speed attribute to its constructor:
...
from . import bullet
class Player(physicalobject.PhysicalObject):
def __init__(self, *args, **kwargs):
super(Player, self).__init__(img=resources.player_image, *args, **kwargs)
...
self.bullet_speed = 700.0
Now we can write the code to create a new bullet and send it hurling off into space. First, we need to resurrect the on_key_press() event handler:
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
self.fire()
The fire() method itself will be a bit more complicated. Most of the calculations will be very similar to the ones for thrusting, but there will be some differences. We’ll need to spawn the bullet out at the nose of the ship, not at its center. We’ll also need to add the ship’s existing velocity to the bullet’s new velocity, or the bullets will end up going slower than the ship if the player gets going fast enough.
As usual, convert to radians and reverse the direction:
def fire(self):
angle_radians = -math.radians(self.rotation)
Next, calculate the bullet’s position and instantiate it:
ship_radius = self.image.width/2
bullet_x = self.x + math.cos(angle_radians) * ship_radius
bullet_y = self.y + math.sin(angle_radians) * ship_radius
new_bullet = bullet.Bullet(bullet_x, bullet_y, batch=self.batch)
Set its velocity using almost the same equations:
bullet_vx = (
self.velocity_x +
math.cos(angle_radians) * self.bullet_speed
)
bullet_vy = (
self.velocity_y +
math.sin(angle_radians) * self.bullet_speed
)
new_bullet.velocity_x = bullet_vx
new_bullet.velocity_y = bullet_vy
Finally, add it to the new_objects list so that the main loop will pick it up and add it to game_objects:
self.new_objects.append(new_bullet)
At this point, you should be able to fire bullets out of the front of your ship. There’s just one problem: as soon as you fire, your ship disappears. You may have noticed earlier that asteroids also disappear when they touch each other. To fix this problem, we’ll need to start customizing each class’s handle_collision_with() method.
Customizing collision behavior¶
There are five kinds of collisions in the current version of the game: bullet-asteroid, bullet-player, asteroid-player, bullet-bullet, and asteroid-asteroid. There would be many more in a more complex game.
In general, objects of the same type should not be destroyed when they collide, so we can generalize that behavior in PhysicalObject. Other interactions will require a little more work.
Letting twins ignore each other
To let two asteroids or two bullets pass each other by without a word of acknowledgement (or a dramatic explosion), we just need to check if their classes are equal in the PhysicalObject.handle_collision_with() method:
def handle_collision_with(self, other_object):
if other_object.__class__ == self.__class__:
self.dead = False
else:
self.dead = True
There are a few other, more elegant ways to check for object equality in Python, but the above code gets the job done.
Customizing bullet collisions¶
Since bullet collision behavior can vary so wildly across objects, let’s add a reacts_to_bullets attribute to PhysicalObjects which the Bullet class can check to determine if it should register a collision or not. We should also add an is_bullet attribute so we can check the collision properly from both objects.
(These are not “good” design decisions, but they will work.)
First, initialize the reacts_to_bullets attribute to True in the PhysicalObject constructor:
class PhysicalObject(pyglet.sprite.Sprite):
def __init__(self, *args, **kwargs):
...
self.reacts_to_bullets = True
self.is_bullet = False
...
class Bullet(physicalobject.PhysicalObject):
def __init__(self, *args, **kwargs):
...
self.is_bullet = True
Then, insert a bit of code in PhysicalObject.collides_with() to ignore bullets under the right circumstances:
def collides_with(self, other_object):
if not self.reacts_to_bullets and other_object.is_bullet:
return False
if self.is_bullet and not other_object.reacts_to_bullets:
return False
...
Finally, set self.reacts_to_bullets = False in Player.__init__(). The Bullet class is completely finished! Now let’s make something happen when a bullet hits an asteroid.
Making asteroids explode¶
Asteroids is challenging to players because every time you shoot an asteroid, it turns into more asteroids. We need to mimic that behavior if we want our game to be any fun. We’ve already done most of the hard parts. All that remains is to make another subclass of PhysicalObject and write a custom handle_collision_with() method, along with a couple of maintenance tweaks.
Writing the asteroid class¶
Create a new submodule of game called asteroid.py. Write the usual constructor to pass a specific image to the superclass, passing along any other parameters:
import pyglet
from . import resources, physicalobject
class Asteroid(physicalobject.PhysicalObject):
def __init__(self, *args, **kwargs):
super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)
Now we need to write a new handle_collision_with() method. It should create a random number of new, smaller asteroids with random velocities. However, it should only do that if it’s big enough. An asteroid should divide at most twice, and if we scale it down by half each time, then an asteroid should stop dividing when it’s 1/4 the size of a new asteroid.
We want to keep the old behavior of ignoring other asteroids, so start the method with a call to the superclass’s method:
def handle_collision_with(self, other_object):
super(Asteroid, self).handle_collision_with(other_object)
Now we can say that if it’s supposed to die, and it’s big enough, then we should create two or three new asteroids with random rotations and velocities. We should add the old asteroid’s velocity to the new ones to make it look like they come from the same object:
import random
class Asteroid:
def handle_collision_with(self, other_object):
super(Asteroid, self).handle_collision_with(other_object)
if self.dead and self.scale > 0.25:
num_asteroids = random.randint(2, 3)
for i in range(num_asteroids):
new_asteroid = Asteroid(x=self.x, y=self.y, batch=self.batch)
new_asteroid.rotation = random.randint(0, 360)
new_asteroid.velocity_x = (random.random() * 70 + self.velocity_x)
new_asteroid.velocity_y = (random.random() * 70 + self.velocity_y)
new_asteroid.scale = self.scale * 0.5
self.new_objects.append(new_asteroid)
While we’re here, let’s add a small graphical touch to the asteroids by making them rotate a little. To do that, we’ll add a rotate_speed attribute and give it a random value. Then we’ll write an update() method to apply that rotation every frame.
Add the attribute in the constructor:
def __init__(self, *args, **kwargs):
super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)
self.rotate_speed = random.random() * 100.0 - 50.0
Then write the update() method:
def update(self, dt):
super(Asteroid, self).update(dt)
self.rotation += self.rotate_speed * dt
The last thing we need to do is go over to load.py and have the asteroid() method create a new Asteroid instead of a PhysicalObject:
from . import asteroid
def asteroids(num_asteroids, player_position, batch=None):
...
for i in range(num_asteroids):
...
new_asteroid = asteroid.Asteroid(x=asteroid_x, y=asteroid_y, batch=batch)
...
return asteroids
Now we’re looking at something resembling a game. It’s simple, but all of the basics are there.
Next steps¶
So instead of walking you through a standard refactoring session, I’m going to leave it as an exercise for you to do the following:
* Make the Score counter mean something
* Let the player restart the level if they die
* Implement lives and a “Game Over” screen
* Add particle effects
Good luck! With a little effort, you should be able to figure out most of these things on your own. If you have trouble, join us on the pyglet mailing list.
Also, in addition to this example game, there is yet another Asteroids clone available in the /examples/astraea/ folder in the pyglet source directory. In comparison to this example game excercise we’ve just completed, Astraea is a complete game with a proper menu, score system, and additional graphical effects. No step-by-step documentation is available for Astraea, but the code itself should be easy to understand and illustrates some nice techniques.
pyglet¶
pyglet is a cross-platform games and multimedia package.
More information is available at http://www.pyglet.org
-
options
= {'advanced_font_features': False, 'audio': ('xaudio2', 'directsound', 'openal', 'pulse', 'silent'), 'com_mta': False, 'debug_font': False, 'debug_gl': True, 'debug_gl_trace': False, 'debug_gl_trace_args': False, 'debug_graphics_batch': False, 'debug_lib': False, 'debug_media': False, 'debug_texture': False, 'debug_trace': False, 'debug_trace_args': False, 'debug_trace_depth': 1, 'debug_trace_flush': True, 'debug_win32': False, 'debug_x11': False, 'dw_legacy_naming': False, 'graphics_vbo': True, 'headless': False, 'headless_device': 0, 'osx_alt_loop': False, 'search_local_libs': True, 'shadow_window': True, 'vsync': None, 'win32_disable_shaping': False, 'xlib_fullscreen_override_redirect': False, 'xsync': True} Global dict of pyglet options. To change an option from its default, you must import
pyglet
before any sub-packages. For example:import pyglet pyglet.options['debug_gl'] = False
The default options can be overridden from the OS environment. The corresponding environment variable for each option key is prefaced by
PYGLET_
. For example, in Bash you can set thedebug_gl
option with:PYGLET_DEBUG_GL=True; export PYGLET_DEBUG_GL
For options requiring a tuple of values, separate each value with a comma.
The non-development options are:
- audio
A sequence of the names of audio modules to attempt to load, in order of preference. Valid driver names are:
- xaudio2, the Windows Xaudio2 audio module (Windows only)
- directsound, the Windows DirectSound audio module (Windows only)
- pulse, the PulseAudio module (Linux only)
- openal, the OpenAL audio module
- silent, no audio
- debug_lib
- If True, prints the path of each dynamic library loaded.
- debug_gl
- If True, all calls to OpenGL functions are checked afterwards for
errors using
glGetError
. This will severely impact performance, but provides useful exceptions at the point of failure. By default, this option is enabled if__debug__
is (i.e., if Python was not run with the -O option). It is disabled by default when pyglet is “frozen” within a py2exe or py2app library archive. - shadow_window
By default, pyglet creates a hidden window with a GL context when pyglet.gl is imported. This allows resources to be loaded before the application window is created, and permits GL objects to be shared between windows even after they’ve been closed. You can disable the creation of the shadow window by setting this option to False.
Some OpenGL driver implementations may not support shared OpenGL contexts and may require disabling the shadow window (and all resources must be loaded after the window using them was created). Recommended for advanced developers only.
New in version 1.1.
- vsync
- If set, the pyglet.window.Window.vsync property is ignored, and this option overrides it (to either force vsync on or off). If unset, or set to None, the pyglet.window.Window.vsync property behaves as documented.
- xsync
If set (the default), pyglet will attempt to synchronise the drawing of double-buffered windows to the border updates of the X11 window manager. This improves the appearance of the window during resize operations. This option only affects double-buffered windows on X11 servers supporting the Xsync extension with a window manager that implements the _NET_WM_SYNC_REQUEST protocol.
New in version 1.1.
- search_local_libs
If False, pyglet won’t try to search for libraries in the script directory and its lib subdirectory. This is useful to load a local library instead of the system installed version. This option is set to True by default.
New in version 1.2.
-
version
= '1.5.28' The release version of this pyglet installation.
Valid only if pyglet was installed from a source or binary distribution (i.e. not cloned from Git).
pyglet.app¶
Application-wide functionality.
Applications¶
Most applications need only call run()
after creating one or more
windows to begin processing events. For example, a simple application
consisting of one window is:
import pyglet
win = pyglet.window.Window()
pyglet.app.run()
Events¶
To handle events on the main event loop, instantiate it manually. The following example exits the application as soon as any window is closed (the default policy is to wait until all windows are closed):
event_loop = pyglet.app.EventLoop()
@event_loop.event
def on_window_close(window):
event_loop.exit()
New in version 1.1.
Classes¶
-
class
EventLoop
¶ The main run loop of the application.
Calling run begins the application event loop, which processes operating system events, calls
pyglet.clock.tick()
to call scheduled functions and callspyglet.window.Window.on_draw()
andpyglet.window.Window.flip()
to update window contents.Applications can subclass
EventLoop
and override certain methods to integrate another framework’s run loop, or to customise processing in some other way. You should not in general overriderun()
, as this method contains platform-specific code that ensures the application remains responsive to the user while keeping CPU usage to a minimum.Methods
-
run
()¶ Begin processing events, scheduled functions and window updates.
This method returns when
has_exit
is set to True.Developers are discouraged from overriding this method, as the implementation is platform-specific.
-
exit
()¶ Safely exit the event loop at the end of the current iteration.
This method is a thread-safe equivalent for for setting
has_exit
toTrue
. All waiting threads will be interrupted (seesleep()
).
-
sleep
(timeout)¶ Wait for some amount of time, or until the
has_exit
flag is set orexit()
is called.This method is thread-safe.
Parameters: timeout (float) – Time to wait, in seconds. New in version 1.2.
Return type: bool Returns: True
if the has_exit flag is set, otherwiseFalse
.
Events
-
on_enter
()¶ The event loop is about to begin.
This is dispatched when the event loop is prepared to enter the main run loop, and represents the last chance for an application to initialise itself.
-
on_exit
()¶ The event loop is about to exit.
After dispatching this event, the
run()
method returns (the application may not actually exit if you have more code following therun()
invocation).
-
on_window_close
(window)¶ A window was closed.
This event is dispatched when a window is closed. It is not dispatched if the window’s close button was pressed but the window did not close.
The default handler calls
exit()
if no more windows are open. You can override this handler to base your application exit on some other policy.
Attributes
-
has_exit
¶ Flag indicating if the event loop will exit in the next iteration. When set, all waiting threads are interrupted (see
sleep()
).Thread-safe since pyglet 1.2.
See: exit Type: bool
Methods (internal)
-
enter_blocking
()¶ Called by pyglet internal processes when the operating system is about to block due to a user interaction. For example, this is common when the user begins resizing or moving a window.
This method provides the event loop with an opportunity to set up an OS timer on the platform event loop, which will continue to be invoked during the blocking operation.
The default implementation ensures that
idle()
continues to be called as documented.New in version 1.2.
-
exit_blocking
()¶ Called by pyglet internal processes when the blocking operation completes. See
enter_blocking()
.
-
idle
()¶ Called during each iteration of the event loop.
The method is called immediately after any window events (i.e., after any user input). The method can return a duration after which the idle method will be called again. The method may be called earlier if the user creates more input events. The method can return None to only wait for user events.
For example, return
1.0
to have the idle method called every second, or immediately after any user events.The default implementation dispatches the
pyglet.window.Window.on_draw()
event for all windows and usespyglet.clock.tick()
andpyglet.clock.get_sleep_time()
on the default clock to determine the return value.This method should be overridden by advanced users only. To have code execute at regular intervals, use the
pyglet.clock.schedule()
methods.Return type: float Returns: The number of seconds before the idle method should be called again, or None to block for user input.
-
-
class
PlatformEventLoop
¶ Abstract class, implementation depends on platform.
New in version 1.2.
-
dispatch_posted_events
()¶ Immediately dispatch all pending events.
Normally this is called automatically by the runloop iteration.
-
is_running
()¶ Return True if the event loop is currently processing, or False if it is blocked or not activated.
Return type: bool
-
notify
()¶ Notify the event loop that something needs processing.
If the event loop is blocked, it will unblock and perform an iteration immediately. If the event loop is running, another iteration is scheduled for immediate execution afterwards.
-
post_event
(dispatcher, event, *args)¶ Post an event into the main application thread.
The event is queued internally until the
run()
method’s thread is able to dispatch the event. This method can be safely called from any thread.If the method is called from the
run()
method’s thread (for example, from within an event handler), the event may be dispatched within the same runloop iteration or the next one; the choice is nondeterministic.Parameters: - dispatcher (EventDispatcher) – Dispatcher to process the event.
- event (str) – Event name.
- args (sequence) – Arguments to pass to the event handlers.
-
set_timer
(func, interval)¶
-
start
()¶
-
step
(timeout=None)¶
-
stop
()¶
-
Functions¶
-
run
()¶ Begin processing events, scheduled functions and window updates.
This is a convenience function, equivalent to:
pyglet.app.event_loop.run()
-
exit
()¶ Exit the application event loop.
Causes the application event loop to finish, if an event loop is currently running. The application may not necessarily exit (for example, there may be additional code following the run invocation).
This is a convenience function, equivalent to:
event_loop.exit()
Attributes¶
-
event_loop
= <pyglet.app.base.EventLoop object>¶ The global event loop. Applications can replace this with their own subclass of
EventLoop
before callingEventLoop.run()
.
-
platform_event_loop
= <pyglet.app.base.PlatformEventLoop object>¶ Abstract class, implementation depends on platform.
New in version 1.2.
-
windows
= <_weakrefset.WeakSet object>¶ Set of all open windows (including invisible windows). Instances of
pyglet.window.Window
are automatically added to this set upon construction. The set uses weak references, so windows are removed from the set when they are no longer referenced or are closed explicitly.
pyglet.canvas¶
Display and screen management.
Rendering is performed on a Canvas
, which conceptually could be an
off-screen buffer, the content area of a pyglet.window.Window
, or an
entire screen. Currently, canvases can only be created with windows (though
windows can be set fullscreen).
Windows and canvases must belong to a Display
. On Windows and Mac OS X
there is only one display, which can be obtained with get_display()
.
Linux supports multiple displays, corresponding to discrete X11 display
connections and screens. get_display()
on Linux returns the default
display and screen 0 (localhost:0.0
); if a particular screen or display is
required then Display
can be instantiated directly.
Within a display one or more screens are attached. A Screen
often
corresponds to a physical attached monitor, however a monitor or projector set
up to clone another screen will not be listed. Use Display.get_screens()
to get a list of the attached screens; these can then be queried for their
sizes and virtual positions on the desktop.
The size of a screen is determined by its current mode, which can be changed
by the application; see the documentation for Screen
.
New in version 1.2.
-
get_display
()¶ Get the default display device.
If there is already a
Display
connection, that display will be returned. Otherwise, a defaultDisplay
is created and returned. If multiple display connections are active, an arbitrary one is returned.New in version 1.2.
Return type: Display
-
class
Display
(name=None, x_screen=None)¶ A display device supporting one or more screens.
New in version 1.2.
-
get_default_screen
()¶ Get the default (primary) screen as specified by the user’s operating system preferences.
Return type: Screen
-
get_screens
()¶ Get the available screens.
A typical multi-monitor workstation comprises one
Display
with multipleScreen
s. This method returns a list of screens which can be enumerated to select one for full-screen display.For the purposes of creating an OpenGL config, the default screen will suffice.
Return type: list of Screen
-
name
= None¶ Name of this display, if applicable.
Type: str
-
x_screen
= None¶ The X11 screen number of this display, if applicable.
Type: int
-
-
class
Screen
(display, x, y, width, height)¶ A virtual monitor that supports fullscreen windows.
Screens typically map onto a physical display such as a monitor, television or projector. Selecting a screen for a window has no effect unless the window is made fullscreen, in which case the window will fill only that particular virtual screen.
The
width
andheight
attributes of a screen give the current resolution of the screen. Thex
andy
attributes give the global location of the top-left corner of the screen. This is useful for determining if screens are arranged above or next to one another.Use
get_screens()
orget_default_screen()
to obtain an instance of this class.-
get_best_config
(template=None)¶ Get the best available GL config.
Any required attributes can be specified in template. If no configuration matches the template,
NoSuchConfigException
will be raised.Warning
Deprecated. Use
pyglet.gl.Config.match()
.Parameters: template (pyglet.gl.Config) – A configuration with desired attributes filled in. Return type: Config
Returns: A configuration supported by the platform that best fulfils the needs described by the template.
-
get_closest_mode
(width, height)¶ Get the screen mode that best matches a given size.
If no supported mode exactly equals the requested size, a larger one is returned; or
None
if no mode is large enough.Parameters: - width (int) – Requested screen width.
- height (int) – Requested screen height.
Return type: ScreenMode
New in version 1.2.
-
get_matching_configs
(template)¶ Get a list of configs that match a specification.
Any attributes specified in template will have values equal to or greater in each returned config. If no configs satisfy the template, an empty list is returned.
Warning
Deprecated. Use
pyglet.gl.Config.match()
.Parameters: template (pyglet.gl.Config) – A configuration with desired attributes filled in. Return type: list of Config
Returns: A list of matching configs.
-
get_mode
()¶ Get the current display mode for this screen.
Return type: ScreenMode
New in version 1.2.
-
get_modes
()¶ Get a list of screen modes supported by this screen.
Return type: list of ScreenMode
New in version 1.2.
-
restore_mode
()¶ Restore the screen mode to the user’s default.
-
set_mode
(mode)¶ Set the display mode for this screen.
The mode must be one previously returned by
get_mode()
orget_modes()
.Parameters: mode (ScreenMode) – Screen mode to switch this screen to.
-
display
¶ Display this screen belongs to.
-
height
¶ Height of the screen, in pixels.
-
width
¶ Width of the screen, in pixels.
-
x
¶ Left edge of the screen on the virtual desktop.
-
y
¶ Top edge of the screen on the virtual desktop.
-
pyglet.clock¶
Precise framerate calculation function scheduling.
Measuring time¶
The tick and get_fps functions can be used in conjunction to fulfil most games’ basic requirements:
from pyglet import clock
while True:
dt = clock.tick()
# ... update and render ...
print(f"FPS is {clock.get_fps()}")
The dt
value returned gives the number of seconds (as a float) since the
last “tick”.
The get_fps function averages the framerate over a sliding window of
approximately 1 second. (You can calculate the instantaneous framerate by
taking the reciprocal of dt
).
Always remember to tick the clock!
Scheduling¶
You can schedule a function to be called every time the clock is ticked:
def callback(dt):
print(f"{dt} seconds since last callback")
clock.schedule(callback)
The schedule_interval method causes a function to be called every “n” seconds:
clock.schedule_interval(callback, .5) # called twice a second
The schedule_once method causes a function to be called once “n” seconds in the future:
clock.schedule_once(callback, 5) # called in 5 seconds
All of the schedule methods will pass on any additional args or keyword args you specify to the callback function:
def move(dt, velocity, sprite):
sprite.position += dt * velocity
clock.schedule(move, velocity=5.0, sprite=alien)
You can cancel a function scheduled with any of these methods using unschedule:
clock.unschedule(move)
Using multiple clocks¶
The clock functions are all relayed to an instance of
Clock
which is initialised with the module. You can
get this instance to use directly:
clk = clock.get_default()
You can also replace the default clock with your own:
myclk = clock.Clock() clock.set_default(myclk)
Each clock maintains its own set of scheduled functions and FPS measurement. Each clock must be “ticked” separately.
Multiple and derived clocks potentially allow you to separate “game-time” and “wall-time”, or to synchronise your clock to an audio or video stream instead of the system clock.
-
class
Clock
(time_function=<built-in function perf_counter>)¶ Class for calculating and limiting framerate.
It is also used for calling scheduled functions.
-
call_scheduled_functions
(dt)¶ Call scheduled functions that elapsed on the last update_time.
New in version 1.2.
Parameters: dt (float) – The elapsed time since the last update to pass to each scheduled function. This is not used to calculate which functions have elapsed. Return type: bool Returns: True if any functions were called, otherwise False.
-
get_fps
()¶ Get the average clock update frequency of recent history.
The result is the average of a sliding window of the last “n” updates, where “n” is some number designed to cover approximately 1 second. This is not the Window redraw rate.
Return type: float Returns: The measured updates per second.
-
get_sleep_time
(sleep_idle)¶ Get the time until the next item is scheduled.
Applications can choose to continue receiving updates at the maximum framerate during idle time (when no functions are scheduled), or they can sleep through their idle time and allow the CPU to switch to other processes or run in low-power mode.
If sleep_idle is
True
the latter behaviour is selected, andNone
will be returned if there are no scheduled items.Otherwise, if sleep_idle is
False
, or if any scheduled items exist, a value of 0 is returned.Parameters: sleep_idle (bool) – If True, the application intends to sleep through its idle time; otherwise it will continue ticking at the maximum frame rate allowed. Return type: float Returns: Time until the next scheduled event in seconds, or None
if there is no event scheduled.New in version 1.1.
-
schedule
(func, *args, **kwargs)¶ Schedule a function to be called every frame.
The function should have a prototype that includes
dt
as the first argument, which gives the elapsed time, in seconds, since the last clock tick. Any additional arguments given to this function are passed on to the callback:def callback(dt, *args, **kwargs): pass
Parameters: func (callable) – The function to call each frame.
-
schedule_interval
(func, interval, *args, **kwargs)¶ Schedule a function to be called every interval seconds.
Specifying an interval of 0 prevents the function from being called again (see schedule to call a function as often as possible).
The callback function prototype is the same as for schedule.
Parameters: - func (callable) – The function to call when the timer lapses.
- interval (float) – The number of seconds to wait between each call.
-
schedule_interval_soft
(func, interval, *args, **kwargs)¶ Schedule a function to be called every
interval
seconds.This method is similar to schedule_interval, except that the clock will move the interval out of phase with other scheduled functions so as to distribute CPU more load evenly over time.
This is useful for functions that need to be called regularly, but not relative to the initial start time.
pyglet.media
does this for scheduling audio buffer updates, which need to occur regularly – if all audio updates are scheduled at the same time (for example, mixing several tracks of a music score, or playing multiple videos back simultaneously), the resulting load on the CPU is excessive for those intervals but idle outside. Using the soft interval scheduling, the load is more evenly distributed.Soft interval scheduling can also be used as an easy way to schedule graphics animations out of phase; for example, multiple flags waving in the wind.
New in version 1.1.
Parameters: - func (callable) – The function to call when the timer lapses.
- interval (float) – The number of seconds to wait between each call.
-
schedule_once
(func, delay, *args, **kwargs)¶ Schedule a function to be called once after delay seconds.
The callback function prototype is the same as for schedule.
Parameters: - func (callable) – The function to call when the timer lapses.
- delay (float) – The number of seconds to wait before the timer lapses.
-
static
sleep
(microseconds)¶
-
tick
(poll=False)¶ Signify that one frame has passed.
This will call any scheduled functions that have elapsed.
Parameters: poll (bool) – If True, the function will call any scheduled functions but will not sleep or busy-wait for any reason. Recommended for advanced applications managing their own sleep timers only. Since pyglet 1.1. Return type: float Returns: The number of seconds since the last “tick”, or 0 if this was the first frame.
-
unschedule
(func)¶ Remove a function from the schedule.
If the function appears in the schedule more than once, all occurrences are removed. If the function was not scheduled, no error is raised.
Parameters: func (callable) – The function to remove from the schedule.
-
update_time
()¶ Get the elapsed time since the last call to update_time.
This updates the clock’s internal measure of time and returns the difference since the last update (or since the clock was created).
New in version 1.2.
Return type: float Returns: The number of seconds since the last update_time, or 0 if this was the first time it was called.
-
MIN_SLEEP
= 0.005¶ On Windows, MIN_SLEEP is larger because the default timer resolution is set by default to 15 .6 ms.
-
SLEEP_UNDERSHOOT
= 0.004¶ The amount of time in seconds this clock subtracts from sleep values to compensate for lazy operating systems.
-
-
get_default
()¶ Get the pyglet default Clock.
Return the
Clock
instance that is used by all module-level clock functions.Return type: Clock Returns: The default clock.
-
get_fps
()¶ Get the average clock update frequency.
The result is the sliding average of the last “n” updates, where “n” is some number designed to cover approximately 1 second. This is the internal clock update rate, not the Window redraw rate. Platform events, such as moving the mouse rapidly, will cause the clock to refresh more often.
Return type: float Returns: The measured updates per second.
-
get_sleep_time
(sleep_idle)¶ Get the time until the next item is scheduled on the default clock.
See Clock.get_sleep_time for details.
Parameters: sleep_idle (bool) – If True, the application intends to sleep through its idle time; otherwise it will continue ticking at the maximum frame rate allowed. Return type: float Returns: Time until the next scheduled event in seconds, or None
if there is no event scheduled.New in version 1.1.
-
schedule
(func, *args, **kwargs)¶ Schedule ‘func’ to be called every frame on the default clock.
The arguments passed to func are
dt
, followed by any*args
and**kwargs
given here.Parameters: func (callable) – The function to call each frame.
-
schedule_interval
(func, interval, *args, **kwargs)¶ Schedule
func
on the default clock every interval seconds.The arguments passed to
func
aredt
(time since last function call), followed by any*args
and**kwargs
given here.Parameters: - func (callable) – The function to call when the timer lapses.
- interval (float) – The number of seconds to wait between each call.
-
schedule_interval_soft
(func, interval, *args, **kwargs)¶ Schedule
func
on the default clock every interval seconds.The clock will move the interval out of phase with other scheduled functions so as to distribute CPU more load evenly over time.
The arguments passed to
func
aredt
(time since last function call), followed by any*args
and**kwargs
given here.See: Clock.schedule_interval_soft New in version 1.1.
Parameters: - func (callable) – The function to call when the timer lapses.
- interval (float) – The number of seconds to wait between each call.
-
schedule_once
(func, delay, *args, **kwargs)¶ Schedule
func
to be called once afterdelay
seconds.This function uses the default clock.
delay
can be a float. The arguments passed tofunc
aredt
(time since last function call), followed by any*args
and**kwargs
given here.If no default clock is set, the func is queued and will be scheduled on the default clock as soon as it is created.
Parameters: - func (callable) – The function to call when the timer lapses.
- delay (float) – The number of seconds to wait before the timer lapses.
-
set_default
(default)¶ Set the default clock to use for all module-level functions.
By default an instance of
Clock
is used.Parameters: default (Clock) – The default clock to use.
-
tick
(poll=False)¶ Signify that one frame has passed on the default clock.
This will call any scheduled functions that have elapsed.
Parameters: poll (bool) – If True, the function will call any scheduled functions but will not sleep or busy-wait for any reason. Recommended for advanced applications managing their own sleep timers only. Since pyglet 1.1. Return type: float Returns: The number of seconds since the last “tick”, or 0 if this was the first frame.
-
unschedule
(func)¶ Remove
func
from the default clock’s schedule.No error is raised if the
func
was never scheduled.Parameters: func (callable) – The function to remove from the schedule.
pyglet.event¶
Event dispatch framework.
All objects that produce events in pyglet implement EventDispatcher
,
providing a consistent interface for registering and manipulating event
handlers. A commonly used event dispatcher is pyglet.window.Window.
Event types¶
For each event dispatcher there is a set of events that it dispatches; these
correspond with the type of event handlers you can attach. Event types are
identified by their name, for example, ‘’on_resize’’. If you are creating a
new class which implements EventDispatcher
, you must call
EventDispatcher.register_event_type for each event type.
Attaching event handlers¶
An event handler is simply a function or method. You can attach an event handler by setting the appropriate function on the instance:
def on_resize(width, height):
# ...
dispatcher.on_resize = on_resize
There is also a convenience decorator that reduces typing:
@dispatcher.event
def on_resize(width, height):
# ...
You may prefer to subclass and override the event handlers instead:
class MyDispatcher(DispatcherClass):
def on_resize(self, width, height):
# ...
Event handler stack¶
When attaching an event handler to a dispatcher using the above methods, it replaces any existing handler (causing the original handler to no longer be called). Each dispatcher maintains a stack of event handlers, allowing you to insert an event handler “above” the existing one rather than replacing it.
There are two main use cases for “pushing” event handlers:
- Temporarily intercepting the events coming from the dispatcher by pushing a custom set of handlers onto the dispatcher, then later “popping” them all off at once.
- Creating “chains” of event handlers, where the event propagates from the top-most (most recently added) handler to the bottom, until a handler takes care of it.
Use EventDispatcher.push_handlers to create a new level in the stack and attach handlers to it. You can push several handlers at once:
dispatcher.push_handlers(on_resize, on_key_press)
If your function handlers have different names to the events they handle, use keyword arguments:
dispatcher.push_handlers(on_resize=my_resize, on_key_press=my_key_press)
After an event handler has processed an event, it is passed on to the next-lowest event handler, unless the handler returns EVENT_HANDLED, which prevents further propagation.
To remove all handlers on the top stack level, use EventDispatcher.pop_handlers.
Note that any handlers pushed onto the stack have precedence over the
handlers set directly on the instance (for example, using the methods
described in the previous section), regardless of when they were set.
For example, handler foo
is called before handler bar
in the following
example:
dispatcher.push_handlers(on_resize=foo)
dispatcher.on_resize = bar
Dispatching events¶
pyglet uses a single-threaded model for all application code. Event handlers are only ever invoked as a result of calling EventDispatcher.dispatch_events`.
It is up to the specific event dispatcher to queue relevant events until they can be dispatched, at which point the handlers are called in the order the events were originally generated.
This implies that your application runs with a main loop that continuously updates the application state and checks for new events:
while True:
dispatcher.dispatch_events()
# ... additional per-frame processing
Not all event dispatchers require the call to dispatch_events
; check with
the particular class documentation.
Note
In order to prevent issues with garbage collection, the
EventDispatcher
class only holds weak
references to pushed event handlers. That means the following example
will not work, because the pushed object will fall out of scope and be
collected:
dispatcher.push_handlers(MyHandlerClass())
Instead, you must make sure to keep a reference to the object before pushing it. For example:
my_handler_instance = MyHandlerClass()
dispatcher.push_handlers(my_handler_instance)
-
exception
EventException
¶ An exception raised when an event handler could not be attached.
-
class
EventDispatcher
¶ Generic event dispatcher interface.
See the module docstring for usage.
-
dispatch_event
(event_type, *args)¶ Dispatch a single event to the attached handlers.
The event is propagated to all handlers from from the top of the stack until one returns EVENT_HANDLED. This method should be used only by
EventDispatcher
implementors; applications should call thedispatch_events
method.Since pyglet 1.2, the method returns EVENT_HANDLED if an event handler returned EVENT_HANDLED or EVENT_UNHANDLED if all events returned EVENT_UNHANDLED. If no matching event handlers are in the stack,
False
is returned.Parameters: - event_type (str) – Name of the event.
- args (sequence) – Arguments to pass to the event handler.
Return type: bool or None
Returns: (Since pyglet 1.2) EVENT_HANDLED if an event handler returned EVENT_HANDLED; EVENT_UNHANDLED if one or more event handlers were invoked but returned only EVENT_UNHANDLED; otherwise
False
. In pyglet 1.1 and earlier, the return value is alwaysNone
.
-
event
(*args)¶ Function decorator for an event handler.
Usage:
win = window.Window() @win.event def on_resize(self, width, height): # ...
or:
@win.event('on_resize') def foo(self, width, height): # ...
-
pop_handlers
()¶ Pop the top level of event handlers off the stack.
-
push_handlers
(*args, **kwargs)¶ Push a level onto the top of the handler stack, then attach zero or more event handlers.
If keyword arguments are given, they name the event type to attach. Otherwise, a callable’s __name__ attribute will be used. Any other object may also be specified, in which case it will be searched for callables with event names.
-
classmethod
register_event_type
(name)¶ Register an event type with the dispatcher.
Registering event types allows the dispatcher to validate event handler names as they are attached, and to search attached objects for suitable handlers.
Parameters: name (str) – Name of the event to register.
-
remove_handler
(name, handler)¶ Remove a single event handler.
The given event handler is removed from the first handler stack frame it appears in. The handler must be the exact same callable as passed to set_handler, set_handlers or
push_handlers()
; and the name must match the event type it is bound to.No error is raised if the event handler is not set.
Parameters: - name (str) – Name of the event type to remove.
- handler (callable) – Event handler to remove.
-
remove_handlers
(*args, **kwargs)¶ Remove event handlers from the event stack.
See
push_handlers()
for the accepted argument types. All handlers are removed from the first stack frame that contains any of the given handlers. No error is raised if any handler does not appear in that frame, or if no stack frame contains any of the given handlers.If the stack frame is empty after removing the handlers, it is removed from the stack. Note that this interferes with the expected symmetry of
push_handlers()
andpop_handlers()
.
-
set_handler
(name, handler)¶ Attach a single event handler.
Parameters: - name (str) – Name of the event type to attach to.
- handler (callable) – Event handler to attach.
-
set_handlers
(*args, **kwargs)¶ Attach one or more event handlers to the top level of the handler stack.
See
push_handlers()
for the accepted argument types.
-
pyglet.font¶
Load fonts.
pyglet will automatically load any system-installed fonts. You can add additional fonts
(for example, from your program resources) using add_file()
or
add_directory()
. These fonts are then available in the same way as system-installed fonts:
from pyglet import font
font.add_file('action_man.ttf')
action_man = font.load('Action Man', 16)
# or
from pyglet import resource
resource.add_font('action_man.ttf')
action_man = font.load('Action Man')
See the pyglet.font.base
module for documentation on the base classes used
by this package.
-
add_file
(font)¶ Add a font to pyglet’s search path.
In order to load a font that is not installed on the system, you must call this method to tell pyglet that it exists. You can supply either a filename or any file-like object.
The font format is platform-dependent, but is typically a TrueType font file containing a single font face. Note that to use a font added with this method, you should pass the face name (not the file name) to :meth:
pyglet.font.load()
or any other place where you normally specify a font.Parameters: font (str or file-like object) – Filename or file-like object to load fonts from.
-
add_directory
(directory)¶ Add a directory of fonts to pyglet’s search path.
This function simply calls
pyglet.font.add_file()
for each file with a.ttf
extension in the given directory. Subdirectories are not searched.Parameters: dir (str) – Directory that contains font files.
-
load
(name=None, size=None, bold=False, italic=False, stretch=False, dpi=None)¶ Load a font for rendering.
Parameters: - name (str, or list of str) – Font family, for example, “Times New Roman”. If a list of names is provided, the first one matching a known font is used. If no font can be matched to the name(s), a default font is used. In pyglet 1.1, the name may be omitted.
- size (float) – Size of the font, in points. The returned font may be an exact match or the closest available. In pyglet 1.1, the size may be omitted, and defaults to 12pt.
- bold (bool) – If True, a bold variant is returned, if one exists for the given family and size.
- italic (bool) – If True, an italic variant is returned, if one exists for the given family and size.
- dpi (float) – The assumed resolution of the display device, for the purposes of determining the pixel size of the font. Defaults to 96.
Return type: Font
-
have_font
(name)¶ Check if specified system font name is available.
pyglet.gl¶
OpenGL and GLU interface.
This package imports all OpenGL, GLU and registered OpenGL extension functions. Functions have identical signatures to their C counterparts. For example:
from pyglet.gl import *
# [...omitted: set up a GL context and framebuffer]
glBegin(GL_QUADS)
glVertex3f(0, 0, 0)
glVertex3f(0.1, 0.2, 0.3)
glVertex3f(0.1, 0.2, 0.3)
glEnd()
OpenGL is documented in full at the OpenGL Reference Pages.
The OpenGL Programming Guide is a popular reference manual organised by topic. The free online version documents only OpenGL 1.1. Later editions cover more recent versions of the API and can be purchased from a book store.
The following subpackages are imported into this “mega” package already (and
so are available by importing pyglet.gl
):
pyglet.gl.gl
- OpenGL
pyglet.gl.glu
- GLU
pyglet.gl.gl.glext_arb
- ARB registered OpenGL extension functions
These subpackages are also available, but are not imported into this namespace by default:
pyglet.gl.glext_nv
- nVidia OpenGL extension functions
pyglet.gl.agl
- AGL (Mac OS X OpenGL context functions)
pyglet.gl.glx
- GLX (Linux OpenGL context functions)
pyglet.gl.glxext_arb
- ARB registered GLX extension functions
pyglet.gl.glxext_nv
- nvidia GLX extension functions
pyglet.gl.wgl
- WGL (Windows OpenGL context functions)
pyglet.gl.wglext_arb
- ARB registered WGL extension functions
pyglet.gl.wglext_nv
- nvidia WGL extension functions
The information modules are provided for convenience, and are documented below.
-
exception
ConfigException
¶
-
exception
ContextException
¶
-
current_context
= None¶ The active OpenGL context.
You can change the current context by calling Context.set_current; do not modify this global.
Type: Context New in version 1.1.
-
class
GLException
¶
-
class
ObjectSpace
¶
-
class
Config
(**kwargs)¶ Graphics configuration.
A Config stores the preferences for OpenGL attributes such as the number of auxilliary buffers, size of the colour and depth buffers, double buffering, stencilling, multi- and super-sampling, and so on.
Different platforms support a different set of attributes, so these are set with a string key and a value which is integer or boolean.
Variables: - double_buffer (bool) – Specify the presence of a back-buffer for every color buffer.
- stereo (bool) – Specify the presence of separate left and right buffer sets.
- buffer_size (int) – Total bits per sample per color buffer.
- aux_buffers (int) – The number of auxilliary color buffers.
- sample_buffers (int) – The number of multisample buffers.
- samples (int) – The number of samples per pixel, or 0 if there are no multisample buffers.
- red_size (int) – Bits per sample per buffer devoted to the red component.
- green_size (int) – Bits per sample per buffer devoted to the green component.
- blue_size (int) – Bits per sample per buffer devoted to the blue component.
- alpha_size (int) – Bits per sample per buffer devoted to the alpha component.
- depth_size (int) – Bits per sample in the depth buffer.
- stencil_size (int) – Bits per sample in the stencil buffer.
- accum_red_size (int) – Bits per pixel devoted to the red component in the accumulation buffer.
- accum_green_size (int) – Bits per pixel devoted to the green component in the accumulation buffer.
- accum_blue_size (int) – Bits per pixel devoted to the blue component in the accumulation buffer.
- accum_alpha_size (int) – Bits per pixel devoted to the alpha component in the accumulation buffer.
-
create_context
(share)¶ Create a GL context that satisifies this configuration.
Warning
Deprecated. Use CanvasConfig.create_context.
Parameters: share (Context) – If not None, a context with which to share objects with. Return type: Context Returns: The new context.
-
get_gl_attributes
()¶ Return a list of attributes set on this config.
Return type: list of tuple (name, value)
Returns: All attributes, with unset attributes having a value of None
.
-
is_complete
()¶ Determine if this config is complete and able to create a context.
Configs created directly are not complete, they can only serve as templates for retrieving a supported config from the system. For example, pyglet.window.Screen.get_matching_configs returns complete configs.
Warning
Deprecated. Use
isinstance(config, CanvasConfig)
.Return type: bool Returns: True if the config is complete and can create a context.
-
match
(canvas)¶ Return a list of matching complete configs for the given canvas.
New in version 1.2.
Parameters: canvas (Canvas) – Display to host contexts created from the config. Return type: list of CanvasConfig
-
requires_gl_3
()¶
-
debug
= None¶
-
forward_compatible
= None¶
-
major_version
= None¶
-
minor_version
= None¶
-
class
CanvasConfig
(canvas, base_config)¶ Bases:
pyglet.gl.base.Config
OpenGL configuration for a particular canvas.
Use Config.match to obtain an instance of this class.
New in version 1.2.
Variables: canvas (Canvas) – The canvas this config is valid on. -
compatible
(canvas)¶
-
create_context
(share)¶ Create a GL context that satisifies this configuration.
Parameters: share (Context) – If not None, a context with which to share objects with. Return type: Context Returns: The new context.
-
is_complete
()¶ Determine if this config is complete and able to create a context.
Configs created directly are not complete, they can only serve as templates for retrieving a supported config from the system. For example, pyglet.window.Screen.get_matching_configs returns complete configs.
Warning
Deprecated. Use
isinstance(config, CanvasConfig)
.Return type: bool Returns: True if the config is complete and can create a context.
-
-
class
Context
(config, context_share=None)¶ OpenGL context for drawing.
Use CanvasConfig.create_context to create a context.
Variables: object_space (ObjectSpace) – An object which is shared between all contexts that share GL objects. -
attach
(canvas)¶
-
delete_buffer
(buffer_id)¶ Safely delete a buffer object belonging to this context.
This method behaves similarly to
delete_texture()
, though forglDeleteBuffers
instead ofglDeleteTextures
.Parameters: buffer_id (int) – The OpenGL name of the buffer to delete. New in version 1.1.
-
delete_texture
(texture_id)¶ Safely delete a texture belonging to this context.
Usually, the texture is released immediately using
glDeleteTextures
, however if another context that does not share this context’s object space is currently active, the deletion will be deferred until an appropriate context is activated.Parameters: texture_id (int) – The OpenGL name of the texture to delete.
-
destroy
()¶ Release the context.
The context will not be useable after being destroyed. Each platform has its own convention for releasing the context and the buffer(s) that depend on it in the correct order; this should never be called by an application.
-
detach
()¶
-
get_info
()¶ Get the OpenGL information for this context.
New in version 1.2.
Return type: GLInfo
-
set_current
()¶
-
CONTEXT_SHARE_EXISTING
= 1¶ Context share behaviour indicating that objects are shared with the most recently created context (the default).
-
CONTEXT_SHARE_NONE
= None¶ Context share behaviour indicating that objects should not be shared with existing contexts.
-
pyglet.graphics¶
Submodules
pyglet.graphics.allocation¶
Memory allocation algorithm for vertex arrays and buffers.
The region allocator is used to allocate vertex indices within a vertex
domain’s multiple buffers. (“Buffer” refers to any abstract buffer presented
by pyglet.graphics.vertexbuffer
.
The allocator will at times request more space from the buffers. The current policy is to double the buffer size when there is not enough room to fulfil an allocation. The buffer is never resized smaller.
The allocator maintains references to free space only; it is the caller’s responsibility to maintain the allocated regions.
-
exception
AllocatorMemoryException
(requested_capacity)¶ The buffer is not large enough to fulfil an allocation.
Raised by Allocator methods when the operation failed due to lack of buffer space. The buffer should be increased to at least requested_capacity and then the operation retried (guaranteed to pass second time).
-
class
Allocator
(capacity)¶ Buffer space allocation implementation.
-
alloc
(size)¶ Allocate memory in the buffer.
Raises AllocatorMemoryException if the allocation cannot be fulfilled.
Parameters: size (int) – Size of region to allocate. Return type: int Returns: Starting index of the allocated region.
-
dealloc
(start, size)¶ Free a region of the buffer.
Parameters: - start (int) – Starting index of the region.
- size (int) – Size of the region.
-
get_allocated_regions
()¶ Get a list of (aggregate) allocated regions.
The result of this method is
(starts, sizes)
, wherestarts
is a list of starting indices of the regions andsizes
their corresponding lengths.Return type: (list, list)
-
get_fragmentation
()¶ Return fraction of free space that is not expandable.
Return type: float
-
get_fragmented_free_size
()¶ Returns the amount of space unused, not including the final free block.
Return type: int
-
get_free_size
()¶ Return the amount of space unused.
Return type: int
-
get_usage
()¶ Return fraction of capacity currently allocated.
Return type: float
-
realloc
(start, size, new_size)¶ Reallocate a region of the buffer.
This is more efficient than separate dealloc and alloc calls, as the region can often be resized in-place.
Raises AllocatorMemoryException if the allocation cannot be fulfilled.
Parameters: - start (int) – Current starting index of the region.
- size (int) – Current size of the region.
- new_size (int) – New size of the region.
-
set_capacity
(size)¶ Resize the maximum buffer size.
The capaity cannot be reduced.
Parameters: size (int) – New maximum size of the buffer.
-
capacity
¶
-
sizes
¶
-
starts
¶
-
pyglet.graphics.vertexattribute¶
Access byte arrays as arrays of vertex attributes.
Use create_attribute()
to create an attribute accessor given a
simple format string. Alternatively, the classes may be constructed directly.
Attribute format strings¶
An attribute format string specifies the format of a vertex attribute. Format
strings are accepted by the create_attribute()
function as well as most
methods in the pyglet.graphics
module.
Format strings have the following (BNF) syntax:
attribute ::= ( name | index 'g' 'n'? | texture 't' ) count type
name
describes the vertex attribute, and is one of the following
constants for the predefined attributes:
c
- Vertex color
e
- Edge flag
f
- Fog coordinate
n
- Normal vector
s
- Secondary color
t
- Texture coordinate
v
- Vertex coordinate
You can alternatively create a generic indexed vertex attribute by
specifying its index in decimal followed by the constant g
. For
example, 0g
specifies the generic vertex attribute with index 0.
If the optional constant n
is present after the g
, the
attribute is normalised to the range [0, 1]
or [-1, 1]
within
the range of the data type.
Texture coordinates for multiple texture units can be specified with the
texture number before the constant ‘t’. For example, 1t
gives the
texture coordinate attribute for texture unit 1.
count
gives the number of data components in the attribute. For
example, a 3D vertex position has a count of 3. Some attributes
constrain the possible counts that can be used; for example, a normal
vector must have a count of 3.
type
gives the data type of each component of the attribute. The
following types can be used:
b
GLbyte
B
GLubyte
s
GLshort
S
GLushort
i
GLint
I
GLuint
f
GLfloat
d
GLdouble
Some attributes constrain the possible data types; for example,
normal vectors must use one of the signed data types. The use of
some data types, while not illegal, may have severe performance
concerns. For example, the use of GLdouble
is discouraged,
and colours should be specified with GLubyte
.
Whitespace is prohibited within the format string.
Some examples follow:
v3f
- 3-float vertex position
c4b
- 4-byte colour
1eb
- Edge flag
0g3f
- 3-float generic vertex attribute 0
1gn1i
- Integer generic vertex attribute 1, normalized to [-1, 1]
2gn4B
- 4-byte generic vertex attribute 2, normalized to [0, 1] (because the type is unsigned)
3t2f
- 2-float texture coordinate for texture unit 3.
-
class
AbstractAttribute
(count, gl_type)¶ Abstract accessor for an attribute in a mapped buffer.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
get_region
(buffer, start, count)¶ Map a buffer region using this attribute as an accessor.
The returned region can be modified as if the buffer was a contiguous array of this attribute (though it may actually be interleaved or otherwise non-contiguous).
The returned region consists of a contiguous array of component data elements. For example, if this attribute uses 3 floats per vertex, and the count parameter is 4, the number of floats mapped will be
3 * 4 = 12
.Parameters: - buffer (AbstractMappable) – The buffer to map.
- start (int) – Offset of the first vertex to map.
- count (int) – Number of vertices to map
Return type: AbstractBufferRegion
-
set_pointer
(offset)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
set_region
(buffer, start, count, data)¶ Set the data over a region of the buffer.
Parameters: - buffer (AbstractMappable) – The buffer to modify.
- start (int) – Offset of the first vertex to set.
- count (int) – Number of vertices to set.
- data (sequence) – Sequence of data components.
-
-
class
ColorAttribute
(count, gl_type)¶ Color vertex attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'colors'¶
-
-
class
EdgeFlagAttribute
(gl_type)¶ Edge flag attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'edge_flags'¶
-
-
class
FogCoordAttribute
(count, gl_type)¶ Fog coordinate attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'fog_coords'¶
-
-
class
GenericAttribute
(index, normalized, count, gl_type)¶ Generic vertex attribute, used by shader programs.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
-
class
MultiTexCoordAttribute
(texture, count, gl_type)¶ Texture coordinate attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
-
class
NormalAttribute
(gl_type)¶ Normal vector attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'normals'¶
-
-
class
SecondaryColorAttribute
(gl_type)¶ Secondary color attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'secondary_colors'¶
-
-
class
TexCoordAttribute
(count, gl_type)¶ Texture coordinate attribute.
-
convert_to_multi_tex_coord_attribute
()¶ Changes the class of the attribute to MultiTexCoordAttribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'tex_coords'¶
-
-
class
VertexAttribute
(count, gl_type)¶ Vertex coordinate attribute.
-
enable
()¶ Enable the attribute using
glEnableClientState
.
-
set_pointer
(pointer)¶ Setup this attribute to point to the currently bound buffer at the given offset.
offset
should be based on the currently bound buffer’sptr
member.Parameters: offset (int) – Pointer offset to the currently bound buffer for this attribute.
-
plural
= 'vertices'¶
-
-
create_attribute
(format)¶ Create a vertex attribute description from a format string.
The initial stride and offset of the attribute will be 0.
Parameters: format (str) – Attribute format string. See the module summary for details. Return type: AbstractAttribute
-
interleave_attributes
(attributes)¶ Interleave attribute offsets.
Adjusts the offsets and strides of the given attributes so that they are interleaved. Alignment constraints are respected.
Parameters: attributes (sequence of AbstractAttribute) – Attributes to interleave in-place.
-
serialize_attributes
(count, attributes)¶ Serialize attribute offsets.
Adjust the offsets of the given attributes so that they are packed serially against each other for count vertices.
Parameters: - count (int) – Number of vertices.
- attributes (sequence of AbstractAttribute) – Attributes to serialize in-place.
pyglet.graphics.vertexbuffer¶
Byte abstractions of Vertex Buffer Objects and vertex arrays.
Use create_buffer()
or create_mappable_buffer()
to create a
Vertex Buffer Object, or a vertex array if VBOs are not supported by the
current context.
Buffers can optionally be created “mappable” (incorporating the
AbstractMappable
mix-in). In this case the buffer provides a
get_region()
method which provides the most
efficient path for updating partial data within the buffer.
-
class
AbstractBuffer
¶ Abstract buffer of byte data.
Variables: -
bind
()¶ Bind this buffer to its OpenGL target.
-
delete
()¶ Delete this buffer, reducing system resource usage.
-
map
(invalidate=False)¶ Map the entire buffer into system memory.
The mapped region must be subsequently unmapped with unmap before performing any other operations on the buffer.
Parameters: invalidate (bool) – If True, the initial contents of the mapped block need not reflect the actual contents of the buffer. Return type: POINTER(ctypes.c_ubyte)
Returns: Pointer to the mapped block in memory
-
resize
(size)¶ Resize the buffer to a new size.
Parameters: size (int) – New size of the buffer, in bytes
-
set_data
(data)¶ Set the entire contents of the buffer.
Parameters: data (sequence of int or ctypes pointer) – The byte array to set.
-
set_data_region
(data, start, length)¶ Set part of the buffer contents.
Parameters: - data (sequence of int or ctypes pointer) – The byte array of data to set
- start (int) – Offset to start replacing data
- length (int) – Length of region to replace
-
unbind
()¶ Reset the buffer’s OpenGL target.
-
unmap
()¶ Unmap a previously mapped memory block.
-
ptr
= 0¶
-
size
= 0¶
-
-
class
AbstractBufferRegion
¶ A mapped region of a buffer.
Buffer regions are obtained using
get_region()
.Variables: array (ctypes array) – Array of data, of the type and count requested by get_region()
.-
invalidate
()¶ Mark this region as changed.
The buffer may not be updated with the latest contents of the array until this method is called. (However, it may not be updated until the next time the buffer is used, for efficiency).
-
-
class
AbstractMappable
¶ -
get_region
(start, size, ptr_type)¶ Map a region of the buffer into a ctypes array of the desired type. This region does not need to be unmapped, but will become invalid if the buffer is resized.
Note that although a pointer type is required, an array is mapped. For example:
get_region(0, ctypes.sizeof(c_int) * 20, ctypes.POINTER(c_int * 20))
will map bytes 0 to 80 of the buffer to an array of 20 ints.
Changes to the array may not be recognised until the region’s
AbstractBufferRegion.invalidate()
method is called.Parameters: - start (int) – Offset into the buffer to map from, in bytes
- size (int) – Size of the buffer region to map, in bytes
- ptr_type (ctypes pointer type) – Pointer type describing the array format to create
Return type:
-
-
class
IndirectArrayRegion
(region, size, component_count, component_stride)¶ A mapped region in which data elements are not necessarily contiguous.
This region class is used to wrap buffer regions in which the data must be accessed with some stride. For example, in an interleaved buffer this region can be used to access a single interleaved component as if the data was contiguous.
-
invalidate
()¶ Mark this region as changed.
The buffer may not be updated with the latest contents of the array until this method is called. (However, it may not be updated until the next time the buffer is used, for efficiency).
-
-
class
MappableVertexBufferObject
(size, target, usage)¶ A VBO with system-memory backed store.
Updates to the data via
set_data()
,set_data_region()
andmap()
will be held in local memory untilbind()
is called. The advantage is that fewer OpenGL calls are needed, increasing performance.There may also be less performance penalty for resizing this buffer.
Updates to data via
map()
are committed immediately.-
bind
()¶ Bind this buffer to its OpenGL target.
-
get_region
(start, size, ptr_type)¶ Map a region of the buffer into a ctypes array of the desired type. This region does not need to be unmapped, but will become invalid if the buffer is resized.
Note that although a pointer type is required, an array is mapped. For example:
get_region(0, ctypes.sizeof(c_int) * 20, ctypes.POINTER(c_int * 20))
will map bytes 0 to 80 of the buffer to an array of 20 ints.
Changes to the array may not be recognised until the region’s
AbstractBufferRegion.invalidate()
method is called.Parameters: - start (int) – Offset into the buffer to map from, in bytes
- size (int) – Size of the buffer region to map, in bytes
- ptr_type (ctypes pointer type) – Pointer type describing the array format to create
Return type:
-
map
(invalidate=False)¶ Map the entire buffer into system memory.
The mapped region must be subsequently unmapped with unmap before performing any other operations on the buffer.
Parameters: invalidate (bool) – If True, the initial contents of the mapped block need not reflect the actual contents of the buffer. Return type: POINTER(ctypes.c_ubyte)
Returns: Pointer to the mapped block in memory
-
resize
(size)¶ Resize the buffer to a new size.
Parameters: size (int) – New size of the buffer, in bytes
-
set_data
(data)¶ Set the entire contents of the buffer.
Parameters: data (sequence of int or ctypes pointer) – The byte array to set.
-
set_data_region
(data, start, length)¶ Set part of the buffer contents.
Parameters: - data (sequence of int or ctypes pointer) – The byte array of data to set
- start (int) – Offset to start replacing data
- length (int) – Length of region to replace
-
unmap
()¶ Unmap a previously mapped memory block.
-
-
class
VertexArray
(size)¶ A ctypes implementation of a vertex array.
Many of the methods on this class are effectively no-op’s, such as
bind()
,unbind()
,map()
,unmap()
anddelete()
; they exist in order to present a consistent interface withVertexBufferObject
.This buffer type is also mappable, and so
get_region()
can be used.-
bind
()¶ Bind this buffer to its OpenGL target.
-
delete
()¶ Delete this buffer, reducing system resource usage.
-
get_region
(start, size, ptr_type)¶ Map a region of the buffer into a ctypes array of the desired type. This region does not need to be unmapped, but will become invalid if the buffer is resized.
Note that although a pointer type is required, an array is mapped. For example:
get_region(0, ctypes.sizeof(c_int) * 20, ctypes.POINTER(c_int * 20))
will map bytes 0 to 80 of the buffer to an array of 20 ints.
Changes to the array may not be recognised until the region’s
AbstractBufferRegion.invalidate()
method is called.Parameters: - start (int) – Offset into the buffer to map from, in bytes
- size (int) – Size of the buffer region to map, in bytes
- ptr_type (ctypes pointer type) – Pointer type describing the array format to create
Return type:
-
map
(invalidate=False)¶ Map the entire buffer into system memory.
The mapped region must be subsequently unmapped with unmap before performing any other operations on the buffer.
Parameters: invalidate (bool) – If True, the initial contents of the mapped block need not reflect the actual contents of the buffer. Return type: POINTER(ctypes.c_ubyte)
Returns: Pointer to the mapped block in memory
-
resize
(size)¶ Resize the buffer to a new size.
Parameters: size (int) – New size of the buffer, in bytes
-
set_data
(data)¶ Set the entire contents of the buffer.
Parameters: data (sequence of int or ctypes pointer) – The byte array to set.
-
set_data_region
(data, start, length)¶ Set part of the buffer contents.
Parameters: - data (sequence of int or ctypes pointer) – The byte array of data to set
- start (int) – Offset to start replacing data
- length (int) – Length of region to replace
-
unbind
()¶ Reset the buffer’s OpenGL target.
-
unmap
()¶ Unmap a previously mapped memory block.
-
-
class
VertexArrayRegion
(array)¶ A mapped region of a vertex array.
The
invalidate()
method is a no-op but is provided in order to present a consistent interface withVertexBufferObjectRegion()
.
-
class
VertexBufferObject
(size, target, usage)¶ Lightweight representation of an OpenGL VBO.
The data in the buffer is not replicated in any system memory (unless it is done so by the video driver). While this can improve memory usage and possibly performance, updates to the buffer are relatively slow.
This class does not implement
AbstractMappable
, and so has noget_region()
method. SeeMappableVertexBufferObject
for a VBO class that does implementget_region()
.-
bind
()¶ Bind this buffer to its OpenGL target.
-
delete
()¶ Delete this buffer, reducing system resource usage.
-
map
(invalidate=False)¶ Map the entire buffer into system memory.
The mapped region must be subsequently unmapped with unmap before performing any other operations on the buffer.
Parameters: invalidate (bool) – If True, the initial contents of the mapped block need not reflect the actual contents of the buffer. Return type: POINTER(ctypes.c_ubyte)
Returns: Pointer to the mapped block in memory
-
resize
(size)¶ Resize the buffer to a new size.
Parameters: size (int) – New size of the buffer, in bytes
-
set_data
(data)¶ Set the entire contents of the buffer.
Parameters: data (sequence of int or ctypes pointer) – The byte array to set.
-
set_data_region
(data, start, length)¶ Set part of the buffer contents.
Parameters: - data (sequence of int or ctypes pointer) – The byte array of data to set
- start (int) – Offset to start replacing data
- length (int) – Length of region to replace
-
unbind
()¶ Reset the buffer’s OpenGL target.
-
unmap
()¶ Unmap a previously mapped memory block.
-
-
class
VertexBufferObjectRegion
(buffer, start, end, array)¶ A mapped region of a VBO.
-
invalidate
()¶ Mark this region as changed.
The buffer may not be updated with the latest contents of the array until this method is called. (However, it may not be updated until the next time the buffer is used, for efficiency).
-
-
create_buffer
(size, target=34962, usage=35048, vbo=True)¶ Create a buffer of vertex data.
Parameters: - size (int) – Size of the buffer, in bytes
- target (int) – OpenGL target buffer
- usage (int) – OpenGL usage constant
- vbo (bool) – True if a VertexBufferObject should be created if the driver supports it; otherwise only a VertexArray is created.
Return type: AbstractBuffer
-
create_mappable_buffer
(size, target=34962, usage=35048, vbo=True)¶ Create a mappable buffer of vertex data.
Parameters: - size (int) – Size of the buffer, in bytes
- target (int) – OpenGL target buffer
- usage (int) – OpenGL usage constant
- vbo (bool) – True if a
VertexBufferObject
should be created if the driver supports it; otherwise only aVertexArray
is created.
Return type:
pyglet.graphics.vertexdomain¶
Manage related vertex attributes within a single vertex domain.
A vertex “domain” consists of a set of attribute descriptions that together describe the layout of one or more vertex buffers which are used together to specify the vertices in a primitive. Additionally, the domain manages the buffers used to store the data and will resize them as necessary to accommodate new vertices.
Domains can optionally be indexed, in which case they also manage a buffer containing vertex indices. This buffer is grown separately and has no size relation to the attribute buffers.
Applications can create vertices (and optionally, indices) within a domain
with the VertexDomain.create()
method. This returns a
VertexList
representing the list of vertices created. The vertex
attribute data within the group can be modified, and the changes will be made
to the underlying buffers automatically.
The entire domain can be efficiently drawn in one step with the
VertexDomain.draw()
method, assuming all the vertices comprise
primitives of the same OpenGL primitive mode.
-
class
IndexedVertexDomain
(attribute_usages, index_gl_type=5125)¶ Management of a set of indexed vertex lists.
Construction of an indexed vertex domain is usually done with the create_indexed_domain function.
-
create
(count, index_count)¶ Create an
IndexedVertexList
in this domain.Parameters: - count (int) – Number of vertices to create
- index_count – Number of indices to create
-
draw
(mode, vertex_list=None)¶ Draw vertices in the domain.
If vertex_list is not specified, all vertices in the domain are drawn. This is the most efficient way to render primitives.
If vertex_list specifies a
VertexList
, only primitives in that list will be drawn.Parameters: - mode (int) – OpenGL drawing mode, e.g.
GL_POINTS
,GL_LINES
, etc. - vertex_list (IndexedVertexList) – Vertex list to draw, or
None
for all lists in this domain.
- mode (int) – OpenGL drawing mode, e.g.
-
get_index_region
(start, count)¶ Get a region of the index buffer.
Parameters: - start (int) – Start of the region to map.
- count (int) – Number of indices to map.
Return type: Array of int
-
-
class
IndexedVertexList
(domain, start, count, index_start, index_count)¶ A list of vertices within an
IndexedVertexDomain
that are indexed. UseIndexedVertexDomain.create()
to construct this list.-
delete
()¶ Delete this group.
-
draw
(mode)¶ Draw this vertex list in the given OpenGL mode.
Parameters: mode (int) – OpenGL drawing mode, e.g. GL_POINTS
,GL_LINES
, etc.
-
migrate
(domain)¶ Move this group from its current indexed domain and add to the specified one. Attributes on domains must match. (In practice, used to change parent state of some vertices).
Parameters: domain (IndexedVertexDomain) – Indexed domain to migrate this vertex list to.
-
resize
(count, index_count)¶ Resize this group.
Parameters: - count (int) – New number of vertices in the list.
- index_count (int) – New number of indices in the list.
-
indices
¶ Array of index data.
-
-
class
VertexDomain
(attribute_usages)¶ Management of a set of vertex lists.
Construction of a vertex domain is usually done with the
create_domain()
function.-
create
(count)¶ Create a
VertexList
in this domain.Parameters: count (int) – Number of vertices to create. Return type: VertexList
-
draw
(mode, vertex_list=None)¶ Draw vertices in the domain.
If vertex_list is not specified, all vertices in the domain are drawn. This is the most efficient way to render primitives.
If vertex_list specifies a
VertexList
, only primitives in that list will be drawn.Parameters: - mode (int) – OpenGL drawing mode, e.g.
GL_POINTS
,GL_LINES
, etc. - vertex_list (VertexList) – Vertex list to draw, or
None
for all lists in this domain.
- mode (int) – OpenGL drawing mode, e.g.
-
-
class
VertexList
(domain, start, count)¶ A list of vertices within a
VertexDomain
. UseVertexDomain.create()
to construct this list.-
delete
()¶ Delete this group.
-
draw
(mode)¶ Draw this vertex list in the given OpenGL mode.
Parameters: mode (int) – OpenGL drawing mode, e.g. GL_POINTS
,GL_LINES
, etc.
-
get_domain
()¶ Get the domain this vertex list belongs to.
Return type: VertexDomain
-
get_size
()¶ Get the number of vertices in the list.
Return type: int
-
migrate
(domain)¶ Move this group from its current domain and add to the specified one. Attributes on domains must match. (In practice, used to change parent state of some vertices).
Parameters: domain (VertexDomain) – Domain to migrate this vertex list to.
-
resize
(count)¶ Resize this group.
Parameters: count (int) – New number of vertices in the list.
-
colors
¶ Array of color data.
-
edge_flags
¶ Array of edge flag data.
-
fog_coords
¶ Array of fog coordinate data.
-
multi_tex_coords
¶ Multi-array texture coordinate data.
-
normals
¶ Array of normal vector data.
-
secondary_colors
¶ Array of secondary color data.
-
tex_coords
¶ Array of texture coordinate data.
-
vertices
¶ Array of vertex coordinate data.
-
-
create_attribute_usage
(fmt)¶ Create an attribute and usage pair from a format string. The format string is as documented in pyglet.graphics.vertexattribute, with the addition of an optional usage component:
usage ::= attribute ( '/' ('static' | 'dynamic' | 'stream' | 'none') )?
If the usage is not given it defaults to ‘dynamic’. The usage corresponds to the OpenGL VBO usage hint, and for
static
also indicates a preference for interleaved arrays. Ifnone
is specified a buffer object is not created, and vertex data is stored in system memory.Some examples:
v3f/stream
- 3D vertex position using floats, for stream usage
c4b/static
- 4-byte color attribute, for static usage
Returns: attribute, usage
-
create_domain
(*attribute_usage_formats)¶ Create a vertex domain covering the given attribute usage formats. See documentation for
create_attribute_usage()
andpyglet.graphics.vertexattribute.create_attribute()
for the grammar of these format strings.Return type: VertexDomain
-
create_indexed_domain
(*attribute_usage_formats)¶ Create an indexed vertex domain covering the given attribute usage formats. See documentation for
create_attribute_usage
andpyglet.graphics.vertexattribute.create_attribute()
for the grammar of these format strings.Return type: VertexDomain
Details
Low-level graphics rendering.
This module provides an efficient low-level abstraction over OpenGL. It gives very good performance for rendering OpenGL primitives; far better than the typical immediate-mode usage and, on modern graphics cards, better than using display lists in many cases. The module is used internally by other areas of pyglet.
See the Graphics for details on how to use this graphics API.
Batches and groups¶
Without even needing to understand the details on how to draw primitives with
the graphics API, developers can make use of Batch
and Group
objects to improve performance of sprite and text rendering.
The Sprite
, Label()
and TextLayout()
classes all accept a batch
and
group
parameter in their constructors. A batch manages a set of objects
that will be drawn all at once, and a group describes the manner in which an
object is drawn.
The following example creates a batch, adds two sprites to the batch, and then draws the entire batch:
batch = pyglet.graphics.Batch()
car = pyglet.sprite.Sprite(car_image, batch=batch)
boat = pyglet.sprite.Sprite(boat_image, batch=batch)
def on_draw()
batch.draw()
Drawing a complete batch is much faster than drawing the items in the batch individually, especially when those items belong to a common group.
Groups describe the OpenGL state required for an item. This is for the most part managed by the sprite and text classes, however you can also use groups to ensure items are drawn in a particular order. For example, the following example adds a background sprite which is guaranteed to be drawn before the car and the boat:
batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
foreground = pyglet.graphics.OrderedGroup(1)
background = pyglet.sprite.Sprite(background_image,
batch=batch, group=background)
car = pyglet.sprite.Sprite(car_image, batch=batch, group=foreground)
boat = pyglet.sprite.Sprite(boat_image, batch=batch, group=foreground)
def on_draw()
batch.draw()
It’s preferable to manage sprites and text objects within as few batches as possible. If the drawing of sprites or text objects need to be interleaved with other drawing that does not use the graphics API, multiple batches will be required.
Data item parameters¶
Many of the functions and methods in this module accept any number of data
parameters as their final parameters. In the documentation these are notated
as *data
in the formal parameter list.
A data parameter describes a vertex attribute format and an optional sequence to initialise that attribute. Examples of common attribute formats are:
"v3f"
- Vertex position, specified as three floats.
"c4B"
- Vertex color, specified as four unsigned bytes.
"t2f"
- Texture coordinate, specified as two floats.
See pyglet.graphics.vertexattribute for the complete syntax of the vertex format string.
When no initial data is to be given, the data item is just the format string. For example, the following creates a 2 element vertex list with position and color attributes:
vertex_list = pyglet.graphics.vertex_list(2, 'v2f', 'c4B')
When initial data is required, wrap the format string and the initial data in a tuple, for example:
vertex_list = pyglet.graphics.vertex_list(2,
('v2f', (0.0, 1.0, 1.0, 0.0)),
('c4B', (255, 255, 255, 255) * 2))
Drawing modes¶
Methods in this module that accept a mode
parameter will accept any value
in the OpenGL drawing mode enumeration: GL_POINTS
, GL_LINE_STRIP
,
GL_LINE_LOOP
, GL_LINES
, GL_TRIANGLE_STRIP
, GL_TRIANGLE_FAN
,
GL_TRIANGLES
, GL_QUAD_STRIP
, GL_QUADS
, and GL_POLYGON
.
pyglet.graphics.draw(1, GL_POINTS, ('v2i',(10,20)))
However, because of the way the graphics API renders multiple primitives with
shared state, GL_POLYGON
, GL_LINE_LOOP
and GL_TRIANGLE_FAN
cannot
be used — the results are undefined.
When using GL_LINE_STRIP
, GL_TRIANGLE_STRIP
or GL_QUAD_STRIP
care
must be taken to insert degenerate vertices at the beginning and end of each
vertex list. For example, given the vertex list:
A, B, C, D
the correct vertex list to provide the vertex list is:
A, A, B, C, D, D
Alternatively, the NV_primitive_restart
extension can be used if it is
present. This also permits use of GL_POLYGON
, GL_LINE_LOOP
and
GL_TRIANGLE_FAN
. Unfortunately the extension is not provided by older
video drivers, and requires indexed vertex lists.
New in version 1.1.
-
class
Batch
¶ Manage a collection of vertex lists for batched rendering.
Vertex lists are added to a
Batch
using the add and add_indexed methods. An optional group can be specified along with the vertex list, which gives the OpenGL state required for its rendering. Vertex lists with shared mode and group are allocated into adjacent areas of memory and sent to the graphics card in a single operation.Call VertexList.delete to remove a vertex list from the batch.
-
add
(count, mode, group, *data)¶ Add a vertex list to the batch.
Parameters: - count (int) – The number of vertices in the list.
- mode (int) – OpenGL drawing mode enumeration; for example, one of
GL_POINTS
,GL_LINES
,GL_TRIANGLES
, etc. See the module summary for additional information. - group (Group) – Group of the vertex list, or
None
if no group is required. - data (data items) – Attribute formats and initial data for the vertex list. See the module summary for details.
Return type:
-
add_indexed
(count, mode, group, indices, *data)¶ Add an indexed vertex list to the batch.
Parameters: - count (int) – The number of vertices in the list.
- mode (int) – OpenGL drawing mode enumeration; for example, one of
GL_POINTS
,GL_LINES
,GL_TRIANGLES
, etc. See the module summary for additional information. - group (Group) – Group of the vertex list, or
None
if no group is required. - indices (sequence) – Sequence of integers giving indices into the vertex list.
- data (data items) – Attribute formats and initial data for the vertex list. See the module summary for details.
Return type: IndexedVertexList
-
draw
()¶ Draw the batch.
-
draw_subset
(vertex_lists)¶ Draw only some vertex lists in the batch.
The use of this method is highly discouraged, as it is quite inefficient. Usually an application can be redesigned so that batches can always be drawn in their entirety, using draw.
The given vertex lists must belong to this batch; behaviour is undefined if this condition is not met.
Parameters: vertex_lists (sequence of VertexList or IndexedVertexList) – Vertex lists to draw.
-
invalidate
()¶ Force the batch to update the draw list.
This method can be used to force the batch to re-compute the draw list when the ordering of groups has changed.
New in version 1.2.
-
migrate
(vertex_list, mode, group, batch)¶ Migrate a vertex list to another batch and/or group.
vertex_list and mode together identify the vertex list to migrate. group and batch are new owners of the vertex list after migration.
The results are undefined if mode is not correct or if vertex_list does not belong to this batch (they are not checked and will not necessarily throw an exception immediately).
batch can remain unchanged if only a group change is desired.
Parameters: - vertex_list (VertexList) – A vertex list currently belonging to this batch.
- mode (int) – The current GL drawing mode of the vertex list.
- group (Group) – The new group to migrate to.
- batch (Batch) – The batch to migrate to (or the current batch).
-
-
class
Group
(parent=None)¶ Group of common OpenGL state.
Before a vertex list is rendered, its group’s OpenGL state is set; as are that state’s ancestors’ states. This can be defined arbitrarily on subclasses; the default state change has no effect, and groups vertex lists only in the order in which they are drawn.
-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
set_state_recursive
()¶ Set this group and its ancestry.
Call this method if you are using a group in isolation: the parent groups will be called in top-down order, with this class’s set being called last.
-
unset_state
()¶ Repeal the OpenGL state change.
The default implementation does nothing.
-
unset_state_recursive
()¶ Unset this group and its ancestry.
The inverse of set_state_recursive.
-
batches
¶
-
visible
¶
-
-
class
NullGroup
(parent=None)¶ The default group class used when
None
is given to a batch.This implementation has no effect.
-
class
OrderedGroup
(order, parent=None)¶ A group with partial order.
Ordered groups with a common parent are rendered in ascending order of their
order
field. This is a useful way to render multiple layers of a scene within a single batch.
-
class
TextureGroup
(texture, parent=None)¶ A group that enables and binds a texture.
Texture groups are equal if their textures’ targets and names are equal.
-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
unset_state
()¶ Repeal the OpenGL state change.
The default implementation does nothing.
-
-
draw
(size, mode, *data)¶ Draw a primitive immediately.
Parameters: - size (int) – Number of vertices given
- mode (gl primitive type) – OpenGL drawing mode, e.g.
GL_TRIANGLES
, avoiding quotes. - data (data items) – Attribute formats and data. See the module summary for details.
-
draw_indexed
(size, mode, indices, *data)¶ Draw a primitive with indexed vertices immediately.
Parameters: - size (int) – Number of vertices given
- mode (int) – OpenGL drawing mode, e.g.
GL_TRIANGLES
- indices (sequence of int) – Sequence of integers giving indices into the vertex list.
- data (data items) – Attribute formats and data. See the module summary for details.
-
vertex_list
(count, *data)¶ Create a
VertexList
not associated with a batch, group or mode.Parameters: - count (int) – The number of vertices in the list.
- data (data items) – Attribute formats and initial data for the vertex list. See the module summary for details.
Return type:
-
vertex_list_indexed
(count, indices, *data)¶ Create an IndexedVertexList not associated with a batch, group or mode.
Parameters: - count (int) – The number of vertices in the list.
- indices (sequence) – Sequence of integers giving indices into the vertex list.
- data (data items) – Attribute formats and initial data for the vertex list. See the module summary for details.
Return type: IndexedVertexList
pyglet.gui¶
Classes¶
-
class
WidgetBase
(x, y, width, height)¶ Attributes
-
x
¶ X coordinate of the widget.
Type: int
-
y
¶ Y coordinate of the widget.
Type: int
-
width
¶ Width of the widget.
Type: int
-
height
¶ Height of the widget.
Type: int
-
aabb
¶ Bounding box of the widget.
Expresesed as (x, y, x + width, y + height)
Type: (int, int, int, int)
-
-
class
PushButton
(x, y, pressed, depressed, hover=None, batch=None, group=None)¶ Bases:
pyglet.gui.widgets.WidgetBase
Instance of a push button.
Triggers the event ‘on_press’ when it is clicked by the mouse. Triggers the event ‘on_release’ when the mouse is released.
-
on_mouse_drag
(x, y, dx, dy, buttons, modifiers)¶
-
on_mouse_motion
(x, y, dx, dy)¶
-
on_mouse_press
(x, y, buttons, modifiers)¶
-
on_mouse_release
(x, y, buttons, modifiers)¶
-
update_groups
(order)¶
-
event_types
= ['on_press', 'on_release', 'on_toggle']¶
-
value
¶ Query or set the Widget’s value.
This property allows you to set the value of a Widget directly, without any user input. This could be used, for example, to restore Widgets to a previous state, or if some event in your program is meant to naturally change the same value that the Widget controls. Note that events are not dispatched when changing this property.
-
-
class
ToggleButton
(x, y, pressed, depressed, hover=None, batch=None, group=None)¶ Bases:
pyglet.gui.widgets.PushButton
Instance of a toggle button.
Triggers the event ‘on_toggle’ when the mouse is pressed or released.
-
on_mouse_press
(x, y, buttons, modifiers)¶
-
on_mouse_release
(x, y, buttons, modifiers)¶
-
-
class
Slider
(x, y, base, knob, edge=0, batch=None, group=None)¶ Bases:
pyglet.gui.widgets.WidgetBase
Instance of a slider made of a base and a knob image.
Triggers the event ‘on_change’ when the knob position is changed. The knob position can be changed by dragging with the mouse, or scrolling the mouse wheel.
-
on_mouse_drag
(x, y, dx, dy, buttons, modifiers)¶
-
on_mouse_press
(x, y, buttons, modifiers)¶
-
on_mouse_release
(x, y, buttons, modifiers)¶
-
on_mouse_scroll
(x, y, mouse, direction)¶
-
update_groups
(order)¶
-
event_types
= ['on_change']¶
-
value
¶ Query or set the Widget’s value.
This property allows you to set the value of a Widget directly, without any user input. This could be used, for example, to restore Widgets to a previous state, or if some event in your program is meant to naturally change the same value that the Widget controls. Note that events are not dispatched when changing this property.
-
-
class
TextEntry
(text, x, y, width, color=(255, 255, 255, 255), text_color=(0, 0, 0, 255), caret_color=(0, 0, 0), batch=None, group=None)¶ Bases:
pyglet.gui.widgets.WidgetBase
Instance of a text entry widget.
Allows the user to enter and submit text.
-
on_commit
(text)¶
-
on_mouse_drag
(x, y, dx, dy, buttons, modifiers)¶
-
on_mouse_motion
(x, y, dx, dy)¶
-
on_mouse_press
(x, y, buttons, modifiers)¶
-
on_text
(text)¶
-
on_text_motion
(motion)¶
-
on_text_motion_select
(motion)¶
-
update_groups
(order)¶
-
event_types
= ['on_commit']¶
-
value
¶ Query or set the Widget’s value.
This property allows you to set the value of a Widget directly, without any user input. This could be used, for example, to restore Widgets to a previous state, or if some event in your program is meant to naturally change the same value that the Widget controls. Note that events are not dispatched when changing this property.
-
pyglet.image¶
Submodules
pyglet.image.atlas¶
Group multiple small images into larger textures.
This module is used by pyglet.resource
to efficiently pack small
images into larger textures. TextureAtlas
maintains one texture;
TextureBin
manages a collection of atlases of a given size.
Example usage:
# Load images from disk
car_image = pyglet.image.load('car.png')
boat_image = pyglet.image.load('boat.png')
# Pack these images into one or more textures
bin = TextureBin()
car_texture = bin.add(car_image)
boat_texture = bin.add(boat_image)
The result of TextureBin.add()
is a TextureRegion
containing the image. Once added, an image cannot be removed from a bin (or an
atlas); nor can a list of images be obtained from a given bin or atlas – it is
the application’s responsibility to keep track of the regions returned by the
add
methods.
New in version 1.1.
-
exception
AllocatorException
¶ The allocator does not have sufficient free space for the requested image size.
-
class
Allocator
(width, height)¶ Rectangular area allocation algorithm.
Initialise with a given
width
andheight
, then repeatedly call alloc to retrieve free regions of the area and protect that area from future allocations.Allocator uses a fairly simple strips-based algorithm. It performs best when rectangles are allocated in decreasing height order.
-
alloc
(width, height)¶ Get a free area in the allocator of the given size.
After calling alloc, the requested area will no longer be used. If there is not enough room to fit the given area AllocatorException is raised.
Parameters: - width (int) – Width of the area to allocate.
- height (int) – Height of the area to allocate.
Return type: int, int
Returns: The X and Y coordinates of the bottom-left corner of the allocated region.
-
get_fragmentation
()¶ Get the fraction of area that’s unlikely to ever be used, based on current allocation behaviour.
This method is useful for debugging and profiling only.
Return type: float
-
get_usage
()¶ Get the fraction of area already allocated.
This method is useful for debugging and profiling only.
Return type: float
-
height
¶
-
strips
¶
-
used_area
¶
-
width
¶
-
-
class
TextureAtlas
(width=2048, height=2048)¶ Collection of images within a texture.
-
add
(img, border=0)¶ Add an image to the atlas.
This method will fail if the given image cannot be transferred directly to a texture (for example, if it is another texture).
ImageData
is the usual image type for this method.AllocatorException will be raised if there is no room in the atlas for the image.
Parameters: - img (AbstractImage) – The image to add.
- border (int) – Leaves specified pixels of blank space around each image added to the Atlas.
Return type: Returns: The region of the atlas containing the newly added image.
-
-
class
TextureBin
(texture_width=2048, texture_height=2048)¶ Collection of texture atlases.
TextureBin
maintains a collection of texture atlases, and creates new ones as necessary to accommodate images added to the bin.-
add
(img, border=0)¶ Add an image into this texture bin.
This method calls TextureAtlas.add for the first atlas that has room for the image.
AllocatorException is raised if the image exceeds the dimensions of
texture_width
andtexture_height
.Parameters: - img (AbstractImage) – The image to add.
- border (int) – Leaves specified pixels of blank space around each image added to the Atlas.
Return type: Returns: The region of an atlas containing the newly added image.
-
pyglet.image.animation¶
2D Animations
Animations can be used by the Sprite
class in place
of static images. They are essentially containers for individual image frames,
with a duration per frame. They can be infinitely looping, or stop at the last
frame. You can load Animations from disk, such as from GIF files:
ani = pyglet.resource.animation('walking.gif')
sprite = pyglet.sprite.Sprite(img=ani)
Alternatively, you can create your own Animations from a sequence of images
by using the from_image_sequence()
method:
images = [pyglet.resource.image('walk_a.png')
pyglet.resource.image('walk_b.png')
pyglet.resource.image('walk_c.png')]
ani = pyglet.image.Animation.from_image_sequence(images, duration=0.1, loop=True)
You can also use an pyglet.image.ImageGrid
, which is iterable:
sprite_sheet = pyglet.resource.image('my_sprite_sheet.png')
image_grid = pyglet.image.ImageGrid(sprite_sheet, rows=1, columns=5)
ani = pyglet.image.Animation.from_image_sequence(image_grid, duration=0.1)
In the above examples, all of the Animation Frames have the same duration.
If you wish to adjust this, you can manually create the Animation from a list of
AnimationFrame
:
image_a = pyglet.resource.image('walk_a.png')
image_b = pyglet.resource.image('walk_b.png')
image_c = pyglet.resource.image('walk_c.png')
frame_a = pyglet.image.AnimationFrame(image_a, duration=0.1)
frame_b = pyglet.image.AnimationFrame(image_b, duration=0.2)
frame_c = pyglet.image.AnimationFrame(image_c, duration=0.1)
ani = pyglet.image.Animation(frames=[frame_a, frame_b, frame_c])
-
class
Animation
(frames)¶ Sequence of images with timing information.
If no frames of the animation have a duration of
None
, the animation loops continuously; otherwise the animation stops at the first frame with duration ofNone
.Variables: frames (list of ~pyglet.image.AnimationFrame) – The frames that make up the animation. -
add_to_texture_bin
(texture_bin, border=0)¶ Add the images of the animation to a
TextureBin
.The animation frames are modified in-place to refer to the texture bin regions.
Parameters: - texture_bin (TextureBin) – Texture bin to upload animation frames into.
- border (int) – Leaves specified pixels of blank space around each image frame when adding to the TextureBin.
-
classmethod
from_image_sequence
(sequence, duration, loop=True)¶ Create an animation from a list of images and a constant framerate.
Parameters: - sequence (list of ~pyglet.image.AbstractImage) – Images that make up the animation, in sequence.
- duration (float) – Number of seconds to display each image.
- loop (bool) – If True, the animation will loop continuously.
Return type: Animation
-
get_duration
()¶ Get the total duration of the animation in seconds.
Return type: float
-
get_max_height
()¶ Get the maximum image frame height.
This method is useful for determining texture space requirements: due to the use of
anchor_y
the actual required playback area may be larger.Return type: int
-
get_max_width
()¶ Get the maximum image frame width.
This method is useful for determining texture space requirements: due to the use of
anchor_x
the actual required playback area may be larger.Return type: int
-
get_transform
(flip_x=False, flip_y=False, rotate=0)¶ Create a copy of this animation applying a simple transformation.
The transformation is applied around the image’s anchor point of each frame. The texture data is shared between the original animation and the transformed animation.
Parameters: - flip_x (bool) – If True, the returned animation will be flipped horizontally.
- flip_y (bool) – If True, the returned animation will be flipped vertically.
- rotate (int) – Degrees of clockwise rotation of the returned animation. Only 90-degree increments are supported.
Return type: Animation
-
Details
Image load, capture and high-level texture functions.
Only basic functionality is described here; for full reference see the accompanying documentation.
To load an image:
from pyglet import image
pic = image.load('picture.png')
The supported image file types include PNG, BMP, GIF, JPG, and many more, somewhat depending on the operating system. To load an image from a file-like object instead of a filename:
pic = image.load('hint.jpg', file=fileobj)
The hint helps the module locate an appropriate decoder to use based on the file extension. It is optional.
Once loaded, images can be used directly by most other modules of pyglet. All images have a width and height you can access:
width, height = pic.width, pic.height
You can extract a region of an image (this keeps the original image intact; the memory is shared efficiently):
subimage = pic.get_region(x, y, width, height)
Remember that y-coordinates are always increasing upwards.
Drawing images¶
To draw an image at some point on the screen:
pic.blit(x, y, z)
This assumes an appropriate view transform and projection have been applied.
Some images have an intrinsic “anchor point”: this is the point which will be
aligned to the x
and y
coordinates when the image is drawn. By
default the anchor point is the lower-left corner of the image. You can use
the anchor point to center an image at a given point, for example:
pic.anchor_x = pic.width // 2
pic.anchor_y = pic.height // 2
pic.blit(x, y, z)
Texture access¶
If you are using OpenGL directly, you can access the image as a texture:
texture = pic.get_texture()
(This is the most efficient way to obtain a texture; some images are immediately loaded as textures, whereas others go through an intermediate form). To use a texture with pyglet.gl:
from pyglet.gl import *
glEnable(texture.target) # typically target is GL_TEXTURE_2D
glBindTexture(texture.target, texture.id)
# ... draw with the texture
Pixel access¶
To access raw pixel data of an image:
rawimage = pic.get_image_data()
(If the image has just been loaded this will be a very quick operation; however if the image is a texture a relatively expensive readback operation will occur). The pixels can be accessed as a string:
format = 'RGBA'
pitch = rawimage.width * len(format)
pixels = rawimage.get_data(format, pitch)
“format” strings consist of characters that give the byte order of each color component. For example, if rawimage.format is ‘RGBA’, there are four color components: red, green, blue and alpha, in that order. Other common format strings are ‘RGB’, ‘LA’ (luminance, alpha) and ‘I’ (intensity).
The “pitch” of an image is the number of bytes in a row (this may validly be more than the number required to make up the width of the image, it is common to see this for word alignment). If “pitch” is negative the rows of the image are ordered from top to bottom, otherwise they are ordered from bottom to top.
Retrieving data with the format and pitch given in ImageData.format and ImageData.pitch avoids the need for data conversion (assuming you can make use of the data in this arbitrary format).
Classes¶
Images¶
-
class
AbstractImage
(width, height)¶ Abstract class representing an image.
Parameters: - width (int) – Width of image
- height (int) – Height of image
- anchor_x (int) – X coordinate of anchor, relative to left edge of image data
- anchor_y (int) – Y coordinate of anchor, relative to bottom edge of image data
-
blit
(x, y, z=0)¶ Draw this image to the active framebuffers.
The image will be drawn with the lower-left corner at (
x -
anchor_x,y -
anchor_y,z
).
-
blit_into
(source, x, y, z)¶ Draw source on this image.
source will be copied into this image such that its anchor point is aligned with the x and y parameters. If this image is a 3D texture, the z coordinate gives the image slice to copy into.
Note that if source is larger than this image (or the positioning would cause the copy to go out of bounds) then you must pass a region of source to this method, typically using get_region().
-
blit_to_texture
(target, level, x, y, z=0)¶ Draw this image on the currently bound texture at target.
This image is copied into the texture such that this image’s anchor point is aligned with the given x and y coordinates of the destination texture. If the currently bound texture is a 3D texture, the z coordinate gives the image slice to blit into.
-
get_image_data
()¶ Get an ImageData view of this image.
Changes to the returned instance may or may not be reflected in this image.
Return type: ImageData
New in version 1.1.
-
get_mipmapped_texture
()¶ Retrieve a
Texture
instance with all mipmap levels filled in.Requires that image dimensions be powers of 2.
Return type: Texture
New in version 1.1.
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
save
(filename=None, file=None, encoder=None)¶ Save this image to a file.
Parameters: - filename (str) – Used to set the image file format, and to open the output file if file is unspecified.
- file (file-like object or None) – File to write image data to.
- encoder (ImageEncoder or None) – If unspecified, all encoders matching the filename extension are tried. If all fail, the exception from the first one attempted is raised.
-
anchor_x
= 0¶
-
anchor_y
= 0¶
-
class
BufferImage
(x, y, width, height)¶ Bases:
pyglet.image.AbstractImage
An abstract framebuffer.
-
get_image_data
()¶ Get an ImageData view of this image.
Changes to the returned instance may or may not be reflected in this image.
Return type: ImageData
New in version 1.1.
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
format
= ''¶ The format string used for image data.
-
gl_buffer
= 1029¶ The OpenGL read and write target for this buffer.
-
gl_format
= 0¶ The OpenGL format constant for image data.
-
owner
= None¶
-
-
class
BufferImageMask
(x, y, width, height)¶ Bases:
pyglet.image.BufferImage
A single bit of the stencil buffer.
-
format
= 'L'¶
-
gl_format
= 6401¶
-
-
class
ColorBufferImage
(x, y, width, height)¶ Bases:
pyglet.image.BufferImage
A color framebuffer.
This class is used to wrap both the primary color buffer (i.e., the back buffer) or any one of the auxiliary buffers.
-
blit_to_texture
(target, level, x, y, z)¶ Draw this image on the currently bound texture at target.
This image is copied into the texture such that this image’s anchor point is aligned with the given x and y coordinates of the destination texture. If the currently bound texture is a 3D texture, the z coordinate gives the image slice to blit into.
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
format
= 'RGBA'¶
-
gl_format
= 6408¶
-
-
class
DepthBufferImage
(x, y, width, height)¶ Bases:
pyglet.image.BufferImage
The depth buffer.
-
blit_to_texture
(target, level, x, y, z)¶ Draw this image on the currently bound texture at target.
This image is copied into the texture such that this image’s anchor point is aligned with the given x and y coordinates of the destination texture. If the currently bound texture is a 3D texture, the z coordinate gives the image slice to blit into.
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
format
= 'L'¶
-
gl_format
= 6402¶
-
-
class
Texture
(width, height, target, id)¶ Bases:
pyglet.image.AbstractImage
An image loaded into video memory that can be efficiently drawn to the framebuffer.
Typically you will get an instance of Texture by accessing the texture member of any other AbstractImage.
Parameters: - region_class (class (subclass of TextureRegion)) – Class to use when constructing regions of this texture.
- tex_coords (tuple) – 12-tuple of float, named (u1, v1, r1, u2, v2, r2, …). u, v, r give the 3D texture coordinates for vertices 1-4. The vertices are specified in the order bottom-left, bottom-right, top-right and top-left.
- target (int) – The GL texture target (e.g.,
GL_TEXTURE_2D
). - level (int) – The mipmap level of this texture.
-
region_class
¶ alias of
TextureRegion
-
blit
(x, y, z=0, width=None, height=None)¶ Draw this image to the active framebuffers.
The image will be drawn with the lower-left corner at (
x -
anchor_x,y -
anchor_y,z
).
-
blit_into
(source, x, y, z)¶ Draw source on this image.
source will be copied into this image such that its anchor point is aligned with the x and y parameters. If this image is a 3D texture, the z coordinate gives the image slice to copy into.
Note that if source is larger than this image (or the positioning would cause the copy to go out of bounds) then you must pass a region of source to this method, typically using get_region().
-
classmethod
create
(width, height, internalformat=6408, rectangle=False, force_rectangle=False, min_filter=None, mag_filter=None)¶ Create an empty Texture.
If rectangle is
False
or the appropriate driver extensions are not available, a larger texture than requested will be created, and aTextureRegion
corresponding to the requested size will be returned.Parameters: - width (int) – Width of the texture.
- height (int) – Height of the texture.
- internalformat (int) – GL constant giving the internal format of the texture; for
example,
GL_RGBA
. - rectangle (bool) –
True
if a rectangular texture is permitted. See AbstractImage.get_texture. - force_rectangle (bool) –
True
if a rectangular texture is required. See AbstractImage.get_texture. .. versionadded:: 1.1.4. - min_filter (int) – The minifaction filter used for this texture, commonly
GL_LINEAR
orGL_NEAREST
- mag_filter (int) – The magnification filter used for this texture, commonly
GL_LINEAR
orGL_NEAREST
Return type: New in version 1.1.
-
classmethod
create_for_size
(target, min_width, min_height, internalformat=None, min_filter=None, mag_filter=None)¶ Create a Texture with dimensions at least min_width, min_height. On return, the texture will be bound.
Parameters: - target (int) – GL constant giving texture target to use, typically
GL_TEXTURE_2D
. - min_width (int) – Minimum width of texture (may be increased to create a power of 2).
- min_height (int) – Minimum height of texture (may be increased to create a power of 2).
- internalformat (int) – GL constant giving internal format of texture; for example,
GL_RGBA
. If unspecified, the texture will not be initialised (only the texture name will be created on the instance). If specified, the image will be initialised to this format with zero’d data. - min_filter (int) – The minifaction filter used for this texture, commonly
GL_LINEAR
orGL_NEAREST
- mag_filter (int) – The magnification filter used for this texture, commonly
GL_LINEAR
orGL_NEAREST
Return type: - target (int) – GL constant giving texture target to use, typically
-
get_image_data
(z=0)¶ Get the image data of this texture.
Changes to the returned instance will not be reflected in this texture.
Parameters: z (int) – For 3D textures, the image slice to retrieve. Return type: ImageData
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
get_transform
(flip_x=False, flip_y=False, rotate=0)¶ Create a copy of this image applying a simple transformation.
The transformation is applied to the texture coordinates only;
get_image_data()
will return the untransformed data. The transformation is applied around the anchor point.Parameters: - flip_x (bool) – If True, the returned image will be flipped horizontally.
- flip_y (bool) – If True, the returned image will be flipped vertically.
- rotate (int) – Degrees of clockwise rotation of the returned image. Only 90-degree increments are supported.
Return type:
-
default_mag_filter
= 9729¶
-
default_min_filter
= 9729¶
-
images
= 1¶
-
level
= 0¶
-
tex_coords
= (0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0)¶
-
tex_coords_order
= (0, 1, 2, 3)¶
-
x
= 0¶
-
y
= 0¶
-
z
= 0¶
-
class
DepthTexture
(width, height, target, id)¶ Bases:
pyglet.image.Texture
A texture with depth samples (typically 24-bit).
-
blit_into
(source, x, y, z)¶ Draw source on this image.
source will be copied into this image such that its anchor point is aligned with the x and y parameters. If this image is a 3D texture, the z coordinate gives the image slice to copy into.
Note that if source is larger than this image (or the positioning would cause the copy to go out of bounds) then you must pass a region of source to this method, typically using get_region().
-
-
class
TextureRegion
(x, y, z, width, height, owner)¶ Bases:
pyglet.image.Texture
A rectangular region of a texture, presented as if it were a separate texture.
-
blit_into
(source, x, y, z)¶ Draw source on this image.
source will be copied into this image such that its anchor point is aligned with the x and y parameters. If this image is a 3D texture, the z coordinate gives the image slice to copy into.
Note that if source is larger than this image (or the positioning would cause the copy to go out of bounds) then you must pass a region of source to this method, typically using get_region().
-
get_image_data
()¶ Get the image data of this texture.
Changes to the returned instance will not be reflected in this texture.
Parameters: z (int) – For 3D textures, the image slice to retrieve. Return type: ImageData
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
-
class
TileableTexture
(width, height, target, id)¶ Bases:
pyglet.image.Texture
A texture that can be tiled efficiently.
Use
create_for_Image
classmethod to construct.-
blit_tiled
(x, y, z, width, height)¶ Blit this texture tiled over the given area.
The image will be tiled with the bottom-left corner of the destination rectangle aligned with the anchor point of this texture.
-
classmethod
create_for_image
(image)¶
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
Image Sequences¶
-
class
AbstractImageSequence
¶ Abstract sequence of images.
The sequence is useful for storing image animations or slices of a volume. For efficient access, use the texture_sequence member. The class also implements the sequence interface (__len__, __getitem__, __setitem__).
-
get_animation
(period, loop=True)¶ Create an animation over this image sequence for the given constant framerate.
- :Parameters
- period : float
- Number of seconds to display each frame.
- loop : bool
- If True, the animation will loop continuously.
Return type: Animation
New in version 1.1.
-
get_texture_sequence
()¶ Get a TextureSequence.
Return type: TextureSequence New in version 1.1.
-
-
class
TextureSequence
¶ Bases:
pyglet.image.AbstractImageSequence
Interface for a sequence of textures.
Typical implementations store multiple
TextureRegion
s within oneTexture
so as to minimise state changes.-
get_texture_sequence
()¶ Get a TextureSequence.
Return type: TextureSequence New in version 1.1.
-
-
class
UniformTextureSequence
¶ Bases:
pyglet.image.TextureSequence
Interface for a sequence of textures, each with the same dimensions.
Parameters: - item_width (int) – Width of each texture in the sequence.
- item_height (int) – Height of each texture in the sequence.
-
item_height
¶
-
item_width
¶
-
class
TextureGrid
(grid)¶ Bases:
pyglet.image.TextureRegion
,pyglet.image.UniformTextureSequence
A texture containing a regular grid of texture regions.
To construct, create an
ImageGrid
first:image_grid = ImageGrid(...) texture_grid = TextureGrid(image_grid)
The texture grid can be accessed as a single texture, or as a sequence of
TextureRegion
. When accessing as a sequence, you can specify integer indexes, in which the images are arranged in rows from the bottom-left to the top-right:# assume the texture_grid is 3x3: current_texture = texture_grid[3] # get the middle-left image
You can also specify tuples in the sequence methods, which are addressed as
row, column
:# equivalent to the previous example: current_texture = texture_grid[1, 0]
When using tuples in a slice, the returned sequence is over the rectangular region defined by the slice:
# returns center, center-right, center-top, top-right images in that # order: images = texture_grid[(1,1):] # equivalent to images = texture_grid[(1,1):(3,3)]
-
get
(row, column)¶
-
columns
= 1¶
-
item_height
= 0¶
-
item_width
= 0¶
-
items
= ()¶
-
rows
= 1¶
-
-
class
Texture3D
(width, height, target, id)¶ Bases:
pyglet.image.Texture
,pyglet.image.UniformTextureSequence
A texture with more than one image slice.
Use create_for_images or create_for_image_grid classmethod to construct.
-
classmethod
create_for_image_grid
(grid, internalformat=6408)¶
-
classmethod
create_for_images
(images, internalformat=6408)¶
-
item_height
= 0¶
-
item_width
= 0¶
-
items
= ()¶
-
classmethod
Patterns¶
-
class
ImagePattern
¶ Abstract image creation class.
-
create_image
(width, height)¶ Create an image of the given size.
Parameters: - width (int) – Width of image to create
- height (int) – Height of image to create
Return type:
-
-
class
CheckerImagePattern
(color1=(150, 150, 150, 255), color2=(200, 200, 200, 255))¶ Bases:
pyglet.image.ImagePattern
Create an image with a tileable checker image.
-
create_image
(width, height)¶ Create an image of the given size.
Parameters: - width (int) – Width of image to create
- height (int) – Height of image to create
Return type:
-
-
class
SolidColorImagePattern
(color=(0, 0, 0, 0))¶ Bases:
pyglet.image.ImagePattern
Creates an image filled with a solid color.
-
create_image
(width, height)¶ Create an image of the given size.
Parameters: - width (int) – Width of image to create
- height (int) – Height of image to create
Return type:
-
Data¶
-
class
ImageData
(width, height, format, data, pitch=None)¶ Bases:
pyglet.image.AbstractImage
An image represented as a string of unsigned bytes.
Parameters: - data (str) – Pixel data, encoded according to format and pitch.
- format (str) – The format string to use when reading or writing data.
- pitch (int) – Number of bytes per row. Negative values indicate a top-to-bottom arrangement.
-
blit
(x, y, z=0, width=None, height=None)¶ Draw this image to the active framebuffers.
The image will be drawn with the lower-left corner at (
x -
anchor_x,y -
anchor_y,z
).
-
blit_to_texture
(target, level, x, y, z, internalformat=None)¶ Draw this image to to the currently bound texture at target.
This image’s anchor point will be aligned to the given x and y coordinates. If the currently bound texture is a 3D texture, the z parameter gives the image slice to blit into.
If internalformat is specified, glTexImage is used to initialise the texture; otherwise, glTexSubImage is used to update a region.
-
create_texture
(cls, rectangle=False, force_rectangle=False)¶ Create a texture containing this image.
If the image’s dimensions are not powers of 2, a TextureRegion of a larger Texture will be returned that matches the dimensions of this image.
Parameters: - cls (class (subclass of Texture)) – Class to construct.
- rectangle (bool) –
True
if a rectangle can be created; see AbstractImage.get_texture. .. versionadded:: 1.1 - force_rectangle (bool) –
True
if a rectangle must be created; see AbstractImage.get_texture. .. versionadded:: 1.1.4
Return type: cls or cls.region_class
-
get_data
(fmt=None, pitch=None)¶ Get the byte data of the image.
Parameters: - fmt (str) – Format string of the return data.
- pitch (int) – Number of bytes per row. Negative values indicate a top-to-bottom arrangement.
New in version 1.1.
Return type: sequence of bytes, or str
-
get_image_data
()¶ Get an ImageData view of this image.
Changes to the returned instance may or may not be reflected in this image.
Return type: ImageData
New in version 1.1.
-
get_mipmapped_texture
()¶ Return a Texture with mipmaps.
If
set_mipmap_Image
has been called with at least one image, the set of images defined will be used. Otherwise, mipmaps will be automatically generated.The texture dimensions must be powers of 2 to use mipmaps.
Return type: Texture
New in version 1.1.
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image data.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
set_data
(fmt, pitch, data)¶ Set the byte data of the image.
Parameters: - fmt (str) – Format string of the return data.
- pitch (int) – Number of bytes per row. Negative values indicate a top-to-bottom arrangement.
- data (str or sequence of bytes) – Image data.
New in version 1.1.
-
set_mipmap_image
(level, image)¶ Set a mipmap image for a particular level.
The mipmap image will be applied to textures obtained via get_mipmapped_texture.
Parameters: - level (int) – Mipmap level to set image at, must be >= 1.
- image (AbstractImage) – Image to set. Must have correct dimensions for that mipmap level (i.e., width >> level, height >> level)
-
format
¶ Format string of the data. Read-write.
Type: str
-
class
CompressedImageData
(width, height, gl_format, data, extension=None, decoder=None)¶ Bases:
pyglet.image.AbstractImage
Image representing some compressed data suitable for direct uploading to driver.
-
blit_to_texture
(target, level, x, y, z)¶ Draw this image on the currently bound texture at target.
This image is copied into the texture such that this image’s anchor point is aligned with the given x and y coordinates of the destination texture. If the currently bound texture is a 3D texture, the z coordinate gives the image slice to blit into.
-
get_mipmapped_texture
()¶ Retrieve a
Texture
instance with all mipmap levels filled in.Requires that image dimensions be powers of 2.
Return type: Texture
New in version 1.1.
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
set_mipmap_data
(level, data)¶ Set data for a mipmap level.
Supplied data gives a compressed image for the given mipmap level. The image must be of the correct dimensions for the level (i.e., width >> level, height >> level); but this is not checked. If any mipmap levels are specified, they are used; otherwise, mipmaps for mipmapped_texture are generated automatically.
Parameters: - level (int) – Level of mipmap image to set.
- data (sequence) – String or array/list of bytes giving compressed image data. Data must be in same format as specified in constructor.
-
-
class
ImageDataRegion
(x, y, width, height, image_data)¶ Bases:
pyglet.image.ImageData
-
get_data
(fmt=None, pitch=None)¶ Get the byte data of the image.
Parameters: - fmt (str) – Format string of the return data.
- pitch (int) – Number of bytes per row. Negative values indicate a top-to-bottom arrangement.
New in version 1.1.
Return type: sequence of bytes, or str
-
get_region
(x, y, width, height)¶ Retrieve a rectangular region of this image data.
Parameters: - x (int) – Left edge of region.
- y (int) – Bottom edge of region.
- width (int) – Width of region.
- height (int) – Height of region.
Return type:
-
set_data
(fmt, pitch, data)¶ Set the byte data of the image.
Parameters: - fmt (str) – Format string of the return data.
- pitch (int) – Number of bytes per row. Negative values indicate a top-to-bottom arrangement.
- data (str or sequence of bytes) – Image data.
New in version 1.1.
-
Other Classes¶
-
class
BufferManager
¶ Manages the set of framebuffers for a context.
Use
get_buffer_manager()
to obtain the instance of this class for the current context.-
get_aux_buffer
()¶ Get a free auxiliary buffer.
If not aux buffers are available, ImageException is raised. Buffers are released when they are garbage collected.
Return type: ColorBufferImage
-
get_buffer_mask
()¶ Get a free bitmask buffer.
A bitmask buffer is a buffer referencing a single bit in the stencil buffer. If no bits are free, ImageException is raised. Bits are released when the bitmask buffer is garbage collected.
Return type: BufferImageMask
-
get_color_buffer
()¶ Get the color buffer.
Return type: ColorBufferImage
-
get_depth_buffer
()¶ Get the depth buffer.
Return type: DepthBufferImage
-
get_viewport
()¶ Get the current OpenGL viewport dimensions.
Return type: 4-tuple of float. Returns: Left, top, right and bottom dimensions.
-
-
class
ImageGrid
(image, rows, columns, item_width=None, item_height=None, row_padding=0, column_padding=0)¶ Bases:
pyglet.image.AbstractImage
,pyglet.image.AbstractImageSequence
An imaginary grid placed over an image allowing easy access to regular regions of that image.
The grid can be accessed either as a complete image, or as a sequence of images. The most useful applications are to access the grid as a
TextureGrid
:image_grid = ImageGrid(...) texture_grid = image_grid.get_texture_sequence()
or as a
Texture3D
:image_grid = ImageGrid(...) texture_3d = Texture3D.create_for_image_grid(image_grid)
-
get_image_data
()¶ Get an ImageData view of this image.
Changes to the returned instance may or may not be reflected in this image.
Return type: ImageData
New in version 1.1.
-
get_texture
(rectangle=False, force_rectangle=False)¶ A
Texture
view of this image.By default, textures are created with dimensions that are powers of two. Smaller images will return a
TextureRegion
that covers just the image portion of the larger texture. This restriction is required on older video cards, and for compressed textures, or where texture repeat modes will be used, or where mipmapping is desired.If the rectangle parameter is
True
, this restriction is ignored and a texture the size of the image may be created if the driver supports theGL_ARB_texture_rectangle
orGL_NV_texture_rectangle
extensions. If the extensions are not present, the image already is a texture, or the image has power 2 dimensions, the rectangle parameter is ignored.Examine Texture.target to determine if the returned texture is a rectangle (
GL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
) or not (GL_TEXTURE_2D
).If the force_rectangle parameter is
True
, one of these extensions must be present, and the returned texture always has targetGL_TEXTURE_RECTANGLE_ARB
orGL_TEXTURE_RECTANGLE_NV
.Changes to the returned instance may or may not be reflected in this image.
Parameters: - rectangle (bool) – True if the texture can be created as a rectangle.
- force_rectangle (bool) – True if the texture must be created as a rectangle. .. versionadded:: 1.1.4.
Return type: New in version 1.1.
-
get_texture_sequence
()¶ Get a TextureSequence.
Return type: TextureSequence New in version 1.1.
-
Functions¶
-
create
(width, height, pattern=None)¶ Create an image optionally filled with the given pattern.
Note: You can make no assumptions about the return type; usually it will be ImageData or CompressedImageData, but patterns are free to return any subclass of AbstractImage.
Parameters: - width (int) – Width of image to create
- height (int) – Height of image to create
- pattern (ImagePattern or None) – Pattern to fill image with. If unspecified, the image will initially be transparent.
Return type:
-
get_buffer_manager
()¶ Get the buffer manager for the current OpenGL context.
Return type: BufferManager
-
load
(filename, file=None, decoder=None)¶ Load an image from a file.
Note: You can make no assumptions about the return type; usually it will be ImageData or CompressedImageData, but decoders are free to return any subclass of AbstractImage.
Parameters: - filename (str) – Used to guess the image format, and to load the file if file is unspecified.
- file (file-like object or None) – Source of image data in any supported format.
- decoder (ImageDecoder or None) – If unspecified, all decoders that are registered for the filename extension are tried. If none succeed, the exception from the first decoder is raised.
Return type:
-
load_animation
(filename, file=None, decoder=None)¶ Load an animation from a file.
Currently, the only supported format is GIF.
Parameters: - filename (str) – Used to guess the animation format, and to load the file if file is unspecified.
- file (file-like object or None) – File object containing the animation stream.
- decoder (ImageDecoder or None) – If unspecified, all decoders that are registered for the filename extension are tried. If none succeed, the exception from the first decoder is raised.
Return type:
-
get_max_texture_size
()¶ Query the maximum texture size available
pyglet.info¶
Get environment information useful for debugging.
Intended usage is to create a file for bug reports, e.g.:
python -m pyglet.info > info.txt
-
dump
()¶ Dump all information to stdout.
-
dump_al
()¶ Dump OpenAL info.
-
dump_ffmpeg
()¶ Dump FFmpeg info.
-
dump_gl
(context=None)¶ Dump GL info.
-
dump_glu
()¶ Dump GLU info.
-
dump_glx
()¶ Dump GLX info.
-
dump_media
()¶ Dump pyglet.media info.
-
dump_platform
()¶ Dump OS specific
-
dump_pyglet
()¶ Dump pyglet version and options.
-
dump_python
()¶ Dump Python version and environment to stdout.
-
dump_window
()¶ Dump display, window, screen and default config info.
-
dump_wintab
()¶ Dump WinTab info.
pyglet.input¶
Joystick, tablet and USB HID device support.
This module provides a unified interface to almost any input device, besides
the regular mouse and keyboard support provided by
Window
. At the lowest
level, get_devices()
can be used to retrieve a list of all supported
devices, including joysticks, tablets, space controllers, wheels, pedals, remote
controls, keyboards and mice. The set of returned devices varies greatly
depending on the operating system (and, of course, what’s plugged in).
At this level pyglet does not try to interpret what a particular device is,
merely what controls it provides. A Control
can be either a button,
whose value is either True
or False
, or a relative or absolute-valued
axis, whose value is a float. Sometimes the name of a control can be provided
(for example, x
, representing the horizontal axis of a joystick), but often
not. In these cases the device API may still be useful – the user will have
to be asked to press each button in turn or move each axis separately to
identify them.
Higher-level interfaces are provided for joysticks, tablets and the Apple remote control. These devices can usually be identified by pyglet positively, and a base level of functionality for each one provided through a common interface.
To use an input device:
- Call
get_devices()
,get_apple_remote()
orget_joysticks()
to retrieve and identify the device. - For low-level devices (retrieved by
get_devices()
), query the devices list of controls and determine which ones you are interested in. For high-level interfaces the set of controls is provided by the interface. - Optionally attach event handlers to controls on the device.
- Call
Device.open()
to begin receiving events on the device. You can begin querying the control values after this time; they will be updated asynchronously. - Call
Device.close()
when you are finished with the device (not needed if your application quits at this time).
To use a tablet, follow the procedure above using get_tablets()
, but
note that no control list is available; instead, calling Tablet.open()
returns a TabletCanvas
onto which you should set your event
handlers.
New in version 1.2.
Classes¶
-
class
Device
(display, name)¶ Bases:
object
Input device.
Variables: - display (pyglet.canvas.Display) – Display this device is connected to.
- name (str) – Name of the device, as described by the device firmware.
- manufacturer (str) – Name of the device manufacturer, or
None
if the information is not available.
-
close
()¶ Close the device.
-
get_controls
()¶ Get a list of controls provided by the device.
Return type: list of Control
-
open
(window=None, exclusive=False)¶ Open the device to begin receiving input from it.
Parameters: - window (Window) – Optional window to associate with the device. The behaviour of this parameter is device and operating system dependant. It can usually be omitted for most devices.
- exclusive (bool) – If
True
the device will be opened exclusively so that no other application can use it. The method will raise DeviceExclusiveException if the device cannot be opened this way (for example, because another application has already opened it).
-
class
Control
(name, raw_name=None)¶ Bases:
pyglet.event.EventDispatcher
Single value input provided by a device.
A control’s value can be queried when the device is open. Event handlers can be attached to the control to be called when the value changes.
The min and max properties are provided as advertised by the device; in some cases the control’s value will be outside this range.
Variables: - name (str) – Name of the control, or
None
if unknown - raw_name (str) – Unmodified name of the control, as presented by the operating
system; or
None
if unknown. - inverted (bool) – If
True
, the value reported is actually inverted from what the device reported; usually this is to provide consistency across operating systems.
Events
-
on_change
(value)¶ The value changed.
Parameters: value (float) – Current value of the control.
Attributes
-
value
¶ Current value of the control.
The range of the value is device-dependent; for absolute controls the range is given by
min
andmax
(however the value may exceed this range); for relative controls the range is undefined.Type: float
- name (str) – Name of the control, or
-
class
RelativeAxis
(name, raw_name=None)¶ Bases:
pyglet.input.base.Control
An axis whose value represents a relative change from the previous value.
-
RX
= 'rx'¶ Name of the rotational-X axis control
-
RY
= 'ry'¶ Name of the rotational-Y axis control
-
RZ
= 'rz'¶ Name of the rotational-Z axis control
-
WHEEL
= 'wheel'¶ Name of the scroll wheel control
-
X
= 'x'¶ Name of the horizontal axis control
-
Y
= 'y'¶ Name of the vertical axis control
-
Z
= 'z'¶ Name of the Z axis control.
-
value
¶ Current value of the control.
The range of the value is device-dependent; for absolute controls the range is given by
min
andmax
(however the value may exceed this range); for relative controls the range is undefined.Type: float
-
-
class
AbsoluteAxis
(name, min, max, raw_name=None)¶ Bases:
pyglet.input.base.Control
An axis whose value represents a physical measurement from the device.
The value is advertised to range over
min
andmax
.Variables: - min (float) – Minimum advertised value.
- max (float) – Maximum advertised value.
-
HAT
= 'hat'¶ Name of the hat (POV) control, when a single control enumerates all of the hat’s positions.
-
HAT_X
= 'hat_x'¶ Name of the hat’s (POV’s) horizontal control, when the hat position is described by two orthogonal controls.
-
HAT_Y
= 'hat_y'¶ Name of the hat’s (POV’s) vertical control, when the hat position is described by two orthogonal controls.
-
RX
= 'rx'¶ Name of the rotational-X axis control
-
RY
= 'ry'¶ Name of the rotational-Y axis control
-
RZ
= 'rz'¶ Name of the rotational-Z axis control
-
X
= 'x'¶ Name of the horizontal axis control
-
Y
= 'y'¶ Name of the vertical axis control
-
Z
= 'z'¶ Name of the Z axis control.
-
class
Button
(name, raw_name=None)¶ Bases:
pyglet.input.base.Control
A control whose value is boolean.
Events
-
on_press
()¶ The button was pressed.
-
on_release
()¶ The button was released.
Attributes
-
value
¶ Current value of the control.
The range of the value is device-dependent; for absolute controls the range is given by
min
andmax
(however the value may exceed this range); for relative controls the range is undefined.Type: float
-
-
class
Joystick
(device)¶ Bases:
pyglet.event.EventDispatcher
High-level interface for joystick-like devices. This includes analogue and digital joysticks, gamepads, game controllers, and possibly even steering wheels and other input devices. There is unfortunately no way to distinguish between these different device types.
To use a joystick, first call open, then in your game loop examine the values of x, y, and so on. These values are normalized to the range [-1.0, 1.0].
To receive events when the value of an axis changes, attach an on_joyaxis_motion event handler to the joystick. The
Joystick
instance, axis name, and current value are passed as parameters to this event.To handle button events, you should attach on_joybutton_press and on_joy_button_release event handlers to the joystick. Both the
Joystick
instance and the index of the changed button are passed as parameters to these events.Alternately, you may attach event handlers to each individual button in button_controls to receive on_press or on_release events.
To use the hat switch, attach an on_joyhat_motion event handler to the joystick. The handler will be called with both the hat_x and hat_y values whenever the value of the hat switch changes.
The device name can be queried to get the name of the joystick.
Variables: - device (Device) – The underlying device used by this joystick interface.
- x (float) – Current X (horizontal) value ranging from -1.0 (left) to 1.0 (right).
- y (float) – Current y (vertical) value ranging from -1.0 (top) to 1.0 (bottom).
- z (float) – Current Z value ranging from -1.0 to 1.0. On joysticks the Z value is usually the throttle control. On game controllers the Z value is usually the secondary thumb vertical axis.
- rx (float) – Current rotational X value ranging from -1.0 to 1.0.
- ry (float) – Current rotational Y value ranging from -1.0 to 1.0.
- rz (float) – Current rotational Z value ranging from -1.0 to 1.0. On joysticks the RZ value is usually the twist of the stick. On game controllers the RZ value is usually the secondary thumb horizontal axis.
- hat_x (int) – Current hat (POV) horizontal position; one of -1 (left), 0 (centered) or 1 (right).
- hat_y (int) – Current hat (POV) vertical position; one of -1 (bottom), 0 (centered) or 1 (top).
- buttons (list of bool) – List of boolean values representing current states of the buttons.
These are in order, so that button 1 has value at
buttons[0]
, and so on. - x_control (AbsoluteAxis) – Underlying control for x value, or
None
if not available. - y_control (AbsoluteAxis) – Underlying control for y value, or
None
if not available. - z_control (AbsoluteAxis) – Underlying control for z value, or
None
if not available. - rx_control (AbsoluteAxis) – Underlying control for rx value, or
None
if not available. - ry_control (AbsoluteAxis) – Underlying control for ry value, or
None
if not available. - rz_control (AbsoluteAxis) – Underlying control for rz value, or
None
if not available. - hat_x_control (AbsoluteAxis) – Underlying control for hat_x value, or
None
if not available. - hat_y_control (AbsoluteAxis) – Underlying control for hat_y value, or
None
if not available. - button_controls (list of Button) – Underlying controls for buttons values.
Methods
-
open
(window=None, exclusive=False)¶ Open the joystick device. See Device.open.
-
close
()¶ Close the joystick device. See Device.close.
Events
-
on_joyaxis_motion
(joystick, axis, value)¶ The value of a joystick axis changed.
Parameters: - joystick (Joystick) – The joystick device whose axis changed.
- axis (string) – The name of the axis that changed.
- value (float) – The current value of the axis, normalized to [-1, 1].
-
on_joyhat_motion
(joystick, hat_x, hat_y)¶ The value of the joystick hat switch changed.
Parameters: - joystick (Joystick) – The joystick device whose hat control changed.
- hat_x (int) – Current hat (POV) horizontal position; one of -1 (left), 0 (centered) or 1 (right).
- hat_y (int) – Current hat (POV) vertical position; one of -1 (bottom), 0 (centered) or 1 (top).
A button on the joystick was pressed.
Parameters: - joystick (Joystick) – The joystick device whose button was pressed.
- button (int) – The index (in button_controls) of the button that was pressed.
A button on the joystick was released.
Parameters: - joystick (Joystick) – The joystick device whose button was released.
- button (int) – The index (in button_controls) of the button that was released.
-
class
AppleRemote
(device)¶ Bases:
pyglet.event.EventDispatcher
High-level interface for Apple remote control.
This interface provides access to the 6 button controls on the remote. Pressing and holding certain buttons on the remote is interpreted as a separate control.
Variables: - device (Device) – The underlying device used by this interface.
- left_control (Button) – Button control for the left (prev) button.
- left_hold_control (Button) – Button control for holding the left button (rewind).
- right_control (Button) – Button control for the right (next) button.
- right_hold_control (Button) – Button control for holding the right button (fast forward).
- up_control (Button) – Button control for the up (volume increase) button.
- down_control (Button) – Button control for the down (volume decrease) button.
- select_control (Button) – Button control for the select (play/pause) button.
- select_hold_control (Button) – Button control for holding the select button.
- menu_control (Button) – Button control for the menu button.
- menu_hold_control (Button) – Button control for holding the menu button.
Methods
-
open
(window=None, exclusive=False)¶ Open the device. See Device.open.
-
close
()¶ Close the device. See Device.close.
Events
A button on the remote was pressed.
Only the ‘up’ and ‘down’ buttons will generate an event when the button is first pressed. All other buttons on the remote will wait until the button is released and then send both the press and release events at the same time.
Parameters: button (unicode) – The name of the button that was pressed. The valid names are ‘up’, ‘down’, ‘left’, ‘right’, ‘left_hold’, ‘right_hold’, ‘menu’, ‘menu_hold’, ‘select’, and ‘select_hold’
A button on the remote was released.
The ‘select_hold’ and ‘menu_hold’ button release events are sent immediately after the corresponding press events regardless of whether or not the user has released the button.
Parameters: button (unicode) – The name of the button that was released. The valid names are ‘up’, ‘down’, ‘left’, ‘right’, ‘left_hold’, ‘right_hold’, ‘menu’, ‘menu_hold’, ‘select’, and ‘select_hold’
-
class
Tablet
¶ High-level interface to tablet devices.
Unlike other devices, tablets must be opened for a specific window, and cannot be opened exclusively. The open method returns a TabletCanvas object, which supports the events provided by the tablet.
Currently only one tablet device can be used, though it can be opened on multiple windows. If more than one tablet is connected, the behaviour is undefined.
Functions¶
-
get_apple_remote
(display=None)¶ Get the Apple remote control device.
The Apple remote is the small white 6-button remote control that accompanies most recent Apple desktops and laptops. The remote can only be used with Mac OS X.
Parameters: display (Display) – Currently ignored. Return type: AppleRemote Returns: The remote device, or None if the computer does not support it.
-
get_devices
(display=None)¶ Get a list of all attached input devices.
Parameters: display (Display) – The display device to query for input devices. Ignored on Mac OS X and Windows. On Linux, defaults to the default display device. Return type: list of Device
-
get_joysticks
(display=None)¶ Get a list of attached joysticks.
Parameters: display (Display) – The display device to query for input devices. Ignored on Mac OS X and Windows. On Linux, defaults to the default display device. Return type: list of Joystick
-
get_tablets
(display=None)¶ Get a list of tablets.
This function may return a valid tablet device even if one is not attached (for example, it is not possible on Mac OS X to determine if a tablet device is connected). Despite returning a list of tablets, pyglet does not currently support multiple tablets, and the behaviour is undefined if more than one is attached.
Parameters: display (Display) – The display device to query for input devices. Ignored on Mac OS X and Windows. On Linux, defaults to the default display device. Return type: list of Tablet
pyglet.media¶
Submodules
pyglet.media.synthesis¶
-
class
ADSREnvelope
(attack, decay, release, sustain_amplitude=0.5)¶ A four part Attack, Decay, Suspend, Release envelope.
This is a four part ADSR envelope. The attack, decay, and release parameters should be provided in seconds. For example, a value of 0.1 would be 100ms. The sustain_amplitude parameter affects the sustain volume. This defaults to a value of 0.5, but can be provided on a scale from 0.0 to 1.0.
Parameters: - attack (float) – The attack time, in seconds.
- decay (float) – The decay time, in seconds.
- release (float) – The release time, in seconds.
- sustain_amplitude (float) – The sustain amplitude (volume), from 0.0 to 1.0.
-
get_generator
(sample_rate, duration)¶
-
class
Digitar
(duration, frequency=440, decay=0.996, **kwargs)¶ A guitar-like waveform.
A guitar-like waveform, based on the Karplus-Strong algorithm. The sound is similar to a plucked guitar string. The resulting sound decays over time, and so the actual length will vary depending on the frequency. Lower frequencies require a longer length parameter to prevent cutting off abruptly.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- frequency (int) – The frequency, in Hz of the waveform you wish to produce.
- decay (float) – The decay rate of the effect. Defaults to 0.996.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
class
Envelope
¶ Base class for SynthesisSource amplitude envelopes.
-
get_generator
(sample_rate, duration)¶
-
-
class
FM
(duration, carrier=440, modulator=440, mod_index=1, **kwargs)¶ A simple FM waveform.
This is a simplistic frequency modulated waveform, based on the concepts by John Chowning. Basic sine waves are used for both frequency carrier and modulator inputs, of which the frequencies can be provided. The modulation index, or amplitude, can also be adjusted.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- carrier (int) – The carrier frequency, in Hz.
- modulator (int) – The modulator frequency, in Hz.
- mod_index (int) – The modulation index.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
class
FlatEnvelope
(amplitude=0.5)¶ A flat envelope, providing basic amplitude setting.
Parameters: amplitude (float) – The amplitude (volume) of the wave, from 0.0 to 1.0. Values outside of this range will be clamped. -
get_generator
(sample_rate, duration)¶
-
-
class
LinearDecayEnvelope
(peak=1.0)¶ A linearly decaying envelope.
This envelope linearly decays the amplitude from the peak value to 0, over the length of the waveform.
Parameters: peak (float) – The Initial peak value of the envelope, from 0.0 to 1.0. Values outside of this range will be clamped. -
get_generator
(sample_rate, duration)¶
-
-
class
Sawtooth
(duration, frequency=440, **kwargs)¶ A sawtooth waveform.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- frequency (int) – The frequency, in Hz of the waveform you wish to produce.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
class
Silence
(duration, sample_rate=44800, sample_size=16, envelope=None)¶ A silent waveform.
-
class
Sine
(duration, frequency=440, **kwargs)¶ A sinusoid (sine) waveform.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- frequency (int) – The frequency, in Hz of the waveform you wish to produce.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
class
Square
(duration, frequency=440, **kwargs)¶ A square (pulse) waveform.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- frequency (int) – The frequency, in Hz of the waveform you wish to produce.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
class
SynthesisSource
(duration, sample_rate=44800, sample_size=16, envelope=None)¶ Base class for synthesized waveforms.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
get_audio_data
(num_bytes, compensation_time=0.0)¶ Return num_bytes bytes of audio data.
-
save
(filename)¶ Save the audio to disk as a standard RIFF Wave.
A standard RIFF wave header will be added to the raw PCM audio data when it is saved to disk.
Parameters: filename (str) – The file name to save as.
-
seek
(timestamp)¶ Seek to given timestamp.
Parameters: timestamp (float) – Time where to seek in the source. The timestamp
will be clamped to the duration of the source.
-
class
TremoloEnvelope
(depth, rate, amplitude=0.5)¶ A tremolo envelope, for modulation amplitude.
A tremolo envelope that modulates the amplitude of the waveform with a sinusoidal pattern. The depth and rate of modulation can be specified. Depth is calculated as a percentage of the maximum amplitude. For example: a depth of 0.2 and amplitude of 0.5 will fluctuate the amplitude between 0.4 an 0.5.
Parameters: - depth (float) – The amount of fluctuation, from 0.0 to 1.0.
- rate (float) – The fluctuation frequency, in seconds.
- amplitude (float) – The peak amplitude (volume), from 0.0 to 1.0.
-
get_generator
(sample_rate, duration)¶
-
class
Triangle
(duration, frequency=440, **kwargs)¶ A triangle waveform.
Parameters: - duration (float) – The length, in seconds, of audio that you wish to generate.
- frequency (int) – The frequency, in Hz of the waveform you wish to produce.
- sample_rate (int) – Audio samples per second. (CD quality is 44100).
- sample_size (int) – The bit precision. Must be either 8 or 16.
-
class
WhiteNoise
(duration, sample_rate=44800, sample_size=16, envelope=None)¶ A white noise, random waveform.
Details
Audio and video playback.
pyglet can play WAV files, and if FFmpeg is installed, many other audio and video formats.
Playback is handled by the Player
class, which reads raw data from
Source
objects and provides methods for pausing, seeking, adjusting
the volume, and so on. The Player
class implements the best
available audio device.
player = Player()
A Source
is used to decode arbitrary audio and video files. It is
associated with a single player by “queueing” it:
source = load('background_music.mp3')
player.queue(source)
Use the Player
to control playback.
If the source contains video, the Source.video_format()
attribute
will be non-None, and the Player.texture
attribute will contain the
current video image synchronised to the audio.
Decoding sounds can be processor-intensive and may introduce latency,
particularly for short sounds that must be played quickly, such as bullets or
explosions. You can force such sounds to be decoded and retained in memory
rather than streamed from disk by wrapping the source in a
StaticSource
:
bullet_sound = StaticSource(load('bullet.wav'))
The other advantage of a StaticSource
is that it can be queued on
any number of players, and so played many times simultaneously.
Pyglet relies on Python’s garbage collector to release resources when a player has finished playing a source. In this way some operations that could affect the application performance can be delayed.
The player provides a Player.delete()
method that can be used to
release resources immediately.
Classes¶
-
class
Player
¶ High-level sound and video player.
Methods
-
play
()¶ Begin playing the current source.
This has no effect if the player is already playing.
-
pause
()¶ Pause playback of the current source.
This has no effect if the player is already paused.
-
queue
(source)¶ Queue the source on this player.
If the player has no source, the player will start to play immediately or pause depending on its
playing
attribute.Parameters: source (Source or Iterable[Source]) – The source to queue.
-
seek
(timestamp)¶ Seek for playback to the indicated timestamp on the current source.
Timestamp is expressed in seconds. If the timestamp is outside the duration of the source, it will be clamped to the end.
Parameters: timestamp (float) – The time where to seek in the source, clamped to the beginning and end of the source.
-
seek_next_frame
()¶ Step forwards one video frame in the current source.
-
get_texture
()¶ Get the texture for the current video frame.
You should call this method every time you display a frame of video, as multiple textures might be used. The return value will be None if there is no video in the current source.
Returns: pyglet.image.Texture
Deprecated since version 1.4: Use
texture
instead
-
next_source
()¶ Move immediately to the next source in the current playlist.
If the playlist is empty, discard it and check if another playlist is queued. There may be a gap in playback while the audio buffer is refilled.
-
delete
()¶ Release the resources acquired by this player.
The internal audio player and the texture will be deleted.
-
update_texture
(dt=None)¶ Manually update the texture from the current source.
This happens automatically, so you shouldn’t need to call this method.
Parameters: dt (float) – The time elapsed since the last call to update_texture
.
Events
-
on_eos
()¶ The current source ran out of data.
The default behaviour is to advance to the next source in the playlist if the
loop
attribute is set toFalse
. Ifloop
attribute is set toTrue
, the current source will start to play again untilnext_source()
is called orloop
is set toFalse
.
-
on_player_eos
()¶ The player ran out of sources. The playlist is empty.
-
on_player_next_source
()¶ The player starts to play the next queued source in the playlist.
This is a useful event for adjusting the window size to the new source
VideoFormat
for example.
Attributes
-
cone_inner_angle
¶ The interior angle of the inner cone.
The angle is given in degrees, and defaults to 360. When the listener is positioned within the volume defined by the inner cone, the sound is played at normal gain (see
volume
).
-
cone_outer_angle
¶ The interior angle of the outer cone.
The angle is given in degrees, and defaults to 360. When the listener is positioned within the volume defined by the outer cone, but outside the volume defined by the inner cone, the gain applied is a smooth interpolation between
volume
andcone_outer_gain
.
-
cone_orientation
¶ The direction of the sound in 3D space.
The direction is specified as a tuple of floats (x, y, z), and has no unit. The default direction is (0, 0, -1). Directional effects are only noticeable if the other cone properties are changed from their default values.
-
cone_outer_gain
¶ The gain applied outside the cone.
When the listener is positioned outside the volume defined by the outer cone, this gain is applied instead of
volume
.
-
min_distance
¶ The distance beyond which the sound volume drops by half, and within which no attenuation is applied.
The minimum distance controls how quickly a sound is attenuated as it moves away from the listener. The gain is clamped at the nominal value within the min distance. By default the value is 1.0.
The unit defaults to meters, but can be modified with the listener properties.
-
max_distance
¶ The distance at which no further attenuation is applied.
When the distance from the listener to the player is greater than this value, attenuation is calculated as if the distance were value. By default the maximum distance is infinity.
The unit defaults to meters, but can be modified with the listener properties.
-
pitch
¶ The pitch shift to apply to the sound.
The nominal pitch is 1.0. A pitch of 2.0 will sound one octave higher, and play twice as fast. A pitch of 0.5 will sound one octave lower, and play twice as slow. A pitch of 0.0 is not permitted.
-
playing
¶ Read-only. Determine if the player state is playing.
The playing property is irrespective of whether or not there is actually a source to play. If playing is
True
and a source is queued, it will begin to play immediately. If playing isFalse
, it is implied that the player is paused. There is no other possible state.Type: bool
-
position
¶ The position of the sound in 3D space.
The position is given as a tuple of floats (x, y, z). The unit defaults to meters, but can be modified with the listener properties.
-
texture
¶ Get the texture for the current video frame.
You should call this method every time you display a frame of video, as multiple textures might be used. The return value will be None if there is no video in the current source.
Type: pyglet.image.Texture
-
time
¶ Read-only. Current playback time of the current source.
The playback time is a float expressed in seconds, with 0.0 being the beginning of the media. The playback time returned represents the player master clock time which is used to synchronize both the audio and the video.
Type: float
-
volume
¶ The volume level of sound playback.
The nominal level is 1.0, and 0.0 is silence.
The volume level is affected by the distance from the listener (if positioned).
-
loop
¶ Loop the current source indefinitely or until
next_source()
is called. Defaults toFalse
.Type: bool New in version 1.4.
-
-
class
PlayerGroup
(players)¶ Group of players that can be played and paused simultaneously.
Create a player group for the given list of players.
All players in the group must currently not belong to any other group.
Parameters: players (List[Player]) – List of Player
s in this group.-
play
()¶ Begin playing all players in the group simultaneously.
-
pause
()¶ Pause all players in the group simultaneously.
-
-
class
AudioFormat
(channels, sample_size, sample_rate)¶ Audio details.
An instance of this class is provided by sources with audio tracks. You should not modify the fields, as they are used internally to describe the format of data provided by the source.
Parameters: - channels (int) – The number of channels: 1 for mono or 2 for stereo (pyglet does not yet support surround-sound sources).
- sample_size (int) – Bits per sample; only 8 or 16 are supported.
- sample_rate (int) – Samples per second (in Hertz).
-
class
VideoFormat
(width, height, sample_aspect=1.0)¶ Video details.
An instance of this class is provided by sources with a video stream. You should not modify the fields.
Note that the sample aspect has no relation to the aspect ratio of the video image. For example, a video image of 640x480 with sample aspect 2.0 should be displayed at 1280x480. It is the responsibility of the application to perform this scaling.
Parameters: - width (int) – Width of video image, in pixels.
- height (int) – Height of video image, in pixels.
- sample_aspect (float) – Aspect ratio (width over height) of a single video pixel.
- frame_rate (float) –
Frame rate (frames per second) of the video.
New in version 1.2.
-
class
AudioData
(data, length, timestamp, duration, events)¶ A single packet of audio data.
This class is used internally by pyglet.
Parameters: - data (str or ctypes array or pointer) – Sample data.
- length (int) – Size of sample data, in bytes.
- timestamp (float) – Time of the first sample, in seconds.
- duration (float) – Total data duration, in seconds.
- events (List[
pyglet.media.events.MediaEvent
]) – List of events contained within this packet. Events are timestamped relative to this audio packet.
-
consume
(num_bytes, audio_format)¶ Remove some data from the beginning of the packet.
All events are cleared.
Parameters: - num_bytes (int) – The number of bytes to consume from the packet.
- audio_format (
AudioFormat
) – The packet audio format.
-
get_string_data
()¶ Return data as a bytestring.
Returns: Data as a (byte)string. Return type: bytes
-
class
SourceInfo
¶ Source metadata information.
Fields are the empty string or zero if the information is not available.
Parameters: - title (str) – Title
- author (str) – Author
- copyright (str) – Copyright statement
- comment (str) – Comment
- album (str) – Album name
- year (int) – Year
- track (int) – Track number
- genre (str) – Genre
New in version 1.2.
-
class
Source
¶ An audio and/or video source.
Parameters: - audio_format (
AudioFormat
) – Format of the audio in this source, orNone
if the source is silent. - video_format (
VideoFormat
) – Format of the video in this source, orNone
if there is no video. - info (
SourceInfo
) –Source metadata such as title, artist, etc; or
None
if the` information is not available.New in version 1.2.
-
is_player_source
¶ Determine if this source is a player current source.
Check on a
Player
if this source is the current source.Type: bool
-
get_animation
()¶ Import all video frames into memory.
An empty animation will be returned if the source has no video. Otherwise, the animation will contain all unplayed video frames (the entire source, if it has not been queued on a player). After creating the animation, the source will be at EOS (end of stream).
This method is unsuitable for videos running longer than a few seconds.
New in version 1.1.
Returns: pyglet.image.Animation
-
get_audio_data
(num_bytes, compensation_time=0.0)¶ Get next packet of audio data.
Parameters: - num_bytes (int) – Maximum number of bytes of data to return.
- compensation_time (float) – Time in sec to compensate due to a difference between the master clock and the audio clock.
Returns: Next packet of audio data, or
None
if there is no (more) data.Return type:
-
get_next_video_frame
()¶ Get the next video frame.
New in version 1.1.
Returns: The next video frame image, or None
if the video frame could not be decoded or there are no more video frames.Return type: pyglet.image.AbstractImage
-
get_next_video_timestamp
()¶ Get the timestamp of the next video frame.
New in version 1.1.
Returns: The next timestamp, or None
if there are no more video frames.Return type: float
-
get_queue_source
()¶ Return the
Source
to be used as the queue source for a player.Default implementation returns self.
-
play
()¶ Play the source.
This is a convenience method which creates a Player for this source and plays it immediately.
Returns: Player
-
save
(filename, file=None, encoder=None)¶ Save this Source to a file.
Parameters: - filename (str) – Used to set the file format, and to open the output file if file is unspecified.
- file (file-like object or None) – File to write audio data to.
- encoder (MediaEncoder or None) – If unspecified, all encoders matching the filename extension are tried. If all fail, the exception from the first one attempted is raised.
-
seek
(timestamp)¶ Seek to given timestamp.
Parameters: timestamp (float) – Time where to seek in the source. The timestamp
will be clamped to the duration of the source.
-
duration
¶ The length of the source, in seconds.
Not all source durations can be determined; in this case the value is
None
.Read-only.
Type: float
- audio_format (
-
class
StreamingSource
¶ Bases:
pyglet.media.codecs.base.Source
A source that is decoded as it is being played.
The source can only be played once at a time on any
Player
.-
delete
()¶ Release the resources held by this StreamingSource.
-
-
class
StaticSource
(source)¶ Bases:
pyglet.media.codecs.base.Source
A source that has been completely decoded in memory.
This source can be queued onto multiple players any number of times.
Construct a
StaticSource
for the data insource
.Parameters: source (Source) – The source to read and decode audio and video data from. -
get_audio_data
(num_bytes, compensation_time=0.0)¶ The StaticSource does not provide audio data.
When the StaticSource is queued on a
Player
, it creates aStaticMemorySource
containing its internal audio data and audio format.Raises: RuntimeError
-
get_queue_source
()¶ Return the
Source
to be used as the queue source for a player.Default implementation returns self.
-
-
class
StaticMemorySource
(data, audio_format)¶ Bases:
pyglet.media.codecs.base.StaticSource
Helper class for default implementation of
StaticSource
.Do not use directly. This class is used internally by pyglet.
Parameters: - data (AudioData) – The audio data.
- audio_format (AudioFormat) – The audio format.
-
get_audio_data
(num_bytes, compensation_time=0.0)¶ Get next packet of audio data.
Parameters: - num_bytes (int) – Maximum number of bytes of data to return.
- compensation_time (float) – Not used in this class.
Returns: Next packet of audio data, or
None
if there is no (more) data.Return type:
-
seek
(timestamp)¶ Seek to given timestamp.
Parameters: timestamp (float) – Time where to seek in the source.
-
class
AbstractListener
¶ The listener properties for positional audio.
You can obtain the singleton instance of this class by calling
AbstractAudioDriver.get_listener()
.-
forward_orientation
¶ A vector giving the direction the listener is facing.
The orientation is given as a tuple of floats (x, y, z), and has no unit. The forward orientation should be orthagonal to the up orientation.
Type: 3-tuple of float
-
position
¶ The position of the listener in 3D space.
The position is given as a tuple of floats (x, y, z). The unit defaults to meters, but can be modified with the listener properties.
Type: 3-tuple of float
-
up_orientation
¶ A vector giving the “up” orientation of the listener.
The orientation is given as a tuple of floats (x, y, z), and has no unit. The up orientation should be orthagonal to the forward orientation.
Type: 3-tuple of float
-
volume
¶ The master volume for sound playback.
All sound volumes are multiplied by this master volume before being played. A value of 0 will silence playback (but still consume resources). The nominal volume is 1.0.
Type: float
-
-
class
MediaEvent
(timestamp, event, *args)¶ Representation of a media event.
These events are used internally by some audio driver implementation to communicate events to the
Player
. One example is theon_eos
event.Parameters: - timestamp (float) – The time where this event happens.
- event (str) – Event description.
- *args – Any required positional argument to go along with this event.
Functions¶
-
get_audio_driver
()¶ Get the preferred audio driver for the current platform.
See
pyglet.options
audio
, and the Programming guide, section Sound and video for more information on setting the preferred driver.Returns: - The concrete implementation of the preferred
- audio driver for this platform.
Return type: AbstractAudioDriver
-
load
(filename, file=None, streaming=True, decoder=None)¶ Load a Source from a file.
All decoders that are registered for the filename extension are tried. If none succeed, the exception from the first decoder is raised. You can also specifically pass a decoder to use.
Parameters: - filename (str) – Used to guess the media format, and to load the file if file is unspecified.
- file (file-like object or None) – Source of media data in any supported format.
- streaming (bool) – If False, a
StaticSource
will be returned; otherwise (default) aStreamingSource
is created. - decoder (MediaDecoder or None) – A specific decoder you wish to use, rather than relying on automatic detection. If specified, no other decoders are tried.
Return type:
-
have_ffmpeg
()¶ Check if FFmpeg library is available.
Returns: True if FFmpeg is found. Return type: bool New in version 1.4.
pyglet.resource¶
Load application resources from a known path.
Loading resources by specifying relative paths to filenames is often problematic in Python, as the working directory is not necessarily the same directory as the application’s script files.
This module allows applications to specify a search path for resources.
Relative paths are taken to be relative to the application’s __main__
module. ZIP files can appear on the path; they will be searched inside. The
resource module also behaves as expected when applications are bundled using
Freezers such as PyInstaller, py2exe, py2app, etc..
In addition to providing file references (with the file()
function),
the resource module also contains convenience functions for loading images,
textures, fonts, media and documents.
3rd party modules or packages not bound to a specific application should
construct their own Loader
instance and override the path to use the
resources in the module’s directory.
Path format¶
The resource path path
(see also Loader.__init__()
and
Loader.path()
)
is a list of locations to search for resources. Locations are searched in the
order given in the path. If a location is not valid (for example, if the
directory does not exist), it is skipped.
Locations in the path beginning with an “at” symbol (‘’@’’) specify Python packages. Other locations specify a ZIP archive or directory on the filesystem. Locations that are not absolute are assumed to be relative to the script home. Some examples:
# Search just the `res` directory, assumed to be located alongside the
# main script file.
path = ['res']
# Search the directory containing the module `levels.level1`, followed
# by the `res/images` directory.
path = ['@levels.level1', 'res/images']
Paths are always case-sensitive and forward slashes are always used as path separators, even in cases when the filesystem or platform does not do this. This avoids a common programmer error when porting applications between platforms.
The default path is ['.']
. If you modify the path, you must call
reindex()
.
New in version 1.1.
-
exception
ResourceNotFoundException
(name)¶ The named resource was not found on the search path.
-
class
FileLocation
(path)¶ Location on the filesystem.
-
open
(filename, mode='rb')¶ Open a file at this location.
Parameters: - filename (str) – The filename to open. Absolute paths are not supported. Relative paths are not supported by most locations (you should specify only a filename with no path component).
- mode (str) – The file mode to open with. Only files opened on the filesystem make use of this parameter; others ignore it.
Return type: file object
-
-
class
Loader
(path=None, script_home=None)¶ Load program resource files from disk.
The loader contains a search path which can include filesystem directories, ZIP archives and Python packages.
Variables: - path (list of str) – List of search locations. After modifying the path you must call the reindex method.
- script_home (str) – Base resource location, defaulting to the location of the application script.
-
add_font
(name)¶ Add a font resource to the application.
Fonts not installed on the system must be added to pyglet before they can be used with font.load. Although the font is added with its filename using this function, it is loaded by specifying its family name. For example:
resource.add_font('action_man.ttf') action_man = font.load('Action Man')
Parameters: name (str) – Filename of the font resource to add.
-
animation
(name, flip_x=False, flip_y=False, rotate=0, border=1)¶ Load an animation with optional transformation.
Animations loaded from the same source but with different transformations will use the same textures.
Parameters: - name (str) – Filename of the animation source to load.
- flip_x (bool) – If True, the returned image will be flipped horizontally.
- flip_y (bool) – If True, the returned image will be flipped vertically.
- rotate (int) – The returned image will be rotated clockwise by the given number of degrees (a multiple of 90).
- border (int) – Leaves specified pixels of blank space around each image in an atlas, which may help reduce texture bleeding.
Return type: Animation
-
attributed
(name)¶ Load an attributed text document.
See pyglet.text.formats.attributed for details on this format.
Parameters: name (str) – Filename of the attribute text resource to load. Return type: FormattedDocument
-
file
(name, mode='rb')¶ Load a resource.
Parameters: - name (str) – Filename of the resource to load.
- mode (str) – Combination of
r
,w
,a
,b
andt
characters with the meaning as for the builtinopen
function.
Return type: file object
-
get_cached_animation_names
()¶ Get a list of animation filenames that have been cached.
This is useful for debugging and profiling only.
Return type: list Returns: List of str
-
get_cached_image_names
()¶ Get a list of image filenames that have been cached.
This is useful for debugging and profiling only.
Return type: list Returns: List of str
-
get_cached_texture_names
()¶ Get the names of textures currently cached.
Return type: list of str
-
get_texture_bins
()¶ Get a list of texture bins in use.
This is useful for debugging and profiling only.
Return type: list Returns: List of TextureBin
-
html
(name)¶ Load an HTML document.
Parameters: name (str) – Filename of the HTML resource to load. Return type: FormattedDocument
-
image
(name, flip_x=False, flip_y=False, rotate=0, atlas=True, border=1)¶ Load an image with optional transformation.
This is similar to texture, except the resulting image will be packed into a
TextureBin
if it is an appropriate size for packing. This is more efficient than loading images into separate textures.Parameters: - name (str) – Filename of the image source to load.
- flip_x (bool) – If True, the returned image will be flipped horizontally.
- flip_y (bool) – If True, the returned image will be flipped vertically.
- rotate (int) – The returned image will be rotated clockwise by the given number of degrees (a multiple of 90).
- atlas (bool) – If True, the image will be loaded into an atlas managed by pyglet. If atlas loading is not appropriate for specific texturing reasons (e.g. border control is required) then set this argument to False.
- border (int) – Leaves specified pixels of blank space around each image in an atlas, which may help reduce texture bleeding.
Return type: Texture
Returns: A complete texture if the image is large or not in an atlas, otherwise a
TextureRegion
of a texture atlas.
-
location
(name)¶ Get the location of a resource.
This method is useful for opening files referenced from a resource. For example, an HTML file loaded as a resource might reference some images. These images should be located relative to the HTML file, not looked up individually in the loader’s path.
Parameters: name (str) – Filename of the resource to locate. Return type: Location
-
media
(name, streaming=True)¶ Load a sound or video resource.
The meaning of streaming is as for media.load. Compressed sources cannot be streamed (that is, video and compressed audio cannot be streamed from a ZIP archive).
Parameters: - name (str) – Filename of the media source to load.
- streaming (bool) – True if the source should be streamed from disk, False if it should be entirely decoded into memory immediately.
Return type: media.Source
-
model
(name, batch=None)¶ Load a 3D model.
Parameters: - name (str) – Filename of the 3D model to load.
- batch (Batch or None) – An optional Batch instance to add this model to.
Return type: Model
-
reindex
()¶ Refresh the file index.
You must call this method if path is changed or the filesystem layout changes.
-
text
(name)¶ Load a plain text document.
Parameters: name (str) – Filename of the plain text resource to load. Return type: UnformattedDocument
-
texture
(name)¶ Load a texture.
The named image will be loaded as a single OpenGL texture. If the dimensions of the image are not powers of 2 a
TextureRegion
will be returned.Parameters: name (str) – Filename of the image resource to load. Return type: Texture
-
class
Location
¶ Abstract resource location.
Given a location, a file can be loaded from that location with the open method. This provides a convenient way to specify a path to load files from, and not necessarily have that path reside on the filesystem.
-
open
(filename, mode='rb')¶ Open a file at this location.
Parameters: - filename (str) – The filename to open. Absolute paths are not supported. Relative paths are not supported by most locations (you should specify only a filename with no path component).
- mode (str) – The file mode to open with. Only files opened on the filesystem make use of this parameter; others ignore it.
Return type: file object
-
-
class
URLLocation
(base_url)¶ Location on the network.
This class uses the
urlparse
andurllib2
modules to open files on the network given a URL.-
open
(filename, mode='rb')¶ Open a file at this location.
Parameters: - filename (str) – The filename to open. Absolute paths are not supported. Relative paths are not supported by most locations (you should specify only a filename with no path component).
- mode (str) – The file mode to open with. Only files opened on the filesystem make use of this parameter; others ignore it.
Return type: file object
-
-
class
ZIPLocation
(zip, dir)¶ Location within a ZIP file.
-
open
(filename, mode='rb')¶ Open a file at this location.
Parameters: - filename (str) – The filename to open. Absolute paths are not supported. Relative paths are not supported by most locations (you should specify only a filename with no path component).
- mode (str) – The file mode to open with. Only files opened on the filesystem make use of this parameter; others ignore it.
Return type: file object
-
-
get_script_home
()¶ Get the directory containing the program entry module.
For ordinary Python scripts, this is the directory containing the
__main__
module. For executables created with py2exe the result is the directory containing the running executable file. For OS X bundles created using Py2App the result is the Resources directory within the running bundle.If none of the above cases apply and the file for
__main__
cannot be determined the working directory is returned.When the script is being run by a Python profiler, this function may return the directory where the profiler is running instead of the directory of the real script. To workaround this behaviour the full path to the real script can be specified in
pyglet.resource.path
.Return type: str
-
get_settings_path
(name)¶ Get a directory to save user preferences.
Different platforms have different conventions for where to save user preferences, saved games, and settings. This function implements those conventions. Note that the returned path may not exist: applications should use
os.makedirs
to construct it if desired.On Linux, a directory name in the user’s configuration directory is returned (usually under
~/.config
).On Windows (including under Cygwin) the name directory in the user’s
Application Settings
directory is returned.On Mac OS X the name directory under
~/Library/Application Support
is returned.Parameters: name (str) – The name of the application. Return type: str
-
path
= ['.']¶ Default resource search path.
Locations in the search path are searched in order and are always case-sensitive. After changing the path you must call reindex.
See the module documentation for details on the path format.
Type: list of str
-
reindex
()¶ Refresh the file index.
You must call this method if path is changed or the filesystem layout changes.
-
file
(name, mode='rb')¶ Load a resource.
Parameters: - name (str) – Filename of the resource to load.
- mode (str) – Combination of
r
,w
,a
,b
andt
characters with the meaning as for the builtinopen
function.
Return type: file object
-
location
(name)¶ Get the location of a resource.
This method is useful for opening files referenced from a resource. For example, an HTML file loaded as a resource might reference some images. These images should be located relative to the HTML file, not looked up individually in the loader’s path.
Parameters: name (str) – Filename of the resource to locate. Return type: Location
-
add_font
(name)¶ Add a font resource to the application.
Fonts not installed on the system must be added to pyglet before they can be used with font.load. Although the font is added with its filename using this function, it is loaded by specifying its family name. For example:
resource.add_font('action_man.ttf') action_man = font.load('Action Man')
Parameters: name (str) – Filename of the font resource to add.
-
image
(name, flip_x=False, flip_y=False, rotate=0, atlas=True, border=1)¶ Load an image with optional transformation.
This is similar to texture, except the resulting image will be packed into a
TextureBin
if it is an appropriate size for packing. This is more efficient than loading images into separate textures.Parameters: - name (str) – Filename of the image source to load.
- flip_x (bool) – If True, the returned image will be flipped horizontally.
- flip_y (bool) – If True, the returned image will be flipped vertically.
- rotate (int) – The returned image will be rotated clockwise by the given number of degrees (a multiple of 90).
- atlas (bool) – If True, the image will be loaded into an atlas managed by pyglet. If atlas loading is not appropriate for specific texturing reasons (e.g. border control is required) then set this argument to False.
- border (int) – Leaves specified pixels of blank space around each image in an atlas, which may help reduce texture bleeding.
Return type: Texture
Returns: A complete texture if the image is large or not in an atlas, otherwise a
TextureRegion
of a texture atlas.
-
animation
(name, flip_x=False, flip_y=False, rotate=0, border=1)¶ Load an animation with optional transformation.
Animations loaded from the same source but with different transformations will use the same textures.
Parameters: - name (str) – Filename of the animation source to load.
- flip_x (bool) – If True, the returned image will be flipped horizontally.
- flip_y (bool) – If True, the returned image will be flipped vertically.
- rotate (int) – The returned image will be rotated clockwise by the given number of degrees (a multiple of 90).
- border (int) – Leaves specified pixels of blank space around each image in an atlas, which may help reduce texture bleeding.
Return type: Animation
-
get_cached_image_names
()¶ Get a list of image filenames that have been cached.
This is useful for debugging and profiling only.
Return type: list Returns: List of str
-
get_cached_animation_names
()¶ Get a list of animation filenames that have been cached.
This is useful for debugging and profiling only.
Return type: list Returns: List of str
-
get_texture_bins
()¶ Get a list of texture bins in use.
This is useful for debugging and profiling only.
Return type: list Returns: List of TextureBin
-
media
(name, streaming=True)¶ Load a sound or video resource.
The meaning of streaming is as for media.load. Compressed sources cannot be streamed (that is, video and compressed audio cannot be streamed from a ZIP archive).
Parameters: - name (str) – Filename of the media source to load.
- streaming (bool) – True if the source should be streamed from disk, False if it should be entirely decoded into memory immediately.
Return type: media.Source
-
texture
(name)¶ Load a texture.
The named image will be loaded as a single OpenGL texture. If the dimensions of the image are not powers of 2 a
TextureRegion
will be returned.Parameters: name (str) – Filename of the image resource to load. Return type: Texture
-
html
(name)¶ Load an HTML document.
Parameters: name (str) – Filename of the HTML resource to load. Return type: FormattedDocument
-
attributed
(name)¶ Load an attributed text document.
See pyglet.text.formats.attributed for details on this format.
Parameters: name (str) – Filename of the attribute text resource to load. Return type: FormattedDocument
-
text
(name)¶ Load a plain text document.
Parameters: name (str) – Filename of the plain text resource to load. Return type: UnformattedDocument
-
get_cached_texture_names
()¶ Get the names of textures currently cached.
Return type: list of str
pyglet.sprite¶
Display positioned, scaled and rotated images.
A sprite is an instance of an image displayed on-screen. Multiple sprites can display the same image at different positions on the screen. Sprites can also be scaled larger or smaller, rotated at any angle and drawn at a fractional opacity.
The following complete example loads a "ball.png"
image and creates a
sprite for that image. The sprite is then drawn in the window’s
draw event handler:
import pyglet
ball_image = pyglet.image.load('ball.png')
ball = pyglet.sprite.Sprite(ball_image, x=50, y=50)
window = pyglet.window.Window()
@window.event
def on_draw():
ball.draw()
pyglet.app.run()
The sprite can be moved by modifying the x
and
y
properties. Other
properties determine the sprite’s rotation
,
scale
and
opacity
.
By default sprite coordinates are restricted to integer values to avoid
sub-pixel artifacts. If you require to use floats, for example for smoother
animations, you can set the subpixel
parameter to True
when creating
the sprite (:since: pyglet 1.2).
The sprite’s positioning, rotation and scaling all honor the original
image’s anchor (anchor_x
,
anchor_y
).
Drawing multiple sprites¶
Sprites can be “batched” together and drawn at once more quickly than if each
of their draw
methods were called individually. The following example
creates one hundred ball sprites and adds each of them to a Batch
. The
entire batch of sprites is then drawn in one call:
batch = pyglet.graphics.Batch()
ball_sprites = []
for i in range(100):
x, y = i * 10, 50
ball_sprites.append(pyglet.sprite.Sprite(ball_image, x, y, batch=batch))
@window.event
def on_draw():
batch.draw()
Sprites can be freely modified in any way even after being added to a batch,
however a sprite can belong to at most one batch. See the documentation for
pyglet.graphics
for more details on batched rendering, and grouping of
sprites within batches.
New in version 1.1.
-
class
Sprite
(img, x=0, y=0, blend_src=770, blend_dest=771, batch=None, group=None, usage='dynamic', subpixel=False)¶ Instance of an on-screen image.
See the module documentation for usage.
Methods
-
delete
()¶ Force immediate removal of the sprite from video memory.
This is often necessary when using batches, as the Python garbage collector will not necessarily call the finalizer as soon as the sprite is garbage.
-
draw
()¶ Draw the sprite at its current position.
See the module documentation for hints on drawing multiple sprites efficiently.
-
update
(x=None, y=None, rotation=None, scale=None, scale_x=None, scale_y=None)¶ Simultaneously change the position, rotation or scale.
This method is provided for performance. In cases where multiple Sprite attributes need to be updated at the same time, it is more efficent to update them together using the update method, rather than modifying them one by one.
Parameters: - x (int) – X coordinate of the sprite.
- y (int) – Y coordinate of the sprite.
- rotation (float) – Clockwise rotation of the sprite, in degrees.
- scale (float) – Scaling factor.
- scale_x (float) – Horizontal scaling factor.
- scale_y (float) – Vertical scaling factor.
Events
-
on_animation_end
()¶ The sprite animation reached the final frame.
The event is triggered only if the sprite has an animation, not an image. For looping animations, the event is triggered each time the animation loops.
Attributes
-
batch
¶ Graphics batch.
The sprite can be migrated from one batch to another, or removed from its batch (for individual drawing). Note that this can be an expensive operation.
Type: pyglet.graphics.Batch
-
color
¶ Blend color.
This property sets the color of the sprite’s vertices. This allows the sprite to be drawn with a color tint.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
group
¶ Parent graphics group.
The sprite can change its rendering group, however this can be an expensive operation.
Type: pyglet.graphics.Group
-
height
¶ Scaled height of the sprite.
Read-only. Invariant under rotation.
Type: int
-
image
¶ Image or animation to display.
Type: AbstractImage
orAnimation
-
opacity
¶ Blend opacity.
This property sets the alpha component of the colour of the sprite’s vertices. With the default blend mode (see the constructor), this allows the sprite to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the sprite appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the sprite, as a tuple.
Parameters: - x (int) – X coordinate of the sprite.
- y (int) – Y coordinate of the sprite.
-
rotation
¶ Clockwise rotation of the sprite, in degrees.
The sprite image will be rotated about its image’s (anchor_x, anchor_y) position.
Type: float
-
scale
¶ Base Scaling factor.
A scaling factor of 1 (the default) has no effect. A scale of 2 will draw the sprite at twice the native size of its image.
Type: float
-
scale_x
¶ Horizontal scaling factor.
A scaling factor of 1 (the default) has no effect. A scale of 2 will draw the sprite at twice the native width of its image.Type: float
-
scale_y
¶ Vertical scaling factor.
A scaling factor of 1 (the default) has no effect. A scale of 2 will draw the sprite at twice the native height of its image.Type: float
-
visible
¶ True if the sprite will be drawn.
Type: bool
-
width
¶ Scaled width of the sprite.
Read-only. Invariant under rotation.
Type: int
-
x
¶ X coordinate of the sprite.
Type: int
-
y
¶ Y coordinate of the sprite.
Type: int
-
-
class
SpriteGroup
(texture, blend_src, blend_dest, parent=None)¶ Shared sprite rendering group.
The group is automatically coalesced with other sprite groups sharing the same parent group, texture and blend parameters.
-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
unset_state
()¶ Repeal the OpenGL state change.
The default implementation does nothing.
-
pyglet.shapes¶
2D shapes.
This module provides classes for a variety of simplistic 2D shapes,
such as Rectangles, Circles, and Lines. These shapes are made
internally from OpenGL primitives, and provide excellent performance
when drawn as part of a Batch
.
Convenience methods are provided for positioning, changing color
and opacity, and rotation (where applicable). To create more
complex shapes than what is provided here, the lower level
graphics API is more appropriate.
See the Graphics for more details.
A simple example of drawing shapes:
import pyglet
from pyglet import shapes
window = pyglet.window.Window(960, 540)
batch = pyglet.graphics.Batch()
circle = shapes.Circle(700, 150, 100, color=(50, 225, 30), batch=batch)
square = shapes.Rectangle(200, 200, 200, 200, color=(55, 55, 255), batch=batch)
rectangle = shapes.Rectangle(250, 300, 400, 200, color=(255, 22, 20), batch=batch)
rectangle.opacity = 128
rectangle.rotation = 33
line = shapes.Line(100, 100, 100, 200, width=19, batch=batch)
line2 = shapes.Line(150, 150, 444, 111, width=4, color=(200, 20, 20), batch=batch)
star = shapes.Star(800, 400, 60, 40, num_spikes=20, color=(255, 255, 0), batch=batch)
@window.event
def on_draw():
window.clear()
batch.draw()
pyglet.app.run()
New in version 1.5.4.
-
class
Arc
(x, y, radius, segments=None, angle=6.283185307179586, start_angle=0, closed=False, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
rotation
¶ Clockwise rotation of the arc, in degrees.
The arc will be rotated about its (anchor_x, anchor_y) position.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
Circle
(x, y, radius, segments=None, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
radius
¶ The radius of the circle.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
Ellipse
(x, y, a, b, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
a
¶ The semi-major axes of the ellipse.
Type: float
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
b
¶ The semi-minor axes of the ellipse.
Type: float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
rotation
¶ Clockwise rotation of the arc, in degrees.
The arc will be rotated about its (anchor_x, anchor_y) position.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
Line
(x, y, x2, y2, width=1, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y, x2, y2) coordinates of the line, as a tuple.
Parameters: - x (int or float) – X coordinate of the line.
- y (int or float) – Y coordinate of the line.
- x2 (int or float) – X2 coordinate of the line.
- y2 (int or float) – Y2 coordinate of the line.
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
x2
¶ Second X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
y2
¶ Second Y coordinate of the shape.
Type: int or float
-
-
class
Rectangle
(x, y, width, height, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
height
¶ The height of the rectangle.
Type: float
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
rotation
¶ Clockwise rotation of the rectangle, in degrees.
The Rectangle will be rotated about its (anchor_x, anchor_y) position.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
width
¶ The width of the rectangle.
Type: float
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
BorderedRectangle
(x, y, width, height, border=1, color=(255, 255, 255), border_color=(100, 100, 100), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
border_color
¶ The rectangle’s border color.
This property sets the color of the border of a bordered rectangle.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
height
¶ The height of the rectangle.
Type: float
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
rotation
¶ Clockwise rotation of the rectangle, in degrees.
The Rectangle will be rotated about its (anchor_x, anchor_y) position.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
width
¶ The width of the rectangle.
Type: float
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
Triangle
(x, y, x2, y2, x3, y3, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y, x2, y2, x3, y3) coordinates of the triangle, as a tuple.
Parameters: - x (int or float) – X coordinate of the triangle.
- y (int or float) – Y coordinate of the triangle.
- x2 (int or float) – X2 coordinate of the triangle.
- y2 (int or float) – Y2 coordinate of the triangle.
- x3 (int or float) – X3 coordinate of the triangle.
- y3 (int or float) – Y3 coordinate of the triangle.
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
x2
¶ Second X coordinate of the shape.
Type: int or float
-
x3
¶ Third X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
y2
¶ Second Y coordinate of the shape.
Type: int or float
-
y3
¶ Third Y coordinate of the shape.
Type: int or float
-
-
class
Star
(x, y, outer_radius, inner_radius, num_spikes, rotation=0, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
inner_radius
¶ The inner radius of the star.
-
num_spikes
¶ Number of spikes of the star.
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
outer_radius
¶ The outer radius of the star.
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
rotation
¶ Rotation of the star, in degrees.
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
Polygon
(*coordinates, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the shape.
- y (int or float) – Y coordinate of the shape.
-
rotation
¶ Clockwise rotation of the polygon, in degrees.
The Polygon will be rotated about its (anchor_x, anchor_y) position.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
-
class
Sector
(x, y, radius, segments=None, angle=6.283185307179586, start_angle=0, color=(255, 255, 255), batch=None, group=None)¶ -
draw
()¶ Draw the shape at its current position.
Using this method is not recommended. Instead, add the shape to a pyglet.graphics.Batch for efficient rendering.
-
anchor_position
¶ The (x, y) coordinates of the anchor point, as a tuple.
Parameters: - x (int or float) – X coordinate of the anchor point.
- y (int or float) – Y coordinate of the anchor point.
-
anchor_x
¶ The X coordinate of the anchor point
Type: int or float
-
anchor_y
¶ The Y coordinate of the anchor point
Type: int or float
-
color
¶ The shape color.
This property sets the color of the shape.
The color is specified as an RGB tuple of integers ‘(red, green, blue)’. Each color component must be in the range 0 (dark) to 255 (saturated).
Type: (int, int, int)
-
opacity
¶ Blend opacity.
This property sets the alpha component of the color of the shape. With the default blend mode (see the constructor), this allows the shape to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the shape appear translucent.
Type: int
-
position
¶ The (x, y) coordinates of the shape, as a tuple.
Parameters: - x (int or float) – X coordinate of the sprite.
- y (int or float) – Y coordinate of the sprite.
-
radius
¶ The radius of the circle.
Type: float
-
rotation
¶ Clockwise rotation of the sector, in degrees.
The sector will be rotated about its (anchor_x, anchor_y) position.
Type: float
-
visible
¶ True if the shape will be drawn.
Type: bool
-
x
¶ X coordinate of the shape.
Type: int or float
-
y
¶ Y coordinate of the shape.
Type: int or float
-
pyglet.text¶
Submodules
pyglet.text.caret¶
Provides keyboard and mouse editing procedures for text layout.
Example usage:
from pyglet import window
from pyglet.text import layout, caret
my_window = window.Window(...)
my_layout = layout.IncrementalTextLayout(...)
my_caret = caret.Caret(my_layout)
my_window.push_handlers(my_caret)
New in version 1.1.
-
class
Caret
(layout, batch=None, color=(0, 0, 0))¶ Visible text insertion marker for pyglet.text.layout.IncrementalTextLayout.
The caret is drawn as a single vertical bar at the document position on a text layout object. If mark is not None, it gives the unmoving end of the current text selection. The visible text selection on the layout is updated along with mark and position.
By default the layout’s graphics batch is used, so the caret does not need to be drawn explicitly. Even if a different graphics batch is supplied, the caret will be correctly positioned and clipped within the layout.
Updates to the document (and so the layout) are automatically propagated to the caret.
The caret object can be pushed onto a window event handler stack with Window.push_handlers. The caret will respond correctly to keyboard, text, mouse and activation events, including double- and triple-clicks. If the text layout is being used alongside other graphical widgets, a GUI toolkit will be needed to delegate keyboard and mouse events to the appropriate widget. pyglet does not provide such a toolkit at this stage.
-
delete
()¶ Remove the caret from its batch.
Also disconnects the caret from further layout events.
-
get_style
(attribute)¶ Get the document’s named style at the caret’s current position.
If there is a text selection and the style varies over the selection, pyglet.text.document.STYLE_INDETERMINATE is returned.
Parameters: attribute (str) – Name of style attribute to retrieve. See pyglet.text.document for a list of recognised attribute names. Return type: object
-
move_to_point
(x, y)¶ Move the caret close to the given window coordinate.
The mark will be reset to
None
.Parameters: - x (int) – X coordinate.
- y (int) – Y coordinate.
-
on_activate
()¶ Handler for the pyglet.window.Window.on_activate event.
The caret is hidden when the window is not active.
-
on_deactivate
()¶ Handler for the pyglet.window.Window.on_deactivate event.
The caret is hidden when the window is not active.
-
on_layout_update
()¶
-
on_mouse_drag
(x, y, dx, dy, buttons, modifiers)¶ Handler for the pyglet.window.Window.on_mouse_drag event.
Mouse handlers do not check the bounds of the coordinates: GUI toolkits should filter events that do not intersect the layout before invoking this handler.
-
on_mouse_press
(x, y, button, modifiers)¶ Handler for the pyglet.window.Window.on_mouse_press event.
Mouse handlers do not check the bounds of the coordinates: GUI toolkits should filter events that do not intersect the layout before invoking this handler.
This handler keeps track of the number of mouse presses within a short span of time and uses this to reconstruct double- and triple-click events for selecting words and paragraphs. This technique is not suitable when a GUI toolkit is in use, as the active widget must also be tracked. Do not use this mouse handler if a GUI toolkit is being used.
-
on_mouse_scroll
(x, y, scroll_x, scroll_y)¶ Handler for the pyglet.window.Window.on_mouse_scroll event.
Mouse handlers do not check the bounds of the coordinates: GUI toolkits should filter events that do not intersect the layout before invoking this handler.
The layout viewport is scrolled by SCROLL_INCREMENT pixels per “click”.
-
on_text
(text)¶ Handler for the pyglet.window.Window.on_text event.
Caret keyboard handlers assume the layout always has keyboard focus. GUI toolkits should filter keyboard and text events by widget focus before invoking this handler.
-
on_text_motion
(motion, select=False)¶ Handler for the pyglet.window.Window.on_text_motion event.
Caret keyboard handlers assume the layout always has keyboard focus. GUI toolkits should filter keyboard and text events by widget focus before invoking this handler.
-
on_text_motion_select
(motion)¶ Handler for the pyglet.window.Window.on_text_motion_select event.
Caret keyboard handlers assume the layout always has keyboard focus. GUI toolkits should filter keyboard and text events by widget focus before invoking this handler.
-
select_paragraph
(x, y)¶ Select the paragraph at the given window coordinate.
Parameters: - x (int) – X coordinate.
- y (int) – Y coordinate.
-
select_to_point
(x, y)¶ Move the caret close to the given window coordinate while maintaining the mark.
Parameters: - x (int) – X coordinate.
- y (int) – Y coordinate.
-
select_word
(x, y)¶ Select the word at the given window coordinate.
Parameters: - x (int) – X coordinate.
- y (int) – Y coordinate.
-
set_style
(attributes)¶ Set the document style at the caret’s current position.
If there is a text selection the style is modified immediately. Otherwise, the next text that is entered before the position is modified will take on the given style.
Parameters: attributes (dict) – Dict mapping attribute names to style values. See pyglet.text.document for a list of recognised attribute names.
-
PERIOD
= 0.5¶ Blink period, in seconds.
-
SCROLL_INCREMENT
= 16¶ Pixels to scroll viewport per mouse scroll wheel movement. Defaults to 12pt at 96dpi.
-
color
¶ Caret color.
The default caret color is
[0, 0, 0]
(black). Each RGB color component is in the range 0 to 255.Type: (int, int, int)
-
line
¶ Index of line containing the caret’s position.
When set, position is modified to place the caret on requested line while maintaining the closest possible X offset.
Type: int
-
mark
¶ Position of immovable end of text selection within document.
An interactive text selection is determined by its immovable end (the caret’s position when a mouse drag begins) and the caret’s position, which moves interactively by mouse and keyboard input.
This property is
None
when there is no selection.Type: int
-
position
¶ Position of caret within document.
Type: int
-
visible
¶ Caret visibility.
The caret may be hidden despite this property due to the periodic blinking or by on_deactivate if the event handler is attached to a window.
Type: bool
-
pyglet.text.document¶
Formatted and unformatted document interfaces used by text layout.
Abstract representation¶
Styled text in pyglet is represented by one of the AbstractDocument
classes,
which manage the state representation of text and style independently of how
it is loaded or rendered.
A document consists of the document text (a Unicode string) and a set of named style ranges. For example, consider the following (artificial) example:
0 5 10 15 20
The cat sat on the mat.
+++++++ +++++++ "bold"
++++++ "italic"
If this example were to be rendered, “The cat” and “the mat” would be in bold, and “on the” in italics. Note that the second “the” is both bold and italic.
The document styles recorded for this example would be "bold"
over ranges
(0-7, 15-22) and "italic"
over range (12-18). Overlapping styles are
permitted; unlike HTML and other structured markup, the ranges need not be
nested.
The document has no knowledge of the semantics of "bold"
or "italic"
,
it stores only the style names. The pyglet layout classes give meaning to
these style names in the way they are rendered; but you are also free to
invent your own style names (which will be ignored by the layout classes).
This can be useful to tag areas of interest in a document, or maintain
references back to the source material.
As well as text, the document can contain arbitrary elements represented by
InlineElement
. An inline element behaves like a single character in the
documented, but can be rendered by the application.
Paragraph breaks¶
Paragraph breaks are marked with a “newline” character (U+0010). The Unicode paragraph break (U+2029) can also be used.
Line breaks (U+2028) can be used to force a line break within a paragraph.
See Unicode recommendation UTR #13 for more information: http://unicode.org/reports/tr13/tr13-5.html.
Document classes¶
Any class implementing AbstractDocument
provides an interface to a
document model as described above. In theory a structured document such as
HTML or XML could export this model, though the classes provided by pyglet
implement only unstructured documents.
The UnformattedDocument
class assumes any styles set are set over the entire
document. So, regardless of the range specified when setting a "bold"
style attribute, for example, the entire document will receive that style.
The FormattedDocument
class implements the document model directly, using
the RunList class to represent style runs efficiently.
Style attributes¶
The following character style attribute names are recognised by pyglet:
font_name
- Font family name, as given to
pyglet.font.load()
. font_size
- Font size, in points.
bold
- Boolean.
italic
- Boolean.
underline
- 4-tuple of ints in range (0, 255) giving RGBA underline color, or None (default) for no underline.
kerning
- Additional space to insert between glyphs, in points. Defaults to 0.
baseline
- Offset of glyph baseline from line baseline, in points. Positive values give a superscript, negative values give a subscript. Defaults to 0.
color
- 4-tuple of ints in range (0, 255) giving RGBA text color
background_color
- 4-tuple of ints in range (0, 255) giving RGBA text background color; or
None
for no background fill.
The following paragraph style attribute names are recognised by pyglet. Note that paragraph styles are handled no differently from character styles by the document: it is the application’s responsibility to set the style over an entire paragraph, otherwise results are undefined.
align
left
(default),center
orright
.indent
- Additional horizontal space to insert before the first
leading
- Additional space to insert between consecutive lines within a paragraph, in points. Defaults to 0.
line_spacing
- Distance between consecutive baselines in a paragraph, in points.
Defaults to
None
, which automatically calculates the tightest line spacing for each line based on the font ascent and descent. margin_left
- Left paragraph margin, in pixels.
margin_right
- Right paragraph margin, in pixels.
margin_top
- Margin above paragraph, in pixels.
margin_bottom
- Margin below paragraph, in pixels. Adjacent margins do not collapse.
tab_stops
- List of horizontal tab stops, in pixels, measured from the left edge of the text layout. Defaults to the empty list. When the tab stops are exhausted, they implicitly continue at 50 pixel intervals.
wrap
- Boolean. If True (the default), text wraps within the width of the layout.
Other attributes can be used to store additional style information within the document; it will be ignored by the built-in text classes.
All style attributes (including those not present in a document) default to
None
(including the so-called “boolean” styles listed above). The meaning
of a None
style is style- and application-dependent.
New in version 1.1.
-
class
AbstractDocument
(text='')¶ Abstract document interface used by all
pyglet.text
classes.This class can be overridden to interface pyglet with a third-party document format. It may be easier to implement the document format in terms of one of the supplied concrete classes
FormattedDocument
orUnformattedDocument
.-
delete_text
(start, end)¶ Delete text from the document.
Parameters: - start (int) – Starting character position to delete from.
- end (int) – Ending character position to delete to (exclusive).
-
get_element
(position)¶ Get the element at a specified position.
Parameters: position (int) – Position in the document of the element. Return type: InlineElement
-
get_font
(position, dpi=None)¶ Get the font instance used at the given position.
See: get_font_runs
Parameters: - position (int) – Character position of document to query.
- dpi (float) – Optional resolution to construct fonts at. See
pyglet.font.load()
.
Return type: pyglet.font.Font
Returns: The font at the given position.
-
get_font_runs
(dpi=None)¶ Get a style iterator over the pyglet.font.Font instances used in the document.
The font instances are created on-demand by inspection of the
font_name
,font_size
,bold
anditalic
style attributes.Parameters: dpi (float) – Optional resolution to construct fonts at. See pyglet.font.load()
.Return type: AbstractRunIterator
-
get_paragraph_end
(pos)¶ Get the end position of a paragraph.
Parameters: pos (int) – Character position within paragraph. Return type: int
-
get_paragraph_start
(pos)¶ Get the starting position of a paragraph.
Parameters: pos (int) – Character position within paragraph. Return type: int
-
get_style
(attribute, position=0)¶ Get an attribute style at the given position.
Parameters: - attribute (str) – Name of style attribute to query.
- position (int) – Character position of document to query.
Returns: The style set for the attribute at the given position.
-
get_style_range
(attribute, start, end)¶ Get an attribute style over the given range.
If the style varies over the range, STYLE_INDETERMINATE is returned.
Parameters: - attribute (str) – Name of style attribute to query.
- start (int) – Starting character position.
- end (int) – Ending character position (exclusive).
Returns: The style set for the attribute over the given range, or STYLE_INDETERMINATE if more than one value is set.
-
get_style_runs
(attribute)¶ Get a style iterator over the given style attribute.
Parameters: attribute (str) – Name of style attribute to query. Return type: AbstractRunIterator
-
insert_element
(position, element, attributes=None)¶ Insert a element into the document.
See the
InlineElement
class documentation for details of usage.Parameters: - position (int) – Character insertion point within document.
- element (InlineElement) – Element to insert.
- attributes (dict) – Optional dictionary giving named style attributes of the inserted text.
-
insert_text
(start, text, attributes=None)¶ Insert text into the document.
Parameters: - start (int) – Character insertion point within document.
- text (str) – Text to insert.
- attributes (dict) – Optional dictionary giving named style attributes of the inserted text.
-
on_delete_text
(start, end)¶ Text was deleted from the document.
Parameters: - start (int) – Starting character position of deleted text.
- end (int) – Ending character position of deleted text (exclusive).
-
on_insert_text
(start, text)¶ Text was inserted into the document.
Parameters: - start (int) – Character insertion point within document.
- text (str) – The text that was inserted.
-
on_style_text
(start, end, attributes)¶ Text character style was modified.
Parameters: - start (int) – Starting character position of modified text.
- end (int) – Ending character position of modified text (exclusive).
- attributes (dict) – Dictionary giving updated named style attributes of the text.
-
set_paragraph_style
(start, end, attributes)¶ Set the style for a range of paragraphs.
This is a convenience method for set_style that aligns the character range to the enclosing paragraph(s).
Parameters: - start (int) – Starting character position.
- end (int) – Ending character position (exclusive).
- attributes (dict) – Dictionary giving named style attributes of the paragraphs.
-
set_style
(start, end, attributes)¶ Set text style of some or all of the document.
Parameters: - start (int) – Starting character position.
- end (int) – Ending character position (exclusive).
- attributes (dict) – Dictionary giving named style attributes of the text.
-
event_types
= ['on_insert_text', 'on_delete_text', 'on_style_text']¶
-
text
¶ Document text.
For efficient incremental updates, use the
insert_text()
anddelete_text()
methods instead of replacing this property.Type: str
-
-
class
FormattedDocument
(text='')¶ Simple implementation of a document that maintains text formatting.
Changes to text style are applied according to the description in
AbstractDocument
. All styles default toNone
.-
get_element_runs
()¶
-
get_font
(position, dpi=None)¶ Get the font instance used at the given position.
See: get_font_runs
Parameters: - position (int) – Character position of document to query.
- dpi (float) – Optional resolution to construct fonts at. See
pyglet.font.load()
.
Return type: pyglet.font.Font
Returns: The font at the given position.
-
get_font_runs
(dpi=None)¶ Get a style iterator over the pyglet.font.Font instances used in the document.
The font instances are created on-demand by inspection of the
font_name
,font_size
,bold
anditalic
style attributes.Parameters: dpi (float) – Optional resolution to construct fonts at. See pyglet.font.load()
.Return type: AbstractRunIterator
-
get_style
(attribute, position=0)¶ Get an attribute style at the given position.
Parameters: - attribute (str) – Name of style attribute to query.
- position (int) – Character position of document to query.
Returns: The style set for the attribute at the given position.
-
get_style_runs
(attribute)¶ Get a style iterator over the given style attribute.
Parameters: attribute (str) – Name of style attribute to query. Return type: AbstractRunIterator
-
-
class
InlineElement
(ascent, descent, advance)¶ Arbitrary inline element positioned within a formatted document.
Elements behave like a single glyph in the document. They are measured by their horizontal advance, ascent above the baseline, and descent below the baseline.
The pyglet layout classes reserve space in the layout for elements and call the element’s methods to ensure they are rendered at the appropriate position.
If the size of a element (any of the advance, ascent, or descent instance variables) is modified it is the application’s responsibility to trigger a reflow of the appropriate area in the affected layouts. This can be done by forcing a style change over the element’s position.
Variables: - ascent (int) – Ascent of the element above the baseline, in pixels.
- descent (int) – Descent of the element below the baseline, in pixels. Typically negative.
- advance (int) – Width of the element, in pixels.
-
place
(layout, x, y)¶ Construct an instance of the element at the given coordinates.
Called when the element’s position within a layout changes, either due to the initial condition, changes in the document or changes in the layout size.
It is the responsibility of the element to clip itself against the layout boundaries, and position itself appropriately with respect to the layout’s position and viewport offset.
The TextLayout.top_state graphics state implements this transform and clipping into window space.
Parameters: - layout (pyglet.text.layout.TextLayout) – The layout the element moved within.
- x (int) – Position of the left edge of the element, relative to the left edge of the document, in pixels.
- y (int) – Position of the baseline, relative to the top edge of the document, in pixels. Note that this is typically negative.
-
remove
(layout)¶ Remove this element from a layout.
The counterpart of place; called when the element is no longer visible in the given layout.
Parameters: layout (pyglet.text.layout.TextLayout) – The layout the element was removed from.
-
position
¶ Position of the element within the document. Read-only.
Type: int
-
class
UnformattedDocument
(text='')¶ A document having uniform style over all text.
Changes to the style of text within the document affects the entire document. For convenience, the
position
parameters of the style methods may therefore be omitted.-
get_element_runs
()¶
-
get_font
(position=None, dpi=None)¶ Get the font instance used at the given position.
See: get_font_runs
Parameters: - position (int) – Character position of document to query.
- dpi (float) – Optional resolution to construct fonts at. See
pyglet.font.load()
.
Return type: pyglet.font.Font
Returns: The font at the given position.
-
get_font_runs
(dpi=None)¶ Get a style iterator over the pyglet.font.Font instances used in the document.
The font instances are created on-demand by inspection of the
font_name
,font_size
,bold
anditalic
style attributes.Parameters: dpi (float) – Optional resolution to construct fonts at. See pyglet.font.load()
.Return type: AbstractRunIterator
-
get_style
(attribute, position=None)¶ Get an attribute style at the given position.
Parameters: - attribute (str) – Name of style attribute to query.
- position (int) – Character position of document to query.
Returns: The style set for the attribute at the given position.
-
get_style_runs
(attribute)¶ Get a style iterator over the given style attribute.
Parameters: attribute (str) – Name of style attribute to query. Return type: AbstractRunIterator
-
set_paragraph_style
(start, end, attributes)¶ Set the style for a range of paragraphs.
This is a convenience method for set_style that aligns the character range to the enclosing paragraph(s).
Parameters: - start (int) – Starting character position.
- end (int) – Ending character position (exclusive).
- attributes (dict) – Dictionary giving named style attributes of the paragraphs.
-
set_style
(start, end, attributes)¶ Set text style of some or all of the document.
Parameters: - start (int) – Starting character position.
- end (int) – Ending character position (exclusive).
- attributes (dict) – Dictionary giving named style attributes of the text.
-
-
STYLE_INDETERMINATE
= 'indeterminate'¶ The style attribute takes on multiple values in the document.
pyglet.text.layout¶
Render simple text and formatted documents efficiently.
Three layout classes are provided:
TextLayout
The entire document is laid out before it is rendered. The layout will be grouped with other layouts in the same batch (allowing for efficient rendering of multiple layouts).
Any change to the layout or document, and even querying some properties, will cause the entire document to be laid out again.
ScrollableTextLayout
Based on
TextLayout()
.A separate group is used for layout which crops the contents of the layout to the layout rectangle. Additionally, the contents of the layout can be “scrolled” within that rectangle with the
view_x
andview_y
properties.IncrementalTextLayout
Based on
ScrollableTextLayout
.When the layout or document are modified, only the affected regions are laid out again. This permits efficient interactive editing and styling of text.
Only the visible portion of the layout is actually rendered; as the viewport is scrolled additional sections are rendered and discarded as required. This permits efficient viewing and editing of large documents.
Additionally, this class provides methods for locating the position of a caret in the document, and for displaying interactive text selections.
All three layout classes can be used with either UnformattedDocument
or
FormattedDocument
, and can be either single-line or multiline
. The
combinations of these options effectively provides 12 different text display
possibilities.
Style attributes¶
The following character style attribute names are recognised by the layout classes. Data types and units are as specified.
Where an attribute is marked “as a distance” the value is assumed to be
in pixels if given as an int or float, otherwise a string of the form
"0u"
is required, where 0
is the distance and u
is the unit; one
of "px"
(pixels), "pt"
(points), "pc"
(picas), "cm"
(centimeters), "mm"
(millimeters) or "in"
(inches). For example,
"14pt"
is the distance covering 14 points, which at the default DPI of 96
is 18 pixels.
font_name
- Font family name, as given to
pyglet.font.load()
. font_size
- Font size, in points.
bold
- Boolean.
italic
- Boolean.
underline
- 4-tuple of ints in range (0, 255) giving RGBA underline color, or None (default) for no underline.
kerning
- Additional space to insert between glyphs, as a distance. Defaults to 0.
baseline
- Offset of glyph baseline from line baseline, as a distance. Positive values give a superscript, negative values give a subscript. Defaults to 0.
color
- 4-tuple of ints in range (0, 255) giving RGBA text color
background_color
- 4-tuple of ints in range (0, 255) giving RGBA text background color; or
None
for no background fill.
The following paragraph style attribute names are recognised. Note that paragraph styles are handled no differently from character styles by the document: it is the application’s responsibility to set the style over an entire paragraph, otherwise results are undefined.
align
left
(default),center
orright
.indent
- Additional horizontal space to insert before the first glyph of the first line of a paragraph, as a distance.
leading
- Additional space to insert between consecutive lines within a paragraph, as a distance. Defaults to 0.
line_spacing
- Distance between consecutive baselines in a paragraph, as a distance.
Defaults to
None
, which automatically calculates the tightest line spacing for each line based on the font ascent and descent. margin_left
- Left paragraph margin, as a distance.
margin_right
- Right paragraph margin, as a distance.
margin_top
- Margin above paragraph, as a distance.
margin_bottom
- Margin below paragraph, as a distance. Adjacent margins do not collapse.
tab_stops
- List of horizontal tab stops, as distances, measured from the left edge of the text layout. Defaults to the empty list. When the tab stops are exhausted, they implicitly continue at 50 pixel intervals.
wrap
char
,word
, True (default) or False. The boundaries at which to wrap text to prevent it overflowing a line. Withchar
, the line wraps anywhere in the text; withword
or True, the line wraps at appropriate boundaries between words; with False the line does not wrap, and may overflow the layout width.char
andword
styles are since pyglet 1.2.
Other attributes can be used to store additional style information within the document; they will be ignored by the built-in text classes.
New in version 1.1.
-
class
IncrementalTextLayout
(document, width, height, multiline=False, dpi=None, batch=None, group=None, wrap_lines=True)¶ Displayed text suitable for interactive editing and/or scrolling large documents.
Unlike
TextLayout()
andScrollableTextLayout
, this class generates vertex lists only for lines of text that are visible. As the document is scrolled, vertex lists are deleted and created as appropriate to keep video memory usage to a minimum and improve rendering speed.Changes to the document are quickly reflected in this layout, as only the affected line(s) are reflowed. Use begin_update and end_update to further reduce the amount of processing required.
The layout can also display a text selection (text with a different background color). The
Caret
class implements a visible text cursor and provides event handlers for scrolling, selecting and editing text in an incremental text layout.-
delete
()¶ Remove this layout from its batch.
-
ensure_line_visible
(line)¶ Adjust view_y so that the line with the given index is visible.
Parameters: line (int) – Line index.
-
ensure_x_visible
(x)¶ Adjust view_x so that the given X coordinate is visible.
The X coordinate is given relative to the current view_x.
Parameters: x (int) – X coordinate
-
get_line_count
()¶ Get the number of lines in the text layout.
Return type: int
-
get_line_from_point
(x, y)¶ Get the closest line index to a point.
Parameters: - x (int) – X coordinate.
- y (int) – Y coordinate.
Return type: int
-
get_line_from_position
(position)¶ Get the line index of a character position in the document.
Parameters: position (int) – Document position. Return type: int
-
get_point_from_line
(line)¶ Get the X, Y coordinates of a line index.
Parameters: line (int) – Line index. Return type: (int, int) Returns: (x, y)
-
get_point_from_position
(position, line=None)¶ Get the X, Y coordinates of a position in the document.
The position that ends a line has an ambiguous point: it can be either the end of the line, or the beginning of the next line. You may optionally specify a line index to disambiguate the case.
The resulting Y coordinate gives the baseline of the line.
Parameters: - position (int) – Character position within document.
- line (int) – Line index.
Return type: (int, int)
Returns: (x, y)
-
get_position_from_line
(line)¶ Get the first document character position of a given line index.
Parameters: line (int) – Line index. Return type: int
-
get_position_from_point
(x, y)¶ Get the closest document position to a point.
Parameters: - x (int) – X coordinate
- y (int) – Y coordinate
-
get_position_on_line
(line, x)¶ Get the closest document position for a given line index and X coordinate.
Parameters: - line (int) – Line index.
- x (int) – X coordinate.
Return type: int
-
on_delete_text
(start, end)¶ Event handler for AbstractDocument.on_delete_text.
The event handler is bound by the text layout; there is no need for applications to interact with this method.
-
on_insert_text
(start, text)¶ Event handler for AbstractDocument.on_insert_text.
The event handler is bound by the text layout; there is no need for applications to interact with this method.
-
on_layout_update
()¶ Some or all of the layout text was reflowed.
Text reflow is caused by document edits or changes to the layout’s size. Changes to the layout’s position or active selection, and certain document edits such as text color, do not cause a reflow.
Handle this event to update the position of a graphical element that depends on the laid out position of a glyph or line.
-
on_style_text
(start, end, attributes)¶ Event handler for AbstractDocument.on_style_text.
The event handler is bound by the text layout; there is no need for applications to interact with this method.
-
set_selection
(start, end)¶ Set the text selection range.
If
start
equalsend
no selection will be visible.Parameters: - start (int) – Starting character position of selection.
- end (int) – End of selection, exclusive.
-
anchor_x
¶ Horizontal anchor alignment.
This property determines the meaning of the x coordinate. It is one of the enumerants:
"left"
(default)- The X coordinate gives the position of the left edge of the layout.
"center"
- The X coordinate gives the position of the center of the layout.
"right"
- The X coordinate gives the position of the right edge of the layout.
For the purposes of calculating the position resulting from this alignment, the width of the layout is taken to be width if multiline is True and wrap_lines is True, otherwise content_width.
Type: str
-
anchor_y
¶ Vertical anchor alignment.
This property determines the meaning of the y coordinate. It is one of the enumerants:
"top"
- The Y coordinate gives the position of the top edge of the layout.
"center"
- The Y coordinate gives the position of the center of the layout.
"baseline"
- The Y coordinate gives the position of the baseline of the first line of text in the layout.
"bottom"
(default)- The Y coordinate gives the position of the bottom edge of the layout.
For the purposes of calculating the position resulting from this alignment, the height of the layout is taken to be the smaller of height and content_height.
See also content_valign.
Type: str
-
event_types
= ['on_layout_update']¶
-
height
¶ Height of the layout.
Type: int
-
multiline
¶ Set if multiline layout is enabled.
If multiline is False, newline and paragraph characters are ignored and text is not word-wrapped. If True, the text is word-wrapped only if the wrap_lines is True.
Type: bool
-
position
¶ The (X, Y) coordinates of the layout, as a tuple.
See also
anchor_x
, andanchor_y
.Type: (int, int)
-
selection_background_color
¶ Background color of active selection.
The color is an RGBA tuple with components in range [0, 255].
Type: (int, int, int, int)
-
selection_color
¶ Text color of active selection.
The color is an RGBA tuple with components in range [0, 255].
Type: (int, int, int, int)
-
selection_end
¶ End position of the active selection (exclusive).
See: set_selection Type: int
-
selection_start
¶ Starting position of the active selection.
See: set_selection Type: int
-
view_x
¶ Horizontal scroll offset.
The initial value is 0, and the left edge of the text will touch the left side of the layout bounds. A positive value causes the text to “scroll” to the right. Values are automatically clipped into the range
[0, content_width - width]
Type: int
-
view_y
¶ Vertical scroll offset.
The initial value is 0, and the top of the text will touch the top of the layout bounds (unless the content height is less than the layout height, in which case content_valign is used).
A negative value causes the text to “scroll” upwards. Values outside of the range
[height - content_height, 0]
are automatically clipped in range.Type: int
-
width
¶ Width of the layout.
This property has no effect if multiline is False or wrap_lines is False.
Type: int
-
y
¶ Y coordinate of the layout.
See also anchor_y.
Type: int
-
-
class
IncrementalTextLayoutGroup
(parent=None)¶ Top-level rendering group for
IncrementalTextLayout
.The group maintains internal state for setting the clipping planes and view transform for scrolling. Because the group has internal state specific to the text layout, the group is never shared.
-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
unset_state
()¶ Repeal the OpenGL state change.
The default implementation does nothing.
-
height
¶
-
left
¶
-
top
¶
-
translate_x
= 0¶
-
translate_y
= 0¶
-
view_x
¶
-
view_y
¶
-
width
¶
-
-
class
ScrollableTextLayout
(document, width, height, multiline=False, dpi=None, batch=None, group=None, wrap_lines=True)¶ Display text in a scrollable viewport.
This class does not display a scrollbar or handle scroll events; it merely clips the text that would be drawn in
TextLayout()
to the bounds of the layout given by x, y, width and height; and offsets the text by a scroll offset.Use view_x and view_y to scroll the text within the viewport.
-
anchor_x
¶ Horizontal anchor alignment.
This property determines the meaning of the x coordinate. It is one of the enumerants:
"left"
(default)- The X coordinate gives the position of the left edge of the layout.
"center"
- The X coordinate gives the position of the center of the layout.
"right"
- The X coordinate gives the position of the right edge of the layout.
For the purposes of calculating the position resulting from this alignment, the width of the layout is taken to be width if multiline is True and wrap_lines is True, otherwise content_width.
Type: str
-
anchor_y
¶ Vertical anchor alignment.
This property determines the meaning of the y coordinate. It is one of the enumerants:
"top"
- The Y coordinate gives the position of the top edge of the layout.
"center"
- The Y coordinate gives the position of the center of the layout.
"baseline"
- The Y coordinate gives the position of the baseline of the first line of text in the layout.
"bottom"
(default)- The Y coordinate gives the position of the bottom edge of the layout.
For the purposes of calculating the position resulting from this alignment, the height of the layout is taken to be the smaller of height and content_height.
See also content_valign.
Type: str
-
position
¶ The (X, Y) coordinates of the layout, as a tuple.
See also
anchor_x
, andanchor_y
.Type: (int, int)
-
view_x
¶ Horizontal scroll offset.
The initial value is 0, and the left edge of the text will touch the left side of the layout bounds. A positive value causes the text to “scroll” to the right. Values are automatically clipped into the range
[0, content_width - width]
Type: int
-
view_y
¶ Vertical scroll offset.
The initial value is 0, and the top of the text will touch the top of the layout bounds (unless the content height is less than the layout height, in which case content_valign is used).
A negative value causes the text to “scroll” upwards. Values outside of the range
[height - content_height, 0]
are automatically clipped in range.Type: int
-
y
¶ Y coordinate of the layout.
See also anchor_y.
Type: int
-
-
class
ScrollableTextLayoutGroup
(parent=None)¶ Top-level rendering group for
ScrollableTextLayout
.The group maintains internal state for setting the clipping planes and view transform for scrolling. Because the group has internal state specific to the text layout, the group is never shared.
-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
unset_state
()¶ Repeal the OpenGL state change.
The default implementation does nothing.
-
height
= 0¶
-
view_x
= 0¶
-
view_y
= 0¶
-
width
= 0¶
-
x
= 0¶
-
y
= 0¶
-
-
class
TextLayout
(document, width=None, height=None, multiline=False, dpi=None, batch=None, group=None, wrap_lines=True)¶ Lay out and display documents.
This class is intended for displaying documents that do not change regularly – any change will cost some time to lay out the complete document again and regenerate all vertex lists.
The benefit of this class is that texture state is shared between all layouts of this class. The time to draw one
TextLayout()
may be roughly the same as the time to draw oneIncrementalTextLayout
; but drawing tenTextLayout()
objects in one batch is much faster than drawing ten incremental or scrollable text layouts.Label()
andHTMLLabel()
provide a convenient interface to this class.Variables: - content_width (int) – Calculated width of the text in the layout. This may overflow the desired width if word-wrapping failed.
- content_height (int) – Calculated height of the text in the layout.
- top_group (Group) – Top-level rendering group.
- background_group (Group) – Rendering group for background color.
- foreground_group (Group) – Rendering group for glyphs.
- foreground_decoration_group (Group) – Rendering group for glyph underlines.
-
begin_update
()¶ Indicate that a number of changes to the layout or document are about to occur.
Changes to the layout or document between calls to begin_update and end_update do not trigger any costly relayout of text. Relayout of all changes is performed when end_update is called.
Note that between the begin_update and end_update calls, values such as content_width and content_height are undefined (i.e., they may or may not be updated to reflect the latest changes).
-
delete
()¶ Remove this layout from its batch.
-
draw
()¶ Draw this text layout.
Note that this method performs very badly if a batch was supplied to the constructor. If you add this layout to a batch, you should ideally use only the batch’s draw method.
-
end_update
()¶ Perform pending layout changes since begin_update.
See begin_update.
-
on_delete_text
(start, end)¶ Event handler for AbstractDocument.on_delete_text.
The event handler is bound by the text layout; there is no need for applications to interact with this method.
-
on_insert_text
(start, text)¶ Event handler for AbstractDocument.on_insert_text.
The event handler is bound by the text layout; there is no need for applications to interact with this method.
-
on_style_text
(start, end, attributes)¶ Event handler for AbstractDocument.on_style_text.
The event handler is bound by the text layout; there is no need for applications to interact with this method.
-
update
(x, y)¶ Change both X and Y positions of the layout at once for faster performance.
Parameters: - x (int) – X coordinate of the layout.
- y (int) – Y coordinate of the layout.
-
anchor_x
¶ Horizontal anchor alignment.
This property determines the meaning of the x coordinate. It is one of the enumerants:
"left"
(default)- The X coordinate gives the position of the left edge of the layout.
"center"
- The X coordinate gives the position of the center of the layout.
"right"
- The X coordinate gives the position of the right edge of the layout.
For the purposes of calculating the position resulting from this alignment, the width of the layout is taken to be width if multiline is True and wrap_lines is True, otherwise content_width.
Type: str
-
anchor_y
¶ Vertical anchor alignment.
This property determines the meaning of the y coordinate. It is one of the enumerants:
"top"
- The Y coordinate gives the position of the top edge of the layout.
"center"
- The Y coordinate gives the position of the center of the layout.
"baseline"
- The Y coordinate gives the position of the baseline of the first line of text in the layout.
"bottom"
(default)- The Y coordinate gives the position of the bottom edge of the layout.
For the purposes of calculating the position resulting from this alignment, the height of the layout is taken to be the smaller of height and content_height.
See also content_valign.
Type: str
-
background_group
= OrderedGroup(0)¶
-
batch
¶ The Batch that this Layout is assigned to.
If no Batch is assigned, an internal Batch is created and used.
Type: Batch
-
content_valign
¶ Vertical alignment of content within larger layout box.
This property determines how content is positioned within the layout box when
content_height
is less thanheight
. It is one of the enumerants:top
(default)- Content is aligned to the top of the layout box.
center
- Content is centered vertically within the layout box.
bottom
- Content is aligned to the bottom of the layout box.
This property has no effect when
content_height
is greater thanheight
(in which case the content is aligned to the top) or whenheight
isNone
(in which case there is no vertical layout box dimension).Type: str
-
document
¶ Document to display.
For
IncrementalTextLayout
it is far more efficient to modify a document in-place than to replace the document instance on the layout.Type: AbstractDocument
-
dpi
¶ Get DPI used by this layout.
Type: float
-
foreground_decoration_group
= TextLayoutForegroundDecorationGroup(2)¶
-
foreground_group
= TextLayoutForegroundGroup(1)¶
-
height
¶ Height of the layout.
Type: int
-
multiline
¶ Set if multiline layout is enabled.
If multiline is False, newline and paragraph characters are ignored and text is not word-wrapped. If True, the text is word-wrapped only if the wrap_lines is True.
Type: bool
-
position
¶ The (X, Y) coordinates of the layout, as a tuple.
See also
anchor_x
, andanchor_y
.Type: (int, int)
-
top_group
= TextLayoutGroup(None)¶
-
visible
¶ True if the layout will be drawn.
Type: bool
-
width
¶ Width of the layout.
This property has no effect if multiline is False or wrap_lines is False.
Type: int
-
y
¶ Y coordinate of the layout.
See also anchor_y.
Type: int
-
class
TextLayoutForegroundDecorationGroup
(order, parent=None)¶ Rendering group for decorative elements (e.g., glyph underlines) in all text layouts.
The group disables
GL_TEXTURE_2D
.-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
-
class
TextLayoutForegroundGroup
(order, parent=None)¶ Rendering group for foreground elements (glyphs) in all text layouts.
The group enables
GL_TEXTURE_2D
.-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
-
class
TextLayoutGroup
(parent=None)¶ Top-level rendering group for
TextLayout()
.The blend function is set for glyph rendering (
GL_SRC_ALPHA
/GL_ONE_MINUS_SRC_ALPHA
). The group is shared by allTextLayout()
instances as it has no internal state.-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
unset_state
()¶ Repeal the OpenGL state change.
The default implementation does nothing.
-
-
class
TextLayoutTextureGroup
(texture, parent)¶ Rendering group for a glyph texture in all text layouts.
The group binds its texture to
GL_TEXTURE_2D
. The group is shared between all other text layout uses of the same texture.-
set_state
()¶ Apply the OpenGL state change.
The default implementation does nothing.
-
Details
Text formatting, layout and display.
This module provides classes for loading styled documents from text files, HTML files and a pyglet-specific markup format. Documents can be styled with multiple fonts, colours, styles, text sizes, margins, paragraph alignments, and so on.
Using the layout classes, documents can be laid out on a single line or word-wrapped to fit a rectangle. A layout can then be efficiently drawn in a window or updated incrementally (for example, to support interactive text editing).
The label classes provide a simple interface for the common case where an application simply needs to display some text in a window.
A plain text label can be created with:
label = pyglet.text.Label('Hello, world',
font_name='Times New Roman',
font_size=36,
x=10, y=10)
Alternatively, a styled text label using HTML can be created with:
label = pyglet.text.HTMLLabel('<b>Hello</b>, <i>world</i>',
x=10, y=10)
Either label can then be drawn at any time with:
label.draw()
For details on the subset of HTML supported, see pyglet.text.formats.html.
Refer to the Programming Guide for advanced usage of the document and layout classes, including interactive editing, embedding objects within documents and creating scrollable layouts.
New in version 1.1.
-
exception
DocumentDecodeException
¶ An error occurred decoding document text.
-
class
DocumentDecoder
¶ Abstract document decoder.
-
class
DocumentLabel
(document=None, x=0, y=0, width=None, height=None, anchor_x='left', anchor_y='baseline', multiline=False, dpi=None, batch=None, group=None)¶ Base label class.
A label is a layout that exposes convenience methods for manipulating the associated document.
-
get_style
(name)¶ Get a document style value by name.
If the document has more than one value of the named style, pyglet.text.document.STYLE_INDETERMINATE is returned.
Parameters: name (str) – Style name to query. See documentation for pyglet.text.layout for known style names. Return type: object
-
set_style
(name, value)¶ Set a document style value by name over the whole document.
Parameters: - name (str) – Name of the style to set. See documentation for pyglet.text.layout for known style names.
- value (object) – Value of the style.
-
bold
¶ Bold font style.
Type: bool
-
color
¶ Text color.
Color is a 4-tuple of RGBA components, each in range [0, 255].
Type: (int, int, int, int)
-
font_name
¶ Font family name.
The font name, as passed to
pyglet.font.load()
. A list of names can optionally be given: the first matching font will be used.Type: str or list
-
font_size
¶ Font size, in points.
Type: float
-
italic
¶ Italic font style.
Type: bool
-
opacity
¶ Blend opacity.
This property sets the alpha component of the colour of the label’s vertices. With the default blend mode, this allows the layout to be drawn with fractional opacity, blending with the background.
An opacity of 255 (the default) has no effect. An opacity of 128 will make the label appear semi-translucent.
Type: int
-
text
¶ The text of the label.
Type: str
-
-
class
HTMLLabel
(text='', location=None, x=0, y=0, width=None, height=None, anchor_x='left', anchor_y='baseline', multiline=False, dpi=None, batch=None, group=None)¶ HTML formatted text label.
A subset of HTML 4.01 is supported. See pyglet.text.formats.html for details.
-
text
¶ HTML formatted text of the label.
Type: str
-
-
class
Label
(text='', font_name=None, font_size=None, bold=False, italic=False, stretch=False, color=(255, 255, 255, 255), x=0, y=0, width=None, height=None, anchor_x='left', anchor_y='baseline', align='left', multiline=False, dpi=None, batch=None, group=None)¶ Plain text label.
-
decode_attributed
(text)¶ Create a document directly from some attributed text.
See pyglet.text.formats.attributed for a description of attributed text.
Parameters: text (str) – Attributed text to decode. Return type: FormattedDocument
-
decode_html
(text, location=None)¶ Create a document directly from some HTML formatted text.
Parameters: - text (str) – HTML data to decode.
- location (str) – Location giving the base path for additional resources referenced from the document (e.g., images).
Return type: FormattedDocument
-
decode_text
(text)¶ Create a document directly from some plain text.
Parameters: text (str) – Plain text to initialise the document with. Return type: UnformattedDocument
-
get_decoder
(filename, mimetype=None)¶ Get a document decoder for the given filename and MIME type.
If mimetype is omitted it is guessed from the filename extension.
The following MIME types are supported:
text/plain
- Plain text
text/html
- HTML 4 Transitional
text/vnd.pyglet-attributed
- Attributed text; see pyglet.text.formats.attributed
DocumentDecodeException is raised if another MIME type is given.
Parameters: - filename (str) – Filename to guess the MIME type from. If a MIME type is given, the filename is ignored.
- mimetype (str) – MIME type to lookup, or
None
to guess the type from the filename.
Return type: DocumentDecoder
-
load
(filename, file=None, mimetype=None)¶ Load a document from a file.
Parameters: - filename (str) – Filename of document to load.
- file (file-like object) – File object containing encoded data. If omitted, filename is loaded from disk.
- mimetype (str) – MIME type of the document. If omitted, the filename extension is used to guess a MIME type. See get_decoder for a list of supported MIME types.
Return type: AbstractDocument
pyglet.window¶
Submodules
pyglet.window.key¶
Key constants and utilities for pyglet.window.
Usage:
from pyglet.window import Window
from pyglet.window import key
window = Window()
@window.event
def on_key_press(symbol, modifiers):
# Symbolic names:
if symbol == key.RETURN:
# Alphabet keys:
elif symbol == key.Z:
# Number keys:
elif symbol == key._1:
# Number keypad keys:
elif symbol == key.NUM_1:
# Modifiers:
if modifiers & key.MOD_CTRL:
-
class
KeyStateHandler
¶ Simple handler that tracks the state of keys on the keyboard. If a key is pressed then this handler holds a True value for it. If the window loses focus, all keys will be reset to False to avoid a “sticky” key state.
For example:
>>> win = window.Window >>> keyboard = key.KeyStateHandler() >>> win.push_handlers(keyboard) # Hold down the "up" arrow... >>> keyboard[key.UP] True >>> keyboard[key.DOWN] False
-
modifiers_string
(modifiers)¶ Return a string describing a set of modifiers.
Example:
>>> modifiers_string(MOD_SHIFT | MOD_CTRL) 'MOD_SHIFT|MOD_CTRL'
Parameters: modifiers (int) – Bitwise combination of modifier constants. Return type: str
-
symbol_string
(symbol)¶ Return a string describing a key symbol.
Example:
>>> symbol_string(BACKSPACE) 'BACKSPACE'
Parameters: symbol (int) – Symbolic key constant. Return type: str
-
motion_string
(motion)¶ Return a string describing a text motion.
Example:
>>> motion_string(MOTION_NEXT_WORD) 'MOTION_NEXT_WORD'
Parameters: motion (int) – Text motion constant. Return type: str
-
user_key
(scancode)¶ Return a key symbol for a key not supported by pyglet.
This can be used to map virtual keys or scancodes from unsupported keyboard layouts into a machine-specific symbol. The symbol will be meaningless on any other machine, or under a different keyboard layout.
Applications should use user-keys only when user explicitly binds them (for example, mapping keys to actions in a game options screen).
Key Constants¶
Modifier mask constants¶
MOD_SHIFT |
MOD_CTRL |
MOD_ALT |
MOD_CAPSLOCK |
MOD_NUMLOCK |
MOD_WINDOWS |
MOD_COMMAND |
MOD_OPTION |
MOD_SCROLLLOCK |
MOD_FUNCTION |
MOD_ACCEL (MOD_CTRL on Windows & Linux, MOD_CMD on OS X) |
ASCII commands¶
BACKSPACE |
TAB |
LINEFEED |
CLEAR |
RETURN |
ENTER |
PAUSE |
SCROLLLOCK |
SYSREQ |
ESCAPE |
SPACE |
Cursor control and motion¶
HOME |
LEFT |
UP |
RIGHT |
DOWN |
PAGEUP |
PAGEDOWN |
END |
BEGIN |
Misc functions¶
DELETE |
SELECT |
PRINT |
EXECUTE |
INSERT |
UNDO |
REDO |
MENU |
FIND |
CANCEL |
HELP |
BREAK |
MODESWITCH |
SCRIPTSWITCH |
FUNCTION |
Text motion constants¶
These are allowed to clash with key constants.
MOTION_UP |
MOTION_RIGHT |
MOTION_DOWN |
MOTION_LEFT |
MOTION_NEXT_WORD |
MOTION_PREVIOUS_WORD |
MOTION_BEGINNING_OF_LINE |
MOTION_END_OF_LINE |
MOTION_NEXT_PAGE |
MOTION_PREVIOUS_PAGE |
MOTION_BEGINNING_OF_FILE |
MOTION_END_OF_FILE |
MOTION_BACKSPACE |
MOTION_DELETE |
Number pad¶
NUMLOCK |
NUM_SPACE |
NUM_TAB |
NUM_ENTER |
NUM_F1 |
NUM_F2 |
NUM_F3 |
NUM_F4 |
NUM_HOME |
NUM_LEFT |
NUM_UP |
NUM_RIGHT |
NUM_DOWN |
NUM_PRIOR |
NUM_PAGE_UP |
NUM_NEXT |
NUM_PAGE_DOWN |
NUM_END |
NUM_BEGIN |
NUM_INSERT |
NUM_DELETE |
NUM_EQUAL |
NUM_MULTIPLY |
NUM_ADD |
NUM_SEPARATOR |
NUM_SUBTRACT |
NUM_DECIMAL |
NUM_DIVIDE |
NUM_0 |
NUM_1 |
NUM_2 |
NUM_3 |
NUM_4 |
NUM_5 |
NUM_6 |
NUM_7 |
NUM_8 |
NUM_9 |
Function keys¶
F1 |
F2 |
F3 |
F4 |
F5 |
F6 |
F7 |
F8 |
F9 |
F10 |
F11 |
F12 |
F13 |
F14 |
F15 |
F16 |
F17 |
F18 |
F19 |
F20 |
Modifiers¶
LSHIFT |
RSHIFT |
LCTRL |
RCTRL |
CAPSLOCK |
LMETA |
RMETA |
LALT |
RALT |
LWINDOWS |
RWINDOWS |
LCOMMAND |
RCOMMAND |
LOPTION |
ROPTION |
Latin-1¶
SPACE |
EXCLAMATION |
DOUBLEQUOTE |
HASH |
POUND |
DOLLAR |
PERCENT |
AMPERSAND |
APOSTROPHE |
PARENLEFT |
PARENRIGHT |
ASTERISK |
PLUS |
COMMA |
MINUS |
PERIOD |
SLASH |
_0 |
_1 |
_2 |
_3 |
_4 |
_5 |
_6 |
_7 |
_8 |
_9 |
COLON |
SEMICOLON |
LESS |
EQUAL |
GREATER |
QUESTION |
AT |
BRACKETLEFT |
BACKSLASH |
BRACKETRIGHT |
ASCIICIRCUM |
UNDERSCORE |
GRAVE |
QUOTELEFT |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
N |
O |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
BRACELEFT |
BAR |
BRACERIGHT |
ASCIITILDE |
pyglet.window.mouse¶
Mouse constants and utilities for pyglet.window.
-
class
MouseStateHandler
¶ Simple handler that tracks the state of buttons from the mouse. If a button is pressed then this handler holds a True value for it. If the window loses focus, all buttons will be reset to False to avoid a “sticky” button state.
For example:
>>> win = window.Window() >>> mousebuttons = mouse.MouseStateHandler() >>> win.push_handlers(mousebuttons) # Hold down the "left" button... >>> mousebuttons[mouse.LEFT] True >>> mousebuttons[mouse.RIGHT] False
Return a string describing a set of active mouse buttons.
Example:
>>> buttons_string(LEFT | RIGHT) 'LEFT|RIGHT'
Parameters: buttons (int) – Bitwise combination of mouse button constants. Return type: str
Details
Windowing and user-interface events.
This module allows applications to create and display windows with an OpenGL context. Windows can be created with a variety of border styles or set fullscreen.
You can register event handlers for keyboard, mouse and window events. For games and kiosks you can also restrict the input to your windows, for example disabling users from switching away from the application with certain key combinations or capturing and hiding the mouse.
Getting started¶
Call the Window constructor to create a new window:
from pyglet.window import Window
win = Window(width=640, height=480)
Attach your own event handlers:
@win.event
def on_key_press(symbol, modifiers):
# ... handle this event ...
Place drawing code for the window within the Window.on_draw event handler:
@win.event
def on_draw():
# ... drawing code ...
Call pyglet.app.run to enter the main event loop (by default, this returns when all open windows are closed):
from pyglet import app
app.run()
Creating a game window¶
Use set_exclusive_mouse()
to hide the mouse
cursor and receive relative mouse movement events. Specify fullscreen=True
as a keyword argument to the Window
constructor to
render to the entire screen rather than opening a window:
win = Window(fullscreen=True)
win.set_exclusive_mouse()
Working with multiple screens¶
By default, fullscreen windows are opened on the primary display (typically set by the user in their operating system settings). You can retrieve a list of attached screens and select one manually if you prefer. This is useful for opening a fullscreen window on each screen:
display = pyglet.canvas.get_display()
screens = display.get_screens()
windows = []
for screen in screens:
windows.append(window.Window(fullscreen=True, screen=screen))
Specifying a screen has no effect if the window is not fullscreen.
Specifying the OpenGL context properties¶
Each window has its own context which is created when the window is created. You can specify the properties of the context before it is created by creating a “template” configuration:
from pyglet import gl
# Create template config
config = gl.Config()
config.stencil_size = 8
config.aux_buffers = 4
# Create a window using this config
win = window.Window(config=config)
To determine if a given configuration is supported, query the screen (see above, “Working with multiple screens”):
configs = screen.get_matching_configs(config)
if not configs:
# ... config is not supported
else:
win = window.Window(config=configs[0])
Classes¶
-
class
Window
(width=None, height=None, caption=None, resizable=False, style=None, fullscreen=False, visible=True, vsync=True, file_drops=False, display=None, screen=None, config=None, context=None, mode=None)¶ Bases:
pyglet.event.EventDispatcher
Platform-independent application window.
A window is a “heavyweight” object occupying operating system resources. The “client” or “content” area of a window is filled entirely with an OpenGL viewport. Applications have no access to operating system widgets or controls; all rendering must be done via OpenGL.
Windows may appear as floating regions or can be set to fill an entire screen (fullscreen). When floating, windows may appear borderless or decorated with a platform-specific frame (including, for example, the title bar, minimize and close buttons, resize handles, and so on).
While it is possible to set the location of a window, it is recommended that applications allow the platform to place it according to local conventions. This will ensure it is not obscured by other windows, and appears on an appropriate screen for the user.
To render into a window, you must first call switch_to, to make it the current OpenGL context. If you use only one window in the application, there is no need to do this.
Methods
-
activate
()¶ Attempt to restore keyboard focus to the window.
Depending on the window manager or operating system, this may not be successful. For example, on Windows XP an application is not allowed to “steal” focus from another application. Instead, the window’s taskbar icon will flash, indicating it requires attention.
-
clear
()¶ Clear the window.
This is a convenience method for clearing the color and depth buffer. The window must be the active context (see switch_to).
-
close
()¶ Close the window.
After closing the window, the GL context will be invalid. The window instance cannot be reused once closed (see also set_visible).
The pyglet.app.EventLoop.on_window_close event is dispatched on pyglet.app.event_loop when this method is called.
-
dispatch_event
(*args)¶
-
dispatch_events
()¶ Poll the operating system event queue for new events and call attached event handlers.
This method is provided for legacy applications targeting pyglet 1.0, and advanced applications that must integrate their event loop into another framework.
Typical applications should use pyglet.app.run.
-
draw_mouse_cursor
()¶ Draw the custom mouse cursor.
If the current mouse cursor has
drawable
set, this method is called before the buffers are flipped to render it.This method always leaves the
GL_MODELVIEW
matrix as current, regardless of what it was set to previously. No other GL state is affected.There is little need to override this method; instead, subclass
MouseCursor
and provide your owndraw()
method.
-
flip
()¶ Swap the OpenGL front and back buffers.
Call this method on a double-buffered window to update the visible display with the back buffer. The contents of the back buffer is undefined after this operation.
Windows are double-buffered by default. This method is called automatically by EventLoop after the
on_draw()
event.
-
get_location
()¶ Return the current position of the window.
Return type: (int, int) Returns: The distances of the left and top edges from their respective edges on the virtual desktop, in pixels.
-
get_size
()¶ Return the current size of the window.
The window size does not include the border or title bar.
Return type: (int, int) Returns: The width and height of the window, in pixels.
-
get_system_mouse_cursor
(name)¶ Obtain a system mouse cursor.
Use set_mouse_cursor to make the cursor returned by this method active. The names accepted by this method are the
CURSOR_*
constants defined on this class.Parameters: name (str) – Name describing the mouse cursor to return. For example, CURSOR_WAIT
,CURSOR_HELP
, etc.Return type: MouseCursor Returns: A mouse cursor which can be used with set_mouse_cursor.
-
maximize
()¶ Maximize the window.
The behaviour of this method is somewhat dependent on the user’s display setup. On a multi-monitor system, the window may maximize to either a single screen or the entire virtual desktop.
-
minimize
()¶ Minimize the window.
-
set_caption
(caption)¶ Set the window’s caption.
The caption appears in the titlebar of the window, if it has one, and in the taskbar on Windows and many X11 window managers.
Parameters: caption (str or unicode) – The caption to set.
-
set_exclusive_keyboard
(exclusive=True)¶ Prevent the user from switching away from this window using keyboard accelerators.
When enabled, this feature disables certain operating-system specific key combinations such as Alt+Tab (Command+Tab on OS X). This can be useful in certain kiosk applications, it should be avoided in general applications or games.
Parameters: exclusive (bool) – If True, exclusive keyboard is enabled, otherwise it is disabled.
-
set_exclusive_mouse
(exclusive=True)¶ Hide the mouse cursor and direct all mouse events to this window.
When enabled, this feature prevents the mouse leaving the window. It is useful for certain styles of games that require complete control of the mouse. The position of the mouse as reported in subsequent events is meaningless when exclusive mouse is enabled; you should only use the relative motion parameters
dx
anddy
.Parameters: exclusive (bool) – If True, exclusive mouse is enabled, otherwise it is disabled.
-
set_fullscreen
(fullscreen=True, screen=None, mode=None, width=None, height=None)¶ Toggle to or from fullscreen.
After toggling fullscreen, the GL context should have retained its state and objects, however the buffers will need to be cleared and redrawn.
If width and height are specified and fullscreen is True, the screen may be switched to a different resolution that most closely matches the given size. If the resolution doesn’t match exactly, a higher resolution is selected and the window will be centered within a black border covering the rest of the screen.
Parameters: - fullscreen (bool) – True if the window should be made fullscreen, False if it should be windowed.
- screen (Screen) – If not None and fullscreen is True, the window is moved to the given screen. The screen must belong to the same display as the window.
- mode (ScreenMode) – The screen will be switched to the given mode. The mode must have been obtained by enumerating Screen.get_modes. If None, an appropriate mode will be selected from the given width and height.
- width (int) – Optional width of the window. If unspecified, defaults to the previous window size when windowed, or the screen size if fullscreen. .. versionadded:: 1.2
- height (int) – Optional height of the window. If unspecified, defaults to the previous window size when windowed, or the screen size if fullscreen. .. versionadded:: 1.2
-
set_icon
(*images)¶ Set the window icon.
If multiple images are provided, one with an appropriate size will be selected (if the correct size is not provided, the image will be scaled).
Useful sizes to provide are 16x16, 32x32, 64x64 (Mac only) and 128x128 (Mac only).
Parameters: images (sequence of pyglet.image.AbstractImage) – List of images to use for the window icon.
-
set_location
(x, y)¶ Set the position of the window.
Parameters: - x (int) – Distance of the left edge of the window from the left edge of the virtual desktop, in pixels.
- y (int) – Distance of the top edge of the window from the top edge of the virtual desktop, in pixels.
-
set_maximum_size
(width, height)¶ Set the maximum size of the window.
Once set, the user will not be able to resize the window larger than the given dimensions. There is no way to remove the maximum size constraint on a window (but you could set it to a large value).
The behaviour is undefined if the maximum size is set smaller than the current size of the window.
The window size does not include the border or title bar.
Parameters: - width (int) – Maximum width of the window, in pixels.
- height (int) – Maximum height of the window, in pixels.
-
set_minimum_size
(width, height)¶ Set the minimum size of the window.
Once set, the user will not be able to resize the window smaller than the given dimensions. There is no way to remove the minimum size constraint on a window (but you could set it to 0,0).
The behaviour is undefined if the minimum size is set larger than the current size of the window.
The window size does not include the border or title bar.
Parameters: - width (int) – Minimum width of the window, in pixels.
- height (int) – Minimum height of the window, in pixels.
-
set_mouse_cursor
(cursor=None)¶ Change the appearance of the mouse cursor.
The appearance of the mouse cursor is only changed while it is within this window.
Parameters: cursor (MouseCursor) – The cursor to set, or None to restore the default cursor.
-
set_mouse_platform_visible
(platform_visible=None)¶ Set the platform-drawn mouse cursor visibility. This is called automatically after changing the mouse cursor or exclusive mode.
Applications should not normally need to call this method, see set_mouse_visible instead.
Parameters: platform_visible (bool or None) – If None, sets platform visibility to the required visibility for the current exclusive mode and cursor type. Otherwise, a bool value will override and force a visibility.
-
set_mouse_visible
(visible=True)¶ Show or hide the mouse cursor.
The mouse cursor will only be hidden while it is positioned within this window. Mouse events will still be processed as usual.
Parameters: visible (bool) – If True, the mouse cursor will be visible, otherwise it will be hidden.
-
set_size
(width, height)¶ Resize the window.
The behaviour is undefined if the window is not resizable, or if it is currently fullscreen.
The window size does not include the border or title bar.
Parameters: - width (int) – New width of the window, in pixels.
- height (int) – New height of the window, in pixels.
-
set_visible
(visible=True)¶ Show or hide the window.
Parameters: visible (bool) – If True, the window will be shown; otherwise it will be hidden.
-
switch_to
()¶ Make this window the current OpenGL rendering context.
Only one OpenGL context can be active at a time. This method sets the current window’s context to be current. You should use this method in preference to pyglet.gl.Context.set_current, as it may perform additional initialisation functions.
Events
-
on_activate
()¶ The window was activated.
This event can be triggered by clicking on the title bar, bringing it to the foreground; or by some platform-specific method.
When a window is “active” it has the keyboard focus.
-
on_close
()¶ The user attempted to close the window.
This event can be triggered by clicking on the “X” control box in the window title bar, or by some other platform-dependent manner.
The default handler sets has_exit to
True
. In pyglet 1.1, if pyglet.app.event_loop is being used, close is also called, closing the window immediately.
-
on_context_lost
()¶ The window’s GL context was lost.
When the context is lost no more GL methods can be called until it is recreated. This is a rare event, triggered perhaps by the user switching to an incompatible video mode. When it occurs, an application will need to reload all objects (display lists, texture objects, shaders) as well as restore the GL state.
-
on_context_state_lost
()¶ The state of the window’s GL context was lost.
pyglet may sometimes need to recreate the window’s GL context if the window is moved to another video device, or between fullscreen or windowed mode. In this case it will try to share the objects (display lists, texture objects, shaders) between the old and new contexts. If this is possible, only the current state of the GL context is lost, and the application should simply restore state.
-
on_deactivate
()¶ The window was deactivated.
This event can be triggered by clicking on another application window. When a window is deactivated it no longer has the keyboard focus.
-
on_draw
()¶ The window contents must be redrawn.
The EventLoop will dispatch this event when the window should be redrawn. This will happen during idle time after any window events and after any scheduled functions were called.
The window will already have the GL context, so there is no need to call switch_to. The window’s flip method will be called after this event, so your event handler should not.
You should make no assumptions about the window contents when this event is triggered; a resize or expose event may have invalidated the framebuffer since the last time it was drawn.
New in version 1.1.
-
on_expose
()¶ A portion of the window needs to be redrawn.
This event is triggered when the window first appears, and any time the contents of the window is invalidated due to another window obscuring it.
There is no way to determine which portion of the window needs redrawing. Note that the use of this method is becoming increasingly uncommon, as newer window managers composite windows automatically and keep a backing store of the window contents.
-
on_hide
()¶ The window was hidden.
This event is triggered when a window is minimised or (on Mac OS X) hidden by the user.
-
on_key_press
(symbol, modifiers)¶ A key on the keyboard was pressed (and held down).
In pyglet 1.0 the default handler sets has_exit to
True
if theESC
key is pressed.In pyglet 1.1 the default handler dispatches the
on_close()
event if theESC
key is pressed.Parameters: - symbol (int) – The key symbol pressed.
- modifiers (int) – Bitwise combination of the key modifiers active.
-
on_key_release
(symbol, modifiers)¶ A key on the keyboard was released.
Parameters: - symbol (int) – The key symbol pressed.
- modifiers (int) – Bitwise combination of the key modifiers active.
-
on_mouse_drag
(x, y, dx, dy, buttons, modifiers)¶ The mouse was moved with one or more mouse buttons pressed.
This event will continue to be fired even if the mouse leaves the window, so long as the drag buttons are continuously held down.
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
- dx (int) – Relative X position from the previous mouse position.
- dy (int) – Relative Y position from the previous mouse position.
- buttons (int) – Bitwise combination of the mouse buttons currently pressed.
- modifiers (int) – Bitwise combination of any keyboard modifiers currently active.
-
on_mouse_enter
(x, y)¶ The mouse was moved into the window.
This event will not be triggered if the mouse is currently being dragged.
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
-
on_mouse_leave
(x, y)¶ The mouse was moved outside of the window.
This event will not be triggered if the mouse is currently being dragged. Note that the coordinates of the mouse pointer will be outside of the window rectangle.
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
-
on_mouse_motion
(x, y, dx, dy)¶ The mouse was moved with no buttons held down.
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
- dx (int) – Relative X position from the previous mouse position.
- dy (int) – Relative Y position from the previous mouse position.
-
on_mouse_press
(x, y, button, modifiers)¶ A mouse button was pressed (and held down).
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
- button (int) – The mouse button that was pressed.
- modifiers (int) – Bitwise combination of any keyboard modifiers currently active.
-
on_mouse_release
(x, y, button, modifiers)¶ A mouse button was released.
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
- button (int) – The mouse button that was released.
- modifiers (int) – Bitwise combination of any keyboard modifiers currently active.
-
on_mouse_scroll
(x, y, scroll_x, scroll_y)¶ The mouse wheel was scrolled.
Note that most mice have only a vertical scroll wheel, so scroll_x is usually 0. An exception to this is the Apple Mighty Mouse, which has a mouse ball in place of the wheel which allows both scroll_x and scroll_y movement.
Parameters: - x (int) – Distance in pixels from the left edge of the window.
- y (int) – Distance in pixels from the bottom edge of the window.
- scroll_x (float) – Amount of movement on the horizontal axis.
- scroll_y (float) – Amount of movement on the vertical axis.
-
on_move
(x, y)¶ The window was moved.
Parameters: - x (int) – Distance from the left edge of the screen to the left edge of the window.
- y (int) – Distance from the top edge of the screen to the top edge of the window. Note that this is one of few methods in pyglet which use a Y-down coordinate system.
-
on_resize
(width, height)¶ The window was resized.
The window will have the GL context when this event is dispatched; there is no need to call switch_to in this handler.
Parameters: - width (int) – The new width of the window, in pixels.
- height (int) – The new height of the window, in pixels.
-
on_show
()¶ The window was shown.
This event is triggered when a window is restored after being minimised, or after being displayed for the first time.
-
on_text
(text)¶ The user input some text.
Typically this is called after
on_key_press()
and beforeon_key_release()
, but may also be called multiple times if the key is held down (key repeating); or called without key presses if another input method was used (e.g., a pen input).You should always use this method for interpreting text, as the key symbols often have complex mappings to their unicode representation which this event takes care of.
Parameters: text (unicode) – The text entered by the user.
-
on_text_motion
(motion)¶ The user moved the text input cursor.
Typically this is called after
on_key_press()
and beforeon_key_release()
, but may also be called multiple times if the key is help down (key repeating).You should always use this method for moving the text input cursor (caret), as different platforms have different default keyboard mappings, and key repeats are handled correctly.
The values that motion can take are defined in
pyglet.window.key
:- MOTION_UP
- MOTION_RIGHT
- MOTION_DOWN
- MOTION_LEFT
- MOTION_NEXT_WORD
- MOTION_PREVIOUS_WORD
- MOTION_BEGINNING_OF_LINE
- MOTION_END_OF_LINE
- MOTION_NEXT_PAGE
- MOTION_PREVIOUS_PAGE
- MOTION_BEGINNING_OF_FILE
- MOTION_END_OF_FILE
- MOTION_BACKSPACE
- MOTION_DELETE
Parameters: motion (int) – The direction of motion; see remarks.
-
on_text_motion_select
(motion)¶ The user moved the text input cursor while extending the selection.
Typically this is called after
on_key_press()
and beforeon_key_release()
, but may also be called multiple times if the key is help down (key repeating).You should always use this method for responding to text selection events rather than the raw
on_key_press()
, as different platforms have different default keyboard mappings, and key repeats are handled correctly.The values that motion can take are defined in
pyglet.window.key
:- MOTION_UP
- MOTION_RIGHT
- MOTION_DOWN
- MOTION_LEFT
- MOTION_NEXT_WORD
- MOTION_PREVIOUS_WORD
- MOTION_BEGINNING_OF_LINE
- MOTION_END_OF_LINE
- MOTION_NEXT_PAGE
- MOTION_PREVIOUS_PAGE
- MOTION_BEGINNING_OF_FILE
- MOTION_END_OF_FILE
Parameters: motion (int) – The direction of selection motion; see remarks.
Attributes
-
caption
¶ The window caption (title). Read-only.
Type: str
-
config
¶ A GL config describing the context of this window. Read-only.
Type: pyglet.gl.Config
-
context
¶ The OpenGL context attached to this window. Read-only.
Type: pyglet.gl.Context
-
display
¶ The display this window belongs to. Read-only.
Type: Display
-
fullscreen
¶ True if the window is currently fullscreen. Read-only.
Type: bool
-
has_exit
= False¶
-
height
¶ The height of the window, in pixels. Read-write.
Type: int
-
invalid
= True¶
-
resizeable
¶ True if the window is resizable. Read-only.
Type: bool
-
screen
¶ The screen this window is fullscreen in. Read-only.
Type: Screen
-
style
¶ The window style; one of the
WINDOW_STYLE_*
constants. Read-only.Type: int
-
visible
¶ True if the window is currently visible. Read-only.
Type: bool
-
vsync
¶ True if buffer flips are synchronised to the screen’s vertical retrace. Read-only.
Type: bool
-
width
¶ The width of the window, in pixels. Read-write.
Type: int
Class attributes: cursor names
-
CURSOR_CROSSHAIR
= 'crosshair'¶
-
CURSOR_DEFAULT
= None¶
-
CURSOR_HAND
= 'hand'¶
-
CURSOR_HELP
= 'help'¶
-
CURSOR_NO
= 'no'¶
-
CURSOR_SIZE
= 'size'¶
-
CURSOR_SIZE_DOWN
= 'size_down'¶
-
CURSOR_SIZE_DOWN_LEFT
= 'size_down_left'¶
-
CURSOR_SIZE_DOWN_RIGHT
= 'size_down_right'¶
-
CURSOR_SIZE_LEFT
= 'size_left'¶
-
CURSOR_SIZE_LEFT_RIGHT
= 'size_left_right'¶
-
CURSOR_SIZE_RIGHT
= 'size_right'¶
-
CURSOR_SIZE_UP
= 'size_up'¶
-
CURSOR_SIZE_UP_DOWN
= 'size_up_down'¶
-
CURSOR_SIZE_UP_LEFT
= 'size_up_left'¶
-
CURSOR_SIZE_UP_RIGHT
= 'size_up_right'¶
-
CURSOR_TEXT
= 'text'¶
-
CURSOR_WAIT
= 'wait'¶
-
CURSOR_WAIT_ARROW
= 'wait_arrow'¶
Class attributes: window styles
-
WINDOW_STYLE_BORDERLESS
= 'borderless'¶
-
WINDOW_STYLE_DEFAULT
= None¶
-
WINDOW_STYLE_DIALOG
= 'dialog'¶
-
WINDOW_STYLE_TOOL
= 'tool'¶
-
-
class
FPSDisplay
(window)¶ Bases:
object
Display of a window’s framerate.
This is a convenience class to aid in profiling and debugging. Typical usage is to create an FPSDisplay for each window, and draw the display at the end of the windows’
on_draw()
event handler:window = pyglet.window.Window() fps_display = FPSDisplay(window) @window.event def on_draw(): # ... perform ordinary window drawing operations ... fps_display.draw()
The style and position of the display can be modified via the
Label()
attribute. Different text can be substituted by overriding the set_fps method. The display can be set to update more or less often by setting the update_period attribute. Note: setting the update_period to a value smaller than your Window refresh rate will cause inaccurate readings.Variables: label (Label) – The text label displaying the framerate. -
draw
()¶ Draw the label.
The OpenGL state is assumed to be at default values, except that the MODELVIEW and PROJECTION matrices are ignored. At the return of this method the matrix mode will be MODELVIEW.
-
set_fps
(fps)¶ Set the label text for the given FPS estimation.
Called by update every update_period seconds.
Parameters: fps (float) – Estimated framerate of the window.
-
update
()¶ Records a new data point at the current time. This method is called automatically when the window buffer is flipped.
-
update_period
= 0.25¶ Time in seconds between updates.
Type: float
-
-
class
MouseCursor
¶ An abstract mouse cursor.
-
draw
(x, y)¶ Abstract render method.
The cursor should be drawn with the “hot” spot at the given coordinates. The projection is set to the pyglet default (i.e., orthographic in window-space), however no other aspects of the state can be assumed.
Parameters: - x (int) – X coordinate of the mouse pointer’s hot spot.
- y (int) – Y coordinate of the mouse pointer’s hot spot.
-
gl_drawable
= True¶ Indicates if the cursor is drawn using OpenGL, or natively.
-
hw_drawable
= False¶
-
-
class
DefaultMouseCursor
¶ Bases:
pyglet.window.MouseCursor
The default mouse cursor set by the operating system.
-
class
ImageMouseCursor
(image, hot_x=0, hot_y=0, acceleration=False)¶ Bases:
pyglet.window.MouseCursor
A user-defined mouse cursor created from an image.
Use this class to create your own mouse cursors and assign them to windows. Cursors can be drawn by OpenGL, or optionally passed to the OS to render natively. There are no restrictions on cursors drawn by OpenGL, but natively rendered cursors may have some platform limitations (such as color depth, or size). In general, reasonably sized cursors will render correctly
-
draw
(x, y)¶ Abstract render method.
The cursor should be drawn with the “hot” spot at the given coordinates. The projection is set to the pyglet default (i.e., orthographic in window-space), however no other aspects of the state can be assumed.
Parameters: - x (int) – X coordinate of the mouse pointer’s hot spot.
- y (int) – Y coordinate of the mouse pointer’s hot spot.
-
Exceptions¶
-
class
MouseCursorException
¶ The root exception for all mouse cursor-related errors.
-
class
NoSuchConfigException
¶ An exception indicating the requested configuration is not available.
-
class
NoSuchDisplayException
¶ An exception indicating the requested display is not available.
-
class
WindowException
¶ The root exception for all window-related errors.
Third party libraries¶
Listed here are a few third party libraries that you might find useful when developing your project. Please direct any questions to the respective authors. If you would like to have your library listed here, let us know!
glooey¶
An object-oriented GUI library for pyglet (https://glooey.readthedocs.io).
Every game needs a user interface that matches its look and feel. The purpose of glooey is to help you make such an interface. Towards this end, glooey provides 7 powerful placement widgets, a label widget, an image widget, 3 different button widgets, a text entry widget, avariety of scroll boxes and bars, 4 different dialog box widgets, and a variety of other miscellaneous widgets. The appearance of any widget can be trivially customized, and glooey comes with built-in fantasy, puzzle, and 8-bit themes to prove it (and to help you hit the ground running if your game fits one of those genres).
PyShaders¶
Pythonic OpenGL shader wrapper for python (https://github.com/gabdube/pyshaders)
Pyshaders aims to completely wraps the opengl2.1 shader api in a python module. Pyshaders provides a pythonic OOP api that hides the lower level (ctypes) calls. Pyshaders provides a high level api and a low level api, and it can be integrated easily with existing code because it does not occlude the underlying opengl values.
Ratcave¶
A Simple Python 3D Graphics Engine extension for pyglet, Psychopy and PyGame (https://github.com/neuroneuro15/ratcave).
Ratcave provides a simple OOP interface for loading, positioning, and drawing 3D scenes in OpenGL windows. It’s a great fit for simple games and scientific behavioral experiments!
Projects using pyglet¶
pyglet is a fairly lightweight library, which makes it ideal to build upon. Listed here are a few projects that take advantage of pyglet “under the hood”. If you would like to have your project listed here, let us know!
cocos2d¶
A framework for building 2D games, demos, and other graphical/interactive applications (http://python.cocos2d.org).
Cocos2d is an open source software framework. It can be used to build games, apps and other cross platform GUI based interactive programs.
Arcade¶
A 2D library for game development focusing on simplicity. (https://arcade.academy)
Arcade builds on Pyglet with a focus to make creating 2D arcade games simple and easy for hobbyists and new programmers.
Contributing¶
Communication¶
Pyglet communication occurs mostly in our mailing list.
Issue Tracker¶
You can use the issue tracker to report any bug or compatibility issue.
We prefer the tracker to address discussions on specific bugs, and address broader topics of pyglet in the mailing list.
Getting the latest development version¶
The repository can be found here; it hosts the source, documentation, examples, and development tools. You can get the latest version of the code using:
# clone over https
git clone https://github.com/pyglet/pyglet.git
# or clone over ssh
git clone git@github.com:pyglet/pyglet.git
Contributing to the source¶
If you want to contribute to pyglet, we suggest the following:
- Fork the official repository
- Apply your changes to your fork
- Submit a pull request describing the changes you have made
- Alternatively, you can create a patch and submit it to the issue tracker.
Contributing to the documentation¶
When asking to include your code in the repository, check that you have addressed its respective documentation, both within the code and the API documentation. It is very important to all of us that the documentation matches the latest code and vice-versa.
Consequently, an error in the documentation, either because it is hard to understand or because it doesn’t match the code, is a bug that deserves to be reported on a ticket.
A good way to start contributing to a component of pyglet is by its documentation. When studying the code you are going to work with, also read the associated docs. If you don’t understand the code with the help of the docs, it is a sign that the docs should be improved.
Contact¶
pyglet is developed by many individual volunteers, and there is no central point of contact. If you have a question about developing with pyglet, or you wish to contribute, please join the discord server, or the mailing list.
For legal issues, please contact Alex Holkner.
Development environment¶
To develop pyglet, you need an environment with at least the following:
- Python 3.6+
- pytest
- Your favorite Python editor or IDE
All requirements should already be located in doc/requirements.txt
and tests/requirements.txt
.
pip install -r doc/requirements.txt
pip install -r tests/requirements.txt
To use and test all pyglet functionality you should also have:
To build packages for distribution you need to install:
It is preferred to create a Python virtual environment to develop in. This allows you to easily test on all Python versions supported by pyglet, not pollute your local system with pyglet development dependencies, and not have your local system interfere with pyglet developement. All dependencies you install while inside an activated virtual environment will remain isolated inside that environment. When you’re finished, you can simply delete it.
This section will show you how to set up and use virtual environments. If you’re already familiar with this, you can probably skip the rest of this page.
Linux or Mac OSX¶
Setting up¶
Setting up a virtual environment is almost the same for Linux and OS X. First, use your OS’s package manager (apt, brew, etc) to install the following dependencies:
- Python 3.6+
To create virtual environments, venv
is included in the standard
library since Python 3.3.
Depending on your platform, python may be installed as python
or python3
.
You may want to check which command runs python 3 on your system:
python --version
python3 --version
For the rest of the guide, use whichever gives you the correct python version on your system. Some linux distros may install python with version numbers such as python3.6, so you may need to set up an alias.
Next, we’ll create a virtual environment. Choose the appropriate command for your system to create a virtual environment:
python -m venv pyglet-venv
python3 -m venv pyglet-venv
Once the virtual environment has been created, the next step is to activate it. You’ll then install the dependencies, which will be isolated inside that virtual environment.
Activate the virtual environment
. pyglet-venv/bin/activate
You will see the name of the virtual environment at the start of the command prompt.
[Optional] Make sure pip is the latest version:
pip install --upgrade pip
Now install dependencies in doc/requirements.txt
and
tests/requirements.txt
:
pip install -r doc/requirements.txt
pip install -r tests/requirements.txt
Windows¶
Setting up¶
Make sure you download and install:
Pip should be installed by default with the latest Python installers. Make sure that the boxes for installing PIP and adding python to PATH are checked.
When finished installing, open a command prompt.
To create virtual environments, venv
is included in the standard library
since Python 3.3.
Next, we’ll create a virtual environment.:
python -m venv pyglet-venv
Once the virtual environment has been created, the next step is to activate it. You’ll then install the dependencies, which will be isolated inside that virtual environment.
Activate the virtual environment
. pyglet-venv/bin/activate
You will see the name of the virtual environment at the start of the command prompt.
[Optional] Make sure pip is the latest version:
pip install --upgrade pip
Now install dependencies in doc/requirements.txt
and
tests/requirements.txt
:
pip install -r doc/requirements.txt
pip install -r tests/requirements.txt
Testing pyglet¶
Test Suites¶
Tests for pyglet are divided into 3 suites.
Unit tests¶
Unit tests only cover a single unit of code or a combination of a limited number of units. No resource intensive computations should be included. These tests should run in limited time without any user interaction.
Integration tests¶
Integration tests cover the integration of components of pyglet into the whole of pyglet and the integration into the supported systems. Like unit tests these tests do not require user interaction, but they can take longer to run due to access to system resources.
Interactive tests¶
Interactive tests require the user to verify whether the test is successful and in some cases require the user to perform actions in order for the test to continue. These tests can take a long time to run.
There are currently 3 types of interactive test cases:
- Tests that can only run in fully interactive mode as they require
the user to perform an action in order for the test to continue.
These tests are decorated with
requires_user_action()
. - Tests that can run without user interaction, but that cannot validate
whether they should pass or fail. These tests are docorated with
requires_user_validation()
. - Tests that can run without user interaction and that can compare results to screenshots from a previous run to determine whether they pass or fail. This is the default type.
Running tests¶
The pyglet test suite is based on the pytest framework.
It is preferred to use a virtual environment to run the tests. For instructions to set up virtual environments see Development environment. Make sure the virtual environment for the Python version you want to test is active. It is preferred to run the tests on 3.6+ to make sure changes are compatible with all supported Python versions.
To run all tests, execute pytest in the root of the pyglet repository:
pytest
You can also run just a single suite:
pytest tests/unit
pytest tests/integration
pytest tests/interactive
For the interactive test suites, there are some extra command line switches for pytest:
--non-interactive
: Only run the interactive tests that can only verify themselves using screenshots. The screenshots are created when you run the tests in interactive mode, so you will need to run the tests interactively once, before you can use this option;--sanity
: Do a sanity check by running as many interactive tests without user intervention. Not all tests can run without intervention, so these tests will still be skipped. Mostly useful to quickly check changes in code. Not all tests perform complete validation.
Writing tests¶
Annotations¶
Some control over test execution can be exerted by using annotations in the form of decorators. One function of annotations is to skip tests under certain conditions.
General annotations¶
General test annotations are available in the module tests.annotations
.
-
@
require_platform
(platform)¶ Only run the test on the given platform(s), skip on other platforms.
Parameters: platform (list(str)) – A list of platform identifiers as returned by pyglet.options
. See alsoPlatform
.
-
@
skip_platform
(platform)¶ Skip test on the given platform(s).
Parameters: platform (list(str)) – A list of platform identifiers as returned by pyglet.options
. See alsoPlatform
.
-
class
Platform
¶ Predefined lists of identifiers for platforms. For use with
require_platform()
andskip_platform()
. Combine platforms using +.-
LINUX
= ('linux-compat', 'linux2', 'linux')¶ Linux platforms
-
OSX
= ('darwin',)¶ Mac OS X platforms
-
WINDOWS
= ('win32', 'cygwin')¶ MS Windows platforms
-
-
@
require_gl_extension
(extension)¶ Skip the test if the given GL extension is not available.
Parameters: extension (str) – Name of the extension required.
Suite annotations¶
This is currently not used.
-
@
pytest.mark.
unit
¶ Test belongs to the unit test suite.
-
@
pytest.mark.
integration
¶ Test belongs to the integration test suite.
-
@
pytest.mark.
interactive
¶ Test belongs to the interactive test suite.
Interactive test annotations¶
Interactive test cases can be marked with specific pytest marks. Currently the following marks are used:
-
@
pytest.mark.
requires_user_action
¶ Test requires user interaction to run. It needs to be skipped when running in non-interactive or sanity mode.
-
@
pytest.mark.
requires_user_validation
¶ User validation is required to mark the test passed or failed. However the test can run in sanity mode.
-
@
pytest.mark.
only_interactive
¶ For another reason the test can only run in interactive mode.
Documentation¶
This is the pyglet documentation, generated with Sphinx.
Details:
Date | 2023/09/14 08:52:41 |
pyglet version | 1.5.28 |
Note
See the Sphinx warnings log file for errors.
Writing documentation¶
Familiarize yourself with Sphinx and reStructuredText.
Literature¶
The home page is pyglet/doc/index.rst
. This file create three toctrees:
- The programming guide
- The API docs
- The development guide, which you are reading now
Source code¶
The API documentation is generated from the source code docstrings via autodoc and a few custom extensions.
Example: | class Class1():
'''Short description.
Detailed explanation, formatted as reST.
Can be as detailed as it is needed.
:Ivariables:
`arg1`
description
.. versionadded:: 1.2
'''
attribute1 = None
'''This is an attribute.
More details.
'''
#: This is another attribute.
attribute2 = None
def __init__(self):
'''Constructor
:parameters:
`arg1` : type
description
'''
self.instance_attribute = None
'''This is an instance attribute.
'''
def method(self):
'''Short description.
:returns: return description
:rtype: returned type
'''
def _get_property1(self):
'''Getter Method contains docstrings for a property
:return: property1 value
:rtype: property1 type
'''
def _set_property1(self, value):
'''Setter Method docstrings are ignored
'''
property1 = property(_get_property1, _set_property1,
doc='''Override docstring here if you want''')
|
---|
Pyglet has a special role for deprecations, :deprecated:
.
Source Output :deprecated: Do not use
Warning
Deprecated. Do not use
Building¶
The complete documentation can be generated using sphinx
.
Make sure you prepare your environment as stated in Development environment.
To build the documentation, execute:
./make.py docs --open
Note
Due to a bug in Sphinx, documentation generation currently only works using Python 3.x.
If the build succeeds, the web pages are in doc/_build/html
.
Optionally the standalone way to build docs is through
setup.py
or make
.
# using setup.py (output dir: _build in project root)
python setup.py build_sphinx
# make (make.bat for windows)
cd doc
make html
HTML Theme¶
Note
The custom theme was disabled in 2019 and replaced with
the standard Read the Docs theme sphinx_rtd_theme
.
The custom sphinx theme is in the ext/theme
folder.
Making a pyglet release¶
Clone pyglet into a new directory
Make sure it is up to date:
git pull
Update version string in the following files and commit:
- pyglet/__init__.py
- doc/conf.py
Tag the current changelist with the version number:
git tag -a v0.0.0 -m "release message"
Push the changes to the central repo:
git push git push --tags
Build the wheels and documentation:
./make.py clean ./make.py dist
Upload the wheels and zips to PyPI:
twine upload dist/pyglet-x.y.z*
Start a build of the documentation on https://readthedocs.org/projects/pyglet/builds/
Draft a new release on Github, using the same version number https://github.com/pyglet/pyglet/releases
Tell people!
Major version increase¶
When preparing for a major version you might also want to consider the following:
- Create a maintenance branch for the major version
- Add a readthedocs configuration for that maintenance branch
- Point the url in setup.py to the maintenance branch documentation
OpenGL Interface Implementation¶
See OpenGL Interface for details on the publically-visible modules.
See ctypes Wrapper Generation for details on some of these modules are generated.
ctypes linkage¶
Most functions link to libGL.so (Linux), opengl32.dll (Windows) or
OpenGL.framework (OS X). pyglet.gl.lib
provides some helper types then
imports linker functions for the appropriate platform: one of
pyglet.gl.lib_agl
, pyglet.gl.lib_glx
, pyglet.gl.lib_wgl
.
On any platform, the following steps are taken to link each function during import:
Look in the appropriate library (e.g. libGL.so, libGLU.so, opengl32.dll, etc.) using
cdll
orwindll
.If not found, call
wglGetProcAddress
orglxGetProcAddress
to try to resolve the function’s address dynamically. On OS X, skip this step.On Windows, this will fail if the context hasn’t been created yet. Create and return a proxy object
WGLFunctionProxy
which will try the same resolution again when the object is__call__
’d.The proxy object caches its result so that subsequent calls have only a single extra function-call overhead.
If the function is still not found (either during import or proxy call), the function is replaced with
MissingFunction
(defined inpyglet.gl.lib
), which raises an exception. The exception message details the name of the function, and optionally the name of the extension it requires and any alternative functions that can be used.The extension required is currently guessed by
gengl.py
based on nearby#ifndef
declarations, it is occasionally wrong.The suggestion list is not currently used, but is intended to be implemented such that calling, for example,
glCreateShader
on an older driver suggestsglCreateShaderObjectARB
, etc.
To access the linking function, import pyglet.gl.lib
and use one of
link_AGL
, link_GLX
, link_WGL
, link_GL
or link_GLU
. This
is what the generated modules do.
Missing extensions¶
The latest glext.h
on opengl.org and nvidia does not include some recent
extensions listed on the registry. These must be hand coded into
pyglet.gl.glext_missing
. They should be removed when glext.h
is
updated.
ctypes Wrapper Generation¶
The following modules in pyglet are entirely (or mostly) generated from one or more C header files:
- pyglet.gl.agl
- pyglet.gl.gl
- pyglet.gl.glext_abi
- pyglet.gl.glext_nv
- pyglet.gl.glu
- pyglet.gl.glx
- pyglet.gl.glxext_abi
- pyglet.gl.glxext_nv
- pyglet.gl.wgl
- pyglet.gl.wglext_abi
- pyglet.gl.wglext_nv
- pyglet.window.xlib.xlib
- pyglet.window.xlib.xinerama
The wrapping framework is in tools/wraptypes
, and pyglet-specialised batch
scripts are tools/genwrappers.py
(generates xlib wrappers) and
tools/gengl.py
(generates gl wrappers).
Generating GL wrappers¶
This process needs to be followed when the wraptypes is updated, the header files are updated (e.g., a new release of the operating system), or the GL extensions are updated. Each file can only be generated a a specific platform.
Before beginning, remove the file tools/.gengl.cache
if it exists. This
merely caches header files so they don’t need to be repeatedly downloaded (but
you’d prefer to use the most recent uncached copies if you’re reading this,
presumably).
On Linux, generate pyglet.gl.gl
, pyglet.gl.glext_abi
,
pyglet.gl.glext_nv
and pyglet.gl.glu
(the complete user-visible GL
package):
python tools/gengl.py gl glext_abi glext_nv glu
The header files for pyglet.gl.gl
and pyglet.gl.glu
are located in
/usr/include/GL
. Ensure your Linux distribution has recent versions
of these files (unfortunately they do not seem to be accessible outside of a
distribution or OS).
The header files for pyglet.glext_abi
and pyglet.glext_nv
are
downloaded from http://www.opengl.org and http://developer.nvidia.com,
respectively.
On Linux still, generate pyglet.gl.glx
, pyglet.gl.glxext_abi
and
pyglet.gl.glxext_nv
:
python tools/gengl.py glx glxext_abi glxext_nv
The header file for pyglet.gl.glx
is in /usr/include/GL
, and
is expected to depend on X11 header files from /usr/include/X11
.
glext_abi
and glext_nv
header files are downloaded from the above
websites.
On OS X, generate pyglet.gl.agl
:
python tools/gengl.py agl
Watch a movie while you wait – it uses virtually every header file on the
system. Expect to see one syntax error in PictUtils.h
line 67, it is
unimportant.
On Windows XP, generate pyglet.gl.wgl
, pyglet.gl.wglext_abi
and
pyglet.gl.wglext_nv
:
python tools/gengl.py wgl wglext_abi wglext_nv
You do not need to have a development environment installed on Windows.
pyglet.gl.wgl
is generated from tools/wgl.h
, which is a hand-coded
header file containing the prototypes and constants for WGL and its
dependencies. In a real development environment you would find these mostly
in WinGDI.h
, but wraptypes is not quite sophisticated enough to parse
Windows system headers (see below for what needs implementing). It is
extremely unlikely this header will ever need to change (excepting a bug fix).
The headers for pyglet.gl.wglext_abi
and pyglet.gl.wglext_nv
are
downloaded from the same websites as for GL and GLX.
Generated GL wrappers¶
Each generated file contains a pair of markers # BEGIN GENERATED CONTENT
and # END GENERATED CONTENT
which are searched for when replacing the
file. If either marker is missing or corrupt, the file will not be modified.
This allows for custom content around the generated content. Only glx.py
makes use of this, to include some additional enumerators that are not
generated by default.
If a generating process is interrupted (either you get sick of it, or it crashes), it will leave a partially-complete file written, which will not include both markers. It is up to you to restore the file or otherwise reinsert the markers.
Generating Xlib wrappers¶
On Linux with the Xinerama extension installed (doesn’t have to be in use, just available), run:
python tools/genwrappers.py
This generates pyglet.window.xlib.xlib
and
pyglet.window.xlib.xinerama
.
Note that this process, as well as the generated modules, depend on
pyglet.gl.glx
. So, you should always run this after the above GL
generation.
wraptypes¶
wraptypes is a general utility for creating ctypes wrappers from C header
files. The front-end is tools/wraptypes/wrap.py
, for usage:
python tools/wraptypes/wrap.py -h
There are three components to wraptypes:
- preprocessor.py
- Interprets preprocessor declarations and converts the source header files into a list of tokens.
- cparser.py
- Parses the preprocessed tokens for type and function declarations and
calls
handle_
methods on the class CParser in a similar manner to a SAX parser. - ctypesparser.py
- Interprets C declarations and types from CParser and creates corresponding
ctypes declarations, calling
handle_
methods on the class CtypesParser.
The front-end wrap.py
provides a simple subclass of CtypesParser
,
CtypesWrapper
, which writes the ctypes declarations found to a file in a
format that can be imported as a module.
Parser Modifications¶
The parsers are built upon a modified version of PLY, a Python
implementation of lex and yacc. The modified source is included in
the wraptypes
directory. The modifications are:
- Grammar is abstracted out of Parser, so multiple grammars can easily be defined in the same module.
- Tokens and symbols keep track of their filename as well as line number.
- Lexer state can be pushed onto a stack.
The first time the parsers are run (or after they are modified), PLY creates
pptab.py
and parsetab.py
in the current directory. These are
the generated state machines, which can take a few seconds to generate.
The file parser.out
is created if debugging is enabled, and contains the
parser description (of the last parser that was generated), which is essential
for debugging.
Preprocessor¶
The grammar and parser are defined in preprocessor.py
.
There is only one lexer state. Each token has a type which is a string (e.g.
'CHARACTER_CONSTANT'
) and a value. Token values, when read directly from
the source file are only ever strings. When tokens are written to the output
list they sometimes have tuple values (for example, a PP_DEFINE
token on
output).
Two lexer classes are defined: PreprocessorLexer
, which reads a stack of
files (actually strings) as input, and TokenListLexer
, which reads from a
list of already-parsed tokens (used for parsing expressions).
The preprocessing entry-point is the PreprocessorParser
class. This
creates a PreprocessorLexer
and its grammar during construction. The
system include path includes the GCC search path by default but can be
modified by altering the include_path
and framework_path
lists. The
system_headers
dict allows header files to be implied on the search path
that don’t exist. For example, by setting:
system_headers['stdlib.h'] = '''#ifndef STDLIB_H
#define STDLIB_H
/* ... */
#endif
'''
you can insert your own custom header in place of the one on the filesystem. This is useful when parsing headers from network locations.
Parsing begins when parse
is called. Specify one or both of a filename
and a string of data. If debug
kwarg is True, syntax errors dump the
parser state instead of just the line number where they occurred.
The production rules specify the actions; these are implemented in
PreprocessorGrammar
. The actions call methods on PreprocessorParser
,
such as:
include(self, header)
, to push another file onto the lexer.include_system(self, header)
, to search the system path for a file to push onto the lexererror(self, message, filename, line)
, to signal a parse error. Not all syntax errors get this far, due to limitations in the parser. A parse error at EOF will just print to stderr.write(self, tokens)
, to write tokens to the output list. This is the default action when no preprocessing declaratives are being parsed.
The parser has a stack of ExecutionState
, which specifies whether the
current tokens being parsed are ignored or not (tokens are ignored in an
#if
that evaluates to 0). This is a little more complicated than just a
boolean flag: the parser must also ignore #elif conditions that can have no
effect. The enable_declaratives
and enable_elif_conditionals
return
True if the top-most ExecutionState
allows declaratives and #elif
conditionals to be parsed, respecitively. The execution state stack is
modified with the condition_*
methods.
PreprocessorParser
has a PreprocessorNamespace
which keeps track of
the currently defined macros. You can create and specify your own namespace,
or use one that is created by default. The default namespace includes GCC
platform macros needed for parsing system headers, and some of the STDC
macros.
Macros are expanded when tokens are written to the output list, and when
conditional expressions are parsed.
PreprocessorNamespace.apply_macros(tokens)
takes care of this, replacing
function parameters, variable arguments, macro objects and (mostly) avoiding
infinite recursion. It does not yet handle the #
and ##
operators,
which are needed to parse the Windows system headers.
The process for evaluating a conditional (#if
or #elif
) is:
- Tokens between
PP_IF
orPP_ELIF
andNEWLINE
are expanded byapply_macros
. - The resulting list of tokens is used to construct a
TokenListLexer
. - This lexer is used as input to a
ConstantExpressionParser
. This parser uses theConstantExpressionGrammar
, which builds up an AST ofExpressionNode
objects. parse
is called on theConstantExpressionParser
, which returns the resulting top-levelExpressionNode
, orNone
if there was a syntax error.- The
evaluate
method of theExpressionNode
is called with the preprocessor’s namespace as the evaluation context. This allows the expression nodes to resolvedefined
operators. - The result of
evaluate
is always an int; non-zero values are treated as True.
Because pyglet requires special knowledge of the preprocessor declaratives
that were encountered in the source, these are encoded as pseudo-tokens within
the output token list. For example, after a #ifndef
is evaluated, it
is written to the token list as a PP_IFNDEF
token.
#define
is handled specially. After applying it to the namespace, it is
parsed as an expression immediately. This is allowed (and often expected) to
fail. If it does not fail, a PP_DEFINE_CONSTANT
token is created, and the
value is the result of evaluatin the expression. Otherwise, a PP_DEFINE
token is created, and the value is the string concatenation of the tokens
defined. Special handling of parseable expressions makes it simple to later
parse constants defined as, for example:
#define RED_SHIFT 8
#define RED_MASK (0x0f << RED_SHIFT)
The preprocessor can be tested/debugged by running preprocessor.py
stand-alone with a header file as the sole argument. The resulting token list
will be written to stdout.
CParser¶
The lexer for CParser
, CLexer
, takes as input a list of tokens output
from the preprocessor. The special preprocessor tokens such as PP_DEFINE
are intercepted here and handled immediately; hence they can appear anywhere
in the source header file without causing problems with the parser. At this
point IDENTIFIER
tokens which are found to be the name of a defined type
(the set of defined types is updated continuously during parsing) are
converted to TYPE_NAME
tokens.
The entry-point to parsing C source is the CParser
class. This creates a
preprocessor in its constructor, and defines some default types such as
wchar_t
and __int64_t
. These can be disabled with kwargs.
Preprocessing can be quite time-consuming, especially on OS X where thousands
of #include
declaratives are processed when Carbon is parsed. To minimise
the time required to parse similar (or the same, while debugging) header
files, the token list from preprocessing is cached and reused where possible.
This is handled by CPreprocessorParser
, which overrides push_file
to
check with CParser
if the desired file is cached. The cache is checked
against the file’s modification timestamp as well as a “memento” that
describes the currently defined tokens. This is intended to avoid using a
cached file that would otherwise be parsed differently due to the defined
macros. It is by no means perfect; for example, it won’t pick up on a macro
that has been defined differently. It seems to work well enough for the
header files pyglet requires.
The header cache is saved and loaded automatically in the working directory
as .header.cache
. The cache should be deleted if you make changes to the
preprocessor, or are experiencing cache errors (these are usually accompanied
by a “what-the?” exclamation from the user).
The actions in the grammar construct parts of a “C object model” and call
methods on CParser
. The C object model is not at all complete, containing
only what pyglet (and any other ctypes-wrapping application) requires. The
classes in the object model are:
- Declaration
- A single declaration occuring outside of a function body. This includes
type declarations, function declarations and variable declarations. The
attributes are
declarator
(see below),type
(a Type object) andstorage
(for example, ‘typedef’, ‘const’, ‘static’, ‘extern’, etc). - Declarator
- A declarator is a thing being declared. Declarators have an
identifier
(the name of it, None if the declarator is abstract, as in some function parameter declarations), an optionalinitializer
(currently ignored), an optional linked-list ofarray
(giving the dimensions of the array) and an optional list ofparameters
(if the declarator is a function). - Pointer
- This is a type of declarator that is dereferenced via
pointer
to another declarator. - Array
- Array has size (an int, its dimension, or None if unsized) and a pointer
array
to the next array dimension, if any. - Parameter
- A function parameter consisting of a
type
(Type object),storage
anddeclarator
. - Type
- Type has a list of
qualifiers
(e.g. ‘const’, ‘volatile’, etc) andspecifiers
(the meaty bit). - TypeSpecifier
- A base TypeSpecifier is just a string, such as
'int'
or'Foo'
or'unsigned'
. Note that types can have multiple TypeSpecifiers; not all combinations are valid. - StructTypeSpecifier
- This is the specifier for a struct or union (if
is_union
is True) type.tag
gives the optionalfoo
instruct foo
anddeclarations
is the meat (an empty list for an opaque or unspecified struct). - EnumSpecifier
- This is the specifier for an enum type.
tag
gives the optionalfoo
inenum foo
andenumerators
is the list of Enumerator objects (an empty list for an unspecified enum). - Enumerator
- Enumerators exist only within EnumSpecifier. Contains
name
andexpression
, an ExpressionNode object.
The ExpressionNode
object hierarchy is similar to that used in the
preprocessor, but more fully-featured, and using a different
EvaluationContext
which can evaluate identifiers and the sizeof
operator (currently it actually just returns 0 for both).
Methods are called on CParser as declarations and preprocessor declaratives are parsed. The are mostly self explanatory. For example:
- handle_ifndef(self, name, filename, lineno)
- An
#ifndef
was encountered testing the macroname
in filefilename
at linelineno
. - handle_declaration(self, declaration, filename, lineno)
declaration
is an instance of Declaration.
These methods should be overridden by a subclass to provide functionality.
The DebugCParser
does this and prints out the arguments to each
handle_
method.
The CParser
can be tested in isolation by running it stand-alone with the
filename of a header as the sole argument. A DebugCParser
will be
constructed and used to parse the header.
CtypesParser¶
CtypesParser
is implemented in ctypesparser.py
. It is a subclass of
CParser
and implements the handle_
methods to provide a more
ctypes-friendly interpretation of the declarations.
To use, subclass and override the methods:
- handle_ctypes_constant(self, name, value, filename, lineno)
- An integer or float constant (in a
#define
). - handle_ctypes_type_definition(self, name, ctype, filename, lineno)
- A
typedef
declaration. See below for type ofctype
. - handle_ctypes_function(self, name, restype, argtypes, filename, lineno)
- A function declaration with the given return type and argument list.
- handle_ctypes_variable(self, name, ctype, filename, lineno)
- Any other non-
static
declaration.
Types are represented by instances of CtypesType
. This is more easily
manipulated than a “real” ctypes type. There are subclasses for
CtypesPointer
, CtypesArray
, CtypesFunction
, and so on; see the
module for details.
Each CtypesType
class implements the visit
method, which can be used,
Visitor pattern style, to traverse the type hierarchy. Call the visit
method of any type with an implementation of CtypesTypeVisitor
: all
pointers, array bases, function parameters and return types are traversed
automatically (struct members are not, however).
This is useful when writing the contents of a struct or enum. Before writing
a type declaration for a struct type (which would consist only of the struct’s
tag), visit
the type and handle the visit_struct
method on the visitor
to print out the struct’s members first. Similarly for enums.
ctypesparser.py
can not be run stand-alone. wrap.py
provides a
straight-forward implementation that writes a module of ctypes wrappers. It
can filter the output based on the originating filename. See the module
docstring for usage and extension details.
Media manual¶
Domain knowledge¶
This tutorial http://dranger.com/ffmpeg/ffmpeg.html is a good intro for building some domain knowledge. Bear in mind that the tutorial is rather old, and some ffmpeg functions have become deprecated - but the basics are still valid.
In the FFmpeg base code there is the ffplay.c player - a very good way to see how things are managed. In particular, some newer FFmpeg functions are used, while current pyglet media code still uses functions that have now been deprecated.
Current code architecture¶
The overview of the media code is the following:
Source¶
Found in media/sources folder.
Source
s represent data containing media
information. They can come from disk or be created in memory. A
Source
‘s responsibility is to read data into
and provide audio and/or video data out of its stream. Essentially, it’s a
producer.
FFmpegStreamingSource¶
One implementation of the StreamingSource
is the
FFmpegSource
. It implements the Source
base class
by calling FFmpeg functions wrapped by ctypes and found in
media/sources/ffmpeg_lib. They offer basic functionalities for handling media
streams, such as opening a file, reading stream info, reading a packet, and
decoding audio and video packets.
The FFmpegSource
maintains two queues,
one for audio packets and one for video packets, with a pre-determined maximum
size. When the source is loaded, it will read packets from the stream and will
fill up the queues until one of them is full. It has then to stop because we
never know what type of packet we will get next from the stream. It could be a
packet of the same type as the filled up queue, in which case we would not be
able to store the additional packet.
Whenever a Player
- a consumer of a source -
asks for audio data or a video frame, the
Source
will pop the next packet from the
appropriate queue, decode the data, and return the result to the Player. If
this results in available space in both audio and video queues, it will read
additional packets until one of the queues is full again.
Player¶
Found in media/player.py
The Player
is the main object that drives the
source. It maintains an internal sequence of sources or iterator of sources
that it can play sequentially. Its responsibilities are to play, pause and seek
into the source.
If the source contains audio, the Player
will
instantiate an AudioPlayer
by asking the SoundDriver
to create an
appropriate AudioPlayer
for the given platform. The AudioDriver
is a
singleton created according to which drivers are available. Currently
supported sound drivers are: DirectSound, PulseAudio and OpenAL.
If the source contains video, the Player has a
get_texture()
method returning the current
video frame.
The player has an internal master clock which is used to synchronize the
video and the audio. The audio synchronization is delegated to the
AudioPlayer
. More info found below. The video synchronization is made by
asking the Source
for the next video timestamp.
The Player
then schedules on pyglet event loop a
call to its update_texture()
with a delay
equals to the difference between the next video timestamp and the master clock
current time.
When update_texture()
is called, we will
check if the actual master clock time is not too late compared to the video
timestamp. This could happen if the loop was very busy and the function could
not be called on time. In this case, the frame would be skipped until we find
a frame with a suitable timestamp for the current master clock time.
AudioPlayer¶
Found in media/drivers
The AudioPlayer
is responsible only for the audio data. It can read, pause,
and seek into the Source
.
In order to accomplish these tasks, the audio player keeps a reference to the
AudioDriver
singleton which provides access to the lower level functions
for the selected audio driver.
When instructed to play, it will register itself on pyglet event loop and
check every 0.1 seconds if there is enough space in its audio buffer. If so it
will ask the source for more audio data to refill its audio buffer. It’s also
at this time that it will check for the difference between the estimated audio
time and the Player
master clock. A weighted
average is used to smooth the inaccuracies of the audio time estimation as
explained in http://dranger.com/ffmpeg/tutorial06.html. If the resulting
difference is too big, the Source
get_audio_data()
method has a
compensation_time
argument which allows it to shorten or stretch the
number of audio samples. This allows the audio to get back in synch with the
master clock.
AudioDriver¶
Found in media/drivers
The AudioDriver
is a wrapper around the low-level sound driver available
on the platform. It’s a singleton. It can create an AudioPlayer
appropriate for the current AudioDriver
.
Normal operation of the Player
¶
The client code instantiates a media player this way:
player = pyglet.media.Player()
source = pyglet.media.load(filename)
player.queue(source)
player.play()
When the client code runs player.play()
:
The Player
will check if there is an audio track
on the media. If so it will instantiate an AudioPlayer
appropriate for the
available sound driver on the platform. It will create an empty
Texture
if the media contains video frames and will
schedule its update_texture()
to be called
immediately. Finally it will start the master clock.
The AudioPlayer
will ask its Source
for
audio data. The Source
will pop the next
available audio packet and will decode it. The resulting audio data will be
returned to the AudioPlayer
. If the audio queue and the video queues are
not full, the Source
will read more packets
from the stream until one of the queues is full again.
When the update_texture()
method is called,
the next video timestamp will be checked with the master clock. We allow a
delay up to the frame duration. If the master clock is beyond that time, the
frame will be skipped. We will check the following frames for its timestamp
until we find the appropriate frame for the master clock time. We will set the
texture
to the new video frame. We will
check for the next video frame timestamp and we will schedule a new call to
update_texture()
with a delay equals to the
difference between the next video timestamps and the master clock time.
Helpful tools¶
I’ve found that using the binary ffprobe is a good way to explore the content of a media file. Here’s a couple of things which might be interesting and helpful:
ffprobe samples_v1.01\SampleVideo_320x240_1mb.3gp -show_frames
This will show information about each frame in the file. You can choose only
audio or only video frames by using the v
flag for video and a
for
audio.:
ffprobe samples_v1.01\SampleVideo_320x240_1mb.3gp -show_frames -select_streams v
You can also ask to see a subset of frame information this way:
ffprobe samples_v1.01\SampleVideo_320x240_1mb.3gp -show_frames
-select_streams v -show_entries frame=pkt_pts,pict_type
Finally, you can get a more compact view with the additional compact
flag:
ffprobe samples_v1.01SampleVideo_320x240_1mb.3gp -show_frames -select_streams v -show_entries frame=pkt_pts,pict_type -of compact
Convert video to mkv¶
ffmpeg -i <original_video> -c:v libx264 -preset slow -profile:v high -crf 18
-coder 1 -pix_fmt yuv420p -movflags +faststart -g 30 -bf 2 -c:a aac -b:a 384k
-profile:a aac_low <outputfilename.mkv>
Media logging manual¶
Workflows¶
User submitting debug info¶
Basically:
- get samples
- run a script
- submit that directory
This is detailed in tools/ffmpeg/readme_run_tests.txt
.
Changing code in pyglet ffmpeg subsystem¶
Preparation like in readme_run_tests.txt, optionally install the library bokeh (http://bokeh.pydata.org/en/latest/index.html) for visualization support.
The basic flow goes as:
initialize the active session subsystem: set environment variable
pyglet_mp_samples_dir
to the desired samples_dir.record a session with the initial state:
configure.py new <session> [playlist] run_test_suite.py
Follow this workflow
while True: edit code commit to hg record a new session: configure.py new <new session> [playlist] run_test_suite.py look at the last session reports in samples_dir/session/reports especially 00_summary.txt, which shows defects stats and list condensed info about any sample failing; then to look more details look at the individual reports. compare with prev sessions if desired: compare.py <session1> <session2> render additional reports: report.py sample or visualize the data collected with: bokeh_timeline.py sample if results are as wanted, break done, you may want to delete sessions for intermediate commits
It is possible to return to a previous session to request additional reports:
configure.py activate <session>
report.py ...
You can list the known sessions for the current samples_dir with:
configure.py list
Important
All this debugging machinery depends on a detailed and accurate capture of media_player related state, currently in examples/media_player.py and pyglet.media.player.
Modifications in those modules may require matching modifications in pyglet/media/sources/instrumentation.py, and further propagation to other modules.
Changing the debug code for pyglet ffmpeg¶
For initial debugging of debug code, where there are misspellings and trivial errors to weed out, creating a new session for each run_test_suite.py run may be inconvenient.
The flag dev_debug
can be set to true in the session configuration file;
this will allow to rewrite the session.
Keep in mind that some raw data will be stale or misleading:
- The ones captured at session creation time (currently pyglet.info and pyglet_changeset)
- The collected crashes info (new crashes will not be seen)
- If media_player.py crashes before doing any writing, the state recording will be the previous recording.
The reports using that stale raw data will obviously report stale data.
So it is a good idea to switch to a normal workflow as soon as posible (simply creating a new session and deleting the special session).
Session¶
If playlist_file
is not specified, then all files in samples_dir, except
for the files with extension “.dbg”, “.htm”, “.html”, “.json”, “.log”, “.pkl”,
“.py”, “.txt” will make the implicit playlist; subdirectories of samples_dir
will not be explored.
If a playlist_file
is specified, then it should contain one sample name
per line; a sanity check will be performed ensuring no blacklisted extension
is used, and that the sample exists in samples_dir.
Once the playlist_file
is used in configure.py new
a copy is writen to
the session raw data directory, and this copy will be the authoritative
playlist for the session; playlist_file
can be deleted if desired.
Specifying a playlist is useful in development to restrict the tests to samples relevant to the feature or issue under work.
The session name will be used to create a samples_dir subdir to store the test
results, hence it should be different of previous sessions names, and it must
not contain slashes, /
, backslashes \
or characters forbidden in
directory names.
Active session¶
Most commands and subcommands target the currently active session.
A session becomes active when
- a
configure.py new session [playlist]
is issued- a
configure.py activate session
is issued
The current implementation relies in two pieces of data to determine the active session
- the environment variable
pyglet_mp_samples_dir
specifies samples_dir, the directory where all the media samples reside. Under the current paths schema is also where session data will be stored, one subdir per session.- a file
activation.json
in samples_dir storing the name for the current active session.
Notice that the second precludes running two commands in parallel targeting two different sessions in the same sample_dir.
The concept of active session plus the enforced path schema avoids the need to provide paths at each command invocation, making for less errors, easier docs and less typing.
Commands Summary¶
Primary commands¶
They are the ones normally used by developers
configure.py
, mp.py
: session creation, activation, protection, status
and list all.
run_test_suite.py
: plays session’s samples, reports results.
report.py
: produces the specified report for the specified sample.
timeline.py
: translates the event stream to a stream of media_player
state, useful to pass to other software.
bokeh_timeline.py
: visualization of data collected for the specified
sample.
Helper commands¶
Somehow an artifact of run_test_suite.py
development, can help in testing
the debugging subsystem. run_test_suite.py
is basically playmany.py +
retry_crashed.py + summarize.py
. When trying to change run_test_suite.py
it is easier to first adapt the relevant helper.
playmany.py
: plays active session samples, recording media_player state
along the play.
retry_crashed.py
: plays again samples that have been seen always
crashing, hoping to get a recording with no crash. Motivated by early tests on
Ubuntu, where sometimes (but not always) a sample will crash the media_player.
summarize.py
: using the raw data produced by the two previous commands
elaborates some reports, aiming to give an idea of how well the run was and
what samples should be investigated.
Data directory layout¶
samples_dir/ : directory where the samples live, also used to store
sessions data
<session name>/ : directory to store session info, one per session,
named as the session.
dbg/ : recording of media_player events captured while playing a
sample, one per sample, named as sample.dbg; additional
versioning info, other raw data collected.
_crashes_light.pkl : pickle with info for retry crashed
_pyglet_hg_revision.txt
_pyglet_info.txt
_samples_version.txt
_session_playlist.txt
<one .dbg file per sample in the session playlist, named sample.dbg>
reports/ : human readable reports rendered from the raw data (.txt),
visualizations (.html), intermediate data used by other
tools(.pkl)
configuration.json : session configuration info, mostly permissions
activation.json : holds the name of current active session
<sample> : one for each sample
A subdirectory of samples_dir is detected as a session dir if:
- it is a direct child of session dir
- it has a
configuration.json
file
policies:
- it should be hard to rewrite the .dbg files (recordings of media_player states)
- think of dev analyzing data sent by an user.
Code Layout and conventions¶
The emerging separation of responsabilities goes like
Scripts (commands)¶
Structured as:
uses
if __main__
idiom to allow use as module (testing, sharing)
sysargs_to_mainargs()
:sys.argv
translation tomain
params
main(...)
- params validation and translation to adequate code entities (uses module
fs
).- translates exceptions to prints (uses module
mpexceptions
)- short chain of instantiations / function calls to accomplish the command goals, no logic or calculations here.
other functions and classes: code specific to this command, delegates as much as possible to modules.
When two scripts use some related but not identical functionality, these parts
can be moved to another module. Example: at first summarize
had the code to
collect defects stats, later, when compare
was writen, the module
extractors
was added and the defect collection stats code moved to that
module.
If script B needs a subset of unchanged script A functionality, it imports A
and uses what it needs. Example is retry_crashed
, will call into
playmany
.
Because of the last point, some scripts will also be listed as modules.
Modules¶
buffered_logger¶
Accumulation of debug events while playing media_player, saves when sample’s play ends
instrumentation¶
Defines the events that modify media_player state. Defines which events are potential defects. Gives the low level support to extract info from the recorded data.
For new code here, keep accepting and returning only data structures, no paths or files.
fs¶
Path building for entities into a session directory should be delegated to
fs.PathServices
.
Session’s creation, activation and management at start of fs
.
Versions capture are handled at start of module fs
.
Utility functions to load - save at the end of fs
.
While there isn’t a Session
object, in practice the code identifies and
provides access to a particular session data by handling a fs.PathServices
instance.
extractors¶
Analyzes a media_player recording to build specific info on behalf of
reporters. Uses instrumentation
to get input data about the media_player
state sequence seen while playing a sample.
Defines object types to collect some specific info about a replay.
reports¶
Formats as text info captured / generated elsewhere.
mpexceptions¶
Defines exceptions generated by code in the ffmpeg debug subsystem.
Scripts that also acts as modules¶
timeline¶
Renders the media player’s debug info to a format more suitable to postprocess
in a spreadsheets or other software, particularly to get a data visualization.
(used by bokeh_timeline.py
)
playmany¶
Produces media_player debug recordings. Runs python scripts as subprocesses with a timeout (used by retry_crashed.py).
Commands detailed¶
bokeh_timeline.py¶
Usage:
bokeh_timeline.py sample
Renders media player’s internal state graphically using bokeh.
Arguments:
sample: sample to report
The output will be written to session’s output dir under
reports/sample.timeline.html
.
Notice the plot can be zoomed live with the mouse wheel, but you must click the button that looks as a distorted OP; it also does pan with mouse drag.
Example:
bokeh_timeline.py small.mp4
will write the output to report/small.mp4.timeline.html
.
compare.py¶
Usage:
compare.py --reldir=relpath other_session
Builds a reports comparing the active session with other_session.
Outputs to samples_dir/relpath/comparison_<session>_<other_session>.txt
.
configure.py¶
Usage:
configure.py subcommand [args]
Subcommands:
new session [playlist] : Creates a new session, sets it as the active one
activate session : activates a session
deactivate : no session will be active
protect [target]: forbids overwrite of session data
status : prints configuration for the active session
help [subcommand] : prints help for the given subcommand or topic
list : list all sessions associated the current samples_dir
Creates and manages pyglet media_player debug session configurations.
Most commands and subcommands need an environment variable
pyglet_mp_samples_dir
to be set to the directory where the media samples
reside.
The configuration stores some values used when other commands are executed, mostly protection status.
This command can be called both as configure.py
or mp.py
, they do the
same.
mp.py¶
alias for configure.py
playmany.py¶
Usage:
playmany.py
Uses media_player to play a sequence of samples and record debug info.
A session must be active, see command configure.py
If the active configuration has disallowed dbg overwrites it will do nothing.
If a playlist was provided at session creation, then only the samples in the
playlist will be played, otherwise all files in samples_dir
.
report.py¶
Usage:
report.py sample report_name
Generates a report from the debugging info recorded while playing sample.
Arguments:
sample: sample to report
report_name: desired report, one of
"anomalies": Start, end and interesting events
"all": All data is exposed as text
"counter": How many occurrences of each defect
The report will be written to session’s output dir under
reports/sample.report_name.txt
.
Example:
report anomalies small.mp4
will write the report anomalies to report/small.mp4.anomalies.txt
.
The authoritative list of reports available comes from
reports.available_reports
retry_crashed.py¶
Usage:
retry_crashed.py [--clean] [max_retries]
Inspects the raw data collected to get the list of samples that crashed the last time they were played. Then it replays those samples, recording new raw data for them.
The process is repeated until all samples has a recording with no crashes or
the still crashing samples were played max_tries
times in this command
run.
Notice that only samples recorded as crashing in the last run are retried.
A configuration must be active, see command configure.py
.
Besides the updated debug recordings, a state is build and saved:
total_retries: total retries attempted, including previous runs
sometimes_crashed: list of samples that crashed one time but later
completed a play
always_crashed: list of samples that always crashed
Options:
--clean: discards crash data collected in a previous run
max_retries: defaults to 5
run_test_suite.py¶
Usage:
run_test_suite.py [samples_dir]
Plays media samples with the pyglet media_player, recording debug information for each sample played and writing reports about the data captured.
Arguments:
samples_dir: directory with the media samples to play
If no samples_dir is provided the active session is the target. If an explicit playlist was specified when creating the session, then only the samples in the playlist will be played, otherwise all samples in samples_dir will be played.
If sample_dir is provided, a session named testrun_00
(_01
, _02
,
… if that name was taken) will be created, with no explicit playlist, and
then the command operates as in the previous case.
Output files will be into:
samples_dir/session/dbg : binary capture of media_player events, other raw
data captured
samples_dir/session/reports : human readable reports
Note
This script will refuse to overwrite an existing test_run results
.
Output files will be into subdirectories:
samples_dir/test_run/dbg
Each sample will generate a
sample.dbg
file storing the sequence of player debug events seen while playing the sample. It is simply a pickle of a list of tuples, each tuple an event. There are not meant for direct human use, but to run some analyzers to render useful reports.A
crash_retries.pkl
file, a pickle of(total_retries, sometimes_crashed, still_crashing) <-> (int, set, set)
.A
pyglet.info
captured at session creation to track hw & sw.A pyglet hg revision captured at session creation.
samples_dir/test_run/reports
Human readable outputs, described in command
summarize.py
Later a user can generate visualizations and additional reports that will be stored in this directory
summarize.py¶
Usage:
summarize.py
Summarizes the session info collected with playmany
and retry_crashes
.
A configuration must be active, see command configure.py
.
If a playlist was provided at session creation, then only the samples in the playlist will be played, otherwise all files in samples_dir.
Produces human readable reports, constructed from the .dbg files.
Output will be in
samples_dir/test_run/reports
The files in that directory will be
00_summary.txt
, which provides:
- basics defects stats over all samples
- a paragraph for each non perfect sample play with the count of each anomaly observed
03_pyglet_info.txt
, pyglet.info
output giving OS, python version,
etc (as captured at session creation).
04_pyglet_hg_revision.txt
, pyglet hg revision if running from a repo
clone, non writen if no repo (as captured at session creation).
sample_name.all.txt
and sample_name.anomalies.txt
for each sample that
played non perfect.
sample_name.all.txt
has all info in the sample_name.dbg
in human
readable form, that is, the sequence of player’s internal events along the
play.
sample_name.anomalies.txt
is a reduced version of the .all
.
variant: normal events are not shown, only anomalies.
timeline.py¶
Usage:
timeline.py sample [output_format]
Renders the media player’s debug info to a format more suitable to postprocess in a spreadsheets or other software, particularly to get a data visualization.
See output details in the manual.
Arguments:
sample: sample to report
output_format : one of { "csv", "pkl"}, by default saves as .pkl (pickle)
The output will be written to session’s output dir under
reports/sample.timeline.[.pkl or .csv]
.
Example:
timeline.py small.mp4
will write the output to report/small.mp4.timeline.pkl
.
Note
.csv
sample is currently not implemented.
Samples¶
Samples should be small, at the moment I suggest an arbitrary 2MB 2 minutes
limit. The samples dir contains a _sources.txt
which lists from where
each sample comes.
Caveat:
Samples are not ‘certified to be compliant with the specification’.
When possible, samples should be played with non ffmpeg software for incidental confirmation of well formed
*.mp4
,*.3gp
played well with Windows Media Player for win7
*.ogv
,*. webm
played well with Firefox 54.0
*.flv
,*.mkv
played well with VLC Media player, but VLC uses ffmpeg
Surely the samples set will be refined as time goes.
pycharm notes¶
For examples/video_ffmpeg
module visibility and code completion, that
directory should be a ‘content root’ in pycharm settings | ‘project
structure’; as projects roots cannot nest, the pyglet working copy cannot be a
‘content root’, I removed it; I added also working_copy/pyglet as another
‘content root’ so pycharm plays well also en the library proper. This with
pycharm 2017.2