From ae518fabc938595ff2542d9b634e7d41da41fadd Mon Sep 17 00:00:00 2001 From: Kuba Birecki Date: Thu, 16 Dec 2021 19:02:46 +0100 Subject: [PATCH] Add 'compose' animation --- app/CMakeLists.txt | 1 + .../animations/zmk,animation-compose.yaml | 27 +++++ .../dt-bindings/zmk/animation_compose.h | 12 ++ app/src/animation/animation_compose.c | 106 ++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 app/dts/bindings/animations/zmk,animation-compose.yaml create mode 100644 app/include/dt-bindings/zmk/animation_compose.h create mode 100644 app/src/animation/animation_compose.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 1ee31865..9e5cbdad 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -81,6 +81,7 @@ target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/battery.c) target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/color.c) +target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_compose.c) target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_ripple.c) target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_solid.c) target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation.c) diff --git a/app/dts/bindings/animations/zmk,animation-compose.yaml b/app/dts/bindings/animations/zmk,animation-compose.yaml new file mode 100644 index 00000000..97bdb1ad --- /dev/null +++ b/app/dts/bindings/animations/zmk,animation-compose.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2020, The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: | + Higher-order animation which allows for composing other animation + drivers and using different blending modes. + +compatible: "zmk,animation-compose" + +include: animation_base.yaml + +properties: + label: + type: string + required: true + + animations: + type: phandles + required: true + description: | + Animations to be combined. + + blending-modes: + type: array + required: true + description: | + Blending modes for each animation. diff --git a/app/include/dt-bindings/zmk/animation_compose.h b/app/include/dt-bindings/zmk/animation_compose.h new file mode 100644 index 00000000..7030efec --- /dev/null +++ b/app/include/dt-bindings/zmk/animation_compose.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define BLENDING_MODE_NORMAL 0 +#define BLENDING_MODE_MULTIPLY 1 +#define BLENDING_MODE_LIGHTEN 2 +#define BLENDING_MODE_DARKEN 3 +#define BLENDING_MODE_SCREEN 4 +#define BLENDING_MODE_SUBTRACT 5 diff --git a/app/src/animation/animation_compose.c b/app/src/animation/animation_compose.c new file mode 100644 index 00000000..25c3d2b5 --- /dev/null +++ b/app/src/animation/animation_compose.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_animation_compose + +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +// 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.* +#define ZMK_DT_INST_FOREACH_PROP_ELEM(inst, prop, fn) \ + UTIL_LISTIFY(DT_INST_PROP_LEN(inst, prop), fn, DT_DRV_INST(inst), prop) + +#define PHANDLE_TO_DEVICE(idx, node_id, prop) DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)), + +struct animation_compose_config { + const struct device **animations; + const size_t animations_size; + const uint8_t *blending_modes; +}; + +static void animation_compose_render_pixel(const struct device *dev, + const struct animation_pixel *pixel, + struct zmk_color_rgb *value) { + const struct animation_compose_config *config = dev->config; + + const struct device **animations = config->animations; + const uint8_t *blending_modes = config->blending_modes; + + struct zmk_color_rgb rgb = { + .r = 0, + .g = 0, + .b = 0, + }; + + for (size_t i = 0; i < config->animations_size; ++i) { + animation_render_pixel(animations[i], pixel, + blending_modes[i] == BLENDING_MODE_NORMAL ? value : &rgb); + + switch (blending_modes[i]) { + case BLENDING_MODE_MULTIPLY: + value->r = value->r * rgb.r; + value->g = value->g * rgb.g; + value->b = value->b * rgb.b; + break; + case BLENDING_MODE_LIGHTEN: + value->r = value->r > rgb.r ? value->r : rgb.r; + value->g = value->g > rgb.g ? value->g : rgb.g; + value->b = value->b > rgb.b ? value->b : rgb.b; + break; + case BLENDING_MODE_DARKEN: + value->r = value->r > rgb.r ? rgb.r : value->r; + value->g = value->g > rgb.g ? rgb.g : value->g; + value->b = value->b > rgb.b ? rgb.b : value->b; + break; + case BLENDING_MODE_SCREEN: + value->r = value->r + (1.0f - value->r) * rgb.r; + value->g = value->g + (1.0f - value->g) * rgb.g; + value->b = value->b + (1.0f - value->b) * rgb.b; + break; + case BLENDING_MODE_SUBTRACT: + value->r = value->r - value->r * rgb.r; + value->g = value->g - value->g * rgb.g; + value->b = value->b - value->b * rgb.b; + break; + } + } +} + +static int animation_compose_init(const struct device *dev) { return 0; } + +static const struct animation_api animation_compose_api = { + .on_before_frame = NULL, + .on_after_frame = NULL, + .render_pixel = animation_compose_render_pixel, +}; + +#define ANIMATION_COMPOSE_DEVICE(idx) \ + \ + static const uint8_t animation_compose_##idx##_blending_modes[] = \ + DT_INST_PROP(idx, blending_modes); \ + \ + static const struct device *animation_compose_##idx##_animations[] = { \ + ZMK_DT_INST_FOREACH_PROP_ELEM(idx, animations, PHANDLE_TO_DEVICE)}; \ + \ + static struct animation_compose_config animation_compose_##idx##_config = { \ + .animations = animation_compose_##idx##_animations, \ + .animations_size = DT_INST_PROP_LEN(idx, animations), \ + .blending_modes = animation_compose_##idx##_blending_modes, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, &animation_compose_init, NULL, NULL, \ + &animation_compose_##idx##_config, POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, &animation_compose_api); + +DT_INST_FOREACH_STATUS_OKAY(ANIMATION_COMPOSE_DEVICE);