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);
73 switch(e.get_action()) {
107 bool capture_event =
false;
108 switch(e.get_action()) {
110 mouse_is_on_overlay =
true;
113 mouse_is_on_overlay =
false;
117 capture_event =
true;
120 cursor_position = local_mouse_pos;
121 if(!cursor_label.empty())
125 bool request_clear_selection =
false;
128 request_clear_selection =
is_hit_local(local_mouse_pos);
130 switch(e.get_modifiers()) {
132 if(!get_hit_point(local_mouse_pos)) {
133 add_point(local_mouse_pos);
134 request_clear_selection =
false;
139 cgv::g2d::draggable* hit_point = get_hit_point(local_mouse_pos);
141 remove_point(hit_point);
147 capture_event =
true;
156 if(request_clear_selection) {
157 cmc.color_points.clear_selected();
158 cmc.opacity_points.clear_selected();
168 if(m.
is(layout.total_height)) {
170 size.y() = layout.total_height;
174 if(m.
is(opacity_scale_exponent)) {
175 opacity_scale_exponent = cgv::math::clamp(opacity_scale_exponent, 1.0f, 5.0f);
177 update_point_positions();
182 if(m.
is(resolution)) {
185 cmc.cm->set_resolution(resolution);
186 update_color_map(
false);
189 if(m.
is(use_interpolation)) {
192 cmc.cm->enable_interpolation(use_interpolation);
193 update_color_map(
false);
196 if(m.
is(use_linear_filtering)) {
201 gl_cm->enable_linear_filtering(use_linear_filtering);
203 update_color_map(
false);
206 for(
unsigned i = 0; i < cmc.color_points.size(); ++i) {
207 if(m.
is(cmc.color_points[i].col)) {
208 update_color_map(
true);
213 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i) {
214 if(m.
is(cmc.opacity_points[i].val[1])) {
215 cmc.opacity_points[i].update_pos(layout, opacity_scale_exponent);
216 update_color_map(
true);
221 if(m.
is(supports_opacity)) {
222 layout.total_height = supports_opacity ? 200 : 60;
223 on_set(&layout.total_height);
225 if(supports_opacity) {
226 layout.total_height = 200;
228 layout.total_height = 60;
230 cmc.cm->clear_opacity_points();
231 cmc.opacity_points.clear();
233 update_point_positions();
234 update_color_map(
false);
238 post_recreate_layout();
245 cgv::g2d::ref_msdf_font_regular(ctx, 1);
246 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
248 register_shader(
"rectangle", cgv::g2d::shaders::rectangle);
249 register_shader(
"circle", cgv::g2d::shaders::circle);
250 register_shader(
"histogram",
"heightfield1d.glpr");
251 register_shader(
"background",
"color_map_editor_bg.glpr");
255 success &= color_handle_renderer.init(ctx);
256 success &= opacity_handle_renderer.init(ctx);
257 success &= line_renderer.init(ctx);
258 success &= polygon_renderer.init(ctx);
260 init_preview_texture(ctx);
261 update_color_map(
false);
265 std::vector<rgb> bg_data = { a, b, b, a };
269 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);
270 success &= bg_tex.
create(ctx, bg_dv, 0);
277 if(ensure_layout(ctx)) {
279 layout.update(container_size, supports_opacity);
281 auto& bg_prog = content_canvas.enable_shader(ctx,
"background");
282 float width_factor =
static_cast<float>(layout.opacity_editor_rect.w()) /
static_cast<float>(layout.opacity_editor_rect.h());
283 bg_style.texcoord_scaling =
vec2(5.0f * width_factor, 5.0f);
284 bg_style.apply(ctx, bg_prog);
285 content_canvas.disable_current_shader(ctx);
287 update_point_positions();
290 cmc.color_points.set_constraint(layout.color_handles_rect);
291 cmc.opacity_points.set_constraint(layout.opacity_editor_rect);
301 content_canvas.enable_shader(ctx,
"rectangle");
302 content_canvas.set_style(ctx, border_style);
303 content_canvas.draw_shape(ctx,
ivec2(layout.padding - 1) +
ivec2(0, 10), container_size - 2 * layout.padding + 2 -
ivec2(0, 10));
307 content_canvas.set_style(ctx, color_map_style);
308 preview_tex.
enable(ctx, 0);
309 content_canvas.draw_shape(ctx, layout.color_editor_rect);
313 if(supports_opacity) {
315 auto& bg_prog = content_canvas.enable_shader(ctx,
"background");
316 bg_style.apply(ctx, bg_prog);
317 bg_prog.set_uniform(ctx,
"scale_exponent", opacity_scale_exponent);
319 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
321 content_canvas.disable_current_shader(ctx);
325 auto& hist_prog = content_canvas.enable_shader(ctx,
"histogram");
326 hist_prog.set_uniform(ctx,
"max_value", hist_norm_ignore_zero ? hist_max_non_zero : hist_max);
327 hist_prog.set_uniform(ctx,
"norm_gamma", hist_norm_gamma);
328 hist_prog.set_uniform(ctx,
"sampling_type", cgv::math::clamp(
static_cast<unsigned>(histogram_type) - 1, 0u, 2u));
329 hist_style.apply(ctx, hist_prog);
332 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
334 content_canvas.disable_current_shader(ctx);
337 preview_tex.
enable(ctx, 0);
339 polygon_renderer.render(ctx, content_canvas, cgv::render::PT_TRIANGLE_STRIP, cmc.triangles, polygon_style);
342 line_renderer.render(ctx, content_canvas, cgv::render::PT_LINE_STRIP, cmc.lines, line_style);
346 content_canvas.enable_shader(ctx,
"rectangle");
347 content_canvas.set_style(ctx, border_style);
348 content_canvas.draw_shape(ctx,
349 ivec2(layout.color_editor_rect.x(), layout.color_editor_rect.y1()),
350 ivec2(container_size.
x() - 2 * layout.padding, 1)
352 content_canvas.disable_current_shader(ctx);
357 color_handle_renderer.render(ctx, content_canvas, cgv::render::PT_LINES, cmc.color_handles, color_handle_style);
360 if(supports_opacity) {
361 auto& opacity_handle_prog = opacity_handle_renderer.enable_prog(ctx);
362 opacity_handle_prog.set_attribute(ctx,
"size",
vec2(opacity_point::default_size));
363 opacity_handle_renderer.render(ctx, content_canvas, cgv::render::PT_POINTS, cmc.opacity_handles, opacity_handle_style);
366 content_canvas.disable_current_shader(ctx);
369 auto& font = cgv::g2d::ref_msdf_font_regular(ctx);
370 auto& font_renderer = cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx);
371 cgv::g2d::msdf_gl_font_renderer::text_render_info text_render_info;
373 if(show_value_label) {
374 cgv::g2d::irect rectangle = value_label_rectangle;
375 rectangle.translate(0, 5);
376 rectangle.size +=
ivec2(10, 6);
378 content_canvas.enable_shader(ctx,
"rectangle");
379 content_canvas.set_style(ctx, label_box_style);
380 content_canvas.draw_shape(ctx, rectangle);
381 content_canvas.disable_current_shader(ctx);
384 font_renderer.render(ctx, content_canvas, font, value_label, value_label_rectangle.position, text_render_info, value_label_style);
388 if(mouse_is_on_overlay && !cursor_label.empty()) {
389 vec2 position =
static_cast<vec2>(cursor_position +
ivec2(12, 6));
391 font_renderer.render(ctx, content_canvas, font, cursor_label,
vec3(position, 0.0f), text_render_info, cursor_label_style);
408 std::string height_options =
"min=";
409 height_options += supports_opacity ?
"80" :
"40";
410 height_options +=
";max=500;step=10;ticks=true";
411 add_member_control(
this,
"Height", layout.total_height,
"value_slider", height_options);
412 add_member_control(
this,
"Opacity Scale Exponent", opacity_scale_exponent,
"value_slider",
"min=1.0;max=5.0;step=0.001;ticks=true");
413 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",
" ");
416 if(cmc.cm && cmc.cm->has_texture_support()) {
417 add_member_control(
this,
"Linear Filtering (Texture)", use_linear_filtering,
"check");
423 add_member_control(
this,
"Type", histogram_type,
"dropdown",
"enums='None,Nearest,Linear,Smooth'");
424 add_member_control(
this,
"Ignore Zero for Normalization", hist_norm_ignore_zero,
"check");
425 add_member_control(
this,
"Gamma", hist_norm_gamma,
"value_slider",
"min=0.001;max=2;step=0.001;ticks=true");
428 add_member_control(
this,
"Border Width", hist_style.border_width,
"value_slider",
"min=0;max=10;step=0.5;ticks=true");
433 auto& points = cmc.color_points;
434 for(
unsigned i = 0; i < points.size(); ++i) {
435 std::string label_prefix =
"";
436 std::string options =
"w=48";
437 if(&points[i] == cmc.color_points.get_selected()) {
439 options +=
";label_color=" + highlight_color_hex;
442 add_view(label_prefix + std::to_string(i), points[i].val,
"", options,
" ");
449 if(supports_opacity) {
452 auto& points = cmc.opacity_points;
453 for(
unsigned i = 0; i < points.size(); ++i) {
454 std::string label_prefix =
"";
455 std::string options =
"w=48";
456 if(&points[i] == cmc.opacity_points.get_selected()) {
458 options +=
";label_color=" + highlight_color_hex;
461 add_view(label_prefix + std::to_string(i), points[i].val[0],
"", options,
" ");
470void color_map_editor::set_opacity_support(
bool flag) {
472 supports_opacity = flag;
473 set_color_map(cmc.cm);
474 on_set(&supports_opacity);
483 auto& cp = cmc.cm->ref_color_points();
485 for(
size_t i = 0; i < cp.size(); ++i) {
487 p.val = cgv::math::clamp(cp[i].first, 0.0f, 1.0f);
488 p.col = cp[i].second;
489 cmc.color_points.add(p);
492 if(supports_opacity) {
493 auto& op = cmc.cm->ref_opacity_points();
494 for(
size_t i = 0; i < op.size(); ++i) {
496 p.val.x() = cgv::math::clamp(op[i].first, 0.0f, 1.0f);
497 p.val.y() = cgv::math::clamp(op[i].second, 0.0f, 1.0f);
498 cmc.opacity_points.add(p);
502 use_interpolation = cm.is_interpolation_enabled();
503 use_linear_filtering =
true;
507 use_linear_filtering = gl_cm->is_linear_filtering_enabled();
509 update_point_positions();
510 update_color_map(
false);
516void color_map_editor::set_histogram_data(
const std::vector<unsigned> data) {
519 std::vector<float> float_data(histogram.size(), 0.0f);
521 hist_max_non_zero = 1;
522 for(
size_t i = 0; i < histogram.size(); ++i) {
523 unsigned count = histogram[i];
524 hist_max = std::max(hist_max, count);
526 hist_max_non_zero = std::max(hist_max_non_zero, count);
527 float_data[i] =
static_cast<float>(count);
531 auto& ctx = *ctx_ptr;
536 hist_tex.
create(ctx, dv, 0);
542void color_map_editor::set_selected_color(
rgb color) {
544 auto selected_point = cmc.color_points.get_selected();
546 selected_point->col = color;
547 update_color_map(
true);
553void color_map_editor::init_styles() {
554 auto& theme = cgv::gui::theme_info::instance();
555 handle_color =
rgba(theme.text(), 1.0f);
556 highlight_color =
rgba(theme.highlight(), 1.0f);
557 highlight_color_hex = theme.highlight_hex();
560 border_style.fill_color = theme.border();
561 border_style.border_width = 0.0f;
562 border_style.feather_width = 0.0f;
565 color_map_style = border_style;
566 color_map_style.use_texture =
true;
569 bg_style.use_texture =
true;
570 bg_style.feather_width = 0.0f;
573 hist_style.use_blending =
true;
574 hist_style.feather_width = 1.0f;
575 hist_style.feather_origin = 0.0f;
576 hist_style.fill_color =
rgba(
rgb(0.5f), 0.666f);
577 hist_style.border_color =
rgba(
rgb(0.0f), 0.666f);
578 hist_style.border_width = 1.0f;
581 color_handle_style.use_blending =
true;
582 color_handle_style.use_fill_color =
false;
583 color_handle_style.position_is_center =
true;
584 color_handle_style.border_color = theme.border();
585 color_handle_style.border_width = 1.5f;
586 color_handle_style.border_radius = 2.0f;
587 color_handle_style.stem_width = color_point::default_width;
588 color_handle_style.head_width = color_point::default_width;
590 label_box_style.position_is_center =
true;
591 label_box_style.use_blending =
true;
592 label_box_style.fill_color = handle_color;
593 label_box_style.border_color = theme.border();
594 label_box_style.border_width = 1.5f;
595 label_box_style.border_radius = 4.0f;
598 opacity_handle_style.use_blending =
true;
599 opacity_handle_style.use_fill_color =
false;
600 opacity_handle_style.position_is_center =
true;
601 opacity_handle_style.border_color = theme.border();
602 opacity_handle_style.border_width = 1.5f;
605 line_style.use_blending =
true;
606 line_style.use_fill_color =
false;
607 line_style.use_texture =
true;
608 line_style.use_texture_alpha =
false;
609 line_style.width = 3.0f;
611 polygon_style =
static_cast<cgv::g2d::shape2d_style
>(line_style);
612 polygon_style.use_texture_alpha =
true;
615 cursor_label_style.fill_color =
rgb(0.0f);
616 cursor_label_style.font_size = 16.0f;
618 value_label_style.fill_color = theme.group();
619 value_label_style.font_size = 12.0f;
633 std::vector<uint8_t> data(resolution * 4 * 2, 0u);
635 setup_preview_texture(ctx);
637 preview_tex.
create(ctx, tf_dv, 0);
640void color_map_editor::add_point(
const vec2& pos) {
645 if(layout.color_editor_rect.contains(test_pos)) {
648 p.position =
ivec2(
int(pos.x()), layout.color_handles_rect.y());
649 p.update_val(layout);
650 p.col = cmc.cm->interpolate_color(p.val);
651 size_t index = cmc.color_points.add(p);
652 cmc.color_points.set_selected(index);
654 }
else if(supports_opacity && layout.opacity_editor_rect.contains(test_pos)) {
658 p.update_val(layout, opacity_scale_exponent);
659 size_t index = cmc.opacity_points.add(p);
660 cmc.opacity_points.set_selected(index);
664 update_color_map(
true);
668void color_map_editor::remove_point(
const cgv::g2d::draggable* ptr) {
670 int color_point_idx = -1;
671 int opacity_point_idx = -1;
673 for(
unsigned i = 0; i < cmc.color_points.size(); ++i) {
674 if(&cmc.color_points[i] == ptr) {
680 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i) {
681 if(&cmc.opacity_points[i] == ptr) {
682 opacity_point_idx = i;
687 bool removed =
false;
689 if(color_point_idx > -1) {
690 if(cmc.color_points.size() > 1) {
691 cmc.color_points.ref_draggables().erase(cmc.color_points.ref_draggables().begin() + color_point_idx);
696 if(opacity_point_idx > -1) {
697 if(cmc.opacity_points.size() > 1) {
698 cmc.opacity_points.ref_draggables().erase(cmc.opacity_points.ref_draggables().begin() + opacity_point_idx);
704 update_color_map(
true);
707cgv::g2d::draggable* color_map_editor::get_hit_point(
const vec2& pos) {
709 cgv::g2d::draggable* hit =
nullptr;
711 for(
unsigned i = 0; i < cmc.color_points.size(); ++i) {
712 color_point& p = cmc.color_points[i];
717 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i) {
718 opacity_point& p = cmc.opacity_points[i];
726void color_map_editor::update_value_label_rectangle(
vec2 position,
const cgv::g2d::rect& parent_rectangle) {
728 value_label_rectangle.position = position;
731 auto& font = cgv::g2d::ref_msdf_font_regular(*
get_context());
732 value_label_rectangle.size = font.compute_render_size(value_label, value_label_style.font_size);
735 float padding = std::ceil(0.5f * value_label_rectangle.w()) + 4.0f;
736 float min_x = layout.color_editor_rect.x() + padding;
737 float max_x = layout.color_editor_rect.x1() - padding;
738 value_label_rectangle.position.x() = cgv::math::clamp(value_label_rectangle.position.x(), min_x, max_x);
741void color_map_editor::handle_color_drag(cgv::g2d::DragAction action) {
744 case cgv::g2d::DragAction::kDrag:
746 color_point* dragged_point = cmc.color_points.get_dragged();
748 dragged_point->update_val(layout);
749 update_color_map(
true);
751 show_value_label =
true;
752 value_label = value_to_string(dragged_point->val);
753 update_value_label_rectangle(dragged_point->position, layout.color_editor_rect);
754 value_label_rectangle.position.y() += 25.0f;
756 if(dragged_point && on_color_point_select_callback)
757 on_color_point_select_callback(dragged_point->col);
763 case cgv::g2d::DragAction::kDragEnd:
764 case cgv::g2d::DragAction::kSelect:
772void color_map_editor::handle_opacity_drag(cgv::g2d::DragAction action) {
775 case cgv::g2d::DragAction::kDrag:
777 opacity_point* dragged_point = cmc.opacity_points.get_dragged();
779 dragged_point->update_val(layout, opacity_scale_exponent);
780 update_color_map(
true);
782 show_value_label =
true;
783 std::string x_label = value_to_string(dragged_point->val.x());
785 value_label = x_label +
", " + y_label;
787 update_value_label_rectangle(dragged_point->position, layout.opacity_editor_rect);
788 value_label_rectangle.position.y() = std::min(value_label_rectangle.position.y() + 10.0f,
static_cast<float>(layout.opacity_editor_rect.y1() - 6));
794 case cgv::g2d::DragAction::kDragEnd:
795 case cgv::g2d::DragAction::kSelect:
839void color_map_editor::handle_drag_end() {
841 show_value_label =
false;
844 auto selected_point = cmc.color_points.get_selected();
846 if(on_color_point_select_callback)
847 on_color_point_select_callback(selected_point->col);
849 if(on_color_point_deselect_callback)
850 on_color_point_deselect_callback();
857std::string color_map_editor::value_to_string(
float value) {
859 float display_value = cgv::math::lerp(range.
x(), range.
y(), value);
861 float total = range.
y() - range.
x();
867 int display_value_int =
static_cast<int>(round(display_value));
868 return std::to_string(display_value_int);
872void color_map_editor::sort_points() {
875 sort_opacity_points();
878void color_map_editor::sort_color_points() {
880 auto& points = cmc.color_points;
882 if(points.size() > 1) {
883 int dragged_point_idx = -1;
884 int selected_point_idx = -1;
886 const color_point* dragged_point = points.get_dragged();
887 const color_point* selected_point = points.get_selected();
889 std::vector<std::pair<color_point, int>> sorted(points.size());
891 for(
unsigned i = 0; i < points.size(); ++i) {
892 sorted[i].first = points[i];
893 sorted[i].second = i;
895 if(dragged_point == &points[i])
896 dragged_point_idx = i;
897 if(selected_point == &points[i])
898 selected_point_idx = i;
901 std::sort(sorted.begin(), sorted.end(),
902 [](
const auto& a,
const auto& b) ->
bool {
903 return a.first.val < b.first.val;
907 int new_dragged_point_idx = -1;
908 int new_selected_point_idx = -1;
910 for(
unsigned i = 0; i < sorted.size(); ++i) {
911 points[i] = sorted[i].first;
912 if(dragged_point_idx == sorted[i].second) {
913 new_dragged_point_idx = i;
915 if(selected_point_idx == sorted[i].second) {
916 new_selected_point_idx = i;
920 points.set_dragged(new_dragged_point_idx);
921 points.set_selected(new_selected_point_idx);
925void color_map_editor::sort_opacity_points() {
927 auto& points = cmc.opacity_points;
929 if(points.size() > 1) {
930 int dragged_point_idx = -1;
931 int selected_point_idx = -1;
933 const opacity_point* dragged_point = points.get_dragged();
934 const opacity_point* selected_point = points.get_selected();
936 std::vector<std::pair<opacity_point, int>> sorted(points.size());
938 for(
unsigned i = 0; i < points.size(); ++i) {
939 sorted[i].first = points[i];
940 sorted[i].second = i;
942 if(dragged_point == &points[i])
943 dragged_point_idx = i;
944 if(selected_point == &points[i])
945 selected_point_idx = i;
948 std::sort(sorted.begin(), sorted.end(),
949 [](
const auto& a,
const auto& b) ->
bool {
950 return a.first.val.x() < b.first.val.x();
954 int new_dragged_point_idx = -1;
955 int new_selected_point_idx = -1;
957 for(
unsigned i = 0; i < sorted.size(); ++i) {
958 points[i] = sorted[i].first;
959 if(dragged_point_idx == sorted[i].second) {
960 new_dragged_point_idx = i;
962 if(selected_point_idx == sorted[i].second) {
963 new_selected_point_idx = i;
967 points.set_dragged(new_dragged_point_idx);
968 points.set_selected(new_selected_point_idx);
972void color_map_editor::update_point_positions() {
974 for(
unsigned i = 0; i < cmc.color_points.size(); ++i)
975 cmc.color_points[i].update_pos(layout);
977 for(
unsigned i = 0; i < cmc.opacity_points.size(); ++i)
978 cmc.opacity_points[i].update_pos(layout, opacity_scale_exponent);
981void color_map_editor::update_color_map(
bool is_data_change) {
984 if(!ctx_ptr || !cmc.cm)
return;
988 auto& color_points = cmc.color_points;
989 auto& opacity_points = cmc.opacity_points;
995 for(
unsigned i = 0; i < color_points.size(); ++i) {
996 const color_point& p = color_points[i];
997 cm.add_color_point(p.val, p.col);
1000 if(supports_opacity) {
1001 for(
unsigned i = 0; i < opacity_points.size(); ++i) {
1002 const opacity_point& p = opacity_points[i];
1003 cm.add_opacity_point(p.val.x(), p.val.y());
1007 cm.add_opacity_point(0.0f, 1.0f);
1010 size_t size =
static_cast<size_t>(resolution);
1011 std::vector<rgba> cs_data = cm.interpolate(size);
1013 std::vector<uint8_t> data(4 * 2 * size);
1014 for(
size_t i = 0; i < size; ++i) {
1015 rgba col = cs_data[i];
1016 uint8_t r =
static_cast<uint8_t
>(255.0f * col.R());
1017 uint8_t g =
static_cast<uint8_t
>(255.0f * col.G());
1018 uint8_t b =
static_cast<uint8_t
>(255.0f * col.B());
1019 uint8_t a =
static_cast<uint8_t
>(255.0f * col.alpha());
1033 setup_preview_texture(ctx);
1035 preview_tex.
create(ctx, dv, 0);
1037 if(!supports_opacity)
1038 cm.clear_opacity_points();
1042 if(on_change_callback)
1043 on_change_callback();
1048bool color_map_editor::update_geometry() {
1051 if(!ctx_ptr || !cmc.cm)
return false;
1055 auto& color_points = cmc.color_points;
1056 auto& opacity_points = cmc.opacity_points;
1057 auto& color_handles = cmc.color_handles;
1058 auto& opacity_handles = cmc.opacity_handles;
1059 auto& lines = cmc.lines;
1060 auto& triangles = cmc.triangles;
1062 color_handles.clear();
1063 opacity_handles.clear();
1067 bool success = color_points.size() > 0 && opacity_points.size() > 0;
1070 vec2 pos_offset =
vec2(0.0f, 0.5f * color_point::default_height);
1072 for(
unsigned i = 0; i < color_points.size(); ++i) {
1073 const auto& p = color_points[i];
1074 vec2 pos = p.center();
1075 rgba col = color_points.get_selected() == &p ? highlight_color : handle_color;
1076 color_handles.add(pos - pos_offset, col);
1077 color_handles.add(pos + pos_offset, col);
1081 for(
unsigned i = 0; i < opacity_points.size(); ++i) {
1082 const auto& p = opacity_points[i];
1083 vec2 pos = p.center();
1084 rgba col = opacity_points.get_selected() == &p ? highlight_color : handle_color;
1085 opacity_handles.add(pos, col);
1088 if(opacity_points.size() > 0) {
1089 const auto& pl = opacity_points[0];
1091 vec2 tex_coord(0.0f, 0.5f);
1093 lines.add(
vec2(
float(layout.opacity_editor_rect.x()), pl.center().y()), tex_coord);
1095 triangles.add(
vec2(
float(layout.opacity_editor_rect.x()), pl.center().y()), tex_coord);
1096 triangles.add(layout.opacity_editor_rect.position, tex_coord);
1098 for(
unsigned i = 0; i < opacity_points.size(); ++i) {
1099 const auto& p = opacity_points[i];
1100 vec2 pos = p.center();
1102 tex_coord.
x() = p.val.x();
1104 lines.add(pos, tex_coord);
1106 triangles.add(pos, tex_coord);
1107 triangles.add(
vec2(pos.x(), (
float)layout.opacity_editor_rect.y()), tex_coord);
1110 const auto& pr = opacity_points[opacity_points.size() - 1];
1111 vec2 max_pos = layout.opacity_editor_rect.position +
vec2(1.0f, 0.0f) * layout.opacity_editor_rect.size;
1113 tex_coord.x() = 1.0f;
1115 lines.add(
vec2(max_pos.x(), pr.center().y()), tex_coord);
1117 triangles.add(
vec2(max_pos.x(), pr.center().y()), tex_coord);
1118 triangles.add(max_pos, tex_coord);
More advanced text processing for splitting text into lines or tokens.
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
bool is_hit_local(const ivec2 &local_mouse_pos) const
See is_hit.
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.
class to represent all possible keyboard events with the EID_KEY
class to represent all possible mouse events with the EID_MOUSE
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
T & y()
return second component
T & x()
return first component
static cgv::type::uint32_type size()
return number of components
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