PicoGraphics: HSV Pen (#665)

Co-authored-by: Gee Bartlett <122281230+ageeandakeyboard@users.noreply.github.com>
pull/666/head
Philip Howard 2023-02-09 16:13:37 +00:00 zatwierdzone przez GitHub
rodzic cd2f45dee4
commit c4decc5003
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 88 dodań i 69 usunięć

Wyświetl plik

@ -11,6 +11,7 @@ target_link_libraries(${OUTPUT_NAME}
pico_multicore
hardware_vreg
hardware_pwm
pico_graphics
hub75
interstate75
)

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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