circuitpython/shared-bindings/_pixelmap/PixelMap.c

270 lines
11 KiB
C
Raw Normal View History

Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
/*
* This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Rose Hooper
* Copyright (c) 2022 Jeff Epler for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/objproperty.h"
#include "py/objtype.h"
#include "py/runtime.h"
2022-11-24 10:07:08 -05:00
#include "shared-bindings/_pixelmap/PixelMap.h"
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
#include "shared-bindings/adafruit_pixelbuf/PixelBuf.h"
2022-11-24 10:07:08 -05:00
#include "shared-module/_pixelmap/PixelMap.h"
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
//| from adafruit_pixelbuf import PixelBuf, PixelReturnType, PixelSequence, PixelType
//|
//| class PixelMap:
//| def __init__(self, pixelbuf: PixelBuf, indices: Tuple[Union[int, Tuple[int]]]) -> None:
//| """Construct a PixelMap object that uses the given indices of the underlying pixelbuf"""
STATIC mp_obj_t pixelmap_pixelmap_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_pixelbuf, ARG_indices };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pixelbuf, MP_ARG_REQUIRED },
{ MP_QSTR_indices, MP_ARG_REQUIRED },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t pixelbuf = args[ARG_pixelbuf].u_obj;
mp_obj_t native_pixelbuf = mp_obj_cast_to_native_base(pixelbuf, &pixelbuf_pixelbuf_type);
if (!native_pixelbuf) {
(void)mp_arg_validate_type(args[ARG_pixelbuf].u_obj, &pixelbuf_pixelbuf_type, MP_QSTR_pixelbuf);
}
mp_obj_assert_native_inited(native_pixelbuf);
size_t buflen = common_hal_adafruit_pixelbuf_pixelbuf_get_len(pixelbuf);
mp_obj_t indices = mp_arg_validate_type(args[ARG_indices].u_obj, &mp_type_tuple, MP_QSTR_indices);
// validate indices
size_t len;
mp_obj_t *items;
mp_obj_tuple_get(indices, &len, &items);
mp_arg_validate_length_min(len, 1, MP_QSTR_items);
for (size_t i = 0; i < len; i++) {
mp_obj_t item = items[i];
if (mp_obj_is_small_int(item)) {
mp_arg_validate_index_range(MP_OBJ_SMALL_INT_VALUE(item), 0, buflen - 1, MP_QSTR_index);
} else if (mp_obj_is_tuple_compatible(item)) {
size_t len1;
mp_obj_t *items1;
mp_obj_tuple_get(item, &len1, &items1);
for (size_t j = 0; j < len1; j++) {
mp_obj_t item1 = items1[j];
if (!mp_obj_is_small_int(item1)) {
mp_raise_TypeError(translate("nested index must be int"));
}
mp_arg_validate_index_range(MP_OBJ_SMALL_INT_VALUE(item1), 0, buflen - 1, MP_QSTR_index);
}
} else {
mp_raise_TypeError(translate("index must be tuple or int"));
}
}
pixelmap_pixelmap_obj_t *self = m_new_obj(pixelmap_pixelmap_obj_t);
self->base.type = &pixelmap_pixelmap_type;
shared_module_pixelmap_pixelmap_construct(self, pixelbuf, indices);
return MP_OBJ_FROM_PTR(self);
}
//| auto_write: bool
//| """True if updates should be automatically written"""
STATIC mp_obj_t pixelmap_pixelmap_auto_write_get(const mp_obj_t self_in) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(shared_module_pixelmap_pixelmap_auto_write_get(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(pixelmap_pixelmap_auto_write_get_obj, pixelmap_pixelmap_auto_write_get);
STATIC mp_obj_t pixelmap_pixelmap_auto_write_set(const mp_obj_t self_in, const mp_obj_t arg) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
shared_module_pixelmap_pixelmap_auto_write_set(self, mp_obj_is_true(arg));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(pixelmap_pixelmap_auto_write_set_obj, pixelmap_pixelmap_auto_write_set);
MP_PROPERTY_GETSET(pixelmap_pixelmap_auto_write_obj,
(mp_obj_t)&pixelmap_pixelmap_auto_write_get_obj,
(mp_obj_t)&pixelmap_pixelmap_auto_write_set_obj);
//| bpp: int
//| """The number of bytes per pixel in the buffer (read-only)"""
STATIC mp_obj_t pixelmap_pixelmap_obj_get_bpp(mp_obj_t self_in) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_NEW_SMALL_INT(common_hal_adafruit_pixelbuf_pixelbuf_get_bpp(self->pixelbuf));
}
MP_DEFINE_CONST_FUN_OBJ_1(pixelmap_pixelmap_get_bpp_obj, pixelmap_pixelmap_obj_get_bpp);
MP_PROPERTY_GETTER(pixelmap_pixelmap_bpp_obj,
(mp_obj_t)&pixelmap_pixelmap_get_bpp_obj);
//| byteorder: str
//| """byteorder string for the buffer (read-only)"""
STATIC mp_obj_t pixelmap_pixelmap_obj_get_byteorder(mp_obj_t self_in) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
return common_hal_adafruit_pixelbuf_pixelbuf_get_byteorder_string(self->pixelbuf);
}
MP_DEFINE_CONST_FUN_OBJ_1(pixelmap_pixelmap_get_byteorder, pixelmap_pixelmap_obj_get_byteorder);
MP_PROPERTY_GETTER(pixelmap_pixelmap_byteorder_obj,
(mp_obj_t)&pixelmap_pixelmap_get_byteorder);
//|
2022-11-30 20:16:20 -05:00
//| def fill(self, color: PixelType) -> None:
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
//| """Fill all the pixels in the map with the given color"""
STATIC mp_obj_t pixelmap_pixelmap_fill(const mp_obj_t self_in, const mp_obj_t color) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
shared_module_pixelmap_pixelmap_fill(self, color);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(pixelmap_pixelmap_fill_obj, pixelmap_pixelmap_fill);
//|
2022-11-30 20:16:20 -05:00
//| def indices(self, index: int) -> Tuple[int]:
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
//| """Return the PixelBuf indices for a PixelMap index"""
STATIC mp_obj_t pixelmap_pixelmap_indices(const mp_obj_t self_in, const mp_obj_t index) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
return shared_module_pixelmap_pixelmap_indices(self, mp_obj_get_int(index));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(pixelmap_pixelmap_indices_obj, pixelmap_pixelmap_indices);
2022-11-30 20:16:20 -05:00
//| @overload
//| def __getitem__(self, index: slice) -> PixelReturnSequence:
//| """Retrieve the value of the underlying pixels."""
//| ...
//| @overload
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
//| def __getitem__(self, index: int) -> PixelReturnType:
2022-11-30 20:16:20 -05:00
//| """Retrieve the value of one of the underlying pixels at 'index'."""
//| ...
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
//| @overload
//| def __setitem__(self, index: slice, value: PixelSequence) -> None: ...
//| @overload
//| def __setitem__(self, index: int, value: PixelType) -> None:
//| """Sets the pixel value at the given index. Value can either be a tuple or integer. Tuples are
//| The individual (Red, Green, Blue[, White]) values between 0 and 255. If given an integer, the
//| red, green and blue values are packed into the lower three bytes (0xRRGGBB).
//| For RGBW byteorders, if given only RGB values either as an int or as a tuple, the white value
//| is used instead when the red, green, and blue values are the same."""
//| ...
STATIC mp_obj_t pixelmap_pixelmap_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (value == MP_OBJ_NULL) {
// delete
return MP_OBJ_NULL; // op not supported
}
if (0) {
#if MICROPY_PY_BUILTINS_SLICE
} else if (mp_obj_is_type(index_in, &mp_type_slice)) {
2022-11-30 20:16:20 -05:00
mp_bound_slice_t slice;
mp_seq_get_fast_slice_indexes(self->len, index_in, &slice);
size_t slice_len;
if (slice.step > 0) {
slice_len = slice.stop - slice.start;
} else {
slice_len = 1 + slice.start - slice.stop;
}
if (slice.step > 1 || slice.step < -1) {
size_t step = slice.step > 0 ? slice.step : slice.step * -1;
slice_len = (slice_len / step) + (slice_len % step ? 1 : 0);
}
if (value == MP_OBJ_SENTINEL) { // Get
return shared_module_pixelmap_pixelmap_getslice(self, slice, slice_len);
} else { // Set
shared_module_pixelmap_pixelmap_setslice(self, value, slice, slice_len);
return mp_const_none;
}
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
#endif
2022-11-30 20:16:20 -05:00
} else { // single index
int index = mp_obj_get_int(index_in);
if (value == MP_OBJ_SENTINEL) { // Get
return shared_module_pixelmap_pixelmap_getitem(self, index);
} else {
shared_module_pixelmap_pixelmap_setitem(self, mp_obj_get_int(index_in), value);
return mp_const_none;
}
Add adafruit_pixelmap.PixelMap .. a fast helper for animations. It is similar to and inspired by the PixelMap helper in Adafruit LED Animation library, but with an extremely fast 'paste' method for setting a series of pixels. This is a common operation for many animations, and can give a substantial speed improvement. It's named `adafruit_pixelmap` so that we can package a compatible version in pure Python for systems that can't fit it in C in flash, or for Blinka. This is a proof of concept and can make a very fast comet animation: ```python import time import adafruit_pixelbuf import adafruti_pixelmap import board import neopixel from supervisor import ticks_ms from adafruit_led_animation.animation.solid import Solid from adafruit_led_animation import color pixel_pin = board.GP0 pixel_num = 96 pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=1, auto_write=False, pixel_order="RGB") evens = adafruit_pixelmap.PixelMap(pixels, tuple(range(0, pixel_num, 2))) odd_indices = tuple((i, i+2) for i in range(1, pixel_num, 4)) print(odd_indices) odds = adafruit_pixelbuf.PixelMap(pixels, odd_indices) assert len(odds) == len(odd_indices) comet_length = 16 comet1 = [color.calculate_intensity(color.GREEN, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] comet2 = [color.calculate_intensity(color.PURPLE, ((1+i) / comet_length) ** 2.4) for i in range(comet_length)] pos1 = 0 pos2 = 96//4 while True: evens.paste(comet1, pos1, wrap=True, reverse=False, others=0) pos1 = (pos1 + 1) % len(evens) odds.paste(comet2, pos2, wrap=True, reverse=True, others=0) pos2 = (pos2 - 1) % len(odds) pixels.show() m = ticks_ms() if m % 2000 > 1000: time.sleep(.02) ```
2022-11-10 12:02:31 -05:00
}
}
//| def __len__(self) -> int:
//| """Length of the map"""
STATIC mp_obj_t pixelmap_pixelmap_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
switch (op) {
case MP_UNARY_OP_BOOL:
return mp_const_true;
case MP_UNARY_OP_LEN:
return MP_OBJ_NEW_SMALL_INT(self->len);
default:
return MP_OBJ_NULL; // op not supported
}
}
//| def show(self) -> None:
//| """Transmits the color data to the pixels so that they are shown. This is done automatically
//| when `auto_write` is True."""
//| ...
//|
STATIC mp_obj_t pixelmap_pixelmap_show(mp_obj_t self_in) {
pixelmap_pixelmap_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_adafruit_pixelbuf_pixelbuf_show(self->pixelbuf);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pixelmap_pixelmap_show_obj, pixelmap_pixelmap_show);
STATIC const mp_rom_map_elem_t pixelmap_pixelmap_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_auto_write), MP_ROM_PTR(&pixelmap_pixelmap_auto_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_bpp), MP_ROM_PTR(&pixelmap_pixelmap_bpp_obj) },
{ MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_PTR(&pixelmap_pixelmap_byteorder_obj) },
{ MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&pixelmap_pixelmap_fill_obj) },
{ MP_ROM_QSTR(MP_QSTR_indices), MP_ROM_PTR(&pixelmap_pixelmap_indices_obj) },
{ MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&pixelmap_pixelmap_show_obj) },
};
STATIC MP_DEFINE_CONST_DICT(pixelmap_pixelmap_locals_dict, pixelmap_pixelmap_locals_dict_table);
const mp_obj_type_t pixelmap_pixelmap_type = {
{ &mp_type_type },
.name = MP_QSTR_PixelMap,
.flags = MP_TYPE_FLAG_EXTENDED,
.locals_dict = (mp_obj_t)&pixelmap_pixelmap_locals_dict,
.make_new = pixelmap_pixelmap_make_new,
MP_TYPE_EXTENDED_FIELDS(
.subscr = pixelmap_pixelmap_subscr,
.unary_op = pixelmap_pixelmap_unary_op,
),
};