diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 792a3a7fa2..33985dd00a 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -53,6 +53,41 @@ typedef struct _mp_framebuf_p_t { fill_rect_t fill_rect; } mp_framebuf_p_t; +// constants for formats +#define FRAMEBUF_MVLSB (0) +#define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_GS4_HMSB (2) +#define FRAMEBUF_MHLSB (3) +#define FRAMEBUF_MHMSB (4) + +// Functions for MHLSB and MHMSB + +STATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) { + size_t index = (x + y * fb->stride) >> 3; + int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07); + ((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((color != 0) << offset); +} + +STATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + size_t index = (x + y * fb->stride) >> 3; + int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07); + return (((uint8_t*)fb->buf)[index] >> (offset)) & 0x01; +} + +STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + int reverse = fb->format == FRAMEBUF_MHMSB; + int advance = fb->stride >> 3; + while (w--) { + uint8_t *b = &((uint8_t*)fb->buf)[(x >> 3) + y * advance]; + int offset = reverse ? x & 7 : 7 - (x & 7); + for (int hh = h; hh; --hh) { + *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset); + b += advance; + } + ++x; + } +} + // Functions for MVLSB format STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) { @@ -148,15 +183,12 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, } } -// constants for formats -#define FRAMEBUF_MVLSB (0) -#define FRAMEBUF_RGB565 (1) -#define FRAMEBUF_GS4_HMSB (2) - STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, + [FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, + [FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect}, }; static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) { @@ -207,6 +239,10 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size case FRAMEBUF_RGB565: case FRAMEBUF_GS4_HMSB: break; + case FRAMEBUF_MHLSB: + case FRAMEBUF_MHMSB: + o->stride = (o->stride + 7) & ~7; + break; default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid format")); @@ -545,6 +581,8 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565) }, { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB) }, + { MP_ROM_QSTR(MP_QSTR_MHLSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB) }, + { MP_ROM_QSTR(MP_QSTR_MHMSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB) }, }; STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table); diff --git a/tests/extmod/framebuf1.py b/tests/extmod/framebuf1.py index c204e63aa3..0a8e1ae550 100644 --- a/tests/extmod/framebuf1.py +++ b/tests/extmod/framebuf1.py @@ -7,87 +7,96 @@ except ImportError: w = 5 h = 16 -buf = bytearray(w * h // 8) -fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.MVLSB) +size = w * h // 8 +buf = bytearray(size) +maps = {framebuf.MVLSB : 'MVLSB', + framebuf.MHLSB : 'MHLSB', + framebuf.MHMSB : 'MHMSB'} -# access as buffer -print(memoryview(fbuf)[0]) +for mapping in maps.keys(): + for x in range(size): + buf[x] = 0 + fbuf = framebuf.FrameBuffer(buf, w, h, mapping) + print(maps[mapping]) + # access as buffer + print(memoryview(fbuf)[0]) -# fill -fbuf.fill(1) -print(buf) -fbuf.fill(0) -print(buf) + # fill + fbuf.fill(1) + print(buf) + fbuf.fill(0) + print(buf) -# put pixel -fbuf.pixel(0, 0, 1) -fbuf.pixel(4, 0, 1) -fbuf.pixel(0, 15, 1) -fbuf.pixel(4, 15, 1) -print(buf) + # put pixel + fbuf.pixel(0, 0, 1) + fbuf.pixel(4, 0, 1) + fbuf.pixel(0, 15, 1) + fbuf.pixel(4, 15, 1) + print(buf) -# clear pixel -fbuf.pixel(4, 15, 0) -print(buf) + # clear pixel + fbuf.pixel(4, 15, 0) + print(buf) -# get pixel -print(fbuf.pixel(0, 0), fbuf.pixel(1, 1)) + # get pixel + print(fbuf.pixel(0, 0), fbuf.pixel(1, 1)) -# hline -fbuf.fill(0) -fbuf.hline(0, 1, w, 1) -print('hline', buf) + # hline + fbuf.fill(0) + fbuf.hline(0, 1, w, 1) + print('hline', buf) -# vline -fbuf.fill(0) -fbuf.vline(1, 0, h, 1) -print('vline', buf) + # vline + fbuf.fill(0) + fbuf.vline(1, 0, h, 1) + print('vline', buf) -# rect -fbuf.fill(0) -fbuf.rect(1, 1, 3, 3, 1) -print('rect', buf) + # rect + fbuf.fill(0) + fbuf.rect(1, 1, 3, 3, 1) + print('rect', buf) -#fill rect -fbuf.fill(0) -fbuf.fill_rect(0, 0, 0, 3, 1) # zero width, no-operation -fbuf.fill_rect(1, 1, 3, 3, 1) -print('fill_rect', buf) + #fill rect + fbuf.fill(0) + fbuf.fill_rect(0, 0, 0, 3, 1) # zero width, no-operation + fbuf.fill_rect(1, 1, 3, 3, 1) + print('fill_rect', buf) -# line -fbuf.fill(0) -fbuf.line(1, 1, 3, 3, 1) -print('line', buf) + # line + fbuf.fill(0) + fbuf.line(1, 1, 3, 3, 1) + print('line', buf) -# line steep negative gradient -fbuf.fill(0) -fbuf.line(3, 3, 2, 1, 1) -print('line', buf) + # line steep negative gradient + fbuf.fill(0) + fbuf.line(3, 3, 2, 1, 1) + print('line', buf) -# scroll -fbuf.fill(0) -fbuf.pixel(2, 7, 1) -fbuf.scroll(0, 1) -print(buf) -fbuf.scroll(0, -2) -print(buf) -fbuf.scroll(1, 0) -print(buf) -fbuf.scroll(-1, 0) -print(buf) -fbuf.scroll(2, 2) -print(buf) + # scroll + fbuf.fill(0) + fbuf.pixel(2, 7, 1) + fbuf.scroll(0, 1) + print(buf) + fbuf.scroll(0, -2) + print(buf) + fbuf.scroll(1, 0) + print(buf) + fbuf.scroll(-1, 0) + print(buf) + fbuf.scroll(2, 2) + print(buf) -# print text -fbuf.fill(0) -fbuf.text("hello", 0, 0, 1) -print(buf) -fbuf.text("hello", 0, 0, 0) # clear -print(buf) + # print text + fbuf.fill(0) + fbuf.text("hello", 0, 0, 1) + print(buf) + fbuf.text("hello", 0, 0, 0) # clear + print(buf) -# char out of font range set to chr(127) -fbuf.text(str(chr(31)), 0, 0) -print(buf) + # char out of font range set to chr(127) + fbuf.text(str(chr(31)), 0, 0) + print(buf) + print() # test invalid constructor, and stride argument try: diff --git a/tests/extmod/framebuf1.py.exp b/tests/extmod/framebuf1.py.exp index 83d775d3c4..736ad7a454 100644 --- a/tests/extmod/framebuf1.py.exp +++ b/tests/extmod/framebuf1.py.exp @@ -1,3 +1,4 @@ +MVLSB 0 bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff') bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') @@ -18,4 +19,49 @@ bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') bytearray(b'\x00\x7f\x7f\x04\x04\x00\x00\x00\x00\x00') bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') bytearray(b'\xaaU\xaaU\xaa\x00\x00\x00\x00\x00') + +MHLSB +0 +bytearray(b'\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00') +1 0 +hline bytearray(b'\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00') +vline bytearray(b'@@@@@@@@@@') +rect bytearray(b'\x00pPp\x00\x00\x00\x00\x00\x00') +fill_rect bytearray(b'\x00ppp\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00@ \x10\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00 \x10\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00 \x00') +bytearray(b'\x00\x00\x00\x00\x00\x00 \x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00 \x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00') +bytearray(b'``x````\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'P\xa8P\xa8P\xa8P\xa8\x00\x00') + +MHMSB +0 +bytearray(b'\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00') +1 0 +hline bytearray(b'\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00') +vline bytearray(b'\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02') +rect bytearray(b'\x00\x0e\n\x0e\x00\x00\x00\x00\x00\x00') +fill_rect bytearray(b'\x00\x0e\x0e\x0e\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00\x02\x04\x08\x00\x00\x00\x00\x00\x00') +line bytearray(b'\x00\x04\x04\x08\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00') +bytearray(b'\x06\x06\x1e\x06\x06\x06\x06\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\n\x15\n\x15\n\x15\n\x15\x00\x00') + ValueError