Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Examples

Small programs that show pygraphics drawing on a display. Each one says in
its docstring what it needs and where it has been run. Run them from the
repository's root, so the ones that load a picture or a font find it in
[assets/](assets/).

| Example | What it shows |
|---|---|
| [graphics_simpletest.py](graphics_simpletest.py) | Shapes and text drawn straight on the display |
| [framebuf_simpletest.py](framebuf_simpletest.py) | The same shapes drawn into a FrameBuffer, then copied on |
| [pygraphics_landscape.py](pygraphics_landscape.py) | A landscape drawn in bands, scaled to any display |
| [rotations.py](rotations.py) | The display turned through its four rotations |
| [font_list.py](font_list.py) | Every bitmap font in a folder |
| [pbm_simpletest.py](pbm_simpletest.py) | A one-bit PBM picture shown in colour |
| [pbm_create_new.py](pbm_create_new.py) | A one-bit logo drawn, then shown in colour |
| [bmp565_simpletest.py](bmp565_simpletest.py) | A whole BMP picture loaded and shown |
| [bmp565_sprite.py](bmp565_sprite.py) | A sprite walking, read from a sprite sheet |
| [bmp565_scroll.py](bmp565_scroll.py) | A tall picture scrolled a line at a time |
| [bmp565_scroll_sprite.py](bmp565_scroll_sprite.py) | A runner on a scrolling street, played by touch |

Full apps that use pygraphics are in
[pydevices-examples](https://github.com/PyDevices/pydevices-examples).
Binary file added examples/assets/font_8x14.bin
Binary file not shown.
Binary file added examples/assets/font_8x16.bin
Binary file not shown.
Binary file added examples/assets/font_8x8.bin
Binary file not shown.
Binary file added examples/assets/longstreet.bmp
Binary file not shown.
Binary file added examples/assets/micropython.pbm
Binary file not shown.
Binary file added examples/assets/runner.bmp
Binary file not shown.
Binary file added examples/assets/warrior.bmp
Binary file not shown.
67 changes: 67 additions & 0 deletions examples/bmp565_scroll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT
"""Scroll a tall BMP picture down the display.

Draws a picture taller than the screen one line at a time, then keeps
going with the display's hardware scrolling (vscsad), so it never needs
the whole picture in memory.

Needs: a board_config with a display_drv, which a PyDevices board
package or pydevices-desktop provides, appdev and pygraphics.

Run it from the repository's root:
python examples/bmp565_scroll.py

On a board, copy longstreet.bmp to the board's examples/assets/ first.

Tested on: CPython 3.12 on Linux, in an SDL window.
"""

from board_config import display_drv
import board_config
import appdev

app = appdev.App(board_config)
from pygraphics import BMP565

display_drv.rotation = 0

image = BMP565("examples/assets/longstreet.bmp", streamed=True)
print(f"\n{image.width=}, {image.height=}, {image.bpp=}")


def draw_bg(dest_x, dest_y, source_x, source_y, source_image=image, width=image.width, height=1):
display_drv.blit_rect(
source_image[source_x : source_x + width, source_y : source_y + height],
dest_x,
dest_y,
width,
height,
)


def main():
st = {"phase": "fill", "j": 0, "i": display_drv.height}

def _tick(_=None):
if app.quit_requested:
return
if st["phase"] == "fill":
j = st["j"]
if j < display_drv.height:
draw_bg(0, j, 0, j, height=1)
st["j"] = j + 1
if st["j"] >= display_drv.height:
st["phase"] = "scroll"
return
# scroll phase
i = st["i"]
display_drv.vscsad(i % display_drv.height)
draw_bg(0, i % display_drv.height, 0, i % image.height)
st["i"] = i + 1

app.every(_tick, period=1)


main()
142 changes: 142 additions & 0 deletions examples/bmp565_scroll_sprite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT
"""A runner on a scrolling street.

Scrolls a street picture across the display a column at a time while a
runner sprite runs on it. Touch or click the top half to jump and shoot,
the bottom left to jump, and the bottom right to shoot.

Needs: a board_config with a display_drv, which a PyDevices board
package or pydevices-desktop provides, appdev and pygraphics.

Run it from the repository's root:
python examples/bmp565_scroll_sprite.py

On a board, copy longstreet.bmp and runner.bmp to the board's examples/assets/ first.

Tested on: CPython 3.12 on Linux, in an SDL window.
"""

from collections import namedtuple

from board_config import display_drv
import board_config
import appdev

app = appdev.App(board_config)
from pygraphics import BMP565

point = namedtuple("point", "x y")

display_drv.rotation = 90

display_drv.fill(0)

image = BMP565("examples/assets/longstreet.bmp", streamed=True, mirrored=True)
print(f"\n{image.width=}, {image.height=}, {image.bpp=}")


def draw_bg(dest_x, source_y, count=1, source=image):
# 1D row slice is ``count * source.width`` pixels; blit as a vertical
# strip (width=count, height=source.width). Do not use display_drv.height —
# tall panels (e.g. Android after rotation) are larger than the bitmap.
display_drv.blit_rect(
source[source_y : source_y + count], dest_x, 0, count, source.width
)


char_sprites = BMP565("examples/assets/runner.bmp", streamed=True)
print(f"\n{char_sprites.width=}, {char_sprites.height=}, {char_sprites.bpp=}")
char_height = char_sprites.height // 3
char_width = char_sprites.width // 6
bg = char_sprites[0]
print(f"{char_width=}, {char_height=} {bg=:#0x}\n")

run_sprites = [point(x * char_width, 0) for x in range(6)]
shoot_sprites = [point(x * char_width, char_height) for x in range(6)]
jump_sprites = [point(x * char_width, char_height * 2) for x in range(2)]
jump_shoot_sprites = [point((x + 2) * char_width, char_height * 2) for x in range(2)]
shot_sprite = point(4 * char_width, char_height * 2)


def draw_sprite(
dest_x, dest_y, source_x, source_y, source=char_sprites, width=char_width, height=char_height
):
display_drv.blit_rect(
source[source_x : source_x + width, source_y : source_y + height],
dest_x,
dest_y,
width,
height,
)


def main():
st = {
"i": 0,
"scroll": 0,
"char_y": display_drv.height - char_height,
"char_x": 200,
"shot_location": 0,
"sprites": run_sprites,
}

def _on_motion(event):
if not event.buttons[0]:
st["sprites"] = run_sprites
return
touched_point = event.pos
if touched_point[1] < display_drv.height // 2:
st["sprites"] = jump_shoot_sprites
if not st["shot_location"]:
st["shot_location"] = 1
elif touched_point[0] < display_drv.width // 2:
st["sprites"] = jump_sprites
elif touched_point[0] > display_drv.width // 2:
st["sprites"] = shoot_sprites
if not st["shot_location"]:
st["shot_location"] = 1
else:
st["sprites"] = run_sprites

def _tick(_=None):
# Auto-service handles QUIT; never poll from on_tick.
if app.quit_requested:
return
i = st["i"]
if i > display_drv.width:
st["scroll"] = i % display_drv.width
display_drv.vscsad(st["scroll"])
draw_bg(i % display_drv.width, i % image.height, 1)
st["i"] = i + 1
if i < display_drv.width:
return

draw_x = st["scroll"] + st["char_x"]
sprite = st["sprites"][st["i"] % len(st["sprites"])]
draw_sprite(draw_x, st["char_y"], sprite.x, sprite.y)
if st["shot_location"]:
draw_sprite(
draw_x + char_width + st["shot_location"],
st["char_y"],
shot_sprite.x,
shot_sprite.y,
)
st["shot_location"] += 8
if st["shot_location"] > (display_drv.width - char_width) // 2:
display_drv.fill_rect(
draw_x + char_width + st["shot_location"],
st["char_y"],
char_width,
char_height,
bg,
)
st["shot_location"] = 0

app.on(app.events.MOUSEMOTION, _on_motion)
# ~20 fps once scrolling; first columns also tick so quit is always serviced.
app.every(_tick, period=50)


main()
54 changes: 54 additions & 0 deletions examples/bmp565_simpletest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT
"""Load a BMP picture and show it.

Loads the whole of a 16-bit BMP into memory and copies it to the display
two ways: as a slice, bmp[x0:x1, y0:y1], and as bmp[:]. Loading it all
needs RAM: a small board such as an RP2040 raises MemoryError. See
bmp565_scroll_sprite.py for reading a picture a line at a time instead.

Needs: a board_config with a display_drv, which a PyDevices board
package or pydevices-desktop provides, and pygraphics.

Run it from the repository's root:
python examples/bmp565_simpletest.py

On a board, copy warrior.bmp to the board's examples/assets/ first.

Tested on: CPython 3.12 on Linux, in an SDL window.
"""

from board_config import display_drv
from pygraphics import BMP565, hline

try:
from time import sleep_ms
except ImportError:
from time import sleep

def sleep_ms(milliseconds):
sleep(milliseconds / 1000)


try:
bmp = BMP565("examples/assets/warrior.bmp")
except MemoryError:
raise MemoryError("this board doesn't have enough RAM to load the full image")

print(f"{bmp.width=}, {bmp.height=}, {bmp.bpp=}")

display_drv.fill(0x0)
display_drv.show()
display_drv.blit_rect(bmp[0 : bmp.width, 0 : bmp.height], 0, 0, bmp.width, bmp.height)
display_drv.show()
sleep_ms(1000)

display_drv.fill(0x0)
display_drv.show()
sleep_ms(250)

hline(bmp, 0, bmp.height // 2, bmp.width, 0xFFFF)
display_drv.blit_rect(bmp[:], 0, 0, bmp.width, bmp.height)
display_drv.show()
sleep_ms(1000)
Loading