[Python] universal colors

This commit is contained in:
Joachim LF
2020-04-25 13:54:16 +02:00
committed by LeaNumworks
parent 061fe05b40
commit e76abcf67e
12 changed files with 216 additions and 87 deletions

View File

@@ -430,6 +430,7 @@ Q(st)
Q(hideturtle)
Q(ht)
Q(isvisible)
Q(colormode)
// utime QSTRs
Q(time)

View File

@@ -1,26 +1,10 @@
extern "C" {
#include "modkandinsky.h"
#include <py/objtuple.h>
#include <py/runtime.h>
}
#include <kandinsky.h>
#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_tuple_t *>(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

View File

@@ -1,6 +1,8 @@
extern "C" {
#include "modturtle.h"
#include <py/gc.h>
#include <py/objtuple.h>
#include <py/runtime.h>
}
#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;
}

View File

@@ -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();

View File

@@ -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 },

View File

@@ -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;

View File

@@ -8,6 +8,7 @@ extern "C" {
#include <escher/metric.h>
#include <kandinsky.h>
#include <math.h>
#include <python/port/port.h>
/* 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;

View File

@@ -23,6 +23,8 @@ extern "C" {
#include "mod/matplotlib/pyplot/modpyplot.h"
}
#include <escher/palette.h>
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);
}

View File

@@ -3,9 +3,11 @@
extern "C" {
#include <stddef.h>
#include <py/obj.h>
}
#include <escher/view_controller.h>
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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);
}