14 constexpr uint32_t k_square_cells = 12;
15 constexpr uint32_t k_hue_segments = 6;
16 constexpr float k_marker_half_height = 0.018F;
19 std::vector<Kakshya::MeshVertex>&
out,
20 Kinesis::AABB2D region,
21 glm::vec3 bl, glm::vec3 br, glm::vec3 tl, glm::vec3 tr)
23 using V = Kakshya::MeshVertex;
24 const V vbl { .position = { region.min.x, region.min.y, 0.F }, .color = bl };
25 const V vbr { .position = { region.max.x, region.min.y, 0.F }, .color = br };
26 const V vtl { .position = { region.min.x, region.max.y, 0.F }, .color = tl };
27 const V vtr { .position = { region.max.x, region.max.y, 0.F }, .color = tr };
28 out.insert(
out.end(), { vbl, vbr, vtl, vbr, vtr, vtl });
31 void append_quad(std::vector<Kakshya::MeshVertex>&
out, Kinesis::AABB2D region, glm::vec3
color)
36 void append_marker(std::vector<Kakshya::MeshVertex>&
out, glm::vec2 centre, glm::vec2 half)
38 append_quad(
out, { .min = centre - half, .max = centre + half }, glm::vec3(0.F));
39 append_quad(
out, { .min = centre - half * 0.6F, .max = centre + half * 0.6F }, glm::vec3(1.F));
47 float x_min,
float x_max,
float height)
49 auto& ctx = surface.
ctx();
50 const auto layer_ptr = surface.
layer_ptr();
53 const float width = x_max - x_min;
54 const float y_min = advanced.
min.y;
55 const float y_max = advanced.
max.y;
65 if (
const auto locked =
window.lock()) {
66 const auto& state = locked->get_state();
67 if (state.current_width > 0)
68 aspect =
static_cast<float>(state.current_height) /
static_cast<float>(state.current_width);
70 const glm::vec2 marker { k_marker_half_height * aspect, k_marker_half_height };
72 std::vector<Kakshya::MeshVertex> verts;
73 verts.reserve(
static_cast<size_t>(k_square_cells * k_square_cells + k_hue_segments + 6) * 6);
77 const float cells =
static_cast<float>(k_square_cells);
78 for (uint32_t i = 0; i < k_square_cells; ++i) {
79 for (uint32_t j = 0; j < k_square_cells; ++j) {
80 const float s0 =
static_cast<float>(i) / cells;
81 const float s1 =
static_cast<float>(i + 1) / cells;
82 const float v0 =
static_cast<float>(j) / cells;
83 const float v1 =
static_cast<float>(j + 1) / cells;
85 .
min = { square_rect.min.x + s0 * square_rect.width(), square_rect.min.y + v0 * square_rect.height() },
86 .max = { square_rect.min.x + s1 * square_rect.width(), square_rect.min.y + v1 * square_rect.height() },
88 append_quad(verts, cell,
96 const float segments =
static_cast<float>(k_hue_segments);
97 for (uint32_t k = 0; k < k_hue_segments; ++k) {
98 const float h0 =
static_cast<float>(k) / segments;
99 const float h1 =
static_cast<float>(k + 1) / segments;
101 .
min = { hue_rect.min.x, hue_rect.min.y + h0 * hue_rect.height() },
102 .max = { hue_rect.max.x, hue_rect.min.y + h1 * hue_rect.height() },
106 append_quad(verts, segment, low, low, high, high);
109 const float s = std::clamp(
value.y, 0.F, 1.F);
110 const float v = std::clamp(
value.z, 0.F, 1.F);
112 { square_rect.min.x + s * square_rect.width(), square_rect.min.y + v * square_rect.height() },
115 const float hue_y = hue_rect.min.y + std::clamp(
value.x, 0.F, 1.F) * hue_rect.height();
116 const glm::vec2 hue_half { hue_rect.width() * 0.5F + marker.x, marker.y * 0.5F };
117 append_marker(verts, { hue_rect.min.x + hue_rect.width() * 0.5F, hue_y }, hue_half);
126 auto color_state = std::make_shared<MappedState<glm::vec3>>();
131 layer_ptr->relate(drawn.element.id, square_id);
132 layer_ptr->relate(drawn.element.id, hue_id);
134 auto commit = [hsv_state = drawn.state, color_state,
callback =
m_on_change](glm::vec3 next) {
135 hsv_state->write(next);
137 color_state->write(rgb);
143 auto pick_square = [commit, hsv_state = drawn.state, square_fraction](glm::vec2 ndc) {
144 const glm::vec2 fraction = square_fraction(ndc);
145 commit({ hsv_state->value.x, fraction.x, fraction.y });
147 auto pick_hue = [commit, hsv_state = drawn.state, hue_rect](glm::vec2 ndc) {
148 if (hue_rect.height() <= 0.F)
150 const float hue = std::clamp((ndc.y - hue_rect.min.y) / hue_rect.height(), 0.F, 1.F);
151 commit({ hue, hsv_state->value.y, hsv_state->value.z });
155 [pick_square](uint32_t, glm::vec2 ndc) { pick_square(ndc); });
158 [pick_hue](uint32_t, glm::vec2 ndc) { pick_hue(ndc); });
162 ElementRef { layer_ptr, square_id }, color_state,
nullptr);
165 color = std::move(color_state);
Illustrative geometry functions for common Mapped use cases.
std::weak_ptr< Core::Window > window
NDC-to-value mappings, inverse to the forward placement performed by geometry functions.
std::vector< float > * out
glm::vec3 rgb_to_hsv(glm::vec3 rgb) noexcept
Convert red, green and blue to hue, saturation and value.
glm::vec3 hsv_to_rgb(glm::vec3 hsv) noexcept
Convert hue, saturation and value to red, green and blue.
std::function< glm::vec2(glm::vec2)> unit_square(AABB2D bounds, const std::function< glm::vec2()> &live_offset={}) noexcept
Unit-square coordinates of a point within bounds.
Axis-aligned bounding rectangle in a 2D coordinate space.