1#include "transfer_function_editor.h"
6#include <cgv/gui/key_event.h>
7#include <cgv/gui/mouse_event.h>
8#include <cgv/gui/theme_info.h>
9#include <cgv/math/ftransform.h>
10#include <cgv/utils/algorithm.h>
12#include <cgv/utils/file.h>
13#include <cgv_gl/gl/gl.h>
14#include <cgv_g2d/msdf_font.h>
15#include <cgv_g2d/msdf_gl_font_renderer.h>
20const vec2 transfer_function_editor::color_point_size = { 12.0f, 18.0f };
21const vec2 transfer_function_editor::opacity_point_size = { 12.0f };
23transfer_function_editor::transfer_function_editor() {
27 layout.total_height = supports_opacity ? 200 : 60;
31 color_draggables.set_constraint(layout.color_draggables_rect);
32 color_draggables.callback = std::bind(&transfer_function_editor::handle_drag,
this, std::placeholders::_1, DraggableType::kColor);
34 opacity_draggables.set_constraint(layout.opacity_editor_rect);
35 opacity_draggables.callback = std::bind(&transfer_function_editor::handle_drag,
this, std::placeholders::_1, DraggableType::kOpacity);
37 color_handle_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::arrow);
38 opacity_handle_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::rectangle);
39 line_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::line);
40 polygon_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::polygon);
44 cgv::g2d::ref_msdf_font_regular(ctx, -1);
45 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
49 color_handle_renderer.destruct(ctx);
50 opacity_handle_renderer.destruct(ctx);
51 line_renderer.destruct(ctx);
52 polygon_renderer.destruct(ctx);
60 bool capture_event =
false;
68 if(!get_hit_point(local_mouse_pos)) {
69 add_point(local_mouse_pos);
74 cgv::g2d::draggable* hit_point = get_hit_point(local_mouse_pos);
76 erase_point(hit_point);
98 size.y() = layout.total_height;
102 if(ptr.
points_to(opacity_scale_exponent)) {
103 opacity_scale_exponent = cgv::math::clamp(opacity_scale_exponent, 1.0f, 5.0f);
105 update_point_positions();
119 if(transfer_function) {
120 transfer_function->set_color_interpolation(color_interpolation);
122 transfer_function->set_opacity_interpolation(opacity_interpolation);
124 create_preview_texture();
127 if(on_change_callback)
128 on_change_callback();
133 update_transfer_function_from_data();
134 create_preview_texture();
139 for(
auto& draggable : opacity_draggables) {
141 draggable.set_uv_and_update_position(draggable.uv);
142 update_transfer_function_from_data();
151 layout.total_height = supports_opacity ? 200 : 60;
152 on_set(&layout.total_height);
154 if(!supports_opacity) {
155 if(transfer_function) {
159 update_point_positions();
164 post_recreate_layout();
170 cgv::g2d::ref_msdf_font_regular(ctx, 1);
171 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
173 register_shader(
"rectangle", cgv::g2d::shaders::rectangle);
174 register_shader(
"circle", cgv::g2d::shaders::circle);
175 register_shader(
"histogram",
"heightfield1d.glpr");
177 register_shader(
"background",
"color_map_editor_bg.glpr");
181 success &= color_handle_renderer.init(ctx);
182 success &= opacity_handle_renderer.init(ctx);
183 success &= line_renderer.init(ctx);
184 success &= polygon_renderer.init(ctx);
185 success &= create_background_texture();
193 if(ensure_layout(ctx)) {
197 force_update_data_from_transfer_function();
199 auto& bg_prog = content_canvas.enable_shader(ctx,
"background");
200 float width_factor =
static_cast<float>(layout.opacity_editor_rect.w()) /
static_cast<float>(layout.opacity_editor_rect.h());
201 bg_style.texcoord_scaling =
vec2(5.0f * width_factor, 5.0f);
202 bg_style.apply(ctx, bg_prog);
203 content_canvas.disable_current_shader(ctx);
209 color_draggables.set_constraint(layout.color_draggables_rect);
210 opacity_draggables.set_constraint(layout.opacity_editor_rect);
219 content_canvas.enable_shader(ctx,
"rectangle");
220 content_canvas.set_style(ctx, border_style);
221 content_canvas.draw_shape(ctx,
ivec2(padding() - 1) +
ivec2(0, 10), container_size - 2 * padding() + 2 -
ivec2(0, 10));
223 if(transfer_function && preview_tex.
is_created()) {
225 content_canvas.set_style(ctx, color_map_style);
226 preview_tex.
enable(ctx, 0);
227 content_canvas.draw_shape(ctx, layout.color_editor_rect);
230 if(supports_opacity) {
232 auto& bg_prog = content_canvas.enable_shader(ctx,
"background");
233 bg_style.apply(ctx, bg_prog);
234 bg_prog.set_uniform(ctx,
"scale_exponent", opacity_scale_exponent);
235 background_tex.
enable(ctx, 0);
236 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
238 content_canvas.disable_current_shader(ctx);
241 if(histogram_type != HistogramType::kNone && histogram_tex.
is_created()) {
242 auto& hist_prog = content_canvas.enable_shader(ctx,
"histogram");
243 hist_prog.set_uniform(ctx,
"max_value", hist_norm_ignore_zero ? hist_max_non_zero : hist_max);
244 hist_prog.set_uniform(ctx,
"norm_gamma", hist_norm_gamma);
245 hist_prog.set_uniform(ctx,
"sampling_type", cgv::math::clamp(
static_cast<unsigned>(histogram_type) - 1, 0u, 2u));
246 hist_style.apply(ctx, hist_prog);
248 histogram_tex.
enable(ctx, 1);
249 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
251 content_canvas.disable_current_shader(ctx);
254 preview_tex.
enable(ctx, 0);
256 polygon_renderer.render(ctx, content_canvas, cgv::render::PT_TRIANGLE_STRIP, triangle_geometry, polygon_style);
259 line_renderer.render(ctx, content_canvas, cgv::render::PT_LINE_STRIP, line_geometry, line_style);
263 content_canvas.enable_shader(ctx,
"rectangle");
264 content_canvas.set_style(ctx, border_style);
265 content_canvas.draw_shape(ctx,
266 ivec2(layout.color_editor_rect.x(), layout.color_editor_rect.y1()),
267 ivec2(container_size.
x() - 2 * padding(), 1)
269 content_canvas.disable_current_shader(ctx);
274 color_handle_renderer.render(ctx, content_canvas, cgv::render::PT_LINES, color_draggables_geometry, color_handle_style);
277 if(supports_opacity) {
278 auto& opacity_handle_prog = opacity_handle_renderer.enable_prog(ctx);
279 opacity_handle_prog.set_attribute(ctx,
"size", opacity_point_size);
280 opacity_handle_renderer.render(ctx, content_canvas, cgv::render::PT_POINTS, opacity_draggables_geometry, opacity_handle_style);
283 content_canvas.disable_current_shader(ctx);
286 auto& font = cgv::g2d::ref_msdf_font_regular(ctx);
287 auto& font_renderer = cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx);
288 cgv::g2d::msdf_gl_font_renderer::text_render_info text_render_info;
290 if(!value_label.empty()) {
291 cgv::g2d::irect rectangle = value_label_rectangle;
292 rectangle.translate(0, 5);
293 rectangle.size +=
ivec2(10, 6);
295 content_canvas.enable_shader(ctx,
"rectangle");
296 content_canvas.set_style(ctx, label_box_style);
297 content_canvas.draw_shape(ctx, rectangle);
298 content_canvas.disable_current_shader(ctx);
301 font_renderer.render(ctx, content_canvas, font, value_label, value_label_rectangle.position, text_render_info, value_label_style);
316 std::string height_options =
"min=";
317 height_options += supports_opacity ?
"80" :
"40";
318 height_options +=
";max=500;step=10;ticks=true";
319 add_member_control(
this,
"Height", layout.total_height,
"value_slider", height_options);
326 add_decorator(
"Color",
"heading",
"level=4;font_style=regular;w=94",
" ");
327 add_decorator(
"Opacity",
"heading",
"level=4;font_style=regular;w=94",
"%y-=6\n");
328 const std::string interpolation_enums =
"enums='Step,Linear,Smooth'";
329 add_member_control(
this,
"Interpolation", color_interpolation,
"dropdown", interpolation_enums +
";w=94",
" ");
330 add_member_control(
this,
"", opacity_interpolation,
"dropdown", interpolation_enums +
";w=94");
334 cgv::signal::connect_copy(
add_button(
"Rescale")->click, cgv::signal::rebind(
this, &transfer_function_editor::rescale_domain));
340 auto& points = color_draggables;
341 for(
unsigned i = 0; i < points.size(); ++i) {
342 std::string label_prefix =
"";
343 std::string options =
"w=48";
344 if(&points[i] == selected_color_draggable) {
346 options +=
";label_color=" + cgv::media::to_hex(highlight_color);
349 add_view(label_prefix + std::to_string(i), points[i].uv.x(),
"", options,
" ");
356 if(supports_opacity) {
359 auto& points = opacity_draggables;
360 for(
unsigned i = 0; i < points.size(); ++i) {
361 std::string label_prefix =
"";
362 std::string options =
"w=48";
363 if(&points[i] == selected_opacity_draggable) {
365 options +=
";label_color=" + cgv::media::to_hex(highlight_color);
368 add_view(label_prefix + std::to_string(i), points[i].uv.x(),
"", options,
" ");
377 cgv::signal::connect_copy(
add_button(
"Set selected position")->click, cgv::signal::rebind(
this, &transfer_function_editor::set_selected_point_domain_value));
381 add_member_control(
this,
"Type", histogram_type,
"dropdown",
"enums='None,Nearest,Linear,Smooth'");
382 add_member_control(
this,
"Ignore Zero for Normalization", hist_norm_ignore_zero,
"check");
383 add_member_control(
this,
"Gamma", hist_norm_gamma,
"value_slider",
"min=0.001;max=2;step=0.001;ticks=true");
386 add_member_control(
this,
"Border Width", hist_style.border_width,
"value_slider",
"min=0;max=10;step=0.5;ticks=true");
392void transfer_function_editor::set_opacity_support(
bool flag) {
393 supports_opacity = flag;
395 on_set(&supports_opacity);
398void transfer_function_editor::set_transfer_function(std::shared_ptr<cgv::media::transfer_function> transfer_function) {
399 if(this->transfer_function != transfer_function) {
400 this->transfer_function = transfer_function;
404 this->transfer_function = transfer_function;
405 update_data_from_transfer_function();
409void transfer_function_editor::set_histogram_data(
const std::vector<unsigned> data) {
412 std::vector<float> float_data(histogram.size(), 0.0f);
414 hist_max_non_zero = 1;
415 for(
size_t i = 0; i < histogram.size(); ++i) {
416 unsigned count = histogram[i];
417 hist_max = std::max(hist_max, count);
419 hist_max_non_zero = std::max(hist_max_non_zero, count);
420 float_data[i] =
static_cast<float>(count);
430void transfer_function_editor::set_selected_color(
rgb color) {
431 if(selected_color_draggable) {
432 selected_color_draggable->data = color;
433 on_set(&selected_color_draggable->data);
438void transfer_function_editor::init_styles() {
439 auto& theme = cgv::gui::theme_info::instance();
441 handle_color = theme.text();
442 highlight_color = theme.highlight();
445 border_style.fill_color = theme.border();
446 border_style.border_width = 0.0f;
447 border_style.feather_width = 0.0f;
450 color_map_style = border_style;
451 color_map_style.use_texture =
true;
454 bg_style.use_texture =
true;
455 bg_style.feather_width = 0.0f;
458 hist_style.use_blending =
true;
459 hist_style.feather_width = 1.0f;
460 hist_style.feather_origin = 0.0f;
461 hist_style.fill_color =
rgba(
rgb(0.5f), 0.666f);
462 hist_style.border_color =
rgba(
rgb(0.0f), 0.666f);
463 hist_style.border_width = 1.0f;
466 color_handle_style.use_blending =
true;
467 color_handle_style.use_fill_color =
false;
468 color_handle_style.position_is_center =
true;
469 color_handle_style.border_color = theme.border();
470 color_handle_style.border_width = 1.5f;
471 color_handle_style.border_radius = 2.0f;
472 color_handle_style.stem_width = color_point_size.
x();
473 color_handle_style.head_width = color_point_size.
x();
475 label_box_style.position_is_center =
true;
476 label_box_style.use_blending =
true;
477 label_box_style.fill_color = handle_color;
478 label_box_style.border_color = theme.border();
479 label_box_style.border_width = 1.5f;
480 label_box_style.border_radius = 4.0f;
483 opacity_handle_style.use_blending =
true;
484 opacity_handle_style.use_fill_color =
false;
485 opacity_handle_style.position_is_center =
true;
486 opacity_handle_style.border_color = theme.border();
487 opacity_handle_style.border_width = 1.5f;
490 line_style.use_blending =
true;
491 line_style.use_fill_color =
false;
492 line_style.use_texture =
true;
493 line_style.use_texture_alpha =
false;
494 line_style.width = 3.0f;
496 polygon_style =
static_cast<cgv::g2d::shape2d_style
>(line_style);
497 polygon_style.use_texture_alpha =
true;
500 cursor_label_style.fill_color =
rgb(0.0f);
501 cursor_label_style.font_size = 16.0f;
503 value_label_style.fill_color = theme.group();
504 value_label_style.font_size = 12.0f;
508 int content_height = layout.total_height - 10 - 2 * padding();
509 if(supports_opacity) {
510 layout.color_editor_height =
static_cast<int>(floor(0.15f *
static_cast<float>(content_height)));
511 layout.color_editor_height = cgv::math::clamp(layout.color_editor_height, 4, 80);
512 layout.opacity_editor_height = content_height - layout.color_editor_height - 1;
514 layout.color_editor_height = content_height;
515 layout.opacity_editor_height = 0;
518 int y_off = padding();
520 layout.color_draggables_rect = {
521 ivec2(padding(), 16),
522 ivec2(parent_size.x() - 2 * padding(), 0)
528 layout.color_editor_rect.position =
ivec2(padding(), y_off);
529 layout.color_editor_rect.size =
ivec2(parent_size.x() - 2 * padding(), layout.color_editor_height);
531 y_off += layout.color_editor_height + 1;
533 layout.opacity_editor_rect.position =
ivec2(padding(), y_off);
534 layout.opacity_editor_rect.size =
ivec2(parent_size.x() - 2 * padding(), layout.opacity_editor_height);
537void transfer_function_editor::clear_data() {
538 selected_color_draggable =
nullptr;
539 selected_opacity_draggable =
nullptr;
540 color_draggables.clear();
541 opacity_draggables.clear();
542 color_draggables_geometry.clear();
543 opacity_draggables_geometry.clear();
544 line_geometry.clear();
545 triangle_geometry.clear();
548void transfer_function_editor::force_update_data_from_transfer_function() {
549 if(!transfer_function)
554 const vec2 domain = transfer_function->get_domain();
555 input_domain = domain;
559 for(
const auto& point : transfer_function->get_color_points()) {
560 color_point draggable = make_color_point();
561 draggable.data = point.second;
562 const vec2 uv = { cgv::math::normalize(point.first, domain[0], domain[1]), 0.0f };
563 draggable.set_uv_and_update_position(uv);
564 color_draggables.add(draggable);
567 if(supports_opacity) {
568 for(
const auto& point : transfer_function->get_opacity_points()) {
569 opacity_point draggable = make_opacity_point();
570 const vec2 uv = { cgv::math::normalize(point.first, domain[0], domain[1]), point.second };
571 draggable.set_uv_and_update_position(uv);
572 opacity_draggables.add(draggable);
577 create_preview_texture();
583void transfer_function_editor::update_data_from_transfer_function() {
584 if(!transfer_function)
588 if(!build_time.is_valid() || transfer_function->get_modified_time() > build_time.get_modified_time()) {
589 std::cout <<
"set editor data from tf" << std::endl;
593 force_update_data_from_transfer_function();
595 build_time.modified();
599void transfer_function_editor::update_transfer_function_from_data() {
600 if(!transfer_function)
603 std::vector<std::pair<float, rgb>> colors;
604 std::vector<std::pair<float, float>> opacities;
606 const vec2 domain = transfer_function->get_domain();
608 auto map_to_domain = [domain](
float u) {
609 return cgv::math::map(u, 0.0f, 1.0f, domain[0], domain[1]);
612 std::transform(color_draggables.begin(), color_draggables.end(), std::back_inserter(colors), [&map_to_domain](
const color_point& point) {
613 return std::make_pair(map_to_domain(point.uv.x()), point.data);
615 std::transform(opacity_draggables.begin(), opacity_draggables.end(), std::back_inserter(opacities), [&map_to_domain](
const opacity_point& point) {
616 return std::make_pair(map_to_domain(point.uv.x()), point.uv.y());
619 transfer_function->set_color_points(colors);
620 transfer_function->set_opacity_points(opacities);
627 if(on_change_callback)
628 on_change_callback();
631void transfer_function_editor::rescale_domain() {
632 if(transfer_function) {
633 transfer_function->rescale(input_domain);
634 update_data_from_transfer_function();
636 if(on_change_callback)
637 on_change_callback();
641cgv::g2d::draggable* transfer_function_editor::get_hit_point(
const vec2& pos) {
642 const auto& contains = [&pos](
const auto& draggable) {
643 return draggable.contains(pos);
646 auto color_it = std::find_if(color_draggables.begin(), color_draggables.end(), contains);
647 if(color_it != color_draggables.end())
650 auto opacity_it = std::find_if(opacity_draggables.begin(), opacity_draggables.end(), contains);
651 if(opacity_it != opacity_draggables.end())
658bool is_boundary_point(
const T* point, cgv::g2d::draggable_collection<T>& draggables) {
659 if(draggables.empty())
661 return point == &draggables.ref_draggables().front() || point == &draggables.ref_draggables().back();
664void transfer_function_editor::add_point(
const vec2& pos) {
665 if(!transfer_function)
670 selected_color_draggable =
nullptr;
671 selected_opacity_draggable =
nullptr;
673 if(layout.color_editor_rect.contains(test_pos)) {
674 color_point draggable = make_color_point();
675 draggable.set_position_and_update_uv({ pos.x(), 0.0f });
676 draggable.data = transfer_function->get_mapped_color(draggable.uv.x());
677 size_t index = color_draggables.add(draggable);
680 selected_color_draggable = &color_draggables[index];
681 }
else if(supports_opacity && layout.opacity_editor_rect.contains(test_pos)) {
682 opacity_point draggable = make_opacity_point();
683 draggable.set_position_and_update_uv(pos);
684 size_t index = opacity_draggables.add(draggable);
685 selected_opacity_draggable = &opacity_draggables[index];
689 update_transfer_function_from_data();
690 handle_selection_change();
695void transfer_function_editor::erase_point(
const cgv::g2d::draggable* point) {
696 const auto& try_erase_point_from = [point](
auto& draggables) {
697 if(draggables.size() > 1) {
698 if(point == &draggables.ref_draggables().front() || point == &draggables.ref_draggables().back())
701 auto it = std::remove_if(draggables.begin(), draggables.end(), [point](
const cgv::g2d::draggable& draggable) {
702 return &draggable == point;
704 if(it != draggables.end()) {
705 draggables.ref_draggables().erase(it);
712 if(try_erase_point_from(color_draggables) || try_erase_point_from(opacity_draggables)) {
713 selected_color_draggable =
nullptr;
714 selected_opacity_draggable =
nullptr;
715 update_transfer_function_from_data();
716 handle_selection_change();
717 create_preview_texture();
723void transfer_function_editor::set_selected_point_domain_value() {
724 if(!transfer_function)
727 const vec2 domain = transfer_function->get_domain();
728 const float x = cgv::math::clamp(input_position, domain[0], domain[1]);
729 const float u = cgv::math::normalize(x, domain[0], domain[1]);
731 if(selected_color_draggable && !is_boundary_point(selected_color_draggable, color_draggables))
732 selected_color_draggable->set_uv_and_update_position({ u, 0.0f });
733 else if(selected_opacity_draggable && !is_boundary_point(selected_opacity_draggable, opacity_draggables))
734 selected_opacity_draggable->set_uv_and_update_position({ u, selected_opacity_draggable->uv.
y() });
737 update_transfer_function_from_data();
738 create_preview_texture();
743void transfer_function_editor::set_value_label(
vec2 position,
const std::string& text) {
745 value_label_rectangle.position = position;
748 auto& font = cgv::g2d::ref_msdf_font_regular(*
get_context());
749 value_label_rectangle.size = font.compute_render_size(value_label, value_label_style.font_size);
753 constraint.scale(-0.5f * (value_label_rectangle.size + 4.0f));
754 value_label_rectangle.position = cgv::math::clamp(value_label_rectangle.position, constraint.a(), constraint.b());
757void transfer_function_editor::handle_drag(cgv::g2d::DragAction action, DraggableType type) {
758 bool modified =
false;
761 case cgv::g2d::DragAction::kDragStart:
762 if(type == DraggableType::kColor) {
763 color_point* dragged = color_draggables.get_dragged();
765 color_draggable_start_position = dragged->position;
766 }
else if(type == DraggableType::kOpacity) {
767 opacity_point* dragged = opacity_draggables.get_dragged();
769 opacity_draggable_start_position = dragged->position;
771 case cgv::g2d::DragAction::kDrag:
772 if(type == DraggableType::kColor) {
773 color_point* dragged = color_draggables.get_dragged();
775 if(is_boundary_point(dragged, color_draggables))
776 dragged->position = color_draggable_start_position;
779 dragged->set_position_and_update_uv(dragged->position);
781 dragged->position +
cgv::vec2(0.0f, 25.0f),
782 value_to_string(dragged->uv.x())
784 selected_color_draggable = dragged;
785 selected_opacity_draggable =
nullptr;
788 }
else if(type == DraggableType::kOpacity) {
789 opacity_point* dragged = opacity_draggables.get_dragged();
791 if(is_boundary_point(dragged, opacity_draggables))
792 dragged->position.x() = opacity_draggable_start_position.
x();
795 dragged->set_position_and_update_uv(dragged->position);
798 dragged->position +
cgv::vec2(0.0f, 10.0f),
801 selected_opacity_draggable = dragged;
802 selected_color_draggable =
nullptr;
807 handle_selection_change();
809 case cgv::g2d::DragAction::kDragEnd:
810 handle_selection_change();
822 update_transfer_function_from_data();
823 create_preview_texture();
829void transfer_function_editor::handle_selection_change() {
830 if(selected_color_draggable) {
831 if(on_color_point_select_callback)
832 on_color_point_select_callback(selected_color_draggable->data);
834 if(on_color_point_deselect_callback)
835 on_color_point_deselect_callback();
840std::string transfer_function_editor::value_to_string(
float value) {
841 if(!transfer_function)
844 const vec2 domain = transfer_function->get_domain();
845 float display_value = cgv::math::lerp(domain.x(), domain.y(), value);
847 float total = domain.y() - domain.x();
853 int display_value_int =
static_cast<int>(round(display_value));
854 return std::to_string(display_value_int);
859void sort_draggables(cgv::g2d::draggable_collection<T>& draggables, T*& selected) {
860 if(draggables.empty())
863 int dragged_idx = -1;
864 int selected_idx = -1;
866 for(
size_t i = 0; i < draggables.size(); ++i) {
867 if(&draggables[i] == draggables.get_dragged())
868 dragged_idx =
static_cast<int>(i);
869 if(&draggables[i] == selected)
870 selected_idx =
static_cast<int>(i);
873 std::vector<T> draggables_copy = draggables.ref_draggables();
876 for(
size_t i = 0; i < permutation.size(); ++i) {
877 int permuted_index =
static_cast<int>(permutation[i]);
878 draggables[i] = draggables_copy[permuted_index];
879 if(permuted_index == dragged_idx)
880 draggables.set_dragged(i);
881 if(permuted_index == selected_idx)
882 selected = &draggables[i];
886void transfer_function_editor::sort_points() {
887 sort_draggables(color_draggables, selected_color_draggable);
889 sort_draggables(opacity_draggables, selected_opacity_draggable);
892void transfer_function_editor::update_point_positions() {
893 for(
auto& draggable : color_draggables)
894 draggable.set_position_and_update_uv(draggable.position);
896 for(
auto& draggable : opacity_draggables)
897 draggable.set_position_and_update_uv(draggable.position);
900bool transfer_function_editor::create_preview_texture() {
901 const size_t size =
static_cast<size_t>(256);
902 std::vector<rgba> cs_data = transfer_function->quantize(size);
904 std::vector<cgv::rgba8> texture_data;
905 texture_data.reserve(size);
906 std::transform(cs_data.begin(), cs_data.end(), std::back_inserter(texture_data), [](
const cgv::rgba& color) {
907 return cgv::rgba8(color);
923bool transfer_function_editor::create_background_texture() {
924 const rgb dark(0.75f);
925 const rgb light(0.9f);
926 std::vector<rgb> data = { dark, light, light, dark };
934void transfer_function_editor::create_geometry() {
935 color_draggables_geometry.clear();
936 opacity_draggables_geometry.clear();
937 line_geometry.clear();
938 triangle_geometry.clear();
940 vec2 pos_offset =
vec2(0.0f, 0.5f * color_point_size.
y());
942 for(
const auto& draggable : color_draggables) {
943 vec2 pos = draggable.center();
944 rgba col = selected_color_draggable == &draggable ? highlight_color : handle_color;
945 color_draggables_geometry.add(pos - pos_offset, col);
946 color_draggables_geometry.add(pos + pos_offset, col);
949 if(!opacity_draggables.empty()) {
950 const auto& first = *opacity_draggables.begin();
952 vec2 tex_coord(0.0f, 0.5f);
954 line_geometry.add(
vec2(
static_cast<float>(layout.opacity_editor_rect.x()), first.center().y()), tex_coord);
956 triangle_geometry.add(
vec2(
static_cast<float>(layout.opacity_editor_rect.x()), first.center().y()), tex_coord);
957 triangle_geometry.add(layout.opacity_editor_rect.position, tex_coord);
959 for(
const auto& draggable : opacity_draggables) {
960 vec2 pos = draggable.center();
961 rgba col = selected_opacity_draggable == &draggable ? highlight_color : handle_color;
962 opacity_draggables_geometry.add(pos, col);
964 tex_coord.x() = draggable.uv.x();
966 line_geometry.add(pos, tex_coord);
968 triangle_geometry.add(pos, tex_coord);
969 triangle_geometry.add(
vec2(pos.x(),
static_cast<float>(layout.opacity_editor_rect.y())), tex_coord);
972 const auto& last = *(--opacity_draggables.end());
973 vec2 max_pos = layout.opacity_editor_rect.position +
vec2(1.0f, 0.0f) * layout.opacity_editor_rect.size;
975 tex_coord.x() = 1.0f;
977 line_geometry.add(
vec2(max_pos.x(), last.center().y()), tex_coord);
979 triangle_geometry.add(
vec2(max_pos.x(), last.center().y()), tex_coord);
980 triangle_geometry.add(max_pos, tex_coord);
More advanced text processing for splitting text into lines or tokens.
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 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
button_ptr add_button(const std::string &label, const std::string &options="", const std::string &align="\n")
use the current gui driver to append a new button with the given label
T & y()
return second component
T & x()
return first component
static cgv::type::uint32_type size()
return number of components
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
virtual void on_set(void *member_ptr) override
default implementation of that calls handle_member_change and afterwards upates the member in the gui...
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void set_size(const ivec2 &size)
set the default size of the overlay before stretch gets applied
bool blocks_events() const
return whether this overlay blocks events, i.e. does not pass them to the next event handler
cgv::g2d::irect get_rectangle() const
return the current rectangle area (in screen coordinates) of the overlay taking layout into account
void update_layout()
update the layout of the overlay container
ivec2 get_viewport_size() const
return the current viewport size
virtual void handle_theme_change(const cgv::gui::theme_info &theme) override
override in your class to handle theme changes
cgv::g2d::irect get_content_rectangle() const
return the current rectangle area of the themed_overlay content
void clear(cgv::render::context &ctx) override
clear all objects living in the context like textures or display lists
void handle_theme_change(const cgv::gui::theme_info &theme) override
override in your class to handle theme changes
void create_gui_impl() override
virtual method to implement the derived class gui creation
void handle_member_change(cgv::data::informed_ptr ptr) override
implement to handle member changes
void init_frame(cgv::render::context &ctx) override
this method is called in one pass over all drawables before the draw method
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...
bool init(cgv::render::context &ctx) override
this method is called after creation or recreation of the context, return whether all necessary funct...
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
void set_mag_filter(TextureFilter _mag_filter)
set the magnification filter
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
void set_min_filter(TextureFilter _min_filter, float _anisotropy=2.0f)
set the minification filters, if minification is set to TF_ANISOTROP, the second floating point param...
@ 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
@ MB_RIGHT_BUTTON
right button
@ MB_LEFT_BUTTON
left button
@ MA_PRESS
mouse button pressed
@ 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
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
std::vector< size_t > stable_sort_indices(const RandomIt first, const RandomIt last)
Return a sequence of indices corresponding to the sorted order of values in [first,...
this header is dependency free
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