circuitpython/shared-module/_pixelmap/PixelMap.c

175 lines
6.8 KiB
C

/*
* 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/smallint.h"
#include "py/runtime.h"
#include "shared-bindings/_pixelmap/PixelMap.h"
#include "shared-bindings/adafruit_pixelbuf/PixelBuf.h"
#include "shared-module/_pixelmap/PixelMap.h"
static void pixelmap_set_pixel_rgbw(pixelmap_pixelmap_obj_t *self, size_t i, color_u rgbw) {
mp_arg_validate_index_range(i, 0, self->len - 1, MP_QSTR_index);
mp_obj_t item = self->items[i];
if (mp_obj_is_small_int(item)) {
common_hal_adafruit_pixelbuf_pixelbuf_set_pixel_color(self->pixelbuf, MP_OBJ_SMALL_INT_VALUE(item), rgbw.r, rgbw.g, rgbw.b, rgbw.w);
} else {
size_t len;
mp_obj_t *items;
mp_obj_tuple_get(item, &len, &items);
for (size_t j = 0; j < len; j++) {
common_hal_adafruit_pixelbuf_pixelbuf_set_pixel_color(self->pixelbuf, MP_OBJ_SMALL_INT_VALUE(items[j]), rgbw.r, rgbw.g, rgbw.b, rgbw.w);
}
}
}
static void pixelmap_set_pixel(pixelmap_pixelmap_obj_t *self, size_t i, mp_obj_t color) {
color_u rgbw;
common_hal_adafruit_pixelbuf_pixelbuf_parse_color(self->pixelbuf, color, &rgbw.r, &rgbw.g, &rgbw.b, &rgbw.w);
pixelmap_set_pixel_rgbw(self, i, rgbw);
}
void shared_module_pixelmap_pixelmap_construct(pixelmap_pixelmap_obj_t *self, mp_obj_t pixelbuf, mp_obj_t indices) {
self->pixelbuf = pixelbuf;
self->indices = indices;
mp_obj_tuple_get(indices, &self->len, &self->items);
}
static bool auto_write_get_and_clear(pixelmap_pixelmap_obj_t *self) {
bool auto_write = self->auto_write && common_hal_adafruit_pixelbuf_pixelbuf_get_auto_write(self->pixelbuf);
if (auto_write) {
common_hal_adafruit_pixelbuf_pixelbuf_set_auto_write(self->pixelbuf, false);
}
return auto_write;
}
static void auto_write_reapply(pixelmap_pixelmap_obj_t *self, bool auto_write) {
if (auto_write) {
common_hal_adafruit_pixelbuf_pixelbuf_set_auto_write(self->pixelbuf, true);
common_hal_adafruit_pixelbuf_pixelbuf_show(self->pixelbuf);
}
}
bool shared_module_pixelmap_pixelmap_auto_write_get(pixelmap_pixelmap_obj_t *self) {
return self->auto_write;
}
void shared_module_pixelmap_pixelmap_auto_write_set(pixelmap_pixelmap_obj_t *self, bool auto_write) {
self->auto_write = auto_write;
}
void shared_module_pixelmap_pixelmap_fill(pixelmap_pixelmap_obj_t *self, const mp_obj_t color) {
color_u rgbw;
common_hal_adafruit_pixelbuf_pixelbuf_parse_color(self->pixelbuf, color, &rgbw.r, &rgbw.g, &rgbw.b, &rgbw.w);
bool auto_write = auto_write_get_and_clear(self);
for (size_t i = 0; i < self->len; i++) {
pixelmap_set_pixel_rgbw(self, i, rgbw);
}
auto_write_reapply(self, auto_write);
}
mp_obj_t shared_module_pixelmap_pixelmap_indices(pixelmap_pixelmap_obj_t *self, int index) {
mp_arg_validate_index_range(index, 0, self->len - 1, MP_QSTR_index);
mp_obj_t item = self->items[index];
if (mp_obj_is_small_int(item)) {
return mp_obj_new_tuple(1, &item);
} else {
return item;
}
}
#if MICROPY_PY_BUILTINS_SLICE
mp_obj_t shared_module_pixelmap_pixelmap_getslice(pixelmap_pixelmap_obj_t *self, mp_bound_slice_t slice, size_t slice_len) {
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(slice_len, NULL));
for (uint i = 0; i < slice_len; i++) {
t->items[i] = shared_module_pixelmap_pixelmap_getitem(self, i * slice.step + slice.start);
}
return MP_OBJ_FROM_PTR(t);
}
void shared_module_pixelmap_pixelmap_setslice(pixelmap_pixelmap_obj_t *self, const mp_obj_t values, mp_bound_slice_t slice, size_t slice_len) {
size_t num_items = mp_obj_get_int(mp_obj_len(values));
if (num_items != slice_len) {
mp_raise_ValueError_varg(MP_ERROR_TEXT("Unmatched number of items on RHS (expected %d, got %d)."), slice_len, num_items);
}
bool auto_write = auto_write_get_and_clear(self);
// because we didn't preflight the pixel values, an exception could occur.
// In that case we need to do the auto-write of any pixels that were set
// before re-raising the exception
nlr_buf_t nlr;
size_t start = slice.start;
mp_int_t step = slice.step;
if (nlr_push(&nlr) == 0) {
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(values, &iter_buf);
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
pixelmap_set_pixel(self, start, item);
start += step;
}
nlr_pop();
auto_write_reapply(self, auto_write);
} else {
auto_write_reapply(self, auto_write);
// exception converting color value, re-raise
nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
}
}
#endif
void shared_module_pixelmap_pixelmap_setitem(pixelmap_pixelmap_obj_t *self, mp_int_t i, mp_obj_t color) {
color_u rgbw;
common_hal_adafruit_pixelbuf_pixelbuf_parse_color(self->pixelbuf, color, &rgbw.r, &rgbw.g, &rgbw.b, &rgbw.w);
bool auto_write = auto_write_get_and_clear(self);
pixelmap_set_pixel_rgbw(self, i, rgbw);
auto_write_reapply(self, auto_write);
}
mp_obj_t shared_module_pixelmap_pixelmap_getitem(pixelmap_pixelmap_obj_t *self, mp_int_t i) {
mp_arg_validate_index_range(i, 0, self->len - 1, MP_QSTR_index);
mp_obj_t item = self->items[i];
if (mp_obj_is_small_int(item)) {
return common_hal_adafruit_pixelbuf_pixelbuf_get_pixel(self->pixelbuf, MP_OBJ_SMALL_INT_VALUE(item));
} else {
size_t len;
mp_obj_t *items;
mp_obj_tuple_get(item, &len, &items);
return common_hal_adafruit_pixelbuf_pixelbuf_get_pixel(self->pixelbuf, MP_OBJ_SMALL_INT_VALUE(items[0]));
}
}