micropython-font-to-py/writer/framebuf_utils/framebuf_utils.c

119 wiersze
3.8 KiB
C

#define MICROPY_PY_FRAMEBUF (1)
#include "py/dynruntime.h"
#if !defined(__linux__)
void *memset(void *s, int c, size_t n) {
return mp_fun_table.memset_(s, c, n);
}
#endif
// Match definition from modframebuf.c.
typedef struct _mp_obj_framebuf_t {
mp_obj_base_t base;
mp_obj_t buf_obj; // need to store this to prevent GC from reclaiming buf
void *buf;
uint16_t width, height, stride;
uint8_t format;
} mp_obj_framebuf_t;
// This points to the real mp_type_framebuf from modframebuf.c.
mp_obj_type_t *mp_type_framebuf;
// Unbound FrameBuffer.pixel function.
mp_obj_t framebuf_pixel_obj;
// render(dest, src, x, y, fgcolor, bgcolor=0)
STATIC mp_obj_t framebuf_render(size_t n_args, const mp_obj_t *args) {
// Convert dest/src subclass to the native mp_type_framebuf.
mp_obj_t dest_in = mp_obj_cast_to_native_base(args[0], MP_OBJ_FROM_PTR(mp_type_framebuf));
if (dest_in == MP_OBJ_NULL) {
mp_raise_TypeError(NULL);
}
mp_obj_framebuf_t *dest = MP_OBJ_TO_PTR(dest_in);
mp_obj_t source_in = mp_obj_cast_to_native_base(args[1], MP_OBJ_FROM_PTR(mp_type_framebuf));
if (source_in == MP_OBJ_NULL) {
mp_raise_TypeError(NULL);
}
mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(source_in);
// Pre-build args list for calling framebuf.pixel().
mp_obj_t args_getpixel[3] = { source_in };
mp_obj_t args_setpixel[4] = { dest_in };
mp_int_t x = mp_obj_get_int(args[2]);
mp_int_t y = mp_obj_get_int(args[3]);
mp_int_t fgcol = mp_obj_get_int(args[4]);
mp_int_t bgcol = 0;
if (n_args > 5) {
bgcol = mp_obj_get_int(args[5]);
}
if (
(x >= dest->width) ||
(y >= dest->height) ||
(-x >= source->width) ||
(-y >= source->height)
) {
// Out of bounds, no-op.
return mp_const_none;
}
// Clip.
int x0 = MAX(0, x);
int y0 = MAX(0, y);
int x1 = MAX(0, -x);
int y1 = MAX(0, -y);
int x0end = MIN(dest->width, x + source->width);
int y0end = MIN(dest->height, y + source->height);
for (; y0 < y0end; ++y0) {
int cx1 = x1;
for (int cx0 = x0; cx0 < x0end; ++cx0) {
// source.pixel(cx1, y1)
args_getpixel[1] = MP_OBJ_NEW_SMALL_INT(cx1);
args_getpixel[2] = MP_OBJ_NEW_SMALL_INT(y1);
uint32_t col = mp_obj_get_int(mp_call_function_n_kw(framebuf_pixel_obj, 3, 0, args_getpixel));
// dest.pixel(cx0, y0, bgcol/fgcol)
args_setpixel[1] = MP_OBJ_NEW_SMALL_INT(cx0);
args_setpixel[2] = MP_OBJ_NEW_SMALL_INT(y0);
if (col == 0) {
args_setpixel[3] = MP_OBJ_NEW_SMALL_INT(bgcol);
} else {
args_setpixel[3] = MP_OBJ_NEW_SMALL_INT(fgcol);
}
mp_call_function_n_kw(framebuf_pixel_obj, 4, 0, args_setpixel);
++cx1;
}
++y1;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_render_obj, 5, 6, framebuf_render);
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
MP_DYNRUNTIME_INIT_ENTRY
// import framebuf
mp_obj_t modframebuf = mp_import_name(MP_QSTR_framebuf, mp_const_none, 0);
// mp_type_framebuf = framebuf.FrameBuffer
mp_type_framebuf = MP_OBJ_TO_PTR(mp_load_attr(modframebuf, MP_QSTR_FrameBuffer));
// framebuf_pixel_obj = mp_type_framebuf.pixel
mp_obj_t dest[2];
mp_load_method(MP_OBJ_FROM_PTR(mp_type_framebuf), MP_QSTR_pixel, dest);
// The resulting reference might be heap allocated due to MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG.
// So store a reference to it in globals so the GC knows about it.
framebuf_pixel_obj = dest[0];
mp_store_global(MP_QSTR_pixel, framebuf_pixel_obj);
mp_store_global(MP_QSTR_render, MP_OBJ_FROM_PTR(&framebuf_render_obj));
MP_DYNRUNTIME_INIT_EXIT
}