From 9656e33dc87cc70418f97da53da20dde85dcccc8 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Thu, 21 Oct 2021 22:50:02 +0100 Subject: [PATCH] MicroPython: Bind new text API, cleanup bindings. Remove dead code and deprecated bindings to keep things tidy. Overhaul all state functions: pen, alpha, clip, blend, spritesheet, target, cursor, camera. These now reset to default state when called with no args. Removed: * tick * _reset These are replaced by "start" and "quit". Added: * flip() - flip the screen, can be used in REPL to see your experiments. * w, h = measure("Text String") - measure text Changed: * text --- .flake8 | 7 +- libraries/utility.cpp | 72 --------- micropython/examples/picosystem/launcher.py | 4 +- micropython/examples/picosystem/sprites.py | 2 +- .../modules/picosystem/micropython.cmake | 7 + micropython/modules/picosystem/picosystem.c | 25 ++-- micropython/modules/picosystem/picosystem.cpp | 137 +++-------------- micropython/modules/picosystem/picosystem.h | 17 ++- micropython/modules/picosystem/primitives.cpp | 55 ------- micropython/modules/picosystem/state.cpp | 138 ++++++++++++------ micropython/modules/picosystem/text.cpp | 86 +++++++++++ 11 files changed, 242 insertions(+), 308 deletions(-) create mode 100644 micropython/modules/picosystem/text.cpp diff --git a/.flake8 b/.flake8 index 5dad6e7..a3dbb8a 100644 --- a/.flake8 +++ b/.flake8 @@ -7,11 +7,10 @@ builtins = Buffer, Voice, pen, - tick, + flip, init, start, quit, - _reset, _logo, play, clip, @@ -35,7 +34,7 @@ builtins = blit, sprite, text, - text_width, + measure, rgb, hsv, intersects, @@ -213,4 +212,4 @@ builtins = SWORD9, SWORD10, SWORD11, - CROWN2, \ No newline at end of file + CROWN2, diff --git a/libraries/utility.cpp b/libraries/utility.cpp index e4c1b0c..2fa0927 100644 --- a/libraries/utility.cpp +++ b/libraries/utility.cpp @@ -107,78 +107,6 @@ namespace picosystem { int32_t cx, int32_t cy, int32_t cw, int32_t ch) { return x >= cx && y >= cy && x + w <= cx + cw && y + h <= cy + ch; } -/* - uint32_t text_width(std::string &t) { - // add up length of characters - uint32_t l = 0; - if(_tlw == -1) { - for(auto c : t) { - l += _font[(c - 32) * 9]; - } - }else{ - l = t.size() * _tlw; - } - // add letter spacing - l += _tls * (t.size() - 1); - return l; - } - - uint32_t _word_length(std::string &t, std::size_t &i) { - // skip past any spaces if present - i = t.find_first_not_of(' ', i); - - if(i == std::string::npos) { - return std::string::npos; - } - - // find next space after current word - std::size_t n = t.find(' ', i); - - if(n == std::string::npos) { - n = t.length(); - } - - // add up length of characters - uint32_t l = 0; - while(i < n) { - if(_tlw == -1) { - l += _font[(t[i] - 32) * 9] + _tls; - }else{ - l += _tlw + _tls; - } - i++; - }; - - // remove last letter spacing - l -= _tls; - - return l; - } - - uint32_t wrap(std::string &t, uint32_t w) { - std::size_t i = 0, si = 0, ll = 0; - - while(true) { - uint32_t wl = _word_length(t, i); - - if(i == std::string::npos) { - break; - } - - if(ll + wl >= w) { - // if we would overflow the line then replace space with a newline - t[si] = '\n'; - // next line starts with current word - ll = 0; - } - - ll += wl + (_tlw == -1 ? _font[(t[i] - 32) * 9] : _tlw) + _tls; // 2 == space length, should be a configurable? - - si = i; - } - - return 0; - }*/ std::vector split(const std::string& t, char d) { std::vector l; diff --git a/micropython/examples/picosystem/launcher.py b/micropython/examples/picosystem/launcher.py index b0cc652..4c830c7 100644 --- a/micropython/examples/picosystem/launcher.py +++ b/micropython/examples/picosystem/launcher.py @@ -95,7 +95,7 @@ def draw(tick): pen(15, 15, 15) _logo() label = "".join(["", "Pi", "co", "Sys", "tem"][0:min(note_idx, 5)]) - label_width = text_width(label) + label_width, _ = measure(label) text(label, int(60 - (label_width / 2)), 90) return @@ -128,7 +128,7 @@ def draw(tick): label = files[selected] if label == "__quit__": label = "quit" - label_width = text_width(label) + label_width, _ = measure(label) pen(11, 11, 8) frect(int(60 - label_width / 2 - 3), 102 - 3, label_width + 6, 13) pen(0, 0, 0) diff --git a/micropython/examples/picosystem/sprites.py b/micropython/examples/picosystem/sprites.py index 06ae118..70ae1d1 100644 --- a/micropython/examples/picosystem/sprites.py +++ b/micropython/examples/picosystem/sprites.py @@ -81,7 +81,7 @@ def draw(tick): ) # centre name of weapon at bottom of screen - label_width = text_width(weapons[selected][1]) + label_width, _ = measure(weapons[selected][1]) pen(11, 11, 8) frect(int(60 - label_width / 2 - 3), 102 - 3, label_width + 6, 13) pen(0, 0, 0) diff --git a/micropython/modules/picosystem/micropython.cmake b/micropython/modules/picosystem/micropython.cmake index 736f095..8431a8d 100644 --- a/micropython/modules/picosystem/micropython.cmake +++ b/micropython/modules/picosystem/micropython.cmake @@ -9,6 +9,7 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/buffer.cpp ${CMAKE_CURRENT_LIST_DIR}/state.cpp ${CMAKE_CURRENT_LIST_DIR}/primitives.cpp + ${CMAKE_CURRENT_LIST_DIR}/text.cpp ${CMAKE_CURRENT_LIST_DIR}/utility.cpp ${CMAKE_CURRENT_LIST_DIR}/hardware.cpp ${CMAKE_CURRENT_LIST_DIR}/stats.cpp @@ -17,6 +18,7 @@ target_sources(usermod_${MOD_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/blend.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/state.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/primitives.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/text.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/utility.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/hardware.cpp ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/assets.cpp @@ -53,4 +55,9 @@ set_source_files_properties( ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/primitives.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-compare" +) +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/text.cpp + PROPERTIES COMPILE_FLAGS + "-Wno-error=sign-compare" ) \ No newline at end of file diff --git a/micropython/modules/picosystem/picosystem.c b/micropython/modules/picosystem/picosystem.c index 884ab04..5b8e9fa 100755 --- a/micropython/modules/picosystem/picosystem.c +++ b/micropython/modules/picosystem/picosystem.c @@ -66,11 +66,10 @@ const mp_obj_type_t PicosystemVoice_type = { // picosystem.cpp MP_DEFINE_CONST_FUN_OBJ_0(picosystem_init_obj, picosystem_init); -MP_DEFINE_CONST_FUN_OBJ_0(picosystem_reset_obj, picosystem_reset); -MP_DEFINE_CONST_FUN_OBJ_0(picosystem_tick_obj, picosystem_tick); MP_DEFINE_CONST_FUN_OBJ_0(picosystem_logo_obj, picosystem_logo); -MP_DEFINE_CONST_FUN_OBJ_0(picosystem_run_obj, picosystem_run); +MP_DEFINE_CONST_FUN_OBJ_0(picosystem_start_obj, picosystem_start); MP_DEFINE_CONST_FUN_OBJ_0(picosystem_quit_obj, picosystem_quit); +MP_DEFINE_CONST_FUN_OBJ_0(picosystem_flip_obj, picosystem_flip); // stats.cpp @@ -82,12 +81,15 @@ MP_DEFINE_CONST_FUN_OBJ_KW(picosystem_play_obj, 2, picosystem_audio_play); // state.cpp -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_pen_obj, 1, 4, picosystem_pen); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_clip_obj, 4, 4, picosystem_clip); -MP_DEFINE_CONST_FUN_OBJ_1(picosystem_blend_obj, picosystem_blend); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_pen_obj, 0, 4, picosystem_pen); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_alpha_obj, 0, 4, picosystem_alpha); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_clip_obj, 0, 4, picosystem_clip); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_blend_obj, 0, 1, picosystem_blend); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_target_obj, 0, 1, picosystem_target); -MP_DEFINE_CONST_FUN_OBJ_2(picosystem_camera_obj, picosystem_camera); -MP_DEFINE_CONST_FUN_OBJ_1(picosystem_spritesheet_obj, picosystem_spritesheet); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_camera_obj, 0, 2, picosystem_camera); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_cursor_obj, 0, 2, picosystem_cursor); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_spritesheet_obj, 0, 1, picosystem_spritesheet); +// TODO font? // primitives.cpp @@ -112,8 +114,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR(picosystem_fpoly_obj, 1, picosystem_fpoly); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_line_obj, 4, 4, picosystem_line); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_blit_obj, 7, 7, picosystem_blit); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_sprite_obj, 3, 7, picosystem_sprite); -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_text_obj, 1, 3, picosystem_text); -MP_DEFINE_CONST_FUN_OBJ_1(picosystem_text_width_obj, picosystem_text_width); + +// text.cpp + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_text_obj, 1, 4, picosystem_text); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picosystem_measure_obj, 1, 2, picosystem_measure); // utility.cpp diff --git a/micropython/modules/picosystem/picosystem.cpp b/micropython/modules/picosystem/picosystem.cpp index a7f72e5..4585fb8 100644 --- a/micropython/modules/picosystem/picosystem.cpp +++ b/micropython/modules/picosystem/picosystem.cpp @@ -14,27 +14,9 @@ extern "C" { #include "cstring" #include "py/gc.h" -//#define NOT_INITIALISED_MSG "Cannot call this function, as picodisplay is not initialised. Call picodisplay.init() first." - -//mp_obj_t picodisplay_buf_obj; - -// mp_obj_t picodisplay_init(mp_obj_t buf_obj) { -// mp_buffer_info_t bufinfo; -// mp_get_buffer_raise(buf_obj, &bufinfo, MP_BUFFER_RW); -// picodisplay_buf_obj = buf_obj; -// if(display == nullptr) -// display = new PicoDisplay((uint16_t *)bufinfo.buf); -// display->init(); -// return mp_const_none; -// } - -uint32_t update_rate_ms = 10; -uint32_t pending_update_ms = 0; -uint32_t last_ms = time(); -bool running = true; +bool running = true; uint32_t tick = 0; - static bool done_audio_init = false; mp_obj_t update_callback_obj = mp_const_none; @@ -58,35 +40,8 @@ mp_obj_t pimoroni_mp_load_global(qstr qst) { return elem->value; } -mp_obj_t picosystem_reset() { - running = false; - update_callback_obj = mp_const_none; - draw_callback_obj = mp_const_none; - tick = 0; - return mp_const_none; -} - -mp_obj_t picosystem_logo() { - const uint8_t *s = _picosystem_logo; - - for(int y = 35; y < 85; y++) { - for(int x = 19; x < 101; x+=8) { - for(int bit = 0; bit < 8; bit++) { - if(*s & (0b10000000 >> bit)) { - pixel(x + bit, y); - } - } - s++; - } - } - - return mp_const_none; -} - mp_obj_t picosystem_init() { - //MP_STATE_PORT(picosystem_framebuffer) = m_new(color_t, 120 * 120); - //SCREEN = buffer(120, 120, MP_STATE_PORT(picosystem_framebuffer)); target(SCREEN); update_callback_obj = mp_const_none; @@ -116,19 +71,11 @@ mp_obj_t picosystem_init() { while (_is_flipping()); // wait for the screen to update _wait_vsync(); - _wait_vsync(); + _wait_vsync(); // Need to wait just a little longer to avoid a tiny flash of garbage // Turn the screen on backlight(75); - // call users init() function so they can perform any needed - // setup for world state etc - //init(); - - update_rate_ms = 10; - pending_update_ms = 0; - last_ms = time(); - tick = 0; _io = _gpio_get(); @@ -136,7 +83,7 @@ mp_obj_t picosystem_init() { return mp_const_none; } -mp_obj_t picosystem_run() { +mp_obj_t picosystem_start() { if(update_callback_obj == mp_const_none) { update_callback_obj = pimoroni_mp_load_global(qstr_from_str("update")); if(update_callback_obj == mp_const_none) { @@ -220,80 +167,38 @@ mp_obj_t picosystem_run() { return mp_const_none; } +/* quit() - Break out of the main loop started by start() */ mp_obj_t picosystem_quit(){ running = false; return mp_const_none; } -mp_obj_t picosystem_tick() { - uint32_t start_tick_us = time_us(); - - if(update_callback_obj == mp_const_none) { - update_callback_obj = pimoroni_mp_load_global(qstr_from_str("update")); - if(update_callback_obj == mp_const_none) { - //TODO switch out this URL for the final one - mp_raise_msg(&mp_type_NameError, "a function named 'update(ticks)' is not defined. Check out https://github.com/pimoroni/picosystem/blob/main/micropython/README.md for instructions"); - } - } - - if(draw_callback_obj == mp_const_none) { - draw_callback_obj = mp_load_global(qstr_from_str("draw")); - if(draw_callback_obj == mp_const_none) { - //TODO switch out this URL for the final one - mp_raise_msg(&mp_type_NameError, "a function named 'draw()' is not defined. Check out https://github.com/pimoroni/picosystem/blob/main/micropython/README.md for instructions"); - } - } - - // store previous io state and get new io state - _lio = _io; - _io = _gpio_get(); - - // call users update() function - uint32_t start_update_us = time_us(); - mp_call_function_1(update_callback_obj, mp_obj_new_int(tick++)); - stats.update_us = time_us() - start_update_us; - - // if we're currently transferring the the framebuffer to the screen then - // wait until that is complete before allowing the user to do their drawing - uint32_t wait_us = 0; - uint32_t start_wait_flip_us = time_us(); +/* flip() - Flip the buffer, use this from the repl! (or, your own main loop?) */ +mp_obj_t picosystem_flip() { while(_is_flipping()) { - MICROPY_EVENT_POLL_HOOK + best_effort_wfe_or_timeout(make_timeout_time_us(500)); } - wait_us += time_us() - start_wait_flip_us; - - // call user render function to draw world - uint32_t start_draw_us = time_us(); - mp_call_function_1(draw_callback_obj, mp_obj_new_int(tick)); - stats.draw_us = time_us() - start_draw_us; - - // wait for the screen to vsync before triggering flip - // to ensure no tearing - uint32_t start_wait_vsync_us = time_us(); _wait_vsync(); - wait_us += time_us() - start_wait_vsync_us; - - // flip the framebuffer to the screen _flip(); + return mp_const_none; +} - tick++; - - stats.tick_us = time_us() - start_tick_us; - - // calculate fps and round to nearest value (instead of truncating/floor) - stats.fps = (1000000 - 1) / stats.tick_us + 1; +/* _logo() - Render the 1-bit logo to the center of the screen in the pen colour */ +mp_obj_t picosystem_logo() { + const uint8_t *s = _picosystem_logo; - if(stats.fps > 40) { - // if fps is high enough then we definitely didn't miss vsync - stats.idle = (wait_us * 100) / stats.tick_us; - }else{ - // if we missed vsync then we overran the frame time and hence had - // no idle time - stats.idle = 0; + for(int y = 35; y < 85; y++) { + for(int x = 19; x < 101; x+=8) { + for(int bit = 0; bit < 8; bit++) { + if(*s & (0b10000000 >> bit)) { + pixel(x + bit, y); + } + } + s++; + } } return mp_const_none; } - } diff --git a/micropython/modules/picosystem/picosystem.h b/micropython/modules/picosystem/picosystem.h index 6f3a6dc..e59e0e9 100644 --- a/micropython/modules/picosystem/picosystem.h +++ b/micropython/modules/picosystem/picosystem.h @@ -54,11 +54,10 @@ extern const mp_obj_type_t PicosystemVoice_type; // picosystem.cpp extern mp_obj_t picosystem_init(); -extern mp_obj_t picosystem_tick(); -extern mp_obj_t picosystem_reset(); extern mp_obj_t picosystem_logo(); -extern mp_obj_t picosystem_run(); +extern mp_obj_t picosystem_start(); extern mp_obj_t picosystem_quit(); +extern mp_obj_t picosystem_flip(); // stats.cpp extern mp_obj_t picosystem_stats(); @@ -84,11 +83,13 @@ extern mp_obj_t picosystem_audio_play(size_t n_args, const mp_obj_t *pos_args, m // state.cpp extern mp_obj_t picosystem_clear(); extern mp_obj_t picosystem_pen(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picosystem_alpha(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picosystem_clip(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picosystem_blend(mp_obj_t bf_obj); +extern mp_obj_t picosystem_blend(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picosystem_target(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picosystem_camera(mp_obj_t camx_obj, mp_obj_t camy_obj); -extern mp_obj_t picosystem_spritesheet(mp_obj_t ss_obj); +extern mp_obj_t picosystem_camera(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picosystem_cursor(mp_uint_t n_args, const mp_obj_t *args); +extern mp_obj_t picosystem_spritesheet(mp_uint_t n_args, const mp_obj_t *args); // primitives.cpp extern mp_obj_t picosystem_pixel(mp_obj_t x_obj, mp_obj_t y_obj); @@ -105,8 +106,10 @@ extern mp_obj_t picosystem_fpoly(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picosystem_line(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picosystem_blit(mp_uint_t n_args, const mp_obj_t *args); extern mp_obj_t picosystem_sprite(mp_uint_t n_args, const mp_obj_t *args); + +// text.cpp extern mp_obj_t picosystem_text(mp_uint_t n_args, const mp_obj_t *args); -extern mp_obj_t picosystem_text_width(mp_obj_t str_obj); +extern mp_obj_t picosystem_measure(mp_uint_t n_args, const mp_obj_t *args); // utility.cpp extern mp_obj_t picosystem_rgb(mp_uint_t n_args, const mp_obj_t *args); diff --git a/micropython/modules/picosystem/primitives.cpp b/micropython/modules/picosystem/primitives.cpp index 24a7bac..7c2becb 100644 --- a/micropython/modules/picosystem/primitives.cpp +++ b/micropython/modules/picosystem/primitives.cpp @@ -246,59 +246,4 @@ mp_obj_t picosystem_sprite(mp_uint_t n_args, const mp_obj_t *args) { return mp_const_none; } -mp_obj_t picosystem_text(mp_uint_t n_args, const mp_obj_t *args) { - if(mp_obj_is_str_or_bytes(args[0])) { - GET_STR_DATA_LEN(args[0], str, str_len); - - std::string t((const char*)str); - - if(n_args == 3) { - int x = mp_obj_get_int(args[1]); - int y = mp_obj_get_int(args[2]); - text(t, x, y); - } - else { - text(t); - } - } - else if(mp_obj_is_float(args[0])) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(args[0])) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(args[0])) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - - return mp_const_none; -} - -mp_obj_t picosystem_text_width(mp_obj_t str_obj) { - if(mp_obj_is_str_or_bytes(str_obj)) { - GET_STR_DATA_LEN(str_obj, str, str_len); - - std::string t((const char*)str); - - return mp_obj_new_int(text_width(t)); - } - else if(mp_obj_is_float(str_obj)) { - mp_raise_TypeError("can't convert 'float' object to str implicitly"); - } - else if(mp_obj_is_int(str_obj)) { - mp_raise_TypeError("can't convert 'int' object to str implicitly"); - } - else if(mp_obj_is_bool(str_obj)) { - mp_raise_TypeError("can't convert 'bool' object to str implicitly"); - } - else { - mp_raise_TypeError("can't convert object to str implicitly"); - } - - return mp_const_none; -} - } \ No newline at end of file diff --git a/micropython/modules/picosystem/state.cpp b/micropython/modules/picosystem/state.cpp index 2823f6d..c740703 100644 --- a/micropython/modules/picosystem/state.cpp +++ b/micropython/modules/picosystem/state.cpp @@ -20,11 +20,15 @@ typedef struct _PicosystemBuffer_obj_t { mp_obj_t picosystem_pen(mp_uint_t n_args, const mp_obj_t *args) { switch(n_args) { + case 0: { + pen(); + } break; + case 1: { int p = mp_obj_get_int(args[0]); if(p < 0 || p > 0xffff) { - mp_raise_ValueError("p is not a valid pen."); + mp_raise_ValueError("pen(): p is not a valid pen."); } else { pen(p); @@ -38,19 +42,19 @@ mp_obj_t picosystem_pen(mp_uint_t n_args, const mp_obj_t *args) { int b = mp_obj_get_int(args[2]); if(r < 0 || r > 15) { - mp_raise_ValueError("r out of range. Expected 0 to 15"); + mp_raise_ValueError("pen(): r out of range. Expected 0 to 15"); } else if(g < 0 || g > 15) { - mp_raise_ValueError("g out of range. Expected 0 to 15"); + mp_raise_ValueError("pen(): g out of range. Expected 0 to 15"); } else if(b < 0 || b > 15) { - mp_raise_ValueError("b out of range. Expected 0 to 15"); + mp_raise_ValueError("pen(): b out of range. Expected 0 to 15"); } else { if(n_args == 4) { int a = mp_obj_get_int(args[3]); if(a < 0 || a > 15) { - mp_raise_ValueError("a out of range. Expected 0 to 15"); + mp_raise_ValueError("pen(): a out of range. Expected 0 to 15"); } else { pen(r, g, b, a); @@ -63,40 +67,69 @@ mp_obj_t picosystem_pen(mp_uint_t n_args, const mp_obj_t *args) { } break; default: { - char *buffer; - buffer = (char*)malloc(100); - sprintf(buffer, "function takes 1 (color), 3 (r,g,b), or 4 (r,g,b,a) positional arguments but %d were given", n_args); - mp_raise_TypeError(buffer); - free(buffer); - } break; + __builtin_unreachable(); + break; + } } return mp_const_none; } +mp_obj_t picosystem_alpha(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + int a = mp_obj_get_int(args[0]); + if(a < 0 || a > 15) { + mp_raise_ValueError("alpha(): a out of range. Expected 0 to 15"); + } else { + alpha(a); + } + } else { + alpha(); + } + return mp_const_none; +} + mp_obj_t picosystem_clip(mp_uint_t n_args, const mp_obj_t *args) { - int x = mp_obj_get_int(args[0]); - int y = mp_obj_get_int(args[1]); - int w = mp_obj_get_int(args[2]); - int h = mp_obj_get_int(args[3]); - clip(x, y, w, h); + switch(n_args) { + case 4: { + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + int w = mp_obj_get_int(args[2]); + int h = mp_obj_get_int(args[3]); + clip(x, y, w, h); + } break; + case 0: { + clip(); + } break; + default: { + char *buffer; + buffer = (char*)malloc(256); + snprintf(buffer, 256, "clip() takes 0 (reset) or 4 (x, y, w, h) positional arguments but %d were given", n_args); + mp_raise_TypeError(buffer); + free(buffer); + } break; + } return mp_const_none; } -mp_obj_t picosystem_blend(mp_obj_t bf_obj) { - int bf = mp_obj_get_int(bf_obj); - switch(bf) { - case MODE_COPY: - blend(COPY); - break; - case MODE_ALPHA: - blend(ALPHA); - break; - case MODE_MASK: - blend(MASK); - break; - default: - mp_raise_ValueError("not a valid blend mode. Expected COPY (0), ALPHA (1), or MASK (2)"); +mp_obj_t picosystem_blend(mp_uint_t n_args, const mp_obj_t *args) { + if(n_args == 1) { + int bf = mp_obj_get_int(args[0]); + switch(bf) { + case MODE_COPY: + blend(COPY); + break; + case MODE_ALPHA: + blend(ALPHA); + break; + case MODE_MASK: + blend(MASK); + break; + default: + mp_raise_ValueError("blend(): not a valid blend mode. Expected COPY (0), ALPHA (1), or MASK (2)"); + } + } else { + blend(); } return mp_const_none; } @@ -109,25 +142,48 @@ mp_obj_t picosystem_target(mp_uint_t n_args, const mp_obj_t *args) { } } else { - target(SCREEN); + target(); } return mp_const_none; } -mp_obj_t picosystem_camera(mp_obj_t camx_obj, mp_obj_t camy_obj) { - int camx = mp_obj_get_int(camx_obj); - int camy = mp_obj_get_int(camy_obj); - camera(camx, camy); +mp_obj_t picosystem_camera(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 2) { + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + camera(x, y); + } else if (n_args == 1) { + mp_raise_TypeError("camera() takes 0 (reset) or 2 (x, y) positional arguments."); + } else { + camera(); + } return mp_const_none; } -mp_obj_t picosystem_spritesheet(mp_obj_t ss_obj) { - if(mp_obj_is_type(ss_obj, &PicosystemBuffer_type)) { - _PicosystemBuffer_obj_t *buffer_obj = MP_OBJ_TO_PTR2(ss_obj, _PicosystemBuffer_obj_t); - spritesheet(buffer_obj->buffer); +mp_obj_t picosystem_cursor(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 2) { + int x = mp_obj_get_int(args[0]); + int y = mp_obj_get_int(args[1]); + cursor(x, y); + } else if (n_args == 1) { + mp_raise_TypeError("cursor() takes 0 (reset) or 2 (x, y) positional arguments."); + } else { + cursor(); } - else { - mp_raise_TypeError("spritesheet: not a valid Buffer. Expected a Buffer class"); + return mp_const_none; +} + +mp_obj_t picosystem_spritesheet(mp_uint_t n_args, const mp_obj_t *args) { + if (n_args == 1) { + if(mp_obj_is_type(args[0], &PicosystemBuffer_type)) { + _PicosystemBuffer_obj_t *buffer_obj = MP_OBJ_TO_PTR2(args[0], _PicosystemBuffer_obj_t); + spritesheet(buffer_obj->buffer); + } + else { + mp_raise_TypeError("spritesheet(): not a valid Buffer. Expected a Buffer class"); + } + } else { + spritesheet(); } return mp_const_none; } diff --git a/micropython/modules/picosystem/text.cpp b/micropython/modules/picosystem/text.cpp new file mode 100644 index 0000000..08f97b5 --- /dev/null +++ b/micropython/modules/picosystem/text.cpp @@ -0,0 +1,86 @@ +#include "libraries/picosystem.hpp" + +#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) + +using namespace picosystem; + +extern "C" { +#include "picosystem.h" +#include "math.h" +#include "cstring" + +mp_obj_t picosystem_text(mp_uint_t n_args, const mp_obj_t *args) { + if(mp_obj_is_str_or_bytes(args[0])) { + GET_STR_DATA_LEN(args[0], str, str_len); + + std::string t((const char*)str); + + if(n_args == 4) { + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int w = mp_obj_get_int(args[3]); + text(t, x, y, w); + } + else if(n_args == 3) { + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + text(t, x, y); + } + else if(n_args == 2) { + int w = mp_obj_get_int(args[1]); + text(t, w); + } + else { + text(t); + } + } + else if(mp_obj_is_float(args[0])) { + mp_raise_TypeError("can't convert 'float' object to str implicitly"); + } + else if(mp_obj_is_int(args[0])) { + mp_raise_TypeError("can't convert 'int' object to str implicitly"); + } + else if(mp_obj_is_bool(args[0])) { + mp_raise_TypeError("can't convert 'bool' object to str implicitly"); + } + else { + mp_raise_TypeError("can't convert object to str implicitly"); + } + + return mp_const_none; +} + +mp_obj_t picosystem_measure(mp_uint_t n_args, const mp_obj_t *args) { + mp_obj_t str_obj = args[0]; + if(mp_obj_is_str_or_bytes(str_obj)) { + GET_STR_DATA_LEN(str_obj, str, str_len); + + std::string t((const char*)str); + int32_t w = 0; + int32_t h = 0; + int32_t wrap = n_args == 2 ? mp_obj_get_int(args[1]) : -1; + + measure(t, w, h, wrap); + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(w); + tuple[1] = mp_obj_new_int(h); + return mp_obj_new_tuple(2, tuple); + } + else if(mp_obj_is_float(str_obj)) { + mp_raise_TypeError("can't convert 'float' object to str implicitly"); + } + else if(mp_obj_is_int(str_obj)) { + mp_raise_TypeError("can't convert 'int' object to str implicitly"); + } + else if(mp_obj_is_bool(str_obj)) { + mp_raise_TypeError("can't convert 'bool' object to str implicitly"); + } + else { + mp_raise_TypeError("can't convert object to str implicitly"); + } + + return mp_const_none; +} + +} \ No newline at end of file