diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp index d6a9ecb61..c7fcba8a5 100644 --- a/apps/code/script_template.cpp +++ b/apps/code/script_template.cpp @@ -62,8 +62,17 @@ def roots(a,b,c): constexpr ScriptTemplate spiralScriptTemplate("spiral.py", "\x00" R"(from turtle import * for i in range(255): + # Change pen width + s=int(1+i/16) + if s > 10: + s = 10 + pensize(s) + + # Change pen color gray=255-i - color(gray,int(gray*0.75),int(gray*0.25)) + pencolor(gray,int(gray*0.75),int(gray*0.25)) + + # Draw a segment of the spiral forward(i*0.1) left(10))"); diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index abbb338fe..94fe5e180 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -28,17 +28,33 @@ Q(set_pixel) Q(turtle) Q(forward) +Q(fd) Q(backward) +Q(bk) Q(right) +Q(rt) Q(left) +Q(lt) Q(goto) Q(setheading) +Q(seth) Q(speed) Q(pendown) +Q(pd) +Q(down) Q(penup) +Q(pu) +Q(up) +Q(pensize) +Q(width) -Q(color) +Q(showturtle) +Q(st) +Q(hideturtle) +Q(hd) + +Q(pencolor) Q(reset) // MicroPython QSTRs diff --git a/python/port/modturtle.c b/python/port/modturtle.c index 3bcf536e0..957583567 100644 --- a/python/port/modturtle.c +++ b/python/port/modturtle.c @@ -12,25 +12,46 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_speed_obj, turtle_speed); STATIC MP_DEFINE_CONST_FUN_OBJ_0(turtle_pendown_obj, turtle_pendown); STATIC MP_DEFINE_CONST_FUN_OBJ_0(turtle_penup_obj, turtle_penup); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_pensize_obj, turtle_pensize); STATIC MP_DEFINE_CONST_FUN_OBJ_3(turtle_color_obj, turtle_color); + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(turtle_showturtle_obj, turtle_showturtle); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(turtle_hideturtle_obj, turtle_hideturtle); + STATIC MP_DEFINE_CONST_FUN_OBJ_0(turtle___init___obj, turtle___init__); STATIC const mp_rom_map_elem_t turtle_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_turtle) }, { MP_ROM_QSTR(MP_QSTR___init__), (mp_obj_t)&turtle___init___obj }, { MP_ROM_QSTR(MP_QSTR_forward), (mp_obj_t)&turtle_forward_obj }, + { MP_ROM_QSTR(MP_QSTR_fd), (mp_obj_t)&turtle_forward_obj }, { MP_ROM_QSTR(MP_QSTR_backward), (mp_obj_t)&turtle_backward_obj }, + { MP_ROM_QSTR(MP_QSTR_bk), (mp_obj_t)&turtle_backward_obj }, { MP_ROM_QSTR(MP_QSTR_right), (mp_obj_t)&turtle_right_obj }, + { MP_ROM_QSTR(MP_QSTR_rt), (mp_obj_t)&turtle_right_obj }, { MP_ROM_QSTR(MP_QSTR_left), (mp_obj_t)&turtle_left_obj }, + { MP_ROM_QSTR(MP_QSTR_lt), (mp_obj_t)&turtle_left_obj }, { MP_ROM_QSTR(MP_QSTR_goto), (mp_obj_t)&turtle_goto_obj }, { MP_ROM_QSTR(MP_QSTR_setheading), (mp_obj_t)&turtle_setheading_obj }, + { MP_ROM_QSTR(MP_QSTR_seth), (mp_obj_t)&turtle_setheading_obj }, { MP_ROM_QSTR(MP_QSTR_speed), (mp_obj_t)&turtle_speed_obj }, { MP_ROM_QSTR(MP_QSTR_pendown), (mp_obj_t)&turtle_pendown_obj }, + { MP_ROM_QSTR(MP_QSTR_pd), (mp_obj_t)&turtle_pendown_obj }, + { MP_ROM_QSTR(MP_QSTR_down), (mp_obj_t)&turtle_pendown_obj }, { MP_ROM_QSTR(MP_QSTR_penup), (mp_obj_t)&turtle_penup_obj }, + { MP_ROM_QSTR(MP_QSTR_pu), (mp_obj_t)&turtle_penup_obj }, + { MP_ROM_QSTR(MP_QSTR_up), (mp_obj_t)&turtle_penup_obj }, + { MP_ROM_QSTR(MP_QSTR_pensize), (mp_obj_t)&turtle_pensize_obj }, + { MP_ROM_QSTR(MP_QSTR_width), (mp_obj_t)&turtle_pensize_obj }, - { MP_ROM_QSTR(MP_QSTR_color), (mp_obj_t)&turtle_color_obj }, + { MP_ROM_QSTR(MP_QSTR_pencolor), (mp_obj_t)&turtle_color_obj }, + + { MP_ROM_QSTR(MP_QSTR_showturtle), (mp_obj_t)&turtle_showturtle_obj }, + { MP_ROM_QSTR(MP_QSTR_st), (mp_obj_t)&turtle_showturtle_obj }, + { MP_ROM_QSTR(MP_QSTR_hideturtle), (mp_obj_t)&turtle_hideturtle_obj }, + { MP_ROM_QSTR(MP_QSTR_hd), (mp_obj_t)&turtle_hideturtle_obj }, }; STATIC MP_DEFINE_CONST_DICT(turtle_module_globals, turtle_module_globals_table); diff --git a/python/port/modturtle.h b/python/port/modturtle.h index 622a82466..0a8cabcca 100644 --- a/python/port/modturtle.h +++ b/python/port/modturtle.h @@ -10,8 +10,12 @@ mp_obj_t turtle_speed(mp_obj_t speed); mp_obj_t turtle_pendown(); mp_obj_t turtle_penup(); +mp_obj_t turtle_pensize(mp_obj_t size); mp_obj_t turtle_color(mp_obj_t r, mp_obj_t g, mp_obj_t b); +mp_obj_t turtle_showturtle(); +mp_obj_t turtle_hideturtle(); + mp_obj_t turtle___init__(); void turtle_deinit(); diff --git a/python/port/modturtle_impl.cpp b/python/port/modturtle_impl.cpp index 9e9315a09..c39444866 100644 --- a/python/port/modturtle_impl.cpp +++ b/python/port/modturtle_impl.cpp @@ -13,49 +13,53 @@ constexpr int t_x_offset = Ion::Display::Width / 2; constexpr int t_y_offset = (Ion::Display::Height-18) / 2; constexpr int t_size = 9; constexpr int t_icons = 8; -constexpr KDPoint t_icon_offset(-t_size/2, -t_size/2); +constexpr KDPoint t_icon_offset(-t_size/2 + 1, -t_size/2 + 1); constexpr KDSize t_icon_size(t_size, t_size); static KDColor t_color; static float t_heading; static float t_x, t_y; static bool t_penup; +static bool t_hidden; static int t_speed; +static int t_dotsize; static int t_mileage; static bool t_drawn; static KDColor *t_underneath; static KDColor *t_icon; - -constexpr KDCoordinate dotDiameter = 5; -const uint8_t dotMask[dotDiameter][dotDiameter] = { - {0xE1, 0x45, 0x0C, 0x45, 0xE1}, - {0x45, 0x00, 0x00, 0x00, 0x45}, - {0x00, 0x00, 0x00, 0x00, 0x00}, - {0x45, 0x00, 0x00, 0x00, 0x45}, - {0xE1, 0x45, 0x0C, 0x45, 0xE1}, -}; +static uint8_t *t_dot; static KDPoint pos_turtle(float x, float y) { - return KDPoint(x + t_x_offset, y + t_y_offset); + return KDPoint(round(x + t_x_offset), round(y + t_y_offset)); } void draw_turtle() { MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); - int offset = int((t_heading / (2*M_PI)) * t_icons + 0.5) % t_icons * (t_size*t_size); - - KDIonContext::sharedContext()->fillRectWithPixels(KDRect(pos_turtle(t_x, t_y).translatedBy(t_icon_offset), t_icon_size), &t_icon[offset], nullptr, t_drawn ? nullptr : t_underneath); - - if (t_mileage > 1000) { - if (t_speed > 0) { - Ion::msleep(8 * (8 - t_speed)); - } - t_mileage -= 1000; + int frame = (int)((t_heading / (2*M_PI)) * t_icons + 0.5); + if (frame < 0) { + frame = t_icons - ((-frame) % t_icons) - 1; + } + else { + frame = frame % t_icons; } - t_drawn = true; + int offset = frame * (t_size*t_size); + + if (!t_hidden) { + KDIonContext::sharedContext()->fillRectWithPixels(KDRect(pos_turtle(t_x, t_y).translatedBy(t_icon_offset), t_icon_size), &t_icon[offset], nullptr, t_drawn ? nullptr : t_underneath); + + if (t_mileage > 1000) { + if (t_speed > 0) { + Ion::msleep(8 * (8 - t_speed)); + } + t_mileage -= 1000; + } + + t_drawn = true; + } } void erase_turtle() { @@ -69,9 +73,9 @@ void dot_turtle(float x, float y) { MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox(); if (!t_penup) { - KDColor colors[dotDiameter*dotDiameter]; - KDRect rect(pos_turtle(x, y), KDSize(dotDiameter, dotDiameter)); - KDIonContext::sharedContext()->blendRectWithMask(rect, t_color, &dotMask[0][0], colors); + KDColor colors[t_dotsize*t_dotsize]; + KDRect rect(pos_turtle(x, y).translatedBy(KDPoint(-t_dotsize/2, -t_dotsize/2)), KDSize(t_dotsize, t_dotsize)); + KDIonContext::sharedContext()->blendRectWithMask(rect, t_color, t_dot, colors); } if (t_speed > 0) { @@ -175,11 +179,56 @@ mp_obj_t turtle_penup() { return mp_const_none; } +mp_obj_t turtle_pensize(mp_obj_t size) { + int s = mp_obj_get_int(size); + if (s < 1) { + s = 1; + } + else if (s > 10) { + s = 10; + } + + if (t_dot) { + delete[] t_dot; + } + t_dot = new uint8_t[s*s]; + t_dotsize = s; + + float middle = s / 2; + for (int j = 0; j < s; j++) { + for (int i = 0; i < s; i++) { + float distance = sqrt((j - middle)*(j - middle) + (i - middle)*(i - middle)) / middle; + int value = distance * distance * 255; + if (value < 0) { + value = 0; + } + else if (value > 255) { + value = 255; + } + t_dot[j*s + i] = value; + } + } + + return mp_const_none; +} + mp_obj_t turtle_color(mp_obj_t r, mp_obj_t g, mp_obj_t b) { t_color = KDColor::RGB888(mp_obj_get_int(r), mp_obj_get_int(g), mp_obj_get_int(b)); return mp_const_none; } +mp_obj_t turtle_showturtle() { + t_hidden = false; + draw_turtle(); + return mp_const_none; +} + +mp_obj_t turtle_hideturtle() { + t_hidden = true; + erase_turtle(); + return mp_const_none; +} + mp_obj_t turtle___init__() { if (!t_underneath) { t_underneath = new KDColor[t_size * t_size]; @@ -201,6 +250,9 @@ mp_obj_t turtle___init__() { t_penup = false; t_speed = 6; t_mileage = 0; + t_hidden = false; + + turtle_pensize(MP_OBJ_NEW_SMALL_INT(5)); return mp_const_none; } @@ -210,4 +262,6 @@ void turtle_deinit() { t_underneath = nullptr; delete[] t_icon; t_icon = nullptr; + delete[] t_dot; + t_dot = nullptr; }