diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index db21ede99..71a87feee 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -430,6 +430,7 @@ Q(st) Q(hideturtle) Q(ht) Q(isvisible) +Q(colormode) // utime QSTRs Q(time) diff --git a/python/port/mod/kandinsky/modkandinsky.cpp b/python/port/mod/kandinsky/modkandinsky.cpp index 27b7ec5b1..66f2aaf15 100644 --- a/python/port/mod/kandinsky/modkandinsky.cpp +++ b/python/port/mod/kandinsky/modkandinsky.cpp @@ -1,26 +1,10 @@ extern "C" { #include "modkandinsky.h" -#include #include } #include #include "port.h" -static KDColor ColorForTuple(mp_obj_t tuple) { - size_t len; - mp_obj_t * elem; - - mp_obj_get_array(tuple, &len, &elem); - if (len != 3) { - mp_raise_TypeError("color needs 3 components"); - } - - return KDColor::RGB888( - mp_obj_get_int(elem[0]), - mp_obj_get_int(elem[1]), - mp_obj_get_int(elem[2]) - ); -} static mp_obj_t TupleForRGB(uint8_t r, uint8_t g, uint8_t b) { mp_obj_tuple_t * t = static_cast(MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL))); @@ -56,19 +40,20 @@ mp_obj_t modkandinsky_get_pixel(mp_obj_t x, mp_obj_t y) { return TupleForRGB(c.red(), c.green(), c.blue()); } -mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t color) { +mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t input) { KDPoint point(mp_obj_get_int(x), mp_obj_get_int(y)); - KDColor kdColor = ColorForTuple(color); + KDColor kdColor = MicroPython::ColorParser::ParseColor(input); MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDIonContext::sharedContext()->setPixel(point, kdColor); return mp_const_none; } +//TODO Use good colors mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t * args) { const char * text = mp_obj_str_get_str(args[0]); KDPoint point(mp_obj_get_int(args[1]), mp_obj_get_int(args[2])); - KDColor textColor = (n_args >= 4) ? ColorForTuple(args[3]) : KDColorBlack; - KDColor backgroundColor = (n_args >= 5) ? ColorForTuple(args[4]) : KDColorWhite; + KDColor textColor = (n_args >= 4) ? MicroPython::ColorParser::ParseColor(args[3]) : KDColorBlack; + KDColor backgroundColor = (n_args >= 5) ? MicroPython::ColorParser::ParseColor(args[4]) : KDColorWhite; MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, textColor, backgroundColor); /* Before and after execution of "modkandinsky_draw_string", @@ -98,8 +83,7 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) { y = y - height; } KDRect rect(x, y, width, height); - KDColor color = ColorForTuple(args[4]); - + KDColor color = MicroPython::ColorParser::ParseColor(args[4]); MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); KDIonContext::sharedContext()->fillRect(rect, color); // Cf comment on modkandinsky_draw_string diff --git a/python/port/mod/turtle/modturtle.cpp b/python/port/mod/turtle/modturtle.cpp index 913372a3f..35c960ec3 100644 --- a/python/port/mod/turtle/modturtle.cpp +++ b/python/port/mod/turtle/modturtle.cpp @@ -1,6 +1,8 @@ extern "C" { #include "modturtle.h" #include +#include +#include } #include "turtle.h" #include "../../port.h" @@ -131,37 +133,63 @@ mp_obj_t modturtle_isdown() { } mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args) { - if (n_args == 0) { - // pencolor() - KDColor c = sTurtle.color(); - mp_obj_t mp_col[3]; - mp_col[0] = mp_obj_new_int_from_uint(c.red()); - mp_col[1] = mp_obj_new_int_from_uint(c.green()); - mp_col[2] = mp_obj_new_int_from_uint(c.blue()); - return mp_obj_new_tuple(3, mp_col); - } - if (n_args == 1) { - if (MP_OBJ_IS_STR(args[0])) { - // pencolor("blue") - size_t l; - sTurtle.setColor(mp_obj_str_get_data(args[0], &l)); - } else { - // pencolor((r, g, b)) - mp_obj_t * rgb; - mp_obj_get_array_fixed_n(args[0], 3, &rgb); - sTurtle.setColor( - KDColor::RGB888( - mp_obj_get_int(rgb[0]), - mp_obj_get_int(rgb[1]), - mp_obj_get_int(rgb[2]))); + switch(n_args){ + case 0:{ + // pencolor() + KDColor c = sTurtle.color(); + mp_obj_t mp_col[3]; + if(sTurtle.colorMode() == MicroPython::ColorParser::ColorModes::MaxIntensity255){ + mp_col[0] = mp_obj_new_int_from_uint(c.red()); + mp_col[1] = mp_obj_new_int_from_uint(c.green()); + mp_col[2] = mp_obj_new_int_from_uint(c.blue()); + } else { + mp_col[0] = mp_obj_new_float(c.red() / 255.0); + mp_col[1] = mp_obj_new_float(c.green() / 255.0); + mp_col[2] = mp_obj_new_float(c.blue() / 255.0); + } + return mp_obj_new_tuple(3, mp_col); + } + case 1:{ + sTurtle.setColor(MicroPython::ColorParser::ParseColor(args[0], sTurtle.colorMode())); + break; + } + case 3:{ + // pencolor(r, g, b) + if(sTurtle.colorMode() == MicroPython::ColorParser::ColorModes::MaxIntensity255){ + sTurtle.setColor( + KDColor::RGB888( + mp_obj_get_int(args[0]), + mp_obj_get_int(args[1]), + mp_obj_get_int(args[2]))); + } else { + sTurtle.setColor( + KDColor::RGB888( + mp_obj_get_int(args[0]) * 255, + mp_obj_get_int(args[1]) * 255, + mp_obj_get_int(args[2]) * 255)); + } + break; + } + default:{ + assert(n_args == 2); + mp_raise_TypeError("pencolor() takes 0, 1 or 3 arguments"); + } + } + return mp_const_none; +} + +mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args){ + if(n_args == 0){ + return (sTurtle.colorMode() == MicroPython::ColorParser::ColorModes::MaxIntensity255) ? mp_obj_new_int_from_uint(255) : mp_obj_new_int_from_uint(1); + } else{ + int colorMode = mp_obj_get_int(args[0]); + if(colorMode == 1){ + sTurtle.setColorMode(MicroPython::ColorParser::ColorModes::MaxIntensity1); + } else if(colorMode == 255){ + sTurtle.setColorMode(MicroPython::ColorParser::ColorModes::MaxIntensity255); + } else { + mp_raise_ValueError("Colormodes can be 1 or 255"); } - } else if (n_args == 3) { - // pencolor(r, g, b) - sTurtle.setColor( - KDColor::RGB888( - mp_obj_get_int(args[0]), - mp_obj_get_int(args[1]), - mp_obj_get_int(args[2]))); } return mp_const_none; } diff --git a/python/port/mod/turtle/modturtle.h b/python/port/mod/turtle/modturtle.h index 84fda5010..303ea13d4 100644 --- a/python/port/mod/turtle/modturtle.h +++ b/python/port/mod/turtle/modturtle.h @@ -25,6 +25,7 @@ mp_obj_t modturtle_pensize(size_t n_args, const mp_obj_t *args); mp_obj_t modturtle_isvisible(); mp_obj_t modturtle_pencolor(size_t n_args, const mp_obj_t *args); +mp_obj_t modturtle_colormode(size_t n_args, const mp_obj_t *args); mp_obj_t modturtle_showturtle(); mp_obj_t modturtle_hideturtle(); diff --git a/python/port/mod/turtle/modturtle_table.c b/python/port/mod/turtle/modturtle_table.c index c9f2658a9..c190cc540 100644 --- a/python/port/mod/turtle/modturtle_table.c +++ b/python/port/mod/turtle/modturtle_table.c @@ -18,6 +18,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_pensize_obj, 0, 1, modturtl STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_isdown_obj, modturtle_isdown); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_pencolor_obj, 0, 3, modturtle_pencolor); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modturtle_colormode_obj, 0, 1, modturtle_colormode); STATIC MP_DEFINE_CONST_FUN_OBJ_0(modturtle_reset_obj, modturtle_reset); @@ -64,6 +65,7 @@ STATIC const mp_rom_map_elem_t modturtle_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_color), (mp_obj_t)&modturtle_pencolor_obj }, { MP_ROM_QSTR(MP_QSTR_pencolor), (mp_obj_t)&modturtle_pencolor_obj }, + { MP_ROM_QSTR(MP_QSTR_colormode), (mp_obj_t)&modturtle_colormode_obj }, { MP_ROM_QSTR(MP_QSTR_reset), (mp_obj_t)&modturtle_reset_obj }, diff --git a/python/port/mod/turtle/turtle.cpp b/python/port/mod/turtle/turtle.cpp index 1a5c3abc2..811650c3b 100644 --- a/python/port/mod/turtle/turtle.cpp +++ b/python/port/mod/turtle/turtle.cpp @@ -175,27 +175,6 @@ void Turtle::setVisible(bool visible) { } } -void Turtle::setColor(const char * color) { - constexpr NameColorPair pairs[] = { - NameColorPair("blue", KDColorBlue), - NameColorPair("red", KDColorRed), - NameColorPair("green", Palette::Green), - NameColorPair("yellow", KDColorYellow), - NameColorPair("brown", Palette::Brown), - NameColorPair("black", KDColorBlack), - NameColorPair("white", KDColorWhite), - NameColorPair("pink", Palette::Pink), - NameColorPair("orange", Palette::Orange), - NameColorPair("purple", Palette::Purple), - NameColorPair("grey", Palette::GreyDark) - }; - for (NameColorPair p : pairs) { - if (strcmp(p.name(), color) == 0) { - m_color = p.color(); - return; - } - } -} void Turtle::viewDidDisappear() { m_drawn = false; diff --git a/python/port/mod/turtle/turtle.h b/python/port/mod/turtle/turtle.h index 87aa58e8f..71e4ae5fe 100644 --- a/python/port/mod/turtle/turtle.h +++ b/python/port/mod/turtle/turtle.h @@ -8,6 +8,7 @@ extern "C" { #include #include #include +#include /* We check for keyboard interruptions using micropython_port_vm_hook_loop and * micropython_port_interruptible_msleep, but even if we catch an interruption, @@ -29,6 +30,7 @@ public: m_y(0), m_heading(0), m_color(k_defaultColor), + m_colorMode(MicroPython::ColorParser::ColorModes::MaxIntensity255), m_penDown(true), m_visible(true), m_speed(k_defaultSpeed), @@ -71,7 +73,10 @@ public: void setColor(uint8_t r, uint8_t g, uint8_t b) { m_color = KDColor::RGB888(r, g, b); } - void setColor(const char * color); + MicroPython::ColorParser::ColorModes colorMode() const {return m_colorMode; } + void setColorMode(MicroPython::ColorParser::ColorModes colorMode){ + m_colorMode = colorMode; + } void viewDidDisappear(); @@ -102,19 +107,6 @@ private: Forward = 2 }; - class NameColorPair { - public: - constexpr NameColorPair(const char * name, KDColor color) : - m_name(name), - m_color(color) - {} - const char * name() const { return m_name; } - KDColor color() const { return m_color; } - private: - const char * m_name; - KDColor m_color; - }; - void setHeadingPrivate(mp_float_t angle); KDPoint position(mp_float_t x, mp_float_t y) const; KDPoint position() const { return position(m_x, m_y); } @@ -149,6 +141,7 @@ private: mp_float_t m_heading; KDColor m_color; + MicroPython::ColorParser::ColorModes m_colorMode; bool m_penDown; bool m_visible; diff --git a/python/port/port.cpp b/python/port/port.cpp index 12f5f5588..97fffd671 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -23,6 +23,8 @@ extern "C" { #include "mod/matplotlib/pyplot/modpyplot.h" } +#include + static MicroPython::ScriptProvider * sScriptProvider = nullptr; static MicroPython::ExecutionEnvironment * sCurrentExecutionEnvironment = nullptr; @@ -170,6 +172,83 @@ void MicroPython::collectRootsAtAddress(char * address, int byteLength) { #endif } +KDColor MicroPython::ColorParser::ParseColor(mp_obj_t input, ColorModes ColorMode){ + if(MP_OBJ_IS_STR(input)){ + size_t l; + const char * color = mp_obj_str_get_data(input, &l); + // TODO add cyan + constexpr NameColorPair pairs[] = { + NameColorPair("blue", KDColorBlue), + NameColorPair("b", KDColorBlue), + NameColorPair("red", KDColorRed), + NameColorPair("r", KDColorRed), + NameColorPair("green", Palette::Green), + NameColorPair("g", Palette::Green), + NameColorPair("yellow", KDColorYellow), + NameColorPair("y", KDColorYellow), + NameColorPair("brown", Palette::Brown), + NameColorPair("black", KDColorBlack), + NameColorPair("k", KDColorBlack), + NameColorPair("white", KDColorWhite), + NameColorPair("w", KDColorWhite), + NameColorPair("pink", Palette::Pink), + NameColorPair("orange", Palette::Orange), + NameColorPair("purple", Palette::Purple), + NameColorPair("grey", Palette::GreyDark) + }; + for (NameColorPair p : pairs) { + if (strcmp(p.name(), color) == 0) { + return p.color(); + } + } + + if(color[0] == '#'){ + if(l != 7){ + mp_raise_ValueError("RGB hex values are 6 bytes long"); + } + uint32_t ColorInt = mp_obj_get_int(mp_obj_new_int_via_str(color+1, 16)); + return KDColor::RGB24(ColorInt); + } + + mp_float_t GreyLevel = mp_obj_float_get(mp_obj_new_float_via_str(color)); + if(GreyLevel >= 0 && GreyLevel <= 1){ + return KDColor::RGB888( + 255 * (float) GreyLevel, + 255 * (float) GreyLevel, + 255 * (float) GreyLevel + ); + } + mp_raise_ValueError("Grey levels are between 0.0 and 1.0"); + } else if(mp_obj_is_int(input)) { + mp_raise_TypeError("Int are not colors"); + //See https://github.com/numworks/epsilon/issues/1533#issuecomment-618443492 + } else { + size_t len; + mp_obj_t * elem; + + mp_obj_get_array(input, &len, &elem); + + if (len != 3) { + mp_raise_TypeError("color needs 3 components"); + } + + if(ColorMode == MicroPython::ColorParser::ColorModes::MaxIntensity1){ + return KDColor::RGB888( + mp_obj_get_float(elem[0]), + mp_obj_get_float(elem[1]), + mp_obj_get_float(elem[2]) + ); + } else { + return KDColor::RGB888( + mp_obj_get_int(elem[0]), + mp_obj_get_int(elem[1]), + mp_obj_get_int(elem[2]) + ); + } + } + mp_raise_TypeError("Color couldn't be parsed"); +} + void gc_collect(void) { void * python_stack_top = MP_STATE_THREAD(stack_top); assert(python_stack_top != NULL); @@ -260,3 +339,4 @@ const char * mp_hal_input(const char * prompt) { assert(sCurrentExecutionEnvironment != nullptr); return sCurrentExecutionEnvironment->inputText(prompt); } + diff --git a/python/port/port.h b/python/port/port.h index 9d14ab3a6..73bf7f810 100644 --- a/python/port/port.h +++ b/python/port/port.h @@ -3,9 +3,11 @@ extern "C" { #include +#include } #include + namespace MicroPython { class ScriptProvider { @@ -39,6 +41,31 @@ void deinit(); void registerScriptProvider(ScriptProvider * s); void collectRootsAtAddress(char * address, int len); +class ColorParser { + private: + class NameColorPair { + public: + constexpr NameColorPair(const char * name, KDColor color) : + m_name(name), + m_color(color) + {} + const char * name() const { return m_name; } + KDColor color() const { return m_color; } + private: + const char * m_name; + KDColor m_color; + }; + + public: + enum class ColorModes { + MaxIntensity1, + MaxIntensity255, + }; + + static KDColor ParseColor(mp_obj_t input, ColorModes ColorMode = ColorModes::MaxIntensity255); +}; + + } #endif diff --git a/python/src/py/obj.h b/python/src/py/obj.h index 5b54892ce..e2d2b584a 100644 --- a/python/src/py/obj.h +++ b/python/src/py/obj.h @@ -90,6 +90,7 @@ static inline bool mp_obj_is_qstr(mp_const_obj_t o) { return ((((mp_int_t)(o)) & 3) == 2); } #define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 2) #define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 2) | 2)) +mp_obj_t mp_obj_new_int_via_str(const char* value, int base); #if MICROPY_PY_BUILTINS_FLOAT #define mp_const_float_e MP_ROM_PTR(&mp_const_float_e_obj) @@ -100,6 +101,7 @@ extern const struct _mp_obj_float_t mp_const_float_pi_obj; #define mp_obj_is_float(o) mp_obj_is_type((o), &mp_type_float) mp_float_t mp_obj_float_get(mp_obj_t self_in); mp_obj_t mp_obj_new_float(mp_float_t value); +mp_obj_t mp_obj_new_float_via_str(const char* value); #endif static inline bool mp_obj_is_obj(mp_const_obj_t o) diff --git a/python/src/py/objfloat.c b/python/src/py/objfloat.c index 3da549bb2..c638796ac 100644 --- a/python/src/py/objfloat.c +++ b/python/src/py/objfloat.c @@ -201,6 +201,24 @@ mp_obj_t mp_obj_new_float(mp_float_t value) { return MP_OBJ_FROM_PTR(o); } +mp_obj_t mp_obj_new_float_via_str(const char* value) { + mp_obj_float_t *o = m_new(mp_obj_float_t, 1); + o->base.type = &mp_type_float; + //Avoid \x0 + int length = 0; + for(int i = 0; i <= sizeof(value); i++){ + if(value[i] == '\x0'){ + length = i; + break; + } + }; + if(length == 0){ + length = (int) sizeof(value); + } + o->value = mp_obj_float_get(mp_parse_num_decimal(value, length, false, false, NULL)); + return MP_OBJ_FROM_PTR(o); +} + mp_float_t mp_obj_float_get(mp_obj_t self_in) { assert(mp_obj_is_float(self_in)); mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/python/src/py/objint.c b/python/src/py/objint.c index 2fdcf5864..b139b09bc 100644 --- a/python/src/py/objint.c +++ b/python/src/py/objint.c @@ -462,3 +462,17 @@ const mp_obj_type_t mp_type_int = { .binary_op = mp_obj_int_binary_op, .locals_dict = (mp_obj_dict_t*)&int_locals_dict, }; + +mp_obj_t mp_obj_new_int_via_str(const char* value, int base) { + int length = 0; + for(int i = 0; i <= sizeof(value); i++){ + if(value[i] == '\x0'){ + length = i; + break; + } + }; + if(length == 0){ + length = (int) sizeof(value); + } + return mp_parse_num_integer(value, length, base, NULL); +}