2023-03-30 08:18:31 +00:00
|
|
|
(using-sdl)=
|
|
|
|
|
|
|
|
# Using SDL-based packages in Pyodide
|
|
|
|
|
|
|
|
```{admonition} This is experimental
|
|
|
|
:class: warning
|
|
|
|
|
|
|
|
SDL support in Pyodide is experimental.
|
|
|
|
Pyodide relies on undocumented behavior of Emscripten and SDL,
|
|
|
|
so it may break or change in the future.
|
|
|
|
|
|
|
|
In addition, this feature requires to enable an opt-in flag,
|
|
|
|
`pyodide._api._skip_unwind_fatal_error = true;`
|
|
|
|
which can lead to stack unwinding issues (see {ref}`sdl-known-issues`).
|
|
|
|
```
|
|
|
|
|
|
|
|
Pyodide provides a way to use SDL-based packages in the browser,
|
|
|
|
This document explains how to use SDL-based packages in Pyodide.
|
|
|
|
|
|
|
|
## Setting canvas
|
|
|
|
|
|
|
|
Before using SDL-based packages, you need to set the canvas to draw on.
|
|
|
|
|
|
|
|
The `canvas` object must be a
|
|
|
|
[HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement) object,
|
|
|
|
with the `id` attribute set to `"canvas"`.
|
|
|
|
For example, you can set a canvas like this:
|
|
|
|
|
|
|
|
```js
|
|
|
|
let sdl2Canvas = document.createElement("canvas");
|
|
|
|
sdl2Canvas.id = "canvas";
|
|
|
|
pyodide.canvas.setCanvas2D(sdl2Canvas);
|
|
|
|
```
|
|
|
|
|
|
|
|
See also: {ref}`js-api-pyodide-canvas`
|
|
|
|
|
2024-03-29 08:55:21 +00:00
|
|
|
## Working with infinite loop
|
|
|
|
|
|
|
|
It is common to use an infinite loop to draw animations or game scenes with SDL-based package.
|
|
|
|
|
|
|
|
For instance, a common code pattern in `pygame` (a SDL-based Python game library) is:
|
|
|
|
|
|
|
|
```python
|
|
|
|
clock = pygame.time.Clock()
|
|
|
|
fps = 60
|
|
|
|
def run_game():
|
|
|
|
while True:
|
|
|
|
do_something()
|
|
|
|
draw_canvas()
|
|
|
|
clock.tick(fps)
|
|
|
|
```
|
|
|
|
|
|
|
|
However, in Pyodide, this will not work as expected, because the loop will block the main thread and prevent the browser from updating the canvas.
|
|
|
|
To work around this, you need to use async functions and yield control to the browser.
|
|
|
|
|
|
|
|
```python
|
|
|
|
import asyncio
|
|
|
|
|
|
|
|
async def run_game():
|
|
|
|
while True:
|
|
|
|
do_something()
|
|
|
|
draw_canvas()
|
|
|
|
await asyncio.sleep(1 / fps)
|
|
|
|
```
|
|
|
|
|
|
|
|
Using `asyncio.sleep` will yield control to the browser and allow the canvas to be updated.
|
|
|
|
|
2023-03-30 08:18:31 +00:00
|
|
|
(sdl-known-issues)=
|
|
|
|
|
|
|
|
## Known issues
|
|
|
|
|
|
|
|
There is a known issue that with,
|
|
|
|
|
|
|
|
```
|
|
|
|
pyodide._api._skip_unwind_fatal_error = true;
|
|
|
|
```
|
|
|
|
|
|
|
|
Python call stacks are not being unwound after calling `emscripten_set_main_loop()`.
|
|
|
|
|
|
|
|
see: [pyodide#3697](https://github.com/pyodide/pyodide/issues/3697)
|