mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[python] Initial turtle module
This commit is contained in:
@@ -131,6 +131,8 @@ port_objs += $(addprefix python/port/,\
|
||||
helpers.o \
|
||||
modkandinsky.o \
|
||||
modkandinsky_impl.o \
|
||||
modturtle.o \
|
||||
modturtle_impl.o \
|
||||
mphalport.o \
|
||||
)
|
||||
|
||||
@@ -176,3 +178,5 @@ $(py_objs) $(extmod_objs) $(port_objs): python/port/genhdr/qstrdefs.generated.h
|
||||
# List all objects needed
|
||||
|
||||
objs += $(extmod_objs) $(py_objs) $(port_objs)
|
||||
|
||||
app_images += python/port/turtle_icon.png
|
||||
|
||||
@@ -24,6 +24,23 @@ Q(draw_string)
|
||||
Q(get_pixel)
|
||||
Q(set_pixel)
|
||||
|
||||
// Turtle QSTRs
|
||||
|
||||
Q(turtle)
|
||||
Q(forward)
|
||||
Q(backward)
|
||||
Q(right)
|
||||
Q(left)
|
||||
Q(goto)
|
||||
Q(setheading)
|
||||
Q(speed)
|
||||
|
||||
Q(pendown)
|
||||
Q(penup)
|
||||
|
||||
Q(color)
|
||||
Q(reset)
|
||||
|
||||
// MicroPython QSTRs
|
||||
Q()
|
||||
Q(*)
|
||||
|
||||
41
python/port/modturtle.c
Normal file
41
python/port/modturtle.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "modturtle.h"
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_forward_obj, turtle_forward);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_backward_obj, turtle_backward);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_right_obj, turtle_right);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_left_obj, turtle_left);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(turtle_goto_obj, turtle_goto);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(turtle_setheading_obj, turtle_setheading);
|
||||
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_3(turtle_color_obj, turtle_color);
|
||||
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_backward), (mp_obj_t)&turtle_backward_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_right), (mp_obj_t)&turtle_right_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_left), (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_speed), (mp_obj_t)&turtle_speed_obj },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_pendown), (mp_obj_t)&turtle_pendown_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_penup), (mp_obj_t)&turtle_penup_obj },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_color), (mp_obj_t)&turtle_color_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(turtle_module_globals, turtle_module_globals_table);
|
||||
|
||||
const mp_obj_module_t turtle_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&turtle_module_globals,
|
||||
};
|
||||
17
python/port/modturtle.h
Normal file
17
python/port/modturtle.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "py/obj.h"
|
||||
|
||||
mp_obj_t turtle_forward(mp_obj_t px);
|
||||
mp_obj_t turtle_backward(mp_obj_t px);
|
||||
mp_obj_t turtle_right(mp_obj_t deg);
|
||||
mp_obj_t turtle_left(mp_obj_t deg);
|
||||
mp_obj_t turtle_goto(mp_obj_t x, mp_obj_t y);
|
||||
mp_obj_t turtle_setheading(mp_obj_t deg);
|
||||
mp_obj_t turtle_speed(mp_obj_t speed);
|
||||
|
||||
mp_obj_t turtle_pendown();
|
||||
mp_obj_t turtle_penup();
|
||||
|
||||
mp_obj_t turtle_color(mp_obj_t r, mp_obj_t g, mp_obj_t b);
|
||||
|
||||
mp_obj_t turtle___init__();
|
||||
void turtle_deinit();
|
||||
213
python/port/modturtle_impl.cpp
Normal file
213
python/port/modturtle_impl.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
extern "C" {
|
||||
#include "modturtle.h"
|
||||
}
|
||||
#include <kandinsky.h>
|
||||
#include <ion.h>
|
||||
#include <math.h>
|
||||
#include "port.h"
|
||||
#include "turtle_icon.h"
|
||||
|
||||
constexpr float t_heading_offset = M_PI_2;
|
||||
constexpr float t_heading_scale = M_PI / 180;
|
||||
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 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 int t_speed;
|
||||
|
||||
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 KDPoint pos_turtle(float x, float y) {
|
||||
return KDPoint(x + t_x_offset, 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;
|
||||
}
|
||||
|
||||
t_drawn = true;
|
||||
}
|
||||
|
||||
void erase_turtle() {
|
||||
if (t_drawn) {
|
||||
KDIonContext::sharedContext()->fillRectWithPixels(KDRect(pos_turtle(t_x, t_y).translatedBy(t_icon_offset), t_icon_size), t_underneath, nullptr);
|
||||
t_drawn = false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (t_speed > 0) {
|
||||
t_mileage += sqrt((x - t_x) * (x - t_x) + (y - t_y) * (y - t_y)) * 1000;
|
||||
}
|
||||
|
||||
micropython_port_should_interrupt();
|
||||
|
||||
t_x = x;
|
||||
t_y = y;
|
||||
}
|
||||
|
||||
mp_obj_t turtle_forward(mp_obj_t px) {
|
||||
float x = t_x + mp_obj_get_float(px)*sin(t_heading);
|
||||
float y = t_y + mp_obj_get_float(px)*cos(t_heading);
|
||||
return turtle_goto(mp_obj_new_float(x), mp_obj_new_float(y));
|
||||
}
|
||||
|
||||
mp_obj_t turtle_backward(mp_obj_t px) {
|
||||
return turtle_forward(mp_obj_new_float(-mp_obj_get_float(px)));
|
||||
}
|
||||
|
||||
mp_obj_t turtle_right(mp_obj_t angle) {
|
||||
return turtle_left(mp_obj_new_float(-mp_obj_get_float(angle)));
|
||||
}
|
||||
|
||||
mp_obj_t turtle_left(mp_obj_t angle) {
|
||||
float new_angle = ((t_heading - t_heading_offset) + (mp_obj_get_float(angle) * t_heading_scale)) / t_heading_scale;
|
||||
return turtle_setheading(mp_obj_new_float(new_angle));
|
||||
}
|
||||
|
||||
mp_obj_t turtle_goto(mp_obj_t x, mp_obj_t y) {
|
||||
float newx = mp_obj_get_float(x), newy = mp_obj_get_float(y);
|
||||
float oldx = t_x, oldy = t_y;
|
||||
float length = sqrt((newx - oldx) * (newx - oldx) + (newy - oldy) * (newy - oldy));
|
||||
|
||||
if (length > 1) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
float progress = i / length;
|
||||
|
||||
if (t_speed > 0) {
|
||||
Ion::Display::waitForVBlank();
|
||||
}
|
||||
erase_turtle();
|
||||
dot_turtle(newx * progress + oldx * (1 - progress), newy * progress + oldy * (1 - progress));
|
||||
draw_turtle();
|
||||
}
|
||||
}
|
||||
|
||||
Ion::Display::waitForVBlank();
|
||||
erase_turtle();
|
||||
dot_turtle(newx, newy);
|
||||
draw_turtle();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t turtle_setheading(mp_obj_t angle) {
|
||||
micropython_port_should_interrupt();
|
||||
|
||||
float new_angle = mp_obj_get_float(angle) * t_heading_scale + t_heading_offset;
|
||||
|
||||
//if (t_speed == 0) {
|
||||
t_heading = new_angle;
|
||||
|
||||
if (t_speed > 0) {
|
||||
Ion::Display::waitForVBlank();
|
||||
}
|
||||
erase_turtle();
|
||||
draw_turtle();
|
||||
|
||||
return mp_const_none;/*
|
||||
}
|
||||
|
||||
micropython_port_should_interrupt();
|
||||
|
||||
return mp_const_none;*/
|
||||
}
|
||||
|
||||
mp_obj_t turtle_speed(mp_obj_t speed) {
|
||||
int new_speed = mp_obj_get_int(speed);
|
||||
|
||||
if (new_speed < 0) {
|
||||
new_speed = 0;
|
||||
}
|
||||
else if (new_speed > 10) {
|
||||
new_speed = 10;
|
||||
}
|
||||
|
||||
t_speed = new_speed;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t turtle_pendown() {
|
||||
t_penup = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t turtle_penup() {
|
||||
t_penup = true;
|
||||
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___init__() {
|
||||
if (!t_underneath) {
|
||||
t_underneath = new KDColor[t_size * t_size];
|
||||
}
|
||||
if (!t_icon) {
|
||||
t_icon = new KDColor[t_size * t_size];
|
||||
|
||||
Ion::decompress(
|
||||
ImageStore::TurtleIcon->compressedPixelData(),
|
||||
reinterpret_cast<uint8_t *>(t_icon),
|
||||
ImageStore::TurtleIcon->compressedPixelDataSize(),
|
||||
sizeof(KDColor) * t_size * t_size * t_icons
|
||||
);
|
||||
}
|
||||
|
||||
t_color = KDColorBlack;
|
||||
t_heading = t_heading_offset;
|
||||
t_x = t_y = 0;
|
||||
t_penup = false;
|
||||
t_speed = 6;
|
||||
t_mileage = 0;
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
void turtle_deinit() {
|
||||
delete[] t_underneath;
|
||||
t_underneath = nullptr;
|
||||
delete[] t_icon;
|
||||
t_icon = nullptr;
|
||||
}
|
||||
@@ -107,6 +107,8 @@ typedef long mp_off_t;
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
extern const struct _mp_obj_module_t kandinsky_module;
|
||||
extern const struct _mp_obj_module_t turtle_module;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&kandinsky_module) }
|
||||
{ MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&kandinsky_module) }, \
|
||||
{ MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&turtle_module) }
|
||||
|
||||
@@ -17,6 +17,7 @@ extern "C" {
|
||||
#include "py/repl.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "modturtle.h"
|
||||
#include "mphalport.h"
|
||||
}
|
||||
|
||||
@@ -107,7 +108,8 @@ void MicroPython::init(void * heapStart, void * heapEnd) {
|
||||
mp_init();
|
||||
}
|
||||
|
||||
void MicroPython::deinit(){
|
||||
void MicroPython::deinit() {
|
||||
turtle_deinit();
|
||||
mp_deinit();
|
||||
}
|
||||
|
||||
|
||||
BIN
python/port/turtle_icon.png
Normal file
BIN
python/port/turtle_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 B |
@@ -619,7 +619,7 @@ typedef double mp_float_t;
|
||||
|
||||
// Whether to call __init__ when importing builtin modules for the first time
|
||||
#ifndef MICROPY_MODULE_BUILTIN_INIT
|
||||
#define MICROPY_MODULE_BUILTIN_INIT (0)
|
||||
#define MICROPY_MODULE_BUILTIN_INIT (1)
|
||||
#endif
|
||||
|
||||
// Whether module weak links are supported
|
||||
|
||||
Reference in New Issue
Block a user