Skip to content

Commit cbfa41f

Browse files
committed
Merge remote-tracking branch 'origin/main' into dither3
2 parents 6351de6 + bb71f8c commit cbfa41f

File tree

9 files changed

+170
-8
lines changed

9 files changed

+170
-8
lines changed

locale/circuitpython.pot

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,10 @@ msgstr ""
552552
msgid "Bit depth must be multiple of 8."
553553
msgstr ""
554554

555+
#: shared-bindings/bitmaptools/__init__.c
556+
msgid "Bitmap size and bits per value must match"
557+
msgstr ""
558+
555559
#: supervisor/shared/safe_mode.c
556560
msgid "Boot device must be first device (interface #0)."
557561
msgstr ""
@@ -1071,6 +1075,14 @@ msgstr ""
10711075
msgid "Firmware image is invalid"
10721076
msgstr ""
10731077

1078+
#: shared-bindings/bitmaptools/__init__.c
1079+
msgid "For L8 colorspace, input bitmap must have 8 bits per pixel"
1080+
msgstr ""
1081+
1082+
#: shared-bindings/bitmaptools/__init__.c
1083+
msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel"
1084+
msgstr ""
1085+
10741086
#: ports/cxd56/common-hal/camera/Camera.c
10751087
msgid "Format not supported"
10761088
msgstr ""
@@ -2390,6 +2402,10 @@ msgstr ""
23902402
msgid "Unsupported baudrate"
23912403
msgstr ""
23922404

2405+
#: shared-bindings/bitmaptools/__init__.c
2406+
msgid "Unsupported colorspace"
2407+
msgstr ""
2408+
23932409
#: shared-module/displayio/display_core.c
23942410
msgid "Unsupported display bus type"
23952411
msgstr ""

ports/atmel-samd/boards/pybadge/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ EXTERNAL_FLASH_DEVICES = GD25Q16C
1111
LONGINT_IMPL = MPZ
1212

1313
CIRCUITPY_AESIO = 0
14+
CIRCUITPY_FRAMEBUFFERIO = 0
1415
CIRCUITPY_GAMEPADSHIFT = 1
1516
CIRCUITPY_GIFIO = 0
1617
CIRCUITPY_STAGE = 1

ports/atmel-samd/boards/pygamer/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ EXTERNAL_FLASH_DEVICES = GD25Q64C
1111
LONGINT_IMPL = MPZ
1212

1313
CIRCUITPY_AESIO = 0
14+
CIRCUITPY_FRAMEBUFFERIO = 0
1415
CIRCUITPY_GAMEPADSHIFT = 1
1516
CIRCUITPY_GIFIO = 0
1617
CIRCUITPY_STAGE = 1

ports/atmel-samd/mpconfigport.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
103103
CIRCUITPY_ALARM ?= 0
104104
CIRCUITPY_PS2IO ?= 1
105105
CIRCUITPY_SAMD ?= 1
106-
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FULL_BUILD)
107106
CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
107+
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO)
108108
CIRCUITPY_WATCHDOG ?= 1
109109

110110
endif # samd51
@@ -122,8 +122,8 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
122122

123123
CIRCUITPY_PS2IO ?= 1
124124
CIRCUITPY_SAMD ?= 1
125-
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FULL_BUILD)
126125
CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
126+
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO)
127127

128128
endif # same51
129129
######################################################################

ports/stm/boards/thunderpack_v11/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ LD_COMMON = boards/common_nvm.ld
1717
LD_FILE = boards/STM32F411_nvm.ld
1818

1919
CIRCUITPY_AESIO = 0
20+
CIRCUITPY_BITMAPTOOLS = 0
2021
CIRCUITPY_BLEIO_HCI = 0
2122
CIRCUITPY_VECTORIO = 0
2223
CIRCUITPY_ULAB = 0

ports/stm/common-hal/microcontroller/__init__.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,14 @@
4141
#include "supervisor/shared/safe_mode.h"
4242

4343
void common_hal_mcu_delay_us(uint32_t delay) {
44-
uint32_t ticks_per_us = HAL_RCC_GetSysClockFreq() / 1000000;
44+
uint32_t ticks_per_us = HAL_RCC_GetSysClockFreq() / 1000000UL;
4545
delay *= ticks_per_us;
46+
SysTick->VAL = 0UL;
4647
SysTick->LOAD = delay;
4748
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
4849
while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0) {
4950
}
50-
SysTick->CTRL = 0;
51+
SysTick->CTRL = 0UL;
5152
}
5253

5354
volatile uint32_t nesting_count = 0;

shared-bindings/bitmaptools/__init__.c

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,83 @@ STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args
247247
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
248248
// requires at least 2 arguments (destination bitmap and source bitmap)
249249

250+
//|
251+
//| def alphablend(dest_bitmap, source_bitmap_1, source_bitmap_2, colorspace: displayio.Colorspace, factor1: float=.5, factor2: float=None):
252+
//| """Alpha blend the two source bitmaps into the destination.
253+
//|
254+
//| It is permitted for the destination bitmap to be one of the two
255+
//| source bitmaps.
256+
//|
257+
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
258+
//| :param bitmap source_bitmap_1: The first source bitmap
259+
//| :param bitmap source_bitmap_2: The second source bitmap
260+
//| :param float factor1: The proportion of bitmap 1 to mix in
261+
//| :param float factor2: The proportion of bitmap 2 to mix in. If specified as `None`, ``1-factor1`` is used. Usually the proportions should sum to 1.
262+
//| :param displayio.Colorspace colorspace: The colorspace of the bitmaps. They must all have the same colorspace. Only the following colorspaces are permitted: ``L8``, ``RGB565``, ``RGB565_SWAPPED``, ``BGR565`` and ``BGR565_SWAPPED``.
263+
//|
264+
//| For the L8 colorspace, the bitmaps must have a bits-per-value of 8.
265+
//| For the RGB colorspaces, they must have a bits-per-value of 16."""
266+
//|
267+
268+
STATIC mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
269+
enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2};
270+
271+
static const mp_arg_t allowed_args[] = {
272+
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
273+
{MP_QSTR_source_bitmap_1, MP_ARG_REQUIRED | MP_ARG_OBJ},
274+
{MP_QSTR_source_bitmap_2, MP_ARG_REQUIRED | MP_ARG_OBJ},
275+
{MP_QSTR_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ},
276+
{MP_QSTR_factor_1, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
277+
{MP_QSTR_factor_2, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
278+
};
279+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
280+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
281+
282+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap
283+
displayio_bitmap_t *source1 = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap_1].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap_1)); // the first source bitmap
284+
displayio_bitmap_t *source2 = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap_2].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap_2)); // the second source bitmap
285+
286+
float factor1 = (args[ARG_factor_1].u_obj == mp_const_none) ? .5f : mp_obj_float_get(args[ARG_factor_1].u_obj);
287+
float factor2 = (args[ARG_factor_2].u_obj == mp_const_none) ? 1 - factor1 : mp_obj_float_get(args[ARG_factor_2].u_obj);
288+
289+
displayio_colorspace_t colorspace = (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_colorspace].u_obj);
290+
291+
if (destination->width != source1->width
292+
|| destination->height != source1->height
293+
|| destination->bits_per_value != source1->bits_per_value
294+
|| destination->width != source2->width
295+
|| destination->height != source2->height
296+
|| destination->bits_per_value != source2->bits_per_value
297+
) {
298+
mp_raise_ValueError(translate("Bitmap size and bits per value must match"));
299+
}
300+
301+
switch (colorspace) {
302+
case DISPLAYIO_COLORSPACE_L8:
303+
if (destination->bits_per_value != 8) {
304+
mp_raise_ValueError(translate("For L8 colorspace, input bitmap must have 8 bits per pixel"));
305+
}
306+
break;
307+
308+
case DISPLAYIO_COLORSPACE_RGB565:
309+
case DISPLAYIO_COLORSPACE_RGB565_SWAPPED:
310+
case DISPLAYIO_COLORSPACE_BGR565:
311+
case DISPLAYIO_COLORSPACE_BGR565_SWAPPED:
312+
if (destination->bits_per_value != 16) {
313+
mp_raise_ValueError(translate("For RGB colorspaces, input bitmap must have 16 bits per pixel"));
314+
}
315+
break;
316+
317+
default:
318+
mp_raise_ValueError(translate("Unsupported colorspace"));
319+
}
320+
321+
common_hal_bitmaptools_alphablend(destination, source1, source2, colorspace, factor1, factor2);
322+
323+
return mp_const_none;
324+
}
325+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend);
326+
250327
//|
251328
//| def fill_region(
252329
//| dest_bitmap: displayio.Bitmap,
@@ -279,7 +356,7 @@ STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a
279356
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
280357
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
281358

282-
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
359+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
283360

284361
uint32_t value, color_depth;
285362
value = args[ARG_value].u_int;
@@ -330,7 +407,7 @@ STATIC mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos
330407
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
331408
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
332409

333-
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap
410+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap
334411

335412
uint32_t fill_color_value, color_depth;
336413
fill_color_value = args[ARG_fill_color_value].u_int;
@@ -394,7 +471,7 @@ STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg
394471
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
395472
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
396473

397-
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
474+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
398475

399476
uint32_t value, color_depth;
400477
value = args[ARG_value].u_int;
@@ -659,6 +736,7 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
659736
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
660737
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
661738
{ MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
739+
{ MP_ROM_QSTR(MP_QSTR_alphablend), MP_ROM_PTR(&bitmaptools_alphablend_obj) },
662740
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
663741
{ MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) },
664742
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },

shared-bindings/bitmaptools/__init__.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
2929

3030
#include "shared-module/displayio/Bitmap.h"
31-
#include "shared-module/displayio/Palette.h"
3231
#include "shared-bindings/displayio/ColorConverter.h"
32+
#include "shared-bindings/displayio/__init__.h"
33+
#include "shared-module/displayio/Palette.h"
3334
#include "py/obj.h"
3435
#include "extmod/vfs_fat.h"
3536

@@ -67,4 +68,6 @@ void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *f
6768
void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int element_size, int x1, int y1, int x2, int y2, bool skip_specified, uint32_t skip_index);
6869
void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bitmap_t *source_bitmap, displayio_colorspace_t colorspace, bitmaptools_dither_algorithm_t algorithm);
6970

71+
void common_hal_bitmaptools_alphablend(displayio_bitmap_t *destination, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, float factor1, float factor2);
72+
7073
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H

shared-module/bitmaptools/__init__.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,3 +799,64 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi
799799
displayio_area_t a = { 0, 0, width, height };
800800
displayio_bitmap_set_dirty_area(dest_bitmap, &a);
801801
}
802+
803+
void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, float factor1, float factor2) {
804+
displayio_area_t a = {0, 0, dest->width, dest->height};
805+
displayio_bitmap_set_dirty_area(dest, &a);
806+
807+
int ifactor1 = (int)(factor1 * 256);
808+
int ifactor2 = (int)(factor2 * 256);
809+
810+
if (colorspace == DISPLAYIO_COLORSPACE_L8) {
811+
for (int y = 0; y < dest->height; y++) {
812+
uint8_t *dptr = (uint8_t *)(dest->data + y * dest->stride);
813+
uint8_t *sptr1 = (uint8_t *)(source1->data + y * source1->stride);
814+
uint8_t *sptr2 = (uint8_t *)(source2->data + y * source2->stride);
815+
for (int x = 0; x < dest->width; x++) {
816+
// This is round(l1*f1 + l2*f2) & clip to range in fixed-point
817+
int pixel = (*sptr1++ *ifactor1 + *sptr2++ *ifactor2 + 128) / 256;
818+
*dptr++ = MIN(255, MAX(0, pixel));
819+
}
820+
}
821+
} else {
822+
bool swap = (colorspace == DISPLAYIO_COLORSPACE_RGB565_SWAPPED) || (colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED);
823+
for (int y = 0; y < dest->height; y++) {
824+
uint16_t *dptr = (uint16_t *)(dest->data + y * dest->stride);
825+
uint16_t *sptr1 = (uint16_t *)(source1->data + y * source1->stride);
826+
uint16_t *sptr2 = (uint16_t *)(source2->data + y * source2->stride);
827+
for (int x = 0; x < dest->width; x++) {
828+
int spix1 = *sptr1++;
829+
int spix2 = *sptr2++;
830+
831+
if (swap) {
832+
spix1 = __builtin_bswap16(spix1);
833+
spix2 = __builtin_bswap16(spix2);
834+
}
835+
const int r_mask = 0xf800; // (or b mask, if BGR)
836+
const int g_mask = 0x07e0;
837+
const int b_mask = 0x001f; // (or r mask, if BGR)
838+
839+
// This is round(r1*f1 + r2*f2) & clip to range in fixed-point
840+
// but avoiding shifting it down to start at bit 0
841+
int r = ((spix1 & r_mask) * ifactor1
842+
+ (spix2 & r_mask) * ifactor2 + r_mask / 2) / 256;
843+
r = MIN(r_mask, MAX(0, r)) & r_mask;
844+
845+
// ditto
846+
int g = ((spix1 & g_mask) * ifactor1
847+
+ (spix2 & g_mask) * ifactor2 + g_mask / 2) / 256;
848+
g = MIN(g_mask, MAX(0, g)) & g_mask;
849+
850+
int b = ((spix1 & b_mask) * ifactor1
851+
+ (spix2 & b_mask) * ifactor2 + b_mask / 2) / 256;
852+
b = MIN(b_mask, MAX(0, b)) & b_mask;
853+
854+
uint16_t pixel = r | g | b;
855+
if (swap) {
856+
pixel = __builtin_bswap16(pixel);
857+
}
858+
*dptr++ = pixel;
859+
}
860+
}
861+
}
862+
}

0 commit comments

Comments
 (0)