3535
3636#include "stmhal/font_petme128_8x8.h"
3737
38- // 1-bit frame buffer, each byte is a column of 8 pixels
39- typedef struct _mp_obj_framebuf1_t {
38+ typedef struct _mp_obj_framebuf_t {
4039 mp_obj_base_t base ;
41- uint8_t * buf ;
40+ void * buf ;
4241 uint16_t width , height , stride ;
43- } mp_obj_framebuf1_t ;
42+ uint8_t format ;
43+ } mp_obj_framebuf_t ;
4444
45- STATIC mp_obj_t framebuf1_make_new ( const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
46- mp_arg_check_num ( n_args , n_kw , 3 , 4 , false );
45+ typedef void ( * setpixel_t )( const mp_obj_framebuf_t * , int , int , uint32_t );
46+ typedef uint32_t ( * getpixel_t )( const mp_obj_framebuf_t * , int , int );
4747
48- mp_obj_framebuf1_t * o = m_new_obj (mp_obj_framebuf1_t );
48+ typedef struct _mp_framebuf_p_t {
49+ setpixel_t setpixel ;
50+ getpixel_t getpixel ;
51+ } mp_framebuf_p_t ;
52+
53+ // Functions for MVLSB format
54+
55+ STATIC void mvlsb_setpixel (const mp_obj_framebuf_t * fb , int x , int y , uint32_t color ) {
56+ size_t index = (y >> 3 ) * fb -> stride + x ;
57+ uint8_t offset = y & 0x07 ;
58+ ((uint8_t * )fb -> buf )[index ] = (((uint8_t * )fb -> buf )[index ] & ~(0x01 << offset )) | ((color != 0 ) << offset );
59+ }
60+
61+ STATIC uint32_t mvlsb_getpixel (const mp_obj_framebuf_t * fb , int x , int y ) {
62+ return (((uint8_t * )fb -> buf )[(y >> 3 ) * fb -> stride + x ] >> (y & 0x07 )) & 0x01 ;
63+ }
64+
65+ // Functions for RGB565 format
66+
67+ STATIC void rgb565_setpixel (const mp_obj_framebuf_t * fb , int x , int y , uint32_t color ) {
68+ ((uint16_t * )fb -> buf )[x + y * fb -> stride ] = color ;
69+ }
70+
71+ STATIC uint32_t rgb565_getpixel (const mp_obj_framebuf_t * fb , int x , int y ) {
72+ return ((uint16_t * )fb -> buf )[x + y * fb -> stride ];
73+ }
74+
75+ // constants for formats
76+ #define FRAMEBUF_MVLSB (0)
77+ #define FRAMEBUF_RGB565 (1)
78+
79+ STATIC mp_framebuf_p_t formats [] = {
80+ [FRAMEBUF_MVLSB ] = {mvlsb_setpixel , mvlsb_getpixel },
81+ [FRAMEBUF_RGB565 ] = {rgb565_setpixel , rgb565_getpixel },
82+ };
83+
84+ static inline void setpixel (const mp_obj_framebuf_t * fb , int x , int y , uint32_t color ) {
85+ formats [fb -> format ].setpixel (fb , x , y , color );
86+ }
87+
88+ static inline uint32_t getpixel (const mp_obj_framebuf_t * fb , int x , int y ) {
89+ return formats [fb -> format ].getpixel (fb , x , y );
90+ }
91+
92+ STATIC mp_obj_t framebuf_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
93+ mp_arg_check_num (n_args , n_kw , 4 , 5 , false);
94+
95+ mp_obj_framebuf_t * o = m_new_obj (mp_obj_framebuf_t );
4996 o -> base .type = type ;
5097
5198 mp_buffer_info_t bufinfo ;
@@ -54,98 +101,163 @@ STATIC mp_obj_t framebuf1_make_new(const mp_obj_type_t *type, size_t n_args, siz
54101
55102 o -> width = mp_obj_get_int (args [1 ]);
56103 o -> height = mp_obj_get_int (args [2 ]);
57- o -> stride = o -> width ;
58- if (n_args >= 4 ) {
59- o -> stride = mp_obj_get_int (args [3 ]);
104+ o -> format = mp_obj_get_int (args [3 ]);
105+ if (n_args >= 5 ) {
106+ o -> stride = mp_obj_get_int (args [4 ]);
107+ } else {
108+ o -> stride = o -> width ;
109+ }
110+
111+ switch (o -> format ) {
112+ case FRAMEBUF_MVLSB :
113+ case FRAMEBUF_RGB565 :
114+ break ;
115+ default :
116+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError ,
117+ "invalid format" ));
60118 }
61119
62120 return MP_OBJ_FROM_PTR (o );
63121}
64122
65- STATIC mp_obj_t framebuf1_fill (mp_obj_t self_in , mp_obj_t col_in ) {
66- mp_obj_framebuf1_t * self = MP_OBJ_TO_PTR (self_in );
123+ STATIC mp_obj_t framebuf_fill (mp_obj_t self_in , mp_obj_t col_in ) {
124+ mp_obj_framebuf_t * self = MP_OBJ_TO_PTR (self_in );
67125 mp_int_t col = mp_obj_get_int (col_in );
68- if (col ) {
69- col = 0xff ;
126+ for (int y = 0 ; y < self -> height ; ++ y ) {
127+ for (int x = 0 ; x < self -> width ; ++ x ) {
128+ setpixel (self , x , y , col );
129+ }
70130 }
71- int end = (self -> height + 7 ) >> 3 ;
72- for (int y = 0 ; y < end ; ++ y ) {
73- memset (self -> buf + y * self -> stride , col , self -> width );
131+ return mp_const_none ;
132+ }
133+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (framebuf_fill_obj , framebuf_fill );
134+
135+ STATIC mp_obj_t framebuf_fill_rect (size_t n_args , const mp_obj_t * args ) {
136+ (void )n_args ;
137+
138+ mp_obj_framebuf_t * self = MP_OBJ_TO_PTR (args [0 ]);
139+ mp_int_t x = mp_obj_get_int (args [1 ]);
140+ mp_int_t y = mp_obj_get_int (args [2 ]);
141+ mp_int_t width = mp_obj_get_int (args [3 ]);
142+ mp_int_t height = mp_obj_get_int (args [4 ]);
143+ mp_int_t color = mp_obj_get_int (args [5 ]);
144+
145+ if (x + width <= 0 || y + height <= 0 || y >= self -> height || x >= self -> width ) {
146+ // No operation needed.
147+ return mp_const_none ;
148+ }
149+
150+ // clip to the framebuffer
151+ int xend = MIN (self -> width , x + width );
152+ int yend = MIN (self -> height , y + height );
153+ x = MAX (MIN (x , self -> width ), 0 );
154+ y = MAX (MIN (y , self -> height ), 0 );
155+
156+ for (; y < yend ; ++ y ) {
157+ for (int xc = x ; xc < xend ; ++ xc ) {
158+ setpixel (self , xc , y , color );
159+ }
74160 }
75161 return mp_const_none ;
76162}
77- STATIC MP_DEFINE_CONST_FUN_OBJ_2 ( framebuf1_fill_obj , framebuf1_fill );
163+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN ( framebuf_fill_rect_obj , 6 , 6 , framebuf_fill_rect );
78164
79- STATIC mp_obj_t framebuf1_pixel (size_t n_args , const mp_obj_t * args ) {
80- mp_obj_framebuf1_t * self = MP_OBJ_TO_PTR (args [0 ]);
165+ STATIC mp_obj_t framebuf_pixel (size_t n_args , const mp_obj_t * args ) {
166+ mp_obj_framebuf_t * self = MP_OBJ_TO_PTR (args [0 ]);
81167 mp_int_t x = mp_obj_get_int (args [1 ]);
82168 mp_int_t y = mp_obj_get_int (args [2 ]);
83169 if (0 <= x && x < self -> width && 0 <= y && y < self -> height ) {
84- int index = (y / 8 ) * self -> stride + x ;
85170 if (n_args == 3 ) {
86171 // get
87- return MP_OBJ_NEW_SMALL_INT ((self -> buf [ index ] >> ( y & 7 )) & 1 );
172+ return MP_OBJ_NEW_SMALL_INT (getpixel (self , x , y ) );
88173 } else {
89174 // set
90- if (mp_obj_get_int (args [3 ])) {
91- self -> buf [index ] |= (1 << (y & 7 ));
92- } else {
93- self -> buf [index ] &= ~(1 << (y & 7 ));
94- }
175+ setpixel (self , x , y , mp_obj_get_int (args [3 ]));
95176 }
96177 }
97178 return mp_const_none ;
98179}
99- STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (framebuf1_pixel_obj , 3 , 4 , framebuf1_pixel );
180+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (framebuf_pixel_obj , 3 , 4 , framebuf_pixel );
100181
101- STATIC mp_obj_t framebuf1_scroll (mp_obj_t self_in , mp_obj_t xstep_in , mp_obj_t ystep_in ) {
102- mp_obj_framebuf1_t * self = MP_OBJ_TO_PTR (self_in );
103- mp_int_t xstep = mp_obj_get_int (xstep_in );
104- mp_int_t ystep = mp_obj_get_int (ystep_in );
105- int end = (self -> height + 7 ) >> 3 ;
106- if (ystep > 0 ) {
107- for (int y = end ; y > 0 ;) {
108- -- y ;
109- for (int x = 0 ; x < self -> width ; ++ x ) {
110- int prev = 0 ;
111- if (y > 0 ) {
112- prev = (self -> buf [(y - 1 ) * self -> stride + x ] >> (8 - ystep )) & ((1 << ystep ) - 1 );
113- }
114- self -> buf [y * self -> stride + x ] = (self -> buf [y * self -> stride + x ] << ystep ) | prev ;
115- }
116- }
117- } else if (ystep < 0 ) {
118- for (int y = 0 ; y < end ; ++ y ) {
119- for (int x = 0 ; x < self -> width ; ++ x ) {
120- int prev = 0 ;
121- if (y + 1 < end ) {
122- prev = self -> buf [(y + 1 ) * self -> stride + x ] << (8 + ystep );
123- }
124- self -> buf [y * self -> stride + x ] = (self -> buf [y * self -> stride + x ] >> - ystep ) | prev ;
182+ STATIC mp_obj_t framebuf_blit (size_t n_args , const mp_obj_t * args ) {
183+ mp_obj_framebuf_t * self = MP_OBJ_TO_PTR (args [0 ]);
184+ mp_obj_framebuf_t * source = MP_OBJ_TO_PTR (args [1 ]);
185+ mp_int_t x = mp_obj_get_int (args [2 ]);
186+ mp_int_t y = mp_obj_get_int (args [3 ]);
187+ mp_int_t key = -1 ;
188+ if (n_args > 4 ) {
189+ key = mp_obj_get_int (args [4 ]);
190+ }
191+
192+ if (
193+ (x >= self -> width ) ||
194+ (y >= self -> height ) ||
195+ (- x >= source -> width ) ||
196+ (- y >= source -> height )
197+ ) {
198+ // Out of bounds, no-op.
199+ return mp_const_none ;
200+ }
201+
202+ // Clip.
203+ int x0 = MAX (0 , x );
204+ int y0 = MAX (0 , y );
205+ int x1 = MAX (0 , - x );
206+ int y1 = MAX (0 , - y );
207+ int x0end = MIN (self -> width , x + source -> width );
208+ int y0end = MIN (self -> height , y + source -> height );
209+ uint32_t color ;
210+
211+ for (; y0 < y0end ; ++ y0 ) {
212+ int cx1 = x1 ;
213+ for (int cx0 = x0 ; cx0 < x0end ; ++ cx0 ) {
214+ color = getpixel (source , cx1 , y1 );
215+ if (color != key ) {
216+ setpixel (self , cx0 , y0 , color );
125217 }
218+ ++ cx1 ;
126219 }
220+ ++ y1 ;
127221 }
222+ return mp_const_none ;
223+ }
224+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (framebuf_blit_obj , 4 , 5 , framebuf_blit );
225+
226+ STATIC mp_obj_t framebuf_scroll (mp_obj_t self_in , mp_obj_t xstep_in , mp_obj_t ystep_in ) {
227+ mp_obj_framebuf_t * self = MP_OBJ_TO_PTR (self_in );
228+ mp_int_t xstep = mp_obj_get_int (xstep_in );
229+ mp_int_t ystep = mp_obj_get_int (ystep_in );
230+ int sx , y , xend , yend , dx , dy ;
128231 if (xstep < 0 ) {
129- for (int y = 0 ; y < end ; ++ y ) {
130- for (int x = 0 ; x < self -> width + xstep ; ++ x ) {
131- self -> buf [y * self -> stride + x ] = self -> buf [y * self -> stride + x - xstep ];
132- }
133- }
134- } else if (xstep > 0 ) {
135- for (int y = 0 ; y < end ; ++ y ) {
136- for (int x = self -> width - 1 ; x >= xstep ; -- x ) {
137- self -> buf [y * self -> stride + x ] = self -> buf [y * self -> stride + x - xstep ];
138- }
232+ sx = 0 ;
233+ xend = self -> width + xstep ;
234+ dx = 1 ;
235+ } else {
236+ sx = self -> width - 1 ;
237+ xend = xstep - 1 ;
238+ dx = -1 ;
239+ }
240+ if (ystep < 0 ) {
241+ y = 0 ;
242+ yend = self -> height + ystep ;
243+ dy = 1 ;
244+ } else {
245+ y = self -> height - 1 ;
246+ yend = ystep - 1 ;
247+ dy = -1 ;
248+ }
249+ for (; y != yend ; y += dy ) {
250+ for (int x = sx ; x != xend ; x += dx ) {
251+ setpixel (self , x , y , getpixel (self , x - xstep , y - ystep ));
139252 }
140253 }
141- // TODO: Should we clear the margin created by scrolling?
142254 return mp_const_none ;
143255}
144- STATIC MP_DEFINE_CONST_FUN_OBJ_3 (framebuf1_scroll_obj , framebuf1_scroll );
256+ STATIC MP_DEFINE_CONST_FUN_OBJ_3 (framebuf_scroll_obj , framebuf_scroll );
145257
146- STATIC mp_obj_t framebuf1_text (size_t n_args , const mp_obj_t * args ) {
258+ STATIC mp_obj_t framebuf_text (size_t n_args , const mp_obj_t * args ) {
147259 // extract arguments
148- mp_obj_framebuf1_t * self = MP_OBJ_TO_PTR (args [0 ]);
260+ mp_obj_framebuf_t * self = MP_OBJ_TO_PTR (args [0 ]);
149261 const char * str = mp_obj_str_get_str (args [1 ]);
150262 mp_int_t x0 = mp_obj_get_int (args [2 ]);
151263 mp_int_t y0 = mp_obj_get_int (args [3 ]);
@@ -170,43 +282,39 @@ STATIC mp_obj_t framebuf1_text(size_t n_args, const mp_obj_t *args) {
170282 for (int y = y0 ; vline_data ; vline_data >>= 1 , y ++ ) { // scan over vertical column
171283 if (vline_data & 1 ) { // only draw if pixel set
172284 if (0 <= y && y < self -> height ) { // clip y
173- uint byte_pos = x0 + self -> stride * ((uint )y >> 3 );
174- if (col == 0 ) {
175- // clear pixel
176- self -> buf [byte_pos ] &= ~(1 << (y & 7 ));
177- } else {
178- // set pixel
179- self -> buf [byte_pos ] |= 1 << (y & 7 );
180- }
285+ setpixel (self , x0 , y , col );
181286 }
182287 }
183288 }
184289 }
185290 }
186291 }
187-
188292 return mp_const_none ;
189293}
190- STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (framebuf1_text_obj , 4 , 5 , framebuf1_text );
294+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (framebuf_text_obj , 4 , 5 , framebuf_text );
191295
192- STATIC const mp_rom_map_elem_t framebuf1_locals_dict_table [] = {
193- { MP_ROM_QSTR (MP_QSTR_fill ), MP_ROM_PTR (& framebuf1_fill_obj ) },
194- { MP_ROM_QSTR (MP_QSTR_pixel ), MP_ROM_PTR (& framebuf1_pixel_obj ) },
195- { MP_ROM_QSTR (MP_QSTR_scroll ), MP_ROM_PTR (& framebuf1_scroll_obj ) },
196- { MP_ROM_QSTR (MP_QSTR_text ), MP_ROM_PTR (& framebuf1_text_obj ) },
296+ STATIC const mp_rom_map_elem_t framebuf_locals_dict_table [] = {
297+ { MP_ROM_QSTR (MP_QSTR_fill ), MP_ROM_PTR (& framebuf_fill_obj ) },
298+ { MP_ROM_QSTR (MP_QSTR_fill_rect ), MP_ROM_PTR (& framebuf_fill_rect_obj ) },
299+ { MP_ROM_QSTR (MP_QSTR_pixel ), MP_ROM_PTR (& framebuf_pixel_obj ) },
300+ { MP_ROM_QSTR (MP_QSTR_blit ), MP_ROM_PTR (& framebuf_blit_obj ) },
301+ { MP_ROM_QSTR (MP_QSTR_scroll ), MP_ROM_PTR (& framebuf_scroll_obj ) },
302+ { MP_ROM_QSTR (MP_QSTR_text ), MP_ROM_PTR (& framebuf_text_obj ) },
197303};
198- STATIC MP_DEFINE_CONST_DICT (framebuf1_locals_dict , framebuf1_locals_dict_table );
304+ STATIC MP_DEFINE_CONST_DICT (framebuf_locals_dict , framebuf_locals_dict_table );
199305
200- STATIC const mp_obj_type_t mp_type_framebuf1 = {
306+ STATIC const mp_obj_type_t mp_type_framebuf = {
201307 { & mp_type_type },
202- .name = MP_QSTR_FrameBuffer1 ,
203- .make_new = framebuf1_make_new ,
204- .locals_dict = (mp_obj_t )& framebuf1_locals_dict ,
308+ .name = MP_QSTR_FrameBuffer ,
309+ .make_new = framebuf_make_new ,
310+ .locals_dict = (mp_obj_t )& framebuf_locals_dict ,
205311};
206312
207313STATIC const mp_rom_map_elem_t framebuf_module_globals_table [] = {
208314 { MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_framebuf ) },
209- { MP_ROM_QSTR (MP_QSTR_FrameBuffer1 ), MP_ROM_PTR (& mp_type_framebuf1 ) },
315+ { MP_ROM_QSTR (MP_QSTR_FrameBuffer ), MP_ROM_PTR (& mp_type_framebuf ) },
316+ { MP_ROM_QSTR (MP_QSTR_MVLSB ), MP_OBJ_NEW_SMALL_INT (FRAMEBUF_MVLSB ) },
317+ { MP_ROM_QSTR (MP_QSTR_RGB565 ), MP_OBJ_NEW_SMALL_INT (FRAMEBUF_RGB565 ) },
210318};
211319
212320STATIC MP_DEFINE_CONST_DICT (framebuf_module_globals , framebuf_module_globals_table );
0 commit comments