cgv
Loading...
Searching...
No Matches
color_selector.cxx
1#include "color_selector.h"
2
3#include <cgv/gui/mouse_event.h>
4#include <cgv/gui/theme_info.h>
5#include <cgv_g2d/msdf_gl_font_renderer.h>
6#include <cgv_gl/gl/gl.h>
7
8namespace cgv {
9namespace app {
10
11color_selector::color_selector() {
12
13 set_name("Color Selector");
14 blocks_events(true);
15
16 layout.padding = padding();
17
18 set_size(ivec2(layout.size));
19
20 selector_handles.callback = std::bind(&color_selector::handle_selector_drag, this, std::placeholders::_1);
21 selector_handles.set_use_individual_constraints(true);
22}
23
25
26 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
27
29
30 color_tex.destruct(ctx);
31 hue_tex.destruct(ctx);
32 text_geometry.destruct(ctx);
33}
34
36
38 if (e.get_action() == cgv::gui::MA_PRESS) {
39 int hit_index = -1;
40 cgv::g2d::irect hit_rect;
41
42 if(layout.color_rect.contains(local_mouse_pos)) {
43 hit_index = 0;
44 hit_rect = layout.color_rect;
45 }
46
47 if(layout.hue_rect.contains(local_mouse_pos)) {
48 hit_index = 1;
49 hit_rect = layout.hue_rect;
50 }
51
52 if(layout.opacity_rect.contains(local_mouse_pos)) {
53 hit_index = 2;
54 hit_rect = layout.opacity_rect;
55 }
56
57 if(hit_index > -1 && hit_index < 4) {
58 vec2 hit_rect_realtive_pos = static_cast<vec2>(local_mouse_pos - hit_rect.position);
59 vec2 val = hit_rect_realtive_pos / static_cast<vec2>(hit_rect.size);
60 if(hit_index > 0)
61 val.x() = 0.0f;
62 selector_handles[hit_index].val = val;
63 selector_handles[hit_index].update_pos();
64
65 update_color();
66
67 if(hit_index == 1)
68 update_color_texture();
69
70 post_damage();
71 }
72 }
73 }
74
75 if(selector_handles.handle(e, get_viewport_size(), get_rectangle()))
76 return true;
77
78 return false;
79}
80
82
83 if(m.is(rgb_color))
84 set_rgb_color(rgb_color);
85
86 if(m.is(rgba_color))
87 set_rgba_color(rgba_color);
88
89 if(m.is(layout.size))
90 set_size(ivec2(layout.size));
91}
92
94
95 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
96
97 register_shader("rectangle", cgv::g2d::shaders::rectangle);
98 register_shader("circle", cgv::g2d::shaders::circle);
99 register_shader("grid", cgv::g2d::shaders::grid);
100
101 bool success = canvas_overlay::init(ctx);
102
103 success &= text_geometry.init(ctx);
104
105 texts = { "R", "0", "G", "0", "B", "0", "A", "0" };
106 if(success) {
107 text_geometry.set_text_array(ctx, texts);
108
109 for(size_t i = 0; i < 4; ++i) {
110 text_geometry.alignments.push_back(cgv::render::TA_LEFT);
111 text_geometry.alignments.push_back(cgv::render::TA_RIGHT);
112 }
113
114 text_geometry.positions = std::vector<vec3>(8, { 0.0f });
115 }
116
117 init_textures(ctx);
118
119 // saturation and value handle
121 sh.size = vec2(16.0f);
122 selector_handles.add(sh);
123
124 // hue handle
125 sh.is_rectangular = true;
126 sh.size = vec2(20.0f, 10.0f);
127 sh.position_is_center = false;
128 sh.constraint_reference = cgv::g2d::draggable::CR_MIN_POINT;
129 selector_handles.add(sh);
130
131 // opacity handle
132 selector_handles.add(sh);
133
134 // set constraints
135 selector_handles[0].set_constraint(&layout.color_rect);
136 selector_handles[1].set_constraint(&layout.hue_constraint);
137 selector_handles[2].set_constraint(&layout.opacity_constraint);
138
139 if(has_opacity)
140 set_color(rgba(0.0f, 0.0f, 0.0f, 1.0f), true, true);
141 else
142 set_color(rgb(0.0f), false, true);
143
144 return success;
145}
146
148
149 if(ensure_layout(ctx)) {
151
152 for(size_t i = 0; i < 3; ++i)
153 selector_handles[i].update_pos();
154
155 int w = layout.opacity_rect.w();
156 int h = layout.opacity_rect.h();
157 opacity_bg_style.texcoord_scaling = vec2(1.0f, static_cast<float>(h) / static_cast<float>(w));
158
159 ivec2 text_position = ivec2(layout.preview_rect.b().x() + 10, layout.preview_rect.center().y());
160 for(unsigned i = 0; i < texts.size(); ++i) {
161 //texts.set_position(i, text_position);
162 text_geometry.positions[i] = vec3(text_position, 0.0f);
163 text_position.x() += i & 1 ? 15 : 40;
164 }
165 }
166}
167
168void color_selector::draw_content(cgv::render::context& ctx) {
169
170 begin_content(ctx);
171
172 // draw inner border
173 content_canvas.enable_shader(ctx, "rectangle");
174 content_canvas.set_style(ctx, border_style);
175
176 auto& theme = cgv::gui::theme_info::instance();
177 rgba border_color = rgba(theme.border(), 1.0f);
178 rgba text_background_color = rgba(theme.text_background(), 1.0f);
179 content_canvas.draw_shape(ctx, layout.border_rect, border_color);
180 content_canvas.draw_shape(ctx, layout.preview_rect, rgb_color);
181
182 cgv::g2d::irect text_bg = layout.preview_rect;
183 text_bg.size.x() = 48;
184 int n_labels = has_opacity ? 4 : 3;
185 for(size_t i = 0; i < n_labels; ++i) {
186 text_bg.position.x() = static_cast<int>(text_geometry.positions[2 * i].x() - 4.0f);
187 content_canvas.draw_shape(ctx, text_bg, text_background_color);
188 }
189
190 content_canvas.set_style(ctx, color_texture_style);
191 color_tex.enable(ctx, 0);
192 content_canvas.draw_shape(ctx, layout.color_rect);
193 color_tex.disable(ctx);
194
195 content_canvas.set_style(ctx, hue_texture_style);
196 hue_tex.enable(ctx, 0);
197 content_canvas.draw_shape(ctx, layout.hue_rect);
198 hue_tex.disable(ctx);
199
200 if(has_opacity) {
201 content_canvas.enable_shader(ctx, "grid");
202 content_canvas.set_style(ctx, opacity_bg_style);
203 content_canvas.draw_shape(ctx, layout.opacity_rect);
204 }
205
206 glEnable(GL_SCISSOR_TEST);
207 glScissor(layout.color_rect.x(), layout.color_rect.y(), layout.color_rect.w(), layout.color_rect.h());
208
209 auto& sh = selector_handles;
210 content_canvas.enable_shader(ctx, "circle");
211 content_canvas.set_style(ctx, color_handle_style);
212 glScissor(layout.color_rect.x(), layout.color_rect.y(), layout.color_rect.w(), layout.color_rect.h());
213 content_canvas.draw_shape(ctx, sh[0].position + 0.5f, sh[0].size);
214
215 content_canvas.enable_shader(ctx, "rectangle");
216 content_canvas.set_style(ctx, hue_handle_style);
217 glScissor(layout.hue_rect.x(), layout.hue_rect.y(), layout.hue_rect.w(), layout.hue_rect.h());
218 content_canvas.draw_shape(ctx, sh[1]);
219
220 if(has_opacity) {
221 glScissor(layout.opacity_rect.x(), layout.opacity_rect.y(), layout.opacity_rect.w(), layout.opacity_rect.h());
222
223 const auto& r = layout.opacity_rect;
224 content_canvas.enable_shader(ctx, "rectangle");
225 opacity_color_style.fill_color = rgba(rgb_color, 1.0f);
226 opacity_color_style.feather_width = static_cast<float>(r.h());
227 content_canvas.set_style(ctx, opacity_color_style);
228 content_canvas.draw_shape(ctx, ivec2(r.x(), r.y1() - 1), ivec2(r.w(), 1));
229
230 content_canvas.set_style(ctx, hue_handle_style);
231 content_canvas.draw_shape(ctx, sh[2]);
232 }
233
234 content_canvas.disable_current_shader(ctx);
235
236 glDisable(GL_SCISSOR_TEST);
237
238 //cgv::g2d::ref_msdf_gl_canvas_font_renderer(ctx).render(ctx, content_canvas, texts, text_style, 0, 2 * n_labels);
239 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx).render(ctx, content_canvas, text_geometry, text_style, 0, 2 * n_labels);
240
241 end_content(ctx);
242}
243
245
246 if(begin_tree_node("Settings", layout, false)) {
247 align("\a");
248 add_member_control(this, "Size", layout.size, "value_slider", "min=120;max=1000;step=1;ticks=true");
249 align("\b");
250 end_tree_node(layout);
251 }
252
253 if(has_opacity)
254 add_member_control(this, "Color", rgba_color);
255 else
256 add_member_control(this, "Color", rgb_color);
257}
258
259void color_selector::set_rgb_color(rgb color) {
260 set_color(rgba(color, 1.0f), false);
261}
262
263void color_selector::set_rgba_color(rgba color) {
264 set_color(color, true);
265}
266
267void color_selector::update_layout(const ivec2& parent_size) {
268
269 auto& l = layout;
270 const int slider_width = 20;
271
272 l.border_rect.position = ivec2(l.padding);
273 l.border_rect.size = ivec2(parent_size - 2 * l.padding);
274 l.border_rect.position.y() += 23;
275 l.border_rect.size.y() -= 23;
276
277 cgv::g2d::irect content_rect = l.border_rect;
278 content_rect.translate(1, 1);
279 content_rect.size -= 2;
280
281 int mult = has_opacity ? 2 : 1;
282
283 l.hue_rect.position = ivec2(content_rect.x1() - mult* slider_width - (mult-1), content_rect.y());
284 l.hue_rect.size = ivec2(slider_width, content_rect.h());
285
286 if(has_opacity) {
287 l.opacity_rect = l.hue_rect;
288 l.opacity_rect.translate(slider_width + 1, 0);
289 }
290
291 l.color_rect = content_rect;
292 l.color_rect.w() -= 21 * mult;
293
294 l.preview_rect.position = ivec2(l.padding);
295 l.preview_rect.size = ivec2(20, 20);
296
297 l.hue_constraint = l.hue_rect;
298 l.hue_constraint.translate(0, -5);
299 l.hue_constraint.size.x() = 0;
300
301 l.opacity_constraint = l.opacity_rect;
302 l.opacity_constraint.translate(0, -5);
303 l.opacity_constraint.size.x() = 0;
304
305}
306
307void color_selector::init_styles() {
308 auto& theme = cgv::gui::theme_info::instance();
309
310 // configure style for the border rectangles
311 border_style.border_width = 0.0f;
312 border_style.use_fill_color = false;
313 border_style.feather_width = 0.0f;
314
315 opacity_bg_style.feather_width = 0.0f;
316 opacity_bg_style.fill_color = rgba(rgb(0.75f), 1.0f);
317 opacity_bg_style.border_color = rgba(rgb(0.9f), 1.0f);
318 opacity_bg_style.pattern = cgv::g2d::grid2d_style::GP_CHECKER;
319 opacity_bg_style.scale = 0.5f;
320
321 opacity_color_style.use_blending = true;
322 opacity_color_style.feather_origin = 1.0f;
323
324 // configure style for the color and hue texture rectangles
325 color_texture_style = border_style;
326 color_texture_style.use_texture = true;
327
328 hue_texture_style = color_texture_style;
329 color_texture_style.texcoord_scaling = vec2(0.5f);
330 color_texture_style.texcoord_offset = vec2(0.25f);
331
332 // configure style for color handle
333 color_handle_style.use_blending = true;
334 color_handle_style.use_fill_color = true;
335 color_handle_style.position_is_center = true;
336 color_handle_style.border_color = rgba(rgb(1.0f), 0.75f);
337 color_handle_style.border_width = 1.0f;
338 color_handle_style.fill_color = rgba(rgb(0.0f), 1.0f);
339 color_handle_style.ring_width = 4.0f;
340
341 // configure style for hue handle
342 hue_handle_style = color_handle_style;
343 hue_handle_style.position_is_center = false;
344
345 // configure text style
346 text_style.fill_color = theme.text();
347 text_style.font_size = 14.0f;
348}
349
350void color_selector::init_textures(cgv::render::context& ctx) {
351
352 std::vector<uint8_t> data(3*4, 0u);
353
354 data[6] = 255u;
355 data[7] = 255u;
356 data[8] = 255u;
357 data[9] = 255u;
358
359 color_tex.destruct(ctx);
361 color_tex = cgv::render::texture("uint8[R,G,B]", cgv::render::TF_LINEAR, cgv::render::TF_LINEAR);
362 color_tex.create(ctx, color_dv, 0);
363
364 std::vector<uint8_t> hue_data(2*3*256);
365
366 for(size_t i = 0; i < 256; ++i) {
367 float hue = static_cast<float>(i) / 255.0f;
368 rgb color = cgv::media::color<float, cgv::media::HLS>(hue, 0.5f, 1.0f);
369
370 uint8_t col8[3];
371 col8[0] = static_cast<uint8_t>(round(color.R() * 255.0f));
372 col8[1] = static_cast<uint8_t>(round(color.G() * 255.0f));
373 col8[2] = static_cast<uint8_t>(round(color.B() * 255.0f));
374
375 hue_data[6 * i + 0] = col8[0];
376 hue_data[6 * i + 1] = col8[1];
377 hue_data[6 * i + 2] = col8[2];
378 hue_data[6 * i + 3] = col8[0];
379 hue_data[6 * i + 4] = col8[1];
380 hue_data[6 * i + 5] = col8[2];
381 }
382
383 hue_tex.destruct(ctx);
385 hue_tex = cgv::render::texture("uint8[R,G,B]", cgv::render::TF_LINEAR, cgv::render::TF_LINEAR);
386 hue_tex.create(ctx, hue_dv, 0);
387}
388
389void color_selector::update_color_texture() {
390
391 if(!color_tex.is_created())
392 return;
393
394 std::vector<uint8_t> data(3 * 4, 0u);
395 data[6] = 255u;
396 data[7] = 255u;
397 data[8] = 255u;
398
399 const auto& hp = selector_handles[1];
400 rgb color = cgv::media::color<float, cgv::media::HLS>(hp.val.y(), 0.5f, 1.0f);
401
402 data[9] = static_cast<uint8_t>(round(color.R() * 255.0f));
403 data[10] = static_cast<uint8_t>(round(color.G() * 255.0f));
404 data[11] = static_cast<uint8_t>(round(color.B() * 255.0f));
405
407
408 if(auto* ctx_ptr = get_context())
409 color_tex.replace(*ctx_ptr, 0, 0, color_dv);
410}
411
412void color_selector::update_color() {
413
414 const auto& cp = selector_handles[0];
415 const auto& hp = selector_handles[1];
416 const auto& op = selector_handles[2];
417 rgb_color = cgv::media::color<float, cgv::media::HLS>(hp.val.y(), 0.5f, 1.0f);
418
419 float s = cp.val.x(); // saturation
420 float v = cp.val.y(); // value
421
422 rgb_color = v * rgb_color;
423 rgb_color = (1.0f - s)*rgb(v) + s * rgb_color;
424
425 rgba_color = rgba(rgb_color, op.val.y());
426
427 update_texts();
428
429 if(has_opacity) {
430 if(on_change_rgba_callback)
431 on_change_rgba_callback(rgba_color);
432 } else {
433 if(on_change_rgb_callback)
434 on_change_rgb_callback(rgb_color);
435 }
436
437 update_member(&rgb_color);
438}
439
440void color_selector::update_texts() {
441
442 ivec4 components;
443 components[0] = static_cast<int>(round(rgba_color.R() * 255.0f));
444 components[1] = static_cast<int>(round(rgba_color.G() * 255.0f));
445 components[2] = static_cast<int>(round(rgba_color.B() * 255.0f));
446 components[3] = static_cast<int>(round(rgba_color.alpha() * 255.0f));
447
448 components = cgv::math::clamp(components, 0, 255);
449
450 texts[1] = std::to_string(components[0]);
451 texts[3] = std::to_string(components[1]);
452 texts[5] = std::to_string(components[2]);
453 texts[7] = std::to_string(components[3]);
454
455 if(auto* ctx_ptr = get_context())
456 text_geometry.set_text_array(*ctx_ptr, texts);
457}
458
459void color_selector::handle_selector_drag(cgv::g2d::DragAction action) {
460
461 if(action == cgv::g2d::DragAction::kDrag) {
462 auto* p = selector_handles.get_dragged();
463 p->update_val();
464
465 update_color();
466 if(p == &selector_handles[1])
467 update_color_texture();
468
469 post_damage();
470 }
471}
472
473void color_selector::set_color(rgba color, bool opacity, bool init) {
474
475 this->rgb_color.R() = color.R();
476 this->rgb_color.G() = color.G();
477 this->rgb_color.B() = color.B();
478 this->rgba_color = color;
479
480 float h = color.H();
481 float v = v = color.S() * std::min(color.L(), 1.0f - color.L()) + color.L();
482 float s = v ? 2.0f - 2.0f * color.L() / v : 0.0f;
483
484 selector_handles[0].val = vec2(s, v);
485 selector_handles[1].val.y() = h;
486 selector_handles[2].val.y() = color.alpha();
487
488 selector_handles[0].update_pos();
489 selector_handles[1].update_pos();
490 selector_handles[2].update_pos();
491
492 if(has_opacity != opacity) {
493 // need to recreate the layout and gui in case the opacity usage changed
494 post_recreate_layout();
496 has_opacity = opacity;
497 }
498
499 update_color_texture();
500 update_texts();
501
502 if(!init && auto_show)
503 set_visibility(true);
504
505 post_damage();
506}
507
508}
509}
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
void handle_member_change(const cgv::utils::pointer_test &m) override
implement to handle member changes
void create_gui_impl() override
virtual method to implement the derived class gui creation
bool handle_mouse_event(cgv::gui::mouse_event &e, cgv::ivec2 local_mouse_pos) override
overload this method to handle mouse events; local_mouse_pos is the mouse position in the local coord...
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void init_frame(cgv::render::context &ctx) override
this method is called in one pass over all drawables before the draw method
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
cgv::g2d::irect get_rectangle() const
return the current rectangle area (in screen coordinates) of the overlay taking layout into account
Definition overlay.h:139
void set_visibility(bool visible)
set the visibility of the overlay
Definition overlay.cxx:113
void update_layout()
update the layout of the overlay container
Definition overlay.cxx:215
bool blocks_events() const
return whether this overlay blocks events, i.e. does not pass them to the next event handler
Definition overlay.h:127
ivec2 get_viewport_size() const
return the current viewport size
Definition overlay.h:133
void set_size(const ivec2 &size)
set the default size of the overlay before stretch gets applied
Definition overlay.cxx:108
void set_name(const std::string &_name)
set a new parent node
Definition named.cxx:13
A data_format describes a multidimensional data block of data entries.
Definition data_format.h:17
the data view gives access to a data array of one, two, three or four dimensions.
Definition data_view.h:153
class to represent all possible mouse events with the EID_MOUSE
Definition mouse_event.h:33
MouseAction get_action() const
return the mouse action
unsigned char get_button_state() const
return the button state as values from MouseButton combined with a logical or-operation
void align(const std::string &_align)
send pure alignment information
Definition provider.cxx:36
bool begin_tree_node(const std::string &label, const T &value, bool initial_visibility=false, const std::string &options="", gui_group_ptr ggp=gui_group_ptr())
Begin a sub tree of a tree structured gui.
Definition provider.h:212
virtual void update_member(void *member_ptr)
call this to update all views and controls of a member
Definition provider.cxx:72
data::ref_ptr< control< T > > add_member_control(cgv::base::base *base_ptr, const std::string &label, T &value, const std::string &gui_type="", const std::string &options="", const std::string &align="\n")
add control with callback to cgv::base::on_set method on cgv::gui::control::value_change
Definition provider.h:137
void end_tree_node(const T &value)
template specialization that allows to specify value reference plus node_instance by using the result...
Definition provider.h:222
virtual void post_recreate_gui()
delayed recreation of gui
Definition provider.cxx:509
T & x()
first element
Definition fvec.h:155
base class for all drawables, which is independent of the used rendering API.
Definition context.h:621
context * get_context() const
access the current context. The context will be available latestly in the init method but not in the ...
Definition drawable.cxx:37
virtual bool is_created() const
return whether component has been created
Definition context.cxx:2046
the texture class encapsulates all functionality independent of the rendering api.
Definition texture.h:15
bool create(const context &ctx, TextureType _tt=TT_UNDEF, unsigned width=-1, unsigned height=-1, unsigned depth=-1)
create the texture of dimension and resolution specified in the data format base class.
Definition texture.cxx:208
bool disable(const context &ctx)
disable texture and restore state from before last enable call
Definition texture.cxx:756
bool enable(const context &ctx, int tex_unit=-1)
enable this texture in the given texture unit, -1 corresponds to the current unit.
Definition texture.cxx:745
bool destruct(const context &ctx)
destruct the texture and free texture memory and handle
Definition texture.cxx:730
bool replace(const context &ctx, int x, const cgv::data::const_data_view &data, int level=-1, const std::vector< cgv::data::data_view > *palettes=0)
replace a block within a 1d texture with the given data.
Definition texture.cxx:621
bool is(const void *ptr) const
Test if the stored pointer points to the given pointer address.
@ CF_RGB
color format with two components R and G
@ MB_LEFT_BUTTON
left button
Definition mouse_event.h:26
@ MA_PRESS
mouse button pressed
Definition mouse_event.h:13
@ TA_RIGHT
center of right edge of text bounds
Definition context.h:276
@ TA_LEFT
center of left edge of text bounds
Definition context.h:275
@ TI_UINT8
signed integer stored in 64 bits
Definition type_id.h:23
the cgv namespace
Definition print.h:11
cgv::media::color< float, cgv::media::RGB, cgv::media::OPACITY > rgba
declare rgba color type with 32 bit components
Definition color.h:855
cgv::math::fvec< int32_t, 4 > ivec4
declare type of 4d 32 bit integer vectors
Definition fvec.h:698
cgv::media::color< float, cgv::media::RGB > rgb
declare rgb color type with 32 bit components
Definition color.h:853
cgv::math::fvec< int32_t, 2 > ivec2
declare type of 2d 32 bit integer vectors
Definition fvec.h:694
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
Definition fvec.h:667
cgv::math::fvec< float, 3 > vec3
declare type of 3d single precision floating point vectors
Definition fvec.h:669