PicoGraphics: HSV Pen (#665)
Co-authored-by: Gee Bartlett <122281230+ageeandakeyboard@users.noreply.github.com>
This commit is contained in:
parent
cd2f45dee4
commit
c4decc5003
|
@ -11,6 +11,7 @@ target_link_libraries(${OUTPUT_NAME}
|
|||
pico_multicore
|
||||
hardware_vreg
|
||||
hardware_pwm
|
||||
pico_graphics
|
||||
hub75
|
||||
interstate75
|
||||
)
|
||||
|
|
|
@ -25,33 +25,12 @@ Hub75 hub75(32, 32, nullptr, PANEL_GENERIC, false);
|
|||
//Hub75 hub75(128, 32, nullptr, PANEL_GENERIC, false);
|
||||
|
||||
//Works with our 64x64 panel https://shop.pimoroni.com/products/rgb-led-matrix-panel?variant=3029531983882
|
||||
//Hub75 hub75(64, 64, nullptr, PANEL_GENERIC, false);
|
||||
//Hub75 hub75(64, 64, nullptr, PANEL_GENERIC, true);
|
||||
//or using 2 of these panels
|
||||
//Hub75 hub75(128, 64, nullptr, PANEL_GENERIC, false);
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(hub75.width, hub75.height, nullptr);
|
||||
|
||||
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
|
||||
// Outputs are rgb in the range 0-255 for each channel
|
||||
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Interrupt callback required function
|
||||
void __isr dma_complete() {
|
||||
hub75.dma_complete();
|
||||
|
@ -63,7 +42,13 @@ int main() {
|
|||
|
||||
uint8_t hue_map[hub75.width][3];
|
||||
for(uint i = 0; i < hub75.width; i++) {
|
||||
from_hsv(i / (float) hub75.width, 1.0f, 1.0f, hue_map[i][0], hue_map[i][1], hue_map[i][2]);
|
||||
uint8_t r=0;
|
||||
uint8_t g=0;
|
||||
uint8_t b=0;
|
||||
graphics.from_hsv(i / (float) hub75.width, 1.0f, 0.7f, r, g, b);
|
||||
hue_map[i][0] = r;
|
||||
hue_map[i][1] = g;
|
||||
hue_map[i][2] = b;
|
||||
}
|
||||
|
||||
hub75.start(dma_complete);
|
||||
|
@ -83,12 +68,12 @@ int main() {
|
|||
}
|
||||
|
||||
if(button_a.raw()) {
|
||||
speed += 0.05f;
|
||||
speed += 0.1f;
|
||||
speed = speed >= 10.0f ? 10.0f : speed;
|
||||
animate = true;
|
||||
}
|
||||
if(button_b.raw()) {
|
||||
speed -= 0.05f;
|
||||
speed -= 0.1f;
|
||||
speed = speed <= 0.0f ? 0.0f : speed;
|
||||
animate = true;
|
||||
}
|
||||
|
@ -103,7 +88,7 @@ int main() {
|
|||
|
||||
graphics.set_pen(r, g, b);
|
||||
graphics.pixel(Point(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
hub75.update(&graphics);
|
||||
|
||||
|
@ -111,10 +96,9 @@ int main() {
|
|||
led_h += 0.01;
|
||||
|
||||
|
||||
sleep_ms(20);
|
||||
//sleep_ms(5);
|
||||
}
|
||||
|
||||
printf("done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,4 +4,4 @@ add_library(${LIB_NAME} INTERFACE)
|
|||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hub75 button rgbled hardware_pwm)
|
||||
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hub75 button rgbled hardware_pwm pico_graphics)
|
|
@ -4,9 +4,28 @@ namespace pimoroni {
|
|||
|
||||
const uint8_t dither16_pattern[16] = {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5};
|
||||
|
||||
void PicoGraphics::from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
}
|
||||
|
||||
int PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {return -1;};
|
||||
int PicoGraphics::reset_pen(uint8_t i) {return -1;};
|
||||
int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;};
|
||||
int PicoGraphics::create_pen_hsv(float h, float s, float v){return -1;};
|
||||
void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {};
|
||||
void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {};
|
||||
void PicoGraphics::set_pixel_dither(const Point &p, const uint8_t &c) {};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <math.h>
|
||||
|
||||
#include "libraries/hershey_fonts/hershey_fonts.hpp"
|
||||
#include "libraries/bitmap_fonts/bitmap_fonts.hpp"
|
||||
|
@ -25,6 +26,8 @@ namespace pimoroni {
|
|||
typedef uint8_t RGB332;
|
||||
typedef uint16_t RGB565;
|
||||
typedef uint32_t RGB888;
|
||||
|
||||
|
||||
struct RGB {
|
||||
int16_t r, g, b;
|
||||
|
||||
|
@ -90,6 +93,8 @@ namespace pimoroni {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef int Pen;
|
||||
|
||||
struct Rect;
|
||||
|
@ -171,6 +176,9 @@ namespace pimoroni {
|
|||
Rect bounds;
|
||||
Rect clip;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef std::function<void(void *data, size_t length)> conversion_callback_func;
|
||||
typedef std::function<RGB565()> next_pixel_func;
|
||||
//typedef std::function<void(int y)> scanline_interrupt_func;
|
||||
|
@ -184,6 +192,7 @@ namespace pimoroni {
|
|||
return RGB(r, g, b).to_rgb332();
|
||||
}
|
||||
|
||||
|
||||
static constexpr RGB565 rgb332_to_rgb565(RGB332 c) {
|
||||
uint16_t p = ((c & 0b11100000) << 8) |
|
||||
((c & 0b00011100) << 6) |
|
||||
|
@ -221,6 +230,7 @@ namespace pimoroni {
|
|||
virtual void set_pixel_span(const Point &p, uint l) = 0;
|
||||
|
||||
virtual int create_pen(uint8_t r, uint8_t g, uint8_t b);
|
||||
virtual int create_pen_hsv(float h, float s, float v);
|
||||
virtual int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b);
|
||||
virtual int reset_pen(uint8_t i);
|
||||
virtual void set_pixel_dither(const Point &p, const RGB &c);
|
||||
|
@ -253,6 +263,7 @@ namespace pimoroni {
|
|||
void polygon(const std::vector<Point> &points);
|
||||
void triangle(Point p1, Point p2, Point p3);
|
||||
void line(Point p1, Point p2);
|
||||
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b);
|
||||
|
||||
protected:
|
||||
void frame_convert_rgb565(conversion_callback_func callback, next_pixel_func get_next_pixel);
|
||||
|
@ -400,7 +411,6 @@ namespace pimoroni {
|
|||
void set_pen(uint c) override;
|
||||
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
|
||||
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
|
||||
|
||||
void set_pixel(const Point &p) override;
|
||||
void set_pixel_span(const Point &p, uint l) override;
|
||||
void set_pixel_dither(const Point &p, const RGB &c) override;
|
||||
|
@ -422,6 +432,7 @@ namespace pimoroni {
|
|||
void set_pen(uint c) override;
|
||||
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
|
||||
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
|
||||
int create_pen_hsv(float h, float s, float v) override;
|
||||
void set_pixel(const Point &p) override;
|
||||
void set_pixel_span(const Point &p, uint l) override;
|
||||
static size_t buffer_size(uint w, uint h) {
|
||||
|
@ -429,7 +440,6 @@ namespace pimoroni {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class PicoGraphics_PenRGB888 : public PicoGraphics {
|
||||
public:
|
||||
RGB src_color;
|
||||
|
@ -438,6 +448,7 @@ namespace pimoroni {
|
|||
void set_pen(uint c) override;
|
||||
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
|
||||
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
|
||||
int create_pen_hsv(float h, float s, float v) override;
|
||||
void set_pixel(const Point &p) override;
|
||||
void set_pixel_span(const Point &p, uint l) override;
|
||||
static size_t buffer_size(uint w, uint h) {
|
||||
|
|
|
@ -13,11 +13,18 @@ namespace pimoroni {
|
|||
}
|
||||
void PicoGraphics_PenRGB565::set_pen(uint8_t r, uint8_t g, uint8_t b) {
|
||||
src_color = {r, g, b};
|
||||
color = src_color.to_rgb565();
|
||||
color = src_color.to_rgb565();
|
||||
}
|
||||
int PicoGraphics_PenRGB565::create_pen(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return RGB(r, g, b).to_rgb565();
|
||||
}
|
||||
int PicoGraphics_PenRGB565::create_pen_hsv(float h, float s, float v) {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
from_hsv(h, s, v, r, g, b);
|
||||
return RGB(r, g, b).to_rgb565();
|
||||
}
|
||||
void PicoGraphics_PenRGB565::set_pixel(const Point &p) {
|
||||
uint16_t *buf = (uint16_t *)frame_buffer;
|
||||
buf[p.y * bounds.w + p.x] = color;
|
||||
|
|
|
@ -18,6 +18,13 @@ namespace pimoroni {
|
|||
int PicoGraphics_PenRGB888::create_pen(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return RGB(r, g, b).to_rgb888();
|
||||
}
|
||||
int PicoGraphics_PenRGB888::create_pen_hsv(float h, float s, float v) {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
from_hsv(h, s, v, r, g, b);
|
||||
return RGB(r, g, b).to_rgb888();
|
||||
}
|
||||
void PicoGraphics_PenRGB888::set_pixel(const Point &p) {
|
||||
uint32_t *buf = (uint32_t *)frame_buffer;
|
||||
buf[p.y * bounds.w + p.x] = color;
|
||||
|
|
|
@ -1,60 +1,30 @@
|
|||
import time
|
||||
import math
|
||||
import interstate75
|
||||
|
||||
i75 = interstate75.Interstate75(display=interstate75.DISPLAY_INTERSTATE75_32X32)
|
||||
i75 = interstate75.Interstate75(display=interstate75.DISPLAY_INTERSTATE75_64X64, stb_invert=True)
|
||||
graphics = i75.display
|
||||
|
||||
width = i75.width
|
||||
height = i75.height
|
||||
|
||||
|
||||
@micropython.native # noqa: F821
|
||||
def from_hsv(h, s, v):
|
||||
i = math.floor(h * 6.0)
|
||||
f = h * 6.0 - i
|
||||
v *= 255.0
|
||||
p = v * (1.0 - s)
|
||||
q = v * (1.0 - f * s)
|
||||
t = v * (1.0 - (1.0 - f) * s)
|
||||
|
||||
i = int(i) % 6
|
||||
if i == 0:
|
||||
return int(v), int(t), int(p)
|
||||
if i == 1:
|
||||
return int(q), int(v), int(p)
|
||||
if i == 2:
|
||||
return int(p), int(v), int(t)
|
||||
if i == 3:
|
||||
return int(p), int(q), int(v)
|
||||
if i == 4:
|
||||
return int(t), int(p), int(v)
|
||||
if i == 5:
|
||||
return int(v), int(p), int(q)
|
||||
devs = 1.0 / height
|
||||
|
||||
|
||||
@micropython.native # noqa: F821
|
||||
def draw():
|
||||
global hue_offset, phase
|
||||
phase_percent = phase / 15
|
||||
def draw(offset):
|
||||
for x in range(width):
|
||||
colour = hue_map[int((x + (hue_offset * width)) % width)]
|
||||
graphics.set_pen(graphics.create_pen_hsv(devs * x + offset, 1.0, 0.5))
|
||||
for y in range(height):
|
||||
v = ((math.sin((x + y) / stripe_width + phase_percent) + 1.5) / 2.5)
|
||||
|
||||
graphics.set_pen(graphics.create_pen(int(colour[0] * v), int(colour[1] * v), int(colour[2] * v)))
|
||||
graphics.pixel(x, y)
|
||||
|
||||
i75.update(graphics)
|
||||
|
||||
|
||||
hue_map = [from_hsv(x / width, 1.0, 0.5) for x in range(width)]
|
||||
hue_offset = 0.0
|
||||
|
||||
animate = True
|
||||
stripe_width = 3.0
|
||||
speed = 5.0
|
||||
|
||||
offset = 0.0
|
||||
|
||||
phase = 0
|
||||
while True:
|
||||
|
@ -63,6 +33,7 @@ while True:
|
|||
phase += speed
|
||||
|
||||
start = time.ticks_ms()
|
||||
draw()
|
||||
offset += 0.05
|
||||
draw(offset)
|
||||
|
||||
print("total took: {} ms".format(time.ticks_ms() - start))
|
||||
|
|
|
@ -21,6 +21,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_set_palette_obj, 2, ModPicoGraphics_s
|
|||
// Pen
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(ModPicoGraphics_set_pen_obj, ModPicoGraphics_set_pen);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_create_pen_obj, 4, 4, ModPicoGraphics_create_pen);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_create_pen_hsv_obj, 4, 4, ModPicoGraphics_create_pen_hsv);
|
||||
|
||||
// Primitives
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_set_clip_obj, 5, 5, ModPicoGraphics_set_clip);
|
||||
|
@ -77,6 +78,7 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_sprite), MP_ROM_PTR(&ModPicoGraphics_sprite_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&ModPicoGraphics_create_pen_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_create_pen_hsv), MP_ROM_PTR(&ModPicoGraphics_create_pen_hsv_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&ModPicoGraphics_update_pen_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&ModPicoGraphics_reset_pen_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&ModPicoGraphics_set_palette_obj) },
|
||||
|
|
|
@ -696,6 +696,21 @@ mp_obj_t ModPicoGraphics_create_pen(size_t n_args, const mp_obj_t *args) {
|
|||
return mp_obj_new_int(result);
|
||||
}
|
||||
|
||||
mp_obj_t ModPicoGraphics_create_pen_hsv(size_t n_args, const mp_obj_t *args) {
|
||||
enum { ARG_self, ARG_h, ARG_s, ARG_v };
|
||||
|
||||
ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self], ModPicoGraphics_obj_t);
|
||||
int result = self->graphics->create_pen_hsv(
|
||||
mp_obj_get_float(args[ARG_h]),
|
||||
mp_obj_get_float(args[ARG_s]),
|
||||
mp_obj_get_float(args[ARG_v])
|
||||
);
|
||||
|
||||
if (result == -1) mp_raise_ValueError("create_pen failed. No matching colour or space in palette!");
|
||||
|
||||
return mp_obj_new_int(result);
|
||||
}
|
||||
|
||||
mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
size_t num_tuples = n_args - 1;
|
||||
const mp_obj_t *tuples = pos_args + 1;
|
||||
|
|
|
@ -66,10 +66,12 @@ extern mp_obj_t ModPicoGraphics_set_update_speed(mp_obj_t self_in, mp_obj_t upda
|
|||
extern mp_obj_t ModPicoGraphics_update_pen(size_t n_args, const mp_obj_t *args);
|
||||
extern mp_obj_t ModPicoGraphics_reset_pen(mp_obj_t self_in, mp_obj_t pen);
|
||||
extern mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t ModPicoGraphics_hsv_to_rgb(size_t n_args, const mp_obj_t *args);
|
||||
|
||||
// Pen
|
||||
extern mp_obj_t ModPicoGraphics_set_pen(mp_obj_t self_in, mp_obj_t pen);
|
||||
extern mp_obj_t ModPicoGraphics_create_pen(size_t n_args, const mp_obj_t *args);
|
||||
extern mp_obj_t ModPicoGraphics_create_pen_hsv(size_t n_args, const mp_obj_t *args);
|
||||
|
||||
// Primitives
|
||||
extern mp_obj_t ModPicoGraphics_set_clip(size_t n_args, const mp_obj_t *args);
|
||||
|
|
Loading…
Reference in New Issue