Fix formatting

This commit is contained in:
Kuba Birecki 2021-12-04 19:49:56 +01:00
parent 8e5574ab49
commit 2dfec75038
5 changed files with 135 additions and 182 deletions

View file

@ -37,7 +37,8 @@ typedef void (*animation_api_prep_next_frame)(const struct device *dev);
* *
* @see animation_prep_next_frame() for argument descriptions. * @see animation_prep_next_frame() for argument descriptions.
*/ */
typedef void (*animation_api_get_pixel)(const struct device *dev, const struct animation_pixel_position *pixel_position, typedef void (*animation_api_get_pixel)(const struct device *dev,
const struct animation_pixel_position *pixel_position,
struct zmk_color_rgb *value); struct zmk_color_rgb *value);
struct animation_api { struct animation_api {
@ -50,7 +51,7 @@ struct animation_api {
* @param dev [description] * @param dev [description]
*/ */
static inline void animation_prep_next_frame(const struct device *dev) { static inline void animation_prep_next_frame(const struct device *dev) {
const struct animation_api *api = (const struct animation_api *) dev->api; const struct animation_api *api = (const struct animation_api *)dev->api;
return api->prep_next_frame(dev); return api->prep_next_frame(dev);
} }
@ -60,9 +61,10 @@ static inline void animation_prep_next_frame(const struct device *dev) {
* @param dev [description] * @param dev [description]
* @param pixel [description] * @param pixel [description]
*/ */
static inline void animation_get_pixel(const struct device *dev, const struct animation_pixel_position *pixel_position, static inline void animation_get_pixel(const struct device *dev,
struct zmk_color_rgb *value) { const struct animation_pixel_position *pixel_position,
const struct animation_api *api = (const struct animation_api *) dev->api; struct zmk_color_rgb *value) {
const struct animation_api *api = (const struct animation_api *)dev->api;
return api->get_pixel(dev, pixel_position, value); return api->get_pixel(dev, pixel_position, value);
} }

View file

@ -34,8 +34,8 @@ struct zmk_color_hsl {
/** /**
* Converts color from HSL to RGB. * Converts color from HSL to RGB.
* *
* @param hsl [description] * @param hsl Color to convert
* @param rgb [description] * @param rgb Converted color
*/ */
void zmk_hsl_to_rgb(const struct zmk_color_hsl *hsl, struct zmk_color_rgb *rgb); void zmk_hsl_to_rgb(const struct zmk_color_hsl *hsl, struct zmk_color_rgb *rgb);
@ -43,17 +43,17 @@ void zmk_hsl_to_rgb(const struct zmk_color_hsl *hsl, struct zmk_color_rgb *rgb);
* Converts the internal RGB representation into a led_rgb struct * Converts the internal RGB representation into a led_rgb struct
* for use with led_strip drivers. * for use with led_strip drivers.
* *
* @param rgb [description] * @param rgb Color to convert
* @param led [description] * @param led Converted color
*/ */
void zmk_rgb_to_led_rgb(const struct zmk_color_rgb *rgb, struct led_rgb *led); void zmk_rgb_to_led_rgb(const struct zmk_color_rgb *rgb, struct led_rgb *led);
/** /**
* Returns true if two HSL colors are the same. * Returns true if two HSL colors are the same.
* *
* @param a [description] * @param a HSL color to compare
* @param b [description] * @param b HSL color to compare
* @return [description] * @return True when colors share the same values
*/ */
bool zmk_cmp_hsl(const struct zmk_color_hsl *a, const struct zmk_color_hsl *b); bool zmk_cmp_hsl(const struct zmk_color_hsl *a, const struct zmk_color_hsl *b);
@ -61,10 +61,10 @@ bool zmk_cmp_hsl(const struct zmk_color_hsl *a, const struct zmk_color_hsl *b);
* Perform linear interpolation between HSL values of two colors * Perform linear interpolation between HSL values of two colors
* at a given distance (step) and store the resulting value in the given pointer. * at a given distance (step) and store the resulting value in the given pointer.
* *
* @param from [description] * @param from HSL color to interpolate
* @param to [description] * @param to HSL color to interpolate
* @param result [description] * @param result Resulting HSL color
* @param step [description] * @param step Interpolation step
*/ */
void zmk_interpolate_hsl(const struct zmk_color_hsl *from, const struct zmk_color_hsl *to, void zmk_interpolate_hsl(const struct zmk_color_hsl *from, const struct zmk_color_hsl *to,
struct zmk_color_hsl *result, float step); struct zmk_color_hsl *result, float step);

View file

@ -22,30 +22,29 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
// Zephyr 2.7.0 comes with DT_INST_FOREACH_PROP_ELEM // Zephyr 2.7.0 comes with DT_INST_FOREACH_PROP_ELEM
// that we can't use quite yet as we're still on 2.5.* // that we can't use quite yet as we're still on 2.5.*
#define ZMK_DT_INST_FOREACH_PROP_ELEM(inst, prop, fn) \ #define ZMK_DT_INST_FOREACH_PROP_ELEM(inst, prop, fn) \
UTIL_LISTIFY(DT_INST_PROP_LEN(inst, prop), fn, DT_DRV_INST(inst), prop) UTIL_LISTIFY(DT_INST_PROP_LEN(inst, prop), fn, DT_DRV_INST(inst), prop)
#define PHANDLE_TO_DEVICE(idx, node_id, prop) \ #define PHANDLE_TO_DEVICE(idx, node_id, prop) DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)),
DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)),
#define PHANDLE_TO_CHAIN_LENGTH(idx, node_id, prop) \ #define PHANDLE_TO_CHAIN_LENGTH(idx, node_id, prop) \
DT_PROP_BY_PHANDLE_IDX(node_id, prop, idx, chain_length), DT_PROP_BY_PHANDLE_IDX(node_id, prop, idx, chain_length),
#define PHANDLE_TO_PIXEL(idx, node_id, prop) \ #define PHANDLE_TO_PIXEL(idx, node_id, prop) \
{ \ { \
.animation = PHANDLE_TO_DEVICE(idx, node_id, prop) \ .animation = DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)), \
.position = { \ .position = \
.x = DT_PHA_BY_IDX(node_id, prop, idx, position_x),\ { \
.y = DT_PHA_BY_IDX(node_id, prop, idx, position_y),\ .x = DT_PHA_BY_IDX(node_id, prop, idx, position_x), \
}, \ .y = DT_PHA_BY_IDX(node_id, prop, idx, position_y), \
}, }, \
},
/** /**
* LED Driver device pointers. * LED Driver device pointers.
*/ */
static const struct device *drivers[] = { static const struct device *drivers[] = {
ZMK_DT_INST_FOREACH_PROP_ELEM(0, drivers, PHANDLE_TO_DEVICE) ZMK_DT_INST_FOREACH_PROP_ELEM(0, drivers, PHANDLE_TO_DEVICE)};
};
/** /**
* Size of the LED driver device pointers array. * Size of the LED driver device pointers array.
@ -56,15 +55,13 @@ static const size_t drivers_size = DT_INST_PROP_LEN(0, drivers);
* Array containing the number of LEDs handled by each device. * Array containing the number of LEDs handled by each device.
*/ */
static const uint8_t pixels_per_driver[] = { static const uint8_t pixels_per_driver[] = {
ZMK_DT_INST_FOREACH_PROP_ELEM(0, drivers, PHANDLE_TO_CHAIN_LENGTH) ZMK_DT_INST_FOREACH_PROP_ELEM(0, drivers, PHANDLE_TO_CHAIN_LENGTH)};
};
/** /**
* Pointers to all active animation devices. * Pointers to all active animation devices.
*/ */
static const struct device *animations[] = { static const struct device *animations[] = {
ZMK_DT_INST_FOREACH_PROP_ELEM(0, animations, PHANDLE_TO_DEVICE) ZMK_DT_INST_FOREACH_PROP_ELEM(0, animations, PHANDLE_TO_DEVICE)};
};
/** /**
* Size of the animation device pointers array. * Size of the animation device pointers array.
@ -75,8 +72,7 @@ static const size_t animations_size = DT_INST_PROP_LEN(0, animations);
* Pixel configuration. * Pixel configuration.
*/ */
static const struct animation_pixel pixels[] = { static const struct animation_pixel pixels[] = {
ZMK_DT_INST_FOREACH_PROP_ELEM(0, pixels, PHANDLE_TO_PIXEL) ZMK_DT_INST_FOREACH_PROP_ELEM(0, pixels, PHANDLE_TO_PIXEL)};
};
/** /**
* Size of the pixels array. * Size of the pixels array.
@ -89,49 +85,43 @@ static const size_t pixels_size = DT_INST_PROP_LEN(0, pixels);
static struct led_rgb px_buffer[DT_INST_PROP_LEN(0, pixels)]; static struct led_rgb px_buffer[DT_INST_PROP_LEN(0, pixels)];
static void zmk_animation_tick(struct k_work *work) { static void zmk_animation_tick(struct k_work *work) {
for (size_t i = 0; i < animations_size; ++i) { for (size_t i = 0; i < animations_size; ++i) {
animation_prep_next_frame(animations[i]); animation_prep_next_frame(animations[i]);
} }
for (size_t i = 0; i < pixels_size; ++i) { for (size_t i = 0; i < pixels_size; ++i) {
struct zmk_color_rgb rgb = { struct zmk_color_rgb rgb = {
.r = 0, .r = 0,
.g = 0, .g = 0,
.b = 0, .b = 0,
}; };
animation_get_pixel(pixels[i].animation, &pixels[i].position, &rgb); animation_get_pixel(pixels[i].animation, &pixels[i].position, &rgb);
zmk_rgb_to_led_rgb(&rgb, &px_buffer[i]); zmk_rgb_to_led_rgb(&rgb, &px_buffer[i]);
} }
size_t pixels_updated = 0; size_t pixels_updated = 0;
for (size_t i = 0; i < drivers_size; ++i) { for (size_t i = 0; i < drivers_size; ++i) {
led_strip_update_rgb( led_strip_update_rgb(drivers[i], &px_buffer[pixels_updated], pixels_per_driver[i]);
drivers[i],
&px_buffer[pixels_updated],
pixels_per_driver[i]
);
pixels_updated += (size_t) pixels_per_driver; pixels_updated += (size_t)pixels_per_driver;
} }
} }
K_WORK_DEFINE(animation_work, zmk_animation_tick); K_WORK_DEFINE(animation_work, zmk_animation_tick);
static void zmk_animation_tick_handler(struct k_timer *timer) { static void zmk_animation_tick_handler(struct k_timer *timer) { k_work_submit(&animation_work); }
k_work_submit(&animation_work);
}
K_TIMER_DEFINE(animation_tick, zmk_animation_tick_handler, NULL); K_TIMER_DEFINE(animation_tick, zmk_animation_tick_handler, NULL);
static int zmk_animation_init(const struct device *dev) { static int zmk_animation_init(const struct device *dev) {
LOG_INF("ZMK Animation Ready"); LOG_INF("ZMK Animation Ready");
k_timer_start(&animation_tick, K_NO_WAIT, K_MSEC(1000 / CONFIG_ZMK_ANIMATION_FPS)); k_timer_start(&animation_tick, K_NO_WAIT, K_MSEC(1000 / CONFIG_ZMK_ANIMATION_FPS));
return 0; return 0;
} }
SYS_INIT(zmk_animation_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); SYS_INIT(zmk_animation_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);

View file

@ -45,12 +45,9 @@ static void animation_solid_prep_next_frame(const struct device *dev) {
struct zmk_color_hsl next_hsl; struct zmk_color_hsl next_hsl;
zmk_interpolate_hsl( zmk_interpolate_hsl(&config->colors[from], &config->colors[to], &next_hsl,
&config->colors[from], (data->counter % config->transition_duration) /
&config->colors[to], (float)config->transition_duration);
&next_hsl,
(data->counter % config->transition_duration) / (float) config->transition_duration
);
data->has_changed = !zmk_cmp_hsl(&data->current_hsl, &next_hsl); data->has_changed = !zmk_cmp_hsl(&data->current_hsl, &next_hsl);
@ -60,8 +57,9 @@ static void animation_solid_prep_next_frame(const struct device *dev) {
data->counter = (data->counter + 1) % config->duration; data->counter = (data->counter + 1) % config->duration;
} }
static void animation_solid_get_pixel(const struct device *dev, const struct animation_pixel_position *position, static void animation_solid_get_pixel(const struct device *dev,
struct zmk_color_rgb *value) { const struct animation_pixel_position *position,
struct zmk_color_rgb *value) {
const struct animation_solid_data *data = dev->data; const struct animation_solid_data *data = dev->data;
value->r = data->current_rgb.r; value->r = data->current_rgb.r;
@ -86,59 +84,23 @@ static const struct animation_api animation_solid_api = {
.get_pixel = animation_solid_get_pixel, .get_pixel = animation_solid_get_pixel,
}; };
#define ANIMATION_SOLID_DEVICE(idx) \ #define ANIMATION_SOLID_DEVICE(idx) \
\ \
static struct animation_solid_data animation_solid_##idx##_data; \ static struct animation_solid_data animation_solid_##idx##_data; \
\ \
static uint32_t animation_solid_##idx##_colors[DT_INST_PROP_LEN(idx, colors)] = DT_INST_PROP(idx, colors); \ static uint32_t animation_solid_##idx##_colors[DT_INST_PROP_LEN(idx, colors)] = \
\ DT_INST_PROP(idx, colors); \
static struct animation_solid_config animation_solid_##idx##_config = { \ \
.colors = (struct zmk_color_hsl *) animation_solid_##idx##_colors, \ static struct animation_solid_config animation_solid_##idx##_config = { \
.num_colors = DT_INST_PROP_LEN(idx, colors), \ .colors = (struct zmk_color_hsl *)animation_solid_##idx##_colors, \
.duration = DT_INST_PROP(idx, duration) * CONFIG_ZMK_ANIMATION_FPS, \ .num_colors = DT_INST_PROP_LEN(idx, colors), \
.transition_duration = (DT_INST_PROP(idx, duration) * CONFIG_ZMK_ANIMATION_FPS) / DT_INST_PROP_LEN(idx, colors), \ .duration = DT_INST_PROP(idx, duration) * CONFIG_ZMK_ANIMATION_FPS, \
}; \ .transition_duration = (DT_INST_PROP(idx, duration) * CONFIG_ZMK_ANIMATION_FPS) / \
\ DT_INST_PROP_LEN(idx, colors), \
DEVICE_DT_INST_DEFINE(idx, &animation_solid_init, NULL, &animation_solid_##idx##_data, \ }; \
&animation_solid_##idx##_config, POST_KERNEL, CONFIG_LED_STRIP_INIT_PRIORITY, \ \
&animation_solid_api); DEVICE_DT_INST_DEFINE(idx, &animation_solid_init, NULL, &animation_solid_##idx##_data, \
&animation_solid_##idx##_config, POST_KERNEL, \
CONFIG_APPLICATION_INIT_PRIORITY, &animation_solid_api);
DT_INST_FOREACH_STATUS_OKAY(ANIMATION_SOLID_DEVICE); DT_INST_FOREACH_STATUS_OKAY(ANIMATION_SOLID_DEVICE);
// To do:
//
// STEP 1: single animation
// - Start with a single animation, just color
// - Add layer for taking the output from here and putting it to the led strip
// - Make it work
//
// STEP 2: areas, in fact, instead of defining them explicitly we can just use appropriate x,y coordinates and animation.
// - Split keyboard in two independent areas
// - Make it work
//
// STEP 3: add additional animation effects
// - Basically, carry over rgb_underglow.
// - Make it work
//
// STEP 4: add animation triggers
// - Allow an animation to be triggered by behaviors or key-presses
// - Make it work
//
// STEP 5: add animation layers and a MULTIPLY mode (again, opacity would be set on individual pixels so... that affects some optimizations I guess)
// - Normal mode: overrides layers below
// - Multiply mode: auguments whatever is below (opacity, whatever)
//
// Voila! Animation composition!
//
// STEP 6, BONUS!:
// - Figure out a way to switch animations during runtime?
//
// Notes:
// - Any animation settings go into 'driver' config & data, so they can be updated at runtime.
// - Main limitation is space, so the amount of different animations one can have loaded
//
// More notes:
// - Solid color would be one animation (just transitions between colors)
// - Gradient (SPECTRUM) would be another, you choose how they're distributed accross the keys and if they move?
// - Effects like 'breathe' can be implemented by specifying #000 as one of the colors or using a multiply layer?

View file

@ -9,98 +9,97 @@
#include <zmk/animation.h> #include <zmk/animation.h>
static float fmod(float a, float b) { static float fmod(float a, float b) {
float mod = a < 0 ? -a : a; float mod = a < 0 ? -a : a;
float x = b < 0 ? -b : b; float x = b < 0 ? -b : b;
while (mod >= x) { while (mod >= x) {
mod = mod - x; mod = mod - x;
} }
return a < 0 ? -mod : mod; return a < 0 ? -mod : mod;
} }
static float fabs(float a) { static float fabs(float a) { return a < 0 ? -a : a; }
return a < 0 ? -a : a;
}
/** /**
* HSL chosen over HSV/HSB as it shares the same parameters with LCh or HSLuv. * HSL chosen over HSV/HSB as it shares the same parameters with LCh or HSLuv.
* The latter color spaces could be interesting to experiment with because of their * The latter color spaces could be interesting to experiment with because of their
* perceptual uniformity, but it would come at the cost of some performance. * perceptual uniformity, but it would come at the cost of some performance.
* Using the same parameters would make it easy to toggle any such behavior using a single config flag. * Using the same parameters would make it easy to toggle any such behavior
* using a single config flag.
* *
* Algorithm source: https://www.tlbx.app/color-converter * Algorithm source: https://www.tlbx.app/color-converter
*/ */
void zmk_hsl_to_rgb(const struct zmk_color_hsl *hsl, struct zmk_color_rgb *rgb) { void zmk_hsl_to_rgb(const struct zmk_color_hsl *hsl, struct zmk_color_rgb *rgb) {
float s = (float) hsl->s / 100; float s = (float)hsl->s / 100;
float l = (float) hsl->l / 100; float l = (float)hsl->l / 100;
float a = (float) hsl->h / 60; float a = (float)hsl->h / 60;
float chroma = s * (1 - fabs(2 * l - 1)); float chroma = s * (1 - fabs(2 * l - 1));
float x = chroma * (1 - fabs(fmod(a, 2) - 1)); float x = chroma * (1 - fabs(fmod(a, 2) - 1));
float m = l - chroma / 2; float m = l - chroma / 2;
switch ((uint8_t) a % 6) { switch ((uint8_t)a % 6) {
case 0: case 0:
rgb->r = m + chroma; rgb->r = m + chroma;
rgb->g = m + x; rgb->g = m + x;
rgb->b = m; rgb->b = m;
break; break;
case 1: case 1:
rgb->r = m + x; rgb->r = m + x;
rgb->g = m + chroma; rgb->g = m + chroma;
rgb->b = m; rgb->b = m;
break; break;
case 2: case 2:
rgb->r = m; rgb->r = m;
rgb->g = m + chroma; rgb->g = m + chroma;
rgb->b = m + x; rgb->b = m + x;
break; break;
case 3: case 3:
rgb->r = m; rgb->r = m;
rgb->g = m + x; rgb->g = m + x;
rgb->b = m + chroma; rgb->b = m + chroma;
break; break;
case 4: case 4:
rgb->r = m + x; rgb->r = m + x;
rgb->g = m; rgb->g = m;
rgb->b = m + chroma; rgb->b = m + chroma;
break; break;
case 5: case 5:
rgb->r = m + chroma; rgb->r = m + chroma;
rgb->g = m; rgb->g = m;
rgb->b = m + x; rgb->b = m + x;
break; break;
} }
} }
/** /**
* Converts ZMKs RGB (float) to Zephyr's led_rgb (uint8_t) format. * Converts ZMKs RGB (float) to Zephyr's led_rgb (uint8_t) format.
*/ */
void zmk_rgb_to_led_rgb(const struct zmk_color_rgb *rgb, struct led_rgb *led) { void zmk_rgb_to_led_rgb(const struct zmk_color_rgb *rgb, struct led_rgb *led) {
led->r = (uint8_t) (rgb->r * 255); led->r = rgb->r * 255;
led->g = (uint8_t) (rgb->g * 255); led->g = rgb->g * 255;
led->b = (uint8_t) (rgb->b * 255); led->b = rgb->b * 255;
} }
/** /**
* Compares two HSL colors. * Compares two HSL colors.
*/ */
bool zmk_cmp_hsl(const struct zmk_color_hsl *a, const struct zmk_color_hsl *b) { bool zmk_cmp_hsl(const struct zmk_color_hsl *a, const struct zmk_color_hsl *b) {
return a->h == b->h && a->s == b->s && a->l == b->l; return a->h == b->h && a->s == b->s && a->l == b->l;
} }
/** /**
* Interpolate between two colors using the cylindrical model (HSL). * Interpolate between two colors using the cylindrical model (HSL).
*/ */
void zmk_interpolate_hsl(const struct zmk_color_hsl *from, const struct zmk_color_hsl *to, void zmk_interpolate_hsl(const struct zmk_color_hsl *from, const struct zmk_color_hsl *to,
struct zmk_color_hsl *result, float step) { struct zmk_color_hsl *result, float step) {
int16_t hue_delta; int16_t hue_delta;
hue_delta = from->h - to->h; hue_delta = from->h - to->h;
hue_delta = hue_delta + (180 < abs(hue_delta) ? (hue_delta < 0 ? 360 : -360) : 0); hue_delta = hue_delta + (180 < abs(hue_delta) ? (hue_delta < 0 ? 360 : -360) : 0);
result->h = (uint16_t) (360 + from->h - (hue_delta * step)) % 360; result->h = (uint16_t)(360 + from->h - (hue_delta * step)) % 360;
result->s = from->s - (from->s - to->s) * step; result->s = from->s - (from->s - to->s) * step;
result->l = from->l - (from->l - to->l) * step; result->l = from->l - (from->l - to->l) * step;
} }