Skip to content

Commit 73cf490

Browse files
committed
Add TileGrid
1 parent 63d4561 commit 73cf490

8 files changed

Lines changed: 464 additions & 3 deletions

File tree

ports/atmel-samd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ SRC_SHARED_MODULE = \
389389
displayio/Palette.c \
390390
displayio/Shape.c \
391391
displayio/Sprite.c \
392+
displayio/TileGrid.c \
392393
gamepad/__init__.c \
393394
gamepad/GamePad.c \
394395
_stage/__init__.c \

shared-bindings/displayio/Sprite.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#include "shared-bindings/displayio/Shape.h"
4040
#include "supervisor/shared/translate.h"
4141

42-
void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) {
42+
static void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) {
4343
// TODO(tannewt): Support any value sequence such as bytearray or bytes.
4444
mp_obj_tuple_t *position = MP_OBJ_TO_PTR(position_obj);
4545
if (MP_OBJ_IS_TYPE(position_obj, &mp_type_tuple) && position->len == 2) {
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/*
2+
* This file is part of the Micro Python project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "shared-bindings/displayio/TileGrid.h"
28+
29+
#include <stdint.h>
30+
31+
#include "lib/utils/context_manager_helpers.h"
32+
#include "py/binary.h"
33+
#include "py/objproperty.h"
34+
#include "py/runtime.h"
35+
#include "shared-bindings/displayio/Bitmap.h"
36+
#include "shared-bindings/displayio/ColorConverter.h"
37+
#include "shared-bindings/displayio/OnDiskBitmap.h"
38+
#include "shared-bindings/displayio/Palette.h"
39+
#include "shared-bindings/displayio/Shape.h"
40+
#include "supervisor/shared/translate.h"
41+
42+
static void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) {
43+
// TODO(tannewt): Support any value sequence such as bytearray or bytes.
44+
mp_obj_tuple_t *position = MP_OBJ_TO_PTR(position_obj);
45+
if (MP_OBJ_IS_TYPE(position_obj, &mp_type_tuple) && position->len == 2) {
46+
*x = mp_obj_get_int(position->items[0]);
47+
*y = mp_obj_get_int(position->items[1]);
48+
} else if (position != mp_const_none) {
49+
mp_raise_TypeError(translate("position must be 2-tuple"));
50+
}
51+
}
52+
53+
//| .. currentmodule:: displayio
54+
//|
55+
//| :class:`TileGrid` -- A grid of tiles sourced out of one bitmap
56+
//| ==========================================================================
57+
//|
58+
//| Position a grid of tiles sourced from a bitmap and pixel_shader combination. Multiple grids
59+
//| can share bitmaps and pixel shaders.
60+
//|
61+
//| A single tile grid is also known as a Sprite.
62+
//|
63+
//| .. warning:: This will be changed before 4.0.0. Consider it very experimental.
64+
//|
65+
//| .. class:: TileGrid(bitmap, *, pixel_shader, position, width=1, height=1, tile_width=None, tile_height=None, default_tile=0)
66+
//|
67+
//| Create a TileGrid object. The bitmap is source for 2d pixels. The pixel_shader is used to
68+
//| convert the value and its location to a display native pixel color. This may be a simple color
69+
//| palette lookup, a gradient, a pattern or a color transformer.
70+
//|
71+
//| tile_width and tile_height match the height of the bitmap by default.
72+
//|
73+
//| :param displayio.Bitmap bitmap: The bitmap storing one or more tiles.
74+
//| :param displayio.Palette pixel_shader: The pixel shader that produces colors from values
75+
//| :param tuple position: Upper left corner of the grid
76+
//| :param int width: Width of the grid in tiles.
77+
//| :param int height: Height of the grid in tiles.
78+
//| :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
79+
//| :param int tile_height: Height of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
80+
//| :param in default_tile: Default tile index to show.
81+
//|
82+
STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
83+
enum { ARG_bitmap, ARG_pixel_shader, ARG_position, ARG_width, ARG_height, ARG_tile_width, ARG_tile_height, ARG_default_tile };
84+
static const mp_arg_t allowed_args[] = {
85+
{ MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ },
86+
{ MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
87+
{ MP_QSTR_position, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
88+
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
89+
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
90+
{ MP_QSTR_tile_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
91+
{ MP_QSTR_tile_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
92+
{ MP_QSTR_default_tile, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
93+
};
94+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
95+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
96+
97+
mp_obj_t bitmap = args[ARG_bitmap].u_obj;
98+
99+
uint16_t bitmap_width;
100+
uint16_t bitmap_height;
101+
mp_obj_t native = mp_instance_cast_to_native_base(bitmap, &displayio_shape_type);
102+
if (native != MP_OBJ_NULL) {
103+
displayio_shape_t* bmp = MP_OBJ_TO_PTR(native);
104+
bitmap_width = bmp->width;
105+
bitmap_height = bmp->height;
106+
} else if (MP_OBJ_IS_TYPE(bitmap, &displayio_bitmap_type)) {
107+
displayio_bitmap_t* bmp = MP_OBJ_TO_PTR(bitmap);
108+
native = bitmap;
109+
bitmap_width = bmp->width;
110+
bitmap_height = bmp->height;
111+
} else if (MP_OBJ_IS_TYPE(bitmap, &displayio_ondiskbitmap_type)) {
112+
displayio_ondiskbitmap_t* bmp = MP_OBJ_TO_PTR(bitmap);
113+
native = bitmap;
114+
bitmap_width = bmp->width;
115+
bitmap_height = bmp->height;
116+
} else {
117+
mp_raise_TypeError(translate("unsupported bitmap type"));
118+
}
119+
uint16_t tile_width = args[ARG_tile_width].u_int;
120+
if (tile_width == 0) {
121+
tile_width = bitmap_width;
122+
}
123+
uint16_t tile_height = args[ARG_tile_height].u_int;
124+
if (tile_height == 0) {
125+
tile_height = bitmap_height;
126+
}
127+
if (bitmap_width % tile_width != 0) {
128+
mp_raise_ValueError(translate("Tile width must exactly divide bitmap width"));
129+
}
130+
if (bitmap_height % tile_height != 0) {
131+
mp_raise_ValueError(translate("Tile height must exactly divide bitmap height"));
132+
}
133+
134+
int16_t x = 0;
135+
int16_t y = 0;
136+
mp_obj_t position_obj = args[ARG_position].u_obj;
137+
unpack_position(position_obj, &x, &y);
138+
139+
displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t);
140+
self->base.type = &displayio_tilegrid_type;
141+
common_hal_displayio_tilegrid_construct(self, native, args[ARG_pixel_shader].u_obj,
142+
args[ARG_width].u_int, args[ARG_height].u_int, tile_width, tile_height, x, y,
143+
args[ARG_default_tile].u_int);
144+
return MP_OBJ_FROM_PTR(self);
145+
}
146+
147+
//| .. attribute:: position
148+
//|
149+
//| The position of the top-left corner of the tilegrid.
150+
//|
151+
STATIC mp_obj_t displayio_tilegrid_obj_get_position(mp_obj_t self_in) {
152+
displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in);
153+
int16_t x;
154+
int16_t y;
155+
common_hal_displayio_tilegrid_get_position(self, &x, &y);
156+
157+
mp_obj_t coords[2];
158+
coords[0] = mp_obj_new_int(x);
159+
coords[1] = mp_obj_new_int(y);
160+
161+
return mp_obj_new_tuple(2, coords);
162+
}
163+
MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_position_obj, displayio_tilegrid_obj_get_position);
164+
165+
STATIC mp_obj_t displayio_tilegrid_obj_set_position(mp_obj_t self_in, mp_obj_t value) {
166+
displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in);
167+
168+
int16_t x = 0;
169+
int16_t y = 0;
170+
unpack_position(value, &x, &y);
171+
172+
common_hal_displayio_tilegrid_set_position(self, x, y);
173+
174+
return mp_const_none;
175+
}
176+
MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_position_obj, displayio_tilegrid_obj_set_position);
177+
178+
const mp_obj_property_t displayio_tilegrid_position_obj = {
179+
.base.type = &mp_type_property,
180+
.proxy = {(mp_obj_t)&displayio_tilegrid_get_position_obj,
181+
(mp_obj_t)&displayio_tilegrid_set_position_obj,
182+
(mp_obj_t)&mp_const_none_obj},
183+
};
184+
185+
//| .. attribute:: pixel_shader
186+
//|
187+
//| The pixel shader of the tilegrid.
188+
//|
189+
STATIC mp_obj_t displayio_tilegrid_obj_get_pixel_shader(mp_obj_t self_in) {
190+
displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in);
191+
return common_hal_displayio_tilegrid_get_pixel_shader(self);
192+
}
193+
MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_pixel_shader_obj, displayio_tilegrid_obj_get_pixel_shader);
194+
195+
STATIC mp_obj_t displayio_tilegrid_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) {
196+
displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in);
197+
if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type) && !MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type)) {
198+
mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter"));
199+
}
200+
201+
common_hal_displayio_tilegrid_set_pixel_shader(self, pixel_shader);
202+
203+
return mp_const_none;
204+
}
205+
MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_pixel_shader_obj, displayio_tilegrid_obj_set_pixel_shader);
206+
207+
const mp_obj_property_t displayio_tilegrid_pixel_shader_obj = {
208+
.base.type = &mp_type_property,
209+
.proxy = {(mp_obj_t)&displayio_tilegrid_get_pixel_shader_obj,
210+
(mp_obj_t)&displayio_tilegrid_set_pixel_shader_obj,
211+
(mp_obj_t)&mp_const_none_obj},
212+
};
213+
214+
STATIC const mp_rom_map_elem_t displayio_tilegrid_locals_dict_table[] = {
215+
// Properties
216+
{ MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&displayio_tilegrid_position_obj) },
217+
{ MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&displayio_tilegrid_pixel_shader_obj) },
218+
};
219+
STATIC MP_DEFINE_CONST_DICT(displayio_tilegrid_locals_dict, displayio_tilegrid_locals_dict_table);
220+
221+
const mp_obj_type_t displayio_tilegrid_type = {
222+
{ &mp_type_type },
223+
.name = MP_QSTR_Sprite,
224+
.make_new = displayio_tilegrid_make_new,
225+
.locals_dict = (mp_obj_dict_t*)&displayio_tilegrid_locals_dict,
226+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* This file is part of the Micro Python project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
28+
#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
29+
30+
#include "shared-module/displayio/TileGrid.h"
31+
32+
extern const mp_obj_type_t displayio_tilegrid_type;
33+
34+
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
35+
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
36+
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile);
37+
38+
void common_hal_displayio_tilegrid_get_position(displayio_tilegrid_t *self, int16_t* x, int16_t* y);
39+
void common_hal_displayio_tilegrid_set_position(displayio_tilegrid_t *self, int16_t x, int16_t y);
40+
41+
mp_obj_t common_hal_displayio_tilegrid_get_pixel_shader(displayio_tilegrid_t *self);
42+
void common_hal_displayio_tilegrid_set_pixel_shader(displayio_tilegrid_t *self, mp_obj_t pixel_shader);
43+
44+
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H

shared-bindings/displayio/__init__.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "shared-bindings/displayio/ParallelBus.h"
4141
#include "shared-bindings/displayio/Shape.h"
4242
#include "shared-bindings/displayio/Sprite.h"
43+
#include "shared-bindings/displayio/TileGrid.h"
4344

4445
//| :mod:`displayio` --- Native display driving
4546
//| =========================================================================
@@ -68,6 +69,7 @@
6869
//| ParallelBus
6970
//| Shape
7071
//| Sprite
72+
//| TileGrid
7173
//|
7274
//| All libraries change hardware state but are never deinit
7375
//|
@@ -95,6 +97,7 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = {
9597
{ MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) },
9698
{ MP_ROM_QSTR(MP_QSTR_Shape), MP_ROM_PTR(&displayio_shape_type) },
9799
{ MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&displayio_sprite_type) },
100+
{ MP_ROM_QSTR(MP_QSTR_TileGrid), MP_ROM_PTR(&displayio_tilegrid_type) },
98101

99102
{ MP_ROM_QSTR(MP_QSTR_FourWire), MP_ROM_PTR(&displayio_fourwire_type) },
100103
{ MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&displayio_parallelbus_type) },

shared-module/displayio/Group.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include "py/runtime.h"
3030
#include "shared-bindings/displayio/Sprite.h"
31+
#include "shared-bindings/displayio/TileGrid.h"
3132

3233
void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_size) {
3334
mp_obj_t* children = m_new(mp_obj_t, max_size);
@@ -43,7 +44,10 @@ void common_hal_displayio_group_append(displayio_group_t* self, mp_obj_t layer)
4344
native_layer = mp_instance_cast_to_native_base(layer, &displayio_sprite_type);
4445
}
4546
if (native_layer == MP_OBJ_NULL) {
46-
mp_raise_ValueError(translate("Layer must be a Group or Sprite subclass."));
47+
native_layer = mp_instance_cast_to_native_base(layer, &displayio_tilegrid_type);
48+
}
49+
if (native_layer == MP_OBJ_NULL) {
50+
mp_raise_ValueError(translate("Layer must be a Group or TileGrid subclass."));
4751
}
4852
self->children[self->size] = layer;
4953
self->size++;
@@ -77,7 +81,11 @@ bool displayio_group_get_pixel(displayio_group_t *self, int16_t x, int16_t y, ui
7781
y /= self->scale;
7882
for (int32_t i = self->size - 1; i >= 0 ; i--) {
7983
mp_obj_t layer = self->children[i];
80-
if (MP_OBJ_IS_TYPE(layer, &displayio_sprite_type)) {
84+
if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) {
85+
if (displayio_tilegrid_get_pixel(layer, x, y, pixel)) {
86+
return true;
87+
}
88+
} else if (MP_OBJ_IS_TYPE(layer, &displayio_sprite_type)) {
8189
if (displayio_sprite_get_pixel(layer, x, y, pixel)) {
8290
return true;
8391
}

0 commit comments

Comments
 (0)