1#include "color_map_editor.h"
3#include <cgv/gui/key_event.h>
4#include <cgv/gui/mouse_event.h>
5#include <cgv/gui/theme_info.h>
6#include <cgv/math/ftransform.h>
8#include <cgv/utils/file.h>
9#include <cgv_gl/gl/gl.h>
10#include <cgv_g2d/msdf_font.h>
11#include <cgv_g2d/msdf_gl_font_renderer.h>
16const float color_map_editor::color_point::default_width = 12.0f;
17const float color_map_editor::color_point::default_height = 18.0f;
19const float color_map_editor::opacity_point::default_size = 12.0f;
21color_map_editor::color_map_editor() {
27 opacity_scale_exponent = 1.0f;
28 supports_opacity =
false;
29 use_interpolation =
true;
30 use_linear_filtering =
true;
31 range =
vec2(0.0f, 1.0f);
33 layout.padding = padding();
34 layout.total_height = supports_opacity ? 200 : 60;
38 mouse_is_on_overlay =
false;
39 cursor_position = { 0 };
40 show_value_label =
false;
42 cmc.color_points.set_constraint(layout.color_handles_rect);
43 cmc.color_points.callback = std::bind(&color_map_editor::handle_color_drag,
this, std::placeholders::_1);
45 cmc.opacity_points.set_constraint(layout.opacity_editor_rect);
46 cmc.opacity_points.callback = std::bind(&color_map_editor::handle_opacity_drag,
this, std::placeholders::_1);
48 color_handle_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::arrow);
49 opacity_handle_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::rectangle);
50 line_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::line);
51 polygon_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::polygon);
56 cgv::g2d::ref_msdf_font_regular(ctx, -1);
57 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
61 color_handle_renderer.destruct(ctx);
62 opacity_handle_renderer.destruct(ctx);
63 line_renderer.destruct(ctx);
64 polygon_renderer.destruct(ctx);
109 mouse_is_on_overlay =
true;
112 mouse_is_on_overlay =
false;
118 cursor_position = local_mouse_pos;
119 if(!cursor_label.empty())
124 bool request_clear_selection =
false;
128 request_clear_selection =
is_hit(local_mouse_pos);
132 if(!get_hit_point(local_mouse_pos))
133 add_point(local_mouse_pos);
137 cgv::g2d::draggable* hit_point = get_hit_point(local_mouse_pos);
139 remove_point(hit_point);
153 if(request_clear_selection) {
154 cmc.color_points.clear_selected();
155 cmc.opacity_points.clear_selected();
164 if(m.
is(layout.total_height)) {
166 size.y() = layout.total_height;
170 if(m.
is(opacity_scale_exponent)) {
171 opacity_scale_exponent = cgv::math::clamp(opacity_scale_exponent, 1.0f, 5.0f);
173 update_point_positions();
178 if(m.
is(resolution)) {
181 cmc.cm->set_resolution(resolution);
182 update_color_map(
false);
185 if(m.
is(use_interpolation)) {
188 cmc.cm->enable_interpolation(use_interpolation);
189 update_color_map(
false);
192 if(m.
is(use_linear_filtering)) {
197 gl_cm->enable_linear_filtering(use_linear_filtering);
199 update_color_map(
false);
202 for(
unsigned i = 0; i < cmc.color_points.size(); ++i) {
203 if(m.
is(cmc.color_points[i].col)) {
204 update_color_map(
true);
209 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i) {
210 if(m.
is(cmc.opacity_points[i].val[1])) {
211 cmc.opacity_points[i].update_pos(layout, opacity_scale_exponent);
212 update_color_map(
true);
217 if(m.
is(supports_opacity)) {
218 layout.total_height = supports_opacity ? 200 : 60;
219 on_set(&layout.total_height);
221 if(supports_opacity) {
222 layout.total_height = 200;
224 layout.total_height = 60;
226 cmc.cm->clear_opacity_points();
227 cmc.opacity_points.clear();
229 update_point_positions();
230 update_color_map(
false);
234 post_recreate_layout();
241 cgv::g2d::ref_msdf_font_regular(ctx, 1);
242 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
244 register_shader(
"rectangle", cgv::g2d::shaders::rectangle);
245 register_shader(
"circle", cgv::g2d::shaders::circle);
246 register_shader(
"histogram",
"heightfield1d.glpr");
247 register_shader(
"background",
"color_map_editor_bg.glpr");
251 success &= color_handle_renderer.init(ctx);
252 success &= opacity_handle_renderer.init(ctx);
253 success &= line_renderer.init(ctx);
254 success &= polygon_renderer.init(ctx);
256 init_preview_texture(ctx);
257 update_color_map(
false);
261 std::vector<rgb> bg_data = { a, b, b, a };
265 bg_tex =
cgv::render::texture(
"flt32[R,G,B]", cgv::render::TF_NEAREST, cgv::render::TF_NEAREST, cgv::render::TW_REPEAT, cgv::render::TW_REPEAT);
266 success &= bg_tex.
create(ctx, bg_dv, 0);
273 if(ensure_layout(ctx)) {
275 layout.update(container_size, supports_opacity);
277 auto& bg_prog = content_canvas.enable_shader(ctx,
"background");
278 float width_factor =
static_cast<float>(layout.opacity_editor_rect.w()) /
static_cast<float>(layout.opacity_editor_rect.h());
279 bg_style.texcoord_scaling =
vec2(5.0f * width_factor, 5.0f);
280 bg_style.apply(ctx, bg_prog);
281 content_canvas.disable_current_shader(ctx);
283 update_point_positions();
286 cmc.color_points.set_constraint(layout.color_handles_rect);
287 cmc.opacity_points.set_constraint(layout.opacity_editor_rect);
297 content_canvas.enable_shader(ctx,
"rectangle");
298 content_canvas.set_style(ctx, border_style);
299 content_canvas.draw_shape(ctx,
ivec2(layout.padding - 1) +
ivec2(0, 10), container_size - 2 * layout.padding + 2 -
ivec2(0, 10));
303 content_canvas.set_style(ctx, color_map_style);
304 preview_tex.
enable(ctx, 0);
305 content_canvas.draw_shape(ctx, layout.color_editor_rect);
309 if(supports_opacity) {
311 auto& bg_prog = content_canvas.enable_shader(ctx,
"background");
312 bg_style.apply(ctx, bg_prog);
313 bg_prog.set_uniform(ctx,
"scale_exponent", opacity_scale_exponent);
315 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
317 content_canvas.disable_current_shader(ctx);
321 auto& hist_prog = content_canvas.enable_shader(ctx,
"histogram");
322 hist_prog.set_uniform(ctx,
"max_value", hist_norm_ignore_zero ? hist_max_non_zero : hist_max);
323 hist_prog.set_uniform(ctx,
"norm_gamma", hist_norm_gamma);
324 hist_prog.set_uniform(ctx,
"sampling_type", cgv::math::clamp(
static_cast<unsigned>(histogram_type) - 1, 0u, 2u));
325 hist_style.apply(ctx, hist_prog);
328 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
330 content_canvas.disable_current_shader(ctx);
333 preview_tex.
enable(ctx, 0);
335 polygon_renderer.render(ctx, content_canvas, cgv::render::PT_TRIANGLE_STRIP, cmc.triangles, polygon_style);
338 line_renderer.render(ctx, content_canvas, cgv::render::PT_LINE_STRIP, cmc.lines, line_style);
342 content_canvas.enable_shader(ctx,
"rectangle");
343 content_canvas.set_style(ctx, border_style);
344 content_canvas.draw_shape(ctx,
345 ivec2(layout.color_editor_rect.x(), layout.color_editor_rect.y1()),
346 ivec2(container_size.
x() - 2 * layout.padding, 1)
348 content_canvas.disable_current_shader(ctx);
353 color_handle_renderer.render(ctx, content_canvas, cgv::render::PT_LINES, cmc.color_handles, color_handle_style);
356 if(supports_opacity) {
357 auto& opacity_handle_prog = opacity_handle_renderer.enable_prog(ctx);
358 opacity_handle_prog.set_attribute(ctx,
"size",
vec2(opacity_point::default_size));
359 opacity_handle_renderer.render(ctx, content_canvas, cgv::render::PT_POINTS, cmc.opacity_handles, opacity_handle_style);
362 content_canvas.disable_current_shader(ctx);
365 auto& font = cgv::g2d::ref_msdf_font_regular(ctx);
366 auto& font_renderer = cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx);
367 cgv::g2d::msdf_gl_font_renderer::text_render_info text_render_info;
369 if(show_value_label) {
370 cgv::g2d::irect rectangle = value_label_rectangle;
371 rectangle.translate(0, 5);
372 rectangle.size +=
ivec2(10, 6);
374 content_canvas.enable_shader(ctx,
"rectangle");
375 content_canvas.set_style(ctx, label_box_style);
376 content_canvas.draw_shape(ctx, rectangle);
377 content_canvas.disable_current_shader(ctx);
380 font_renderer.render(ctx, content_canvas, font, value_label, value_label_rectangle.position, text_render_info, value_label_style);
384 if(mouse_is_on_overlay && !cursor_label.empty()) {
385 vec2 position =
static_cast<vec2>(cursor_position +
ivec2(12, 6));
387 font_renderer.render(ctx, content_canvas, font, cursor_label,
vec3(position, 0.0f), text_render_info, cursor_label_style);
404 std::string height_options =
"min=";
405 height_options += supports_opacity ?
"80" :
"40";
406 height_options +=
";max=500;step=10;ticks=true";
407 add_member_control(
this,
"Height", layout.total_height,
"value_slider", height_options);
408 add_member_control(
this,
"Opacity Scale Exponent", opacity_scale_exponent,
"value_slider",
"min=1.0;max=5.0;step=0.001;ticks=true");
409 add_member_control(
this,
"Resolution", resolution,
"dropdown",
"enums='2=2,4=4,8=8,16=16,32=32,64=64,128=128,256=256,512=512,1024=1024,2048=2048';w=106",
" ");
412 if(cmc.cm && cmc.cm->has_texture_support()) {
413 add_member_control(
this,
"Linear Filtering (Texture)", use_linear_filtering,
"check");
419 add_member_control(
this,
"Type", histogram_type,
"dropdown",
"enums='None,Nearest,Linear,Smooth'");
420 add_member_control(
this,
"Ignore Zero for Normalization", hist_norm_ignore_zero,
"check");
421 add_member_control(
this,
"Gamma", hist_norm_gamma,
"value_slider",
"min=0.001;max=2;step=0.001;ticks=true");
424 add_member_control(
this,
"Border Width", hist_style.border_width,
"value_slider",
"min=0;max=10;step=0.5;ticks=true");
429 auto& points = cmc.color_points;
430 for(
unsigned i = 0; i < points.size(); ++i) {
431 std::string label_prefix =
"";
432 std::string options =
"w=48";
433 if(&points[i] == cmc.color_points.get_selected()) {
435 options +=
";label_color=" + highlight_color_hex;
438 add_view(label_prefix + std::to_string(i), points[i].val,
"", options,
" ");
445 if(supports_opacity) {
448 auto& points = cmc.opacity_points;
449 for(
unsigned i = 0; i < points.size(); ++i) {
450 std::string label_prefix =
"";
451 std::string options =
"w=48";
452 if(&points[i] == cmc.opacity_points.get_selected()) {
454 options +=
";label_color=" + highlight_color_hex;
457 add_view(label_prefix + std::to_string(i), points[i].val[0],
"", options,
" ");
466void color_map_editor::set_opacity_support(
bool flag) {
468 supports_opacity = flag;
469 set_color_map(cmc.cm);
470 on_set(&supports_opacity);
479 auto& cp = cmc.cm->ref_color_points();
481 for(
size_t i = 0; i < cp.size(); ++i) {
483 p.val = cgv::math::clamp(cp[i].first, 0.0f, 1.0f);
484 p.col = cp[i].second;
485 cmc.color_points.add(p);
488 if(supports_opacity) {
489 auto& op = cmc.cm->ref_opacity_points();
490 for(
size_t i = 0; i < op.size(); ++i) {
492 p.val.x() = cgv::math::clamp(op[i].first, 0.0f, 1.0f);
493 p.val.y() = cgv::math::clamp(op[i].second, 0.0f, 1.0f);
494 cmc.opacity_points.add(p);
498 use_interpolation = cm.is_interpolation_enabled();
499 use_linear_filtering =
true;
503 use_linear_filtering = gl_cm->is_linear_filtering_enabled();
505 update_point_positions();
506 update_color_map(
false);
512void color_map_editor::set_histogram_data(
const std::vector<unsigned> data) {
515 std::vector<float> float_data(histogram.size(), 0.0f);
517 hist_max_non_zero = 1;
518 for(
size_t i = 0; i < histogram.size(); ++i) {
519 unsigned count = histogram[i];
520 hist_max = std::max(hist_max, count);
522 hist_max_non_zero = std::max(hist_max_non_zero, count);
523 float_data[i] =
static_cast<float>(count);
527 auto& ctx = *ctx_ptr;
532 hist_tex.
create(ctx, dv, 0);
538void color_map_editor::set_selected_color(
rgb color) {
540 auto selected_point = cmc.color_points.get_selected();
542 selected_point->col = color;
543 update_color_map(
true);
549void color_map_editor::init_styles() {
550 auto& theme = cgv::gui::theme_info::instance();
551 handle_color =
rgba(theme.text(), 1.0f);
552 highlight_color =
rgba(theme.highlight(), 1.0f);
553 highlight_color_hex = theme.highlight_hex();
556 border_style.fill_color = theme.border();
557 border_style.border_width = 0.0f;
558 border_style.feather_width = 0.0f;
561 color_map_style = border_style;
562 color_map_style.use_texture =
true;
565 bg_style.use_texture =
true;
566 bg_style.feather_width = 0.0f;
569 hist_style.use_blending =
true;
570 hist_style.feather_width = 1.0f;
571 hist_style.feather_origin = 0.0f;
572 hist_style.fill_color =
rgba(
rgb(0.5f), 0.666f);
573 hist_style.border_color =
rgba(
rgb(0.0f), 0.666f);
574 hist_style.border_width = 1.0f;
577 color_handle_style.use_blending =
true;
578 color_handle_style.use_fill_color =
false;
579 color_handle_style.position_is_center =
true;
580 color_handle_style.border_color = theme.border();
581 color_handle_style.border_width = 1.5f;
582 color_handle_style.border_radius = 2.0f;
583 color_handle_style.stem_width = color_point::default_width;
584 color_handle_style.head_width = color_point::default_width;
586 label_box_style.position_is_center =
true;
587 label_box_style.use_blending =
true;
588 label_box_style.fill_color = handle_color;
589 label_box_style.border_color = theme.border();
590 label_box_style.border_width = 1.5f;
591 label_box_style.border_radius = 4.0f;
594 opacity_handle_style.use_blending =
true;
595 opacity_handle_style.use_fill_color =
false;
596 opacity_handle_style.position_is_center =
true;
597 opacity_handle_style.border_color = theme.border();
598 opacity_handle_style.border_width = 1.5f;
601 line_style.use_blending =
true;
602 line_style.use_fill_color =
false;
603 line_style.use_texture =
true;
604 line_style.use_texture_alpha =
false;
605 line_style.width = 3.0f;
607 polygon_style =
static_cast<cgv::g2d::shape2d_style
>(line_style);
608 polygon_style.use_texture_alpha =
true;
611 cursor_label_style.fill_color =
rgb(0.0f);
612 cursor_label_style.font_size = 16.0f;
614 value_label_style.fill_color = theme.group();
615 value_label_style.font_size = 12.0f;
629 std::vector<uint8_t> data(resolution * 4 * 2, 0u);
631 setup_preview_texture(ctx);
633 preview_tex.
create(ctx, tf_dv, 0);
636void color_map_editor::add_point(
const vec2& pos) {
641 if(layout.color_editor_rect.contains(test_pos)) {
644 p.position =
ivec2(
int(pos.x()), layout.color_handles_rect.y());
645 p.update_val(layout);
646 p.col = cmc.cm->interpolate_color(p.val);
647 cmc.color_points.add(p);
648 }
else if(supports_opacity && layout.opacity_editor_rect.contains(test_pos)) {
652 p.update_val(layout, opacity_scale_exponent);
653 cmc.opacity_points.add(p);
656 update_color_map(
true);
660void color_map_editor::remove_point(
const cgv::g2d::draggable* ptr) {
662 int color_point_idx = -1;
663 int opacity_point_idx = -1;
665 for(
unsigned i = 0; i < cmc.color_points.size(); ++i) {
666 if(&cmc.color_points[i] == ptr) {
672 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i) {
673 if(&cmc.opacity_points[i] == ptr) {
674 opacity_point_idx = i;
679 bool removed =
false;
681 if(color_point_idx > -1) {
682 if(cmc.color_points.size() > 1) {
683 cmc.color_points.ref_draggables().erase(cmc.color_points.ref_draggables().begin() + color_point_idx);
688 if(opacity_point_idx > -1) {
689 if(cmc.opacity_points.size() > 1) {
690 cmc.opacity_points.ref_draggables().erase(cmc.opacity_points.ref_draggables().begin() + opacity_point_idx);
696 update_color_map(
true);
699cgv::g2d::draggable* color_map_editor::get_hit_point(
const vec2& pos) {
701 cgv::g2d::draggable* hit =
nullptr;
703 for(
unsigned i = 0; i < cmc.color_points.size(); ++i) {
704 color_point& p = cmc.color_points[i];
709 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i) {
710 opacity_point& p = cmc.opacity_points[i];
718void color_map_editor::update_value_label_rectangle(
vec2 position,
const cgv::g2d::rect& parent_rectangle) {
720 value_label_rectangle.position = position;
723 auto& font = cgv::g2d::ref_msdf_font_regular(*
get_context());
724 value_label_rectangle.size = font.compute_render_size(value_label, value_label_style.font_size);
727 float padding = std::ceil(0.5f * value_label_rectangle.w()) + 4.0f;
728 float min_x = layout.color_editor_rect.x() + padding;
729 float max_x = layout.color_editor_rect.x1() - padding;
730 value_label_rectangle.position.x() = cgv::math::clamp(value_label_rectangle.position.x(), min_x, max_x);
733void color_map_editor::handle_color_drag(cgv::g2d::DragAction action) {
736 case cgv::g2d::DragAction::kDrag:
738 color_point* dragged_point = cmc.color_points.get_dragged();
740 dragged_point->update_val(layout);
741 update_color_map(
true);
743 show_value_label =
true;
744 value_label = value_to_string(dragged_point->val);
745 update_value_label_rectangle(dragged_point->position, layout.color_editor_rect);
746 value_label_rectangle.position.y() += 25.0f;
748 if(dragged_point && on_color_point_select_callback)
749 on_color_point_select_callback(dragged_point->col);
755 case cgv::g2d::DragAction::kDragEnd:
756 case cgv::g2d::DragAction::kSelect:
764void color_map_editor::handle_opacity_drag(cgv::g2d::DragAction action) {
767 case cgv::g2d::DragAction::kDrag:
769 opacity_point* dragged_point = cmc.opacity_points.get_dragged();
771 dragged_point->update_val(layout, opacity_scale_exponent);
772 update_color_map(
true);
774 show_value_label =
true;
775 std::string x_label = value_to_string(dragged_point->val.x());
777 value_label = x_label +
", " + y_label;
779 update_value_label_rectangle(dragged_point->position, layout.opacity_editor_rect);
780 value_label_rectangle.position.y() = std::min(value_label_rectangle.position.y() + 10.0f,
static_cast<float>(layout.opacity_editor_rect.y1() - 6));
786 case cgv::g2d::DragAction::kDragEnd:
787 case cgv::g2d::DragAction::kSelect:
831void color_map_editor::handle_drag_end() {
833 show_value_label =
false;
836 auto selected_point = cmc.color_points.get_selected();
838 if(on_color_point_select_callback)
839 on_color_point_select_callback(selected_point->col);
841 if(on_color_point_deselect_callback)
842 on_color_point_deselect_callback();
849std::string color_map_editor::value_to_string(
float value) {
851 float display_value = cgv::math::lerp(range.
x(), range.
y(), value);
853 float total = range.
y() - range.
x();
859 int display_value_int =
static_cast<int>(round(display_value));
860 return std::to_string(display_value_int);
864void color_map_editor::sort_points() {
867 sort_opacity_points();
870void color_map_editor::sort_color_points() {
872 auto& points = cmc.color_points;
874 if(points.size() > 1) {
875 int dragged_point_idx = -1;
876 int selected_point_idx = -1;
878 const color_point* dragged_point = points.get_dragged();
879 const color_point* selected_point = points.get_selected();
881 std::vector<std::pair<color_point, int>> sorted(points.size());
883 for(
unsigned i = 0; i < points.size(); ++i) {
884 sorted[i].first = points[i];
885 sorted[i].second = i;
887 if(dragged_point == &points[i])
888 dragged_point_idx = i;
889 if(selected_point == &points[i])
890 selected_point_idx = i;
893 std::sort(sorted.begin(), sorted.end(),
894 [](
const auto& a,
const auto& b) ->
bool {
895 return a.first.val < b.first.val;
899 int new_dragged_point_idx = -1;
900 int new_selected_point_idx = -1;
902 for(
unsigned i = 0; i < sorted.size(); ++i) {
903 points[i] = sorted[i].first;
904 if(dragged_point_idx == sorted[i].second) {
905 new_dragged_point_idx = i;
907 if(selected_point_idx == sorted[i].second) {
908 new_selected_point_idx = i;
912 points.set_dragged(new_dragged_point_idx);
913 points.set_selected(new_selected_point_idx);
917void color_map_editor::sort_opacity_points() {
919 auto& points = cmc.opacity_points;
921 if(points.size() > 1) {
922 int dragged_point_idx = -1;
923 int selected_point_idx = -1;
925 const opacity_point* dragged_point = points.get_dragged();
926 const opacity_point* selected_point = points.get_selected();
928 std::vector<std::pair<opacity_point, int>> sorted(points.size());
930 for(
unsigned i = 0; i < points.size(); ++i) {
931 sorted[i].first = points[i];
932 sorted[i].second = i;
934 if(dragged_point == &points[i])
935 dragged_point_idx = i;
936 if(selected_point == &points[i])
937 selected_point_idx = i;
940 std::sort(sorted.begin(), sorted.end(),
941 [](
const auto& a,
const auto& b) ->
bool {
942 return a.first.val.x() < b.first.val.x();
946 int new_dragged_point_idx = -1;
947 int new_selected_point_idx = -1;
949 for(
unsigned i = 0; i < sorted.size(); ++i) {
950 points[i] = sorted[i].first;
951 if(dragged_point_idx == sorted[i].second) {
952 new_dragged_point_idx = i;
954 if(selected_point_idx == sorted[i].second) {
955 new_selected_point_idx = i;
959 points.set_dragged(new_dragged_point_idx);
960 points.set_selected(new_selected_point_idx);
964void color_map_editor::update_point_positions() {
966 for(
unsigned i = 0; i < cmc.color_points.size(); ++i)
967 cmc.color_points[i].update_pos(layout);
969 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i)
970 cmc.opacity_points[i].update_pos(layout, opacity_scale_exponent);
973void color_map_editor::update_color_map(
bool is_data_change) {
976 if(!ctx_ptr || !cmc.cm)
return;
980 auto& color_points = cmc.color_points;
981 auto& opacity_points = cmc.opacity_points;
987 for(
unsigned i = 0; i < color_points.size(); ++i) {
988 const color_point& p = color_points[i];
989 cm.add_color_point(p.val, p.col);
992 if(supports_opacity) {
993 for(
unsigned i = 0; i < opacity_points.size(); ++i) {
994 const opacity_point& p = opacity_points[i];
995 cm.add_opacity_point(p.val.x(), p.val.y());
999 cm.add_opacity_point(0.0f, 1.0f);
1002 size_t size =
static_cast<size_t>(resolution);
1003 std::vector<rgba> cs_data = cm.interpolate(size);
1005 std::vector<uint8_t> data(4 * 2 * size);
1006 for(
size_t i = 0; i < size; ++i) {
1007 rgba col = cs_data[i];
1008 uint8_t r =
static_cast<uint8_t
>(255.0f * col.R());
1009 uint8_t g =
static_cast<uint8_t
>(255.0f * col.G());
1010 uint8_t b =
static_cast<uint8_t
>(255.0f * col.B());
1011 uint8_t a =
static_cast<uint8_t
>(255.0f * col.alpha());
1025 setup_preview_texture(ctx);
1027 preview_tex.
create(ctx, dv, 0);
1029 if(!supports_opacity)
1030 cm.clear_opacity_points();
1034 if(on_change_callback)
1035 on_change_callback();
1040bool color_map_editor::update_geometry() {
1043 if(!ctx_ptr || !cmc.cm)
return false;
1047 auto& color_points = cmc.color_points;
1048 auto& opacity_points = cmc.opacity_points;
1049 auto& color_handles = cmc.color_handles;
1050 auto& opacity_handles = cmc.opacity_handles;
1051 auto& lines = cmc.lines;
1052 auto& triangles = cmc.triangles;
1054 color_handles.clear();
1055 opacity_handles.clear();
1059 bool success = color_points.size() > 0 && opacity_points.size() > 0;
1062 vec2 pos_offset =
vec2(0.0f, 0.5f * color_point::default_height);
1064 for(
unsigned i = 0; i < color_points.size(); ++i) {
1065 const auto& p = color_points[i];
1066 vec2 pos = p.center();
1067 rgba col = color_points.get_selected() == &p ? highlight_color : handle_color;
1068 color_handles.add(pos - pos_offset, col);
1069 color_handles.add(pos + pos_offset, col);
1073 for(
unsigned i = 0; i < opacity_points.size(); ++i) {
1074 const auto& p = opacity_points[i];
1075 vec2 pos = p.center();
1076 rgba col = opacity_points.get_selected() == &p ? highlight_color : handle_color;
1077 opacity_handles.add(pos, col);
1080 if(opacity_points.size() > 0) {
1081 const auto& pl = opacity_points[0];
1083 vec2 tex_coord(0.0f, 0.5f);
1085 lines.add(
vec2(
float(layout.opacity_editor_rect.x()), pl.center().y()), tex_coord);
1087 triangles.add(
vec2(
float(layout.opacity_editor_rect.x()), pl.center().y()), tex_coord);
1088 triangles.add(layout.opacity_editor_rect.position, tex_coord);
1090 for(
unsigned i = 0; i < opacity_points.size(); ++i) {
1091 const auto& p = opacity_points[i];
1092 vec2 pos = p.center();
1094 tex_coord.
x() = p.val.x();
1096 lines.add(pos, tex_coord);
1098 triangles.add(pos, tex_coord);
1099 triangles.add(
vec2(pos.x(), (
float)layout.opacity_editor_rect.y()), tex_coord);
1102 const auto& pr = opacity_points[opacity_points.size() - 1];
1103 vec2 max_pos = layout.opacity_editor_rect.position +
vec2(1.0f, 0.0f) * layout.opacity_editor_rect.size;
1105 tex_coord.x() = 1.0f;
1107 lines.add(
vec2(max_pos.x(), pr.center().y()), tex_coord);
1109 triangles.add(
vec2(max_pos.x(), pr.center().y()), tex_coord);
1110 triangles.add(max_pos, tex_coord);
More advanced text processing for splitting text into lines or tokens.
bool is_hit(const ivec2 &mouse_pos) const override
Test if the mouse pointer is hovering over this overlay and returns true if this is the case.
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
virtual void on_set(void *member_ptr) override
default implementation of that calls handle_member_change and afterwards upates the member in the gui...
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
bool handle_key_event(cgv::gui::key_event &e) override
overload this method to handle key events
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 handle_theme_change(const cgv::gui::theme_info &theme) override
override in your class to handle theme changes
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
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
cgv::g2d::irect get_rectangle() const
return the current rectangle area (in screen coordinates) of the overlay taking layout into account
bool blocks_events() const
return whether this overlay blocks events, i.e. does not pass them to the next event handler
ivec2 get_viewport_size() const
return the current viewport size
void set_size(const ivec2 &size)
set the default size of the overlay before stretch gets applied
virtual void handle_theme_change(const cgv::gui::theme_info &theme) override
override in your class to handle theme changes
void set_name(const std::string &_name)
set a new parent node
the data view gives access to a data array of one, two, three or four dimensions.
unsigned char get_modifiers() const
return the active modifiers as values from EventModifier combined with a logical or-operation
class to represent all possible keyboard events with the EID_KEY
unsigned short get_key() const
return the key being a capital letter, digit or a value from the Keys enum
KeyAction get_action() const
return the key event action
class to represent all possible mouse events with the EID_MOUSE
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
cgv::base::base_ptr add_decorator(const std::string &label, const std::string &decorator_type, const std::string &options="", const std::string &align="\n")
add a newly created decorator to the group
void align(const std::string &_align)
send pure alignment information
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.
virtual void update_member(void *member_ptr)
call this to update all views and controls of a member
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
void end_tree_node(const T &value)
template specialization that allows to specify value reference plus node_instance by using the result...
virtual void post_recreate_gui()
delayed recreation of gui
data::ref_ptr< view< T > > add_view(const std::string &label, const T &value, const std::string &gui_type="", const std::string &options="", const std::string &align="\n")
use this to add a new view to the gui with a given value type, gui type and init options
static cgv::type::uint32_type size()
return number of elements
base class for all drawables, which is independent of the used rendering API.
context * get_context() const
access the current context. The context will be available latestly in the init method but not in the ...
virtual bool is_created() const
return whether component has been created
the texture class encapsulates all functionality independent of the rendering api.
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.
bool disable(const context &ctx)
disable texture and restore state from before last enable call
bool enable(const context &ctx, int tex_unit=-1)
enable this texture in the given texture unit, -1 corresponds to the current unit.
bool destruct(const context &ctx)
destruct the texture and free texture memory and handle
bool is(const void *ptr) const
Test if the stored pointer points to the given pointer address.
@ CF_RGBA
color format with components R, G and B
@ CF_R
undefinded format with no component
@ CF_RGB
color format with two components R and G
@ KA_PRESS
key press action
@ KA_RELEASE
key release action
@ MB_LEFT_BUTTON
left button
@ KEY_Left_Ctrl
left ctrl key
@ KEY_Left_Alt
left alt key
@ MA_PRESS
mouse button pressed
@ MA_LEAVE
mouse leave window action
@ MA_MOVE
mouse pointer moved
@ MA_ENTER
mouse enter window action
@ MA_DRAG
mouse drag action
@ TA_BOTTOM
center of bottom edge of text bounds
TextureFilter
different texture filter
@ TI_FLT32
floating point type stored in 16 bits
@ TI_UINT8
signed integer stored in 64 bits
DummyEnum
some enum to mark an integral parameter to be of enum type
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
cgv::media::color< float, cgv::media::RGB, cgv::media::OPACITY > rgba
declare rgba color type with 32 bit components
cgv::media::color< float, cgv::media::RGB > rgb
declare rgb color type with 32 bit components
cgv::math::fvec< int32_t, 2 > ivec2
declare type of 2d 32 bit integer vectors
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
cgv::math::fvec< float, 3 > vec3
declare type of 3d single precision floating point vectors