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>
20template<>
vec2 transfer_function_editor::color_point::domain = { 0.0f, 1.0f };
21template<>
vec2 transfer_function_editor::opacity_point::domain = { 0.0f, 1.0f };
22const vec2 transfer_function_editor::color_point_size = { 12.0f, 18.0f };
23const vec2 transfer_function_editor::opacity_point_size = { 12.0f };
24const size_t transfer_function_editor::preview_texture_resolution = 256;
26transfer_function_editor::transfer_function_editor() {
30 layout.total_height = supports_opacity ? 200 : 60;
34 color_draggables.set_constraint(layout.color_draggables_rect);
35 color_draggables.callback = std::bind(&transfer_function_editor::handle_drag,
this, std::placeholders::_1, DraggableType::kColor);
37 opacity_draggables.set_constraint(layout.opacity_editor_rect);
38 opacity_draggables.callback = std::bind(&transfer_function_editor::handle_drag,
this, std::placeholders::_1, DraggableType::kOpacity);
40 color_handle_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::arrow);
41 opacity_handle_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::rectangle);
42 line_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::line);
43 polygon_renderer = cgv::g2d::generic_2d_renderer(cgv::g2d::shaders::polygon);
47 cgv::g2d::ref_msdf_font_regular(ctx, -1);
48 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, -1);
52 color_handle_renderer.destruct(ctx);
53 opacity_handle_renderer.destruct(ctx);
54 line_renderer.destruct(ctx);
55 polygon_renderer.destruct(ctx);
63 bool capture_event =
false;
71 if(!get_hit_point(local_mouse_pos)) {
72 add_point(local_mouse_pos);
77 cgv::g2d::draggable* hit_point = get_hit_point(local_mouse_pos);
79 erase_point(hit_point);
101 size.y() = layout.total_height;
106 if(transfer_function) {
107 transfer_function->set_color_interpolation(color_interpolation);
109 transfer_function->set_opacity_interpolation(opacity_interpolation);
111 create_preview_texture();
114 if(on_change_callback)
115 on_change_callback();
120 update_transfer_function_from_data();
121 create_preview_texture();
126 for(
auto& draggable : opacity_draggables) {
128 draggable.set_uv_and_update_position(draggable.uv);
129 update_transfer_function_from_data();
138 layout.total_height = supports_opacity ? 200 : 60;
139 on_set(&layout.total_height);
141 if(!supports_opacity) {
142 if(transfer_function) {
146 update_point_positions();
151 post_recreate_layout();
157 cgv::g2d::ref_msdf_font_regular(ctx, 1);
158 cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx, 1);
160 register_shader(
"rectangle", cgv::g2d::shaders::rectangle);
161 register_shader(
"circle", cgv::g2d::shaders::circle);
162 register_shader(
"histogram",
"heightfield1d.glpr");
166 success &= color_handle_renderer.init(ctx);
167 success &= opacity_handle_renderer.init(ctx);
168 success &= line_renderer.init(ctx);
169 success &= polygon_renderer.init(ctx);
170 success &= create_background_texture();
176 if(ensure_layout(ctx)) {
180 force_update_data_from_transfer_function();
182 float width_factor =
static_cast<float>(layout.opacity_editor_rect.w()) /
static_cast<float>(layout.opacity_editor_rect.h());
183 background_style.texcoord_scaling =
vec2(5.0f * width_factor, 5.0f);
185 color_draggables.set_constraint(layout.color_draggables_rect);
186 opacity_draggables.set_constraint(layout.opacity_editor_rect);
195 content_canvas.enable_shader(ctx,
"rectangle");
196 content_canvas.set_style(ctx, border_style);
197 content_canvas.draw_shape(ctx,
ivec2(padding() - 1) +
ivec2(0, 10), container_size - 2 * padding() + 2 -
ivec2(0, 10));
199 if(transfer_function && preview_tex.
is_created()) {
201 content_canvas.set_style(ctx, color_map_style);
202 preview_tex.
enable(ctx, 0);
203 content_canvas.draw_shape(ctx, layout.color_editor_rect);
206 if(supports_opacity) {
208 content_canvas.set_style(ctx, background_style);
209 background_tex.
enable(ctx, 0);
210 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
214 if(histogram_type != HistogramType::kNone && histogram_tex.
is_created()) {
215 auto& hist_prog = content_canvas.enable_shader(ctx,
"histogram");
216 hist_prog.set_uniform(ctx,
"max_value", hist_norm_ignore_zero ? hist_max_non_zero : hist_max);
217 hist_prog.set_uniform(ctx,
"norm_gamma", hist_norm_gamma);
218 hist_prog.set_uniform(ctx,
"sampling_type", cgv::math::clamp(
static_cast<unsigned>(histogram_type) - 1, 0u, 2u));
219 histogram_style.apply(ctx, hist_prog);
221 histogram_tex.
enable(ctx, 1);
222 content_canvas.draw_shape(ctx, layout.opacity_editor_rect);
224 content_canvas.disable_current_shader(ctx);
227 preview_tex.
enable(ctx, 0);
229 polygon_renderer.render(ctx, content_canvas, cgv::render::PT_TRIANGLE_STRIP, triangle_geometry, polygon_style);
232 line_renderer.render(ctx, content_canvas, cgv::render::PT_LINE_STRIP, line_geometry, line_style);
236 content_canvas.enable_shader(ctx,
"rectangle");
237 content_canvas.set_style(ctx, border_style);
238 content_canvas.draw_shape(ctx,
239 ivec2(layout.color_editor_rect.x(), layout.color_editor_rect.y1()),
240 ivec2(container_size.
x() - 2 * padding(), 1)
242 content_canvas.disable_current_shader(ctx);
247 color_handle_renderer.render(ctx, content_canvas, cgv::render::PT_LINES, color_draggables_geometry, color_handle_style);
250 if(supports_opacity) {
251 auto& opacity_handle_prog = opacity_handle_renderer.enable_prog(ctx);
252 opacity_handle_prog.set_attribute(ctx,
"size", opacity_point_size);
253 opacity_handle_renderer.render(ctx, content_canvas, cgv::render::PT_POINTS, opacity_draggables_geometry, opacity_handle_style);
256 content_canvas.disable_current_shader(ctx);
259 auto& font = cgv::g2d::ref_msdf_font_regular(ctx);
260 auto& font_renderer = cgv::g2d::ref_msdf_gl_font_renderer_2d(ctx);
261 cgv::g2d::msdf_gl_font_renderer::text_render_info text_render_info;
263 if(!value_label.empty()) {
264 cgv::g2d::irect rectangle = value_label_rectangle;
265 rectangle.translate(0, 5);
266 rectangle.size +=
ivec2(10, 6);
268 content_canvas.enable_shader(ctx,
"rectangle");
269 content_canvas.set_style(ctx, label_box_style);
270 content_canvas.draw_shape(ctx, rectangle);
271 content_canvas.disable_current_shader(ctx);
274 font_renderer.render(ctx, content_canvas, font, value_label, value_label_rectangle.position, text_render_info, value_label_style);
289 std::string height_options =
"min=";
290 height_options += supports_opacity ?
"80" :
"40";
291 height_options +=
";max=500;step=10;ticks=true";
292 add_member_control(
this,
"Height", layout.total_height,
"value_slider", height_options);
297 add_decorator(
"Color",
"heading",
"level=4;font_style=regular;w=94",
" ");
298 add_decorator(
"Opacity",
"heading",
"level=4;font_style=regular;w=94",
"%y-=6\n");
299 const std::string interpolation_enums =
"enums='Step,Linear,Smooth'";
300 add_member_control(
this,
"Interpolation", color_interpolation,
"dropdown", interpolation_enums +
";w=94",
" ");
301 add_member_control(
this,
"", opacity_interpolation,
"dropdown", interpolation_enums +
";w=94");
305 cgv::signal::connect_copy(
add_button(
"Rescale")->click, cgv::signal::rebind(
this, &transfer_function_editor::rescale_domain));
309 auto& points = color_draggables;
310 for(
size_t i = 0; i < points.size(); ++i) {
311 std::string label_prefix =
"";
312 std::string options =
"w=48";
313 if(&points[i] == selected_color_draggable) {
315 options +=
";label_color=" + cgv::media::to_hex(highlight_color);
318 add_view(label_prefix + std::to_string(i), points[i].domain_value,
"", options,
" ");
325 if(supports_opacity) {
328 auto& points = opacity_draggables;
329 for(
size_t i = 0; i < points.size(); ++i) {
330 std::string label_prefix =
"";
331 std::string options =
"w=48";
332 if(&points[i] == selected_opacity_draggable) {
334 options +=
";label_color=" + cgv::media::to_hex(highlight_color);
337 add_view(label_prefix + std::to_string(i), points[i].domain_value,
"", options,
" ");
346 cgv::signal::connect_copy(
add_button(
"Set selected position")->click, cgv::signal::rebind(
this, &transfer_function_editor::set_selected_point_domain_value));
350 add_member_control(
this,
"Type", histogram_type,
"dropdown",
"enums='None,Nearest,Linear,Smooth'");
351 add_member_control(
this,
"Ignore Zero for Normalization", hist_norm_ignore_zero,
"check");
352 add_member_control(
this,
"Gamma", hist_norm_gamma,
"value_slider",
"min=0.001;max=2;step=0.001;ticks=true");
355 add_member_control(
this,
"Border Width", histogram_style.border_width,
"value_slider",
"min=0;max=10;step=0.5;ticks=true");
361void transfer_function_editor::set_opacity_support(
bool flag) {
362 supports_opacity = flag;
364 on_set(&supports_opacity);
367void transfer_function_editor::set_transfer_function(std::shared_ptr<cgv::media::transfer_function> transfer_function) {
368 if(this->transfer_function != transfer_function) {
369 this->transfer_function = transfer_function;
373 this->transfer_function = transfer_function;
374 update_data_from_transfer_function();
378void transfer_function_editor::set_histogram_data(
const std::vector<unsigned> data) {
381 std::vector<float> float_data(histogram.size(), 0.0f);
383 hist_max_non_zero = 1;
384 for(
size_t i = 0; i < histogram.size(); ++i) {
385 unsigned count = histogram[i];
386 hist_max = std::max(hist_max, count);
388 hist_max_non_zero = std::max(hist_max_non_zero, count);
389 float_data[i] =
static_cast<float>(count);
399void transfer_function_editor::set_selected_color(
rgb color) {
400 if(selected_color_draggable) {
401 selected_color_draggable->data = color;
402 on_set(&selected_color_draggable->data);
407void transfer_function_editor::init_styles() {
408 auto& theme = cgv::gui::theme_info::instance();
409 handle_color = theme.text();
410 highlight_color = theme.highlight();
413 border_style.fill_color = theme.border();
414 border_style.border_width = 0.0f;
415 border_style.feather_width = 0.0f;
418 color_map_style = border_style;
419 color_map_style.use_texture =
true;
422 background_style.use_texture =
true;
423 background_style.feather_width = 0.0f;
426 histogram_style.use_blending =
true;
427 histogram_style.feather_width = 1.0f;
428 histogram_style.feather_origin = 0.0f;
429 histogram_style.fill_color =
rgba(
rgb(0.5f), 0.666f);
430 histogram_style.border_color =
rgba(
rgb(0.0f), 0.666f);
431 histogram_style.border_width = 1.0f;
434 color_handle_style.use_blending =
true;
435 color_handle_style.use_fill_color =
false;
436 color_handle_style.position_is_center =
true;
437 color_handle_style.border_color = theme.border();
438 color_handle_style.border_width = 1.5f;
439 color_handle_style.border_radius = 2.0f;
440 color_handle_style.stem_width = color_point_size.
x();
441 color_handle_style.head_width = color_point_size.
x();
443 label_box_style.position_is_center =
true;
444 label_box_style.use_blending =
true;
445 label_box_style.fill_color = handle_color;
446 label_box_style.border_color = theme.border();
447 label_box_style.border_width = 1.5f;
448 label_box_style.border_radius = 4.0f;
451 opacity_handle_style.use_blending =
true;
452 opacity_handle_style.use_fill_color =
false;
453 opacity_handle_style.position_is_center =
true;
454 opacity_handle_style.border_color = theme.border();
455 opacity_handle_style.border_width = 1.5f;
458 line_style.use_blending =
true;
459 line_style.use_fill_color =
false;
460 line_style.use_texture =
true;
461 line_style.use_texture_alpha =
false;
462 line_style.width = 3.0f;
464 polygon_style =
static_cast<cgv::g2d::shape2d_style
>(line_style);
465 polygon_style.use_texture_alpha =
true;
468 cursor_label_style.fill_color =
rgb(0.0f);
469 cursor_label_style.font_size = 16.0f;
471 value_label_style.fill_color = theme.group();
472 value_label_style.font_size = 12.0f;
476 int content_height = layout.total_height - 10 - 2 * padding();
477 if(supports_opacity) {
478 layout.color_editor_height =
static_cast<int>(floor(0.15f *
static_cast<float>(content_height)));
479 layout.color_editor_height = cgv::math::clamp(layout.color_editor_height, 4, 80);
480 layout.opacity_editor_height = content_height - layout.color_editor_height - 1;
482 layout.color_editor_height = content_height;
483 layout.opacity_editor_height = 0;
486 int y_off = padding();
488 layout.color_draggables_rect = {
489 ivec2(padding(), 16),
490 ivec2(parent_size.x() - 2 * padding(), 0)
496 layout.color_editor_rect.position =
ivec2(padding(), y_off);
497 layout.color_editor_rect.size =
ivec2(parent_size.x() - 2 * padding(), layout.color_editor_height);
499 y_off += layout.color_editor_height + 1;
501 layout.opacity_editor_rect.position =
ivec2(padding(), y_off);
502 layout.opacity_editor_rect.size =
ivec2(parent_size.x() - 2 * padding(), layout.opacity_editor_height);
505void transfer_function_editor::clear_data() {
506 selected_color_draggable =
nullptr;
507 selected_opacity_draggable =
nullptr;
508 color_draggables.clear();
509 opacity_draggables.clear();
510 color_draggables_geometry.clear();
511 opacity_draggables_geometry.clear();
512 line_geometry.clear();
513 triangle_geometry.clear();
516void transfer_function_editor::force_update_data_from_transfer_function() {
517 if(!transfer_function)
520 size_t previous_color_point_count = color_draggables.size();
521 size_t previous_opacity_point_count = opacity_draggables.size();
525 const vec2 domain = transfer_function->get_domain();
526 input_domain = domain;
529 color_point::domain = domain;
530 opacity_point::domain = domain;
532 for(
const auto& point : transfer_function->get_color_points()) {
533 color_point draggable = make_color_point();
534 draggable.data = point.second;
535 const vec2 uv = { cgv::math::normalize(point.first, domain[0], domain[1]), 0.0f };
536 draggable.set_uv_and_update_position(uv);
537 color_draggables.add(draggable);
540 if(supports_opacity) {
541 for(
const auto& point : transfer_function->get_opacity_points()) {
542 opacity_point draggable = make_opacity_point();
543 const vec2 uv = { cgv::math::normalize(point.first, domain[0], domain[1]), point.second };
544 draggable.set_uv_and_update_position(uv);
545 opacity_draggables.add(draggable);
550 create_preview_texture();
552 color_interpolation = transfer_function->get_color_interpolation();
553 opacity_interpolation = transfer_function->get_opacity_interpolation();
556 if(previous_color_point_count == color_draggables.size() && previous_opacity_point_count == opacity_draggables.size()) {
559 for(
auto& point : color_draggables) {
563 for(
auto& point : opacity_draggables) {
574void transfer_function_editor::update_data_from_transfer_function() {
575 if(!transfer_function)
578 if(!build_time.is_valid() || transfer_function->get_modified_time() > build_time.get_modified_time()) {
579 force_update_data_from_transfer_function();
580 build_time.modified();
584void transfer_function_editor::update_transfer_function_from_data() {
585 if(!transfer_function)
588 std::vector<std::pair<float, rgb>> colors;
589 std::vector<std::pair<float, float>> opacities;
591 const vec2 domain = transfer_function->get_domain();
593 auto map_to_domain = [domain](
float u) {
594 return cgv::math::map(u, 0.0f, 1.0f, domain[0], domain[1]);
597 std::transform(color_draggables.begin(), color_draggables.end(), std::back_inserter(colors), [&map_to_domain](
const color_point& point) {
598 return std::make_pair(map_to_domain(point.uv.x()), point.data);
600 std::transform(opacity_draggables.begin(), opacity_draggables.end(), std::back_inserter(opacities), [&map_to_domain](
const opacity_point& point) {
601 return std::make_pair(map_to_domain(point.uv.x()), point.uv.y());
604 transfer_function->set_color_points(colors);
605 transfer_function->set_opacity_points(opacities);
607 if(on_change_callback)
608 on_change_callback();
611void transfer_function_editor::rescale_domain() {
612 if(transfer_function) {
613 transfer_function->rescale(input_domain);
614 update_data_from_transfer_function();
616 if(on_change_callback)
617 on_change_callback();
621cgv::g2d::draggable* transfer_function_editor::get_hit_point(
const vec2& pos) {
622 const auto& contains = [&pos](
const auto& draggable) {
623 return draggable.contains(pos);
626 auto color_it = std::find_if(color_draggables.begin(), color_draggables.end(), contains);
627 if(color_it != color_draggables.end())
630 auto opacity_it = std::find_if(opacity_draggables.begin(), opacity_draggables.end(), contains);
631 if(opacity_it != opacity_draggables.end())
638bool is_boundary_point(
const T* point, cgv::g2d::draggable_collection<T>& draggables) {
639 if(draggables.empty())
641 return point == &draggables.ref_draggables().front() || point == &draggables.ref_draggables().back();
644void transfer_function_editor::add_point(
const vec2& pos) {
645 if(!transfer_function)
650 selected_color_draggable =
nullptr;
651 selected_opacity_draggable =
nullptr;
653 if(layout.color_editor_rect.contains(test_pos)) {
654 color_point draggable = make_color_point();
655 draggable.set_position_and_update_uv({ pos.x(), 0.0f });
656 draggable.data = transfer_function->get_mapped_color(draggable.uv.x());
657 size_t index = color_draggables.add(draggable);
658 selected_color_draggable = &color_draggables[index];
659 }
else if(supports_opacity && layout.opacity_editor_rect.contains(test_pos)) {
660 opacity_point draggable = make_opacity_point();
661 draggable.set_position_and_update_uv(pos);
662 size_t index = opacity_draggables.add(draggable);
663 selected_opacity_draggable = &opacity_draggables[index];
667 update_transfer_function_from_data();
668 handle_selection_change();
673void transfer_function_editor::erase_point(
const cgv::g2d::draggable* point) {
674 const auto& try_erase_point_from = [point](
auto& draggables) {
675 if(draggables.size() > 1) {
676 if(point == &draggables.ref_draggables().front() || point == &draggables.ref_draggables().back())
679 auto it = std::remove_if(draggables.begin(), draggables.end(), [point](
const cgv::g2d::draggable& draggable) {
680 return &draggable == point;
682 if(it != draggables.end()) {
683 draggables.ref_draggables().erase(it);
690 if(try_erase_point_from(color_draggables) || try_erase_point_from(opacity_draggables)) {
691 selected_color_draggable =
nullptr;
692 selected_opacity_draggable =
nullptr;
693 update_transfer_function_from_data();
694 handle_selection_change();
695 create_preview_texture();
701void transfer_function_editor::set_selected_point_domain_value() {
702 if(!transfer_function)
705 const vec2 domain = transfer_function->get_domain();
706 const float x = cgv::math::clamp(input_position, domain[0], domain[1]);
707 const float u = cgv::math::normalize(x, domain[0], domain[1]);
709 if(selected_color_draggable && !is_boundary_point(selected_color_draggable, color_draggables)) {
710 selected_color_draggable->set_uv_and_update_position({ u, 0.0f });
713 else if(selected_opacity_draggable && !is_boundary_point(selected_opacity_draggable, opacity_draggables)) {
714 selected_opacity_draggable->set_uv_and_update_position({ u, selected_opacity_draggable->uv.
y() });
719 update_transfer_function_from_data();
720 create_preview_texture();
725void transfer_function_editor::set_value_label(
vec2 position,
const std::string& text) {
727 value_label_rectangle.position = position;
730 auto& font = cgv::g2d::ref_msdf_font_regular(*
get_context());
731 value_label_rectangle.size = font.compute_render_size(value_label, value_label_style.font_size);
735 constraint.scale(-0.5f * (value_label_rectangle.size + 4.0f));
736 value_label_rectangle.position = cgv::math::clamp(value_label_rectangle.position, constraint.a(), constraint.b());
739void transfer_function_editor::handle_drag(cgv::g2d::DragAction action, DraggableType type) {
740 bool modified =
false;
743 case cgv::g2d::DragAction::kDragStart:
744 if(type == DraggableType::kColor) {
745 color_point* dragged = color_draggables.get_dragged();
747 color_draggable_start_position = dragged->position;
748 }
else if(type == DraggableType::kOpacity) {
749 opacity_point* dragged = opacity_draggables.get_dragged();
751 opacity_draggable_start_position = dragged->position;
753 case cgv::g2d::DragAction::kDrag:
754 if(type == DraggableType::kColor) {
755 color_point* dragged = color_draggables.get_dragged();
757 if(is_boundary_point(dragged, color_draggables))
758 dragged->position = color_draggable_start_position;
761 dragged->set_position_and_update_uv(dragged->position);
763 dragged->position +
cgv::vec2(0.0f, 25.0f),
764 value_to_string(dragged->uv.x())
766 selected_color_draggable = dragged;
767 selected_opacity_draggable =
nullptr;
770 }
else if(type == DraggableType::kOpacity) {
771 opacity_point* dragged = opacity_draggables.get_dragged();
773 if(is_boundary_point(dragged, opacity_draggables))
774 dragged->position.x() = opacity_draggable_start_position.
x();
777 dragged->set_position_and_update_uv(dragged->position);
780 dragged->position +
cgv::vec2(0.0f, 10.0f),
783 selected_opacity_draggable = dragged;
784 selected_color_draggable =
nullptr;
789 handle_selection_change();
791 case cgv::g2d::DragAction::kDragEnd:
792 handle_selection_change();
804 update_transfer_function_from_data();
805 create_preview_texture();
811void transfer_function_editor::handle_selection_change() {
812 if(selected_color_draggable) {
813 if(on_color_point_select_callback)
814 on_color_point_select_callback(selected_color_draggable->data);
816 if(on_color_point_deselect_callback)
817 on_color_point_deselect_callback();
822std::string transfer_function_editor::value_to_string(
float value) {
823 if(!transfer_function)
826 const vec2 domain = transfer_function->get_domain();
827 float display_value = cgv::math::lerp(domain.x(), domain.y(), value);
829 float total = domain.y() - domain.x();
835 int display_value_int =
static_cast<int>(round(display_value));
836 return std::to_string(display_value_int);
841void sort_draggables(cgv::g2d::draggable_collection<T>& draggables, T*& selected) {
842 if(draggables.empty())
845 int dragged_idx = -1;
846 int selected_idx = -1;
848 for(
size_t i = 0; i < draggables.size(); ++i) {
849 if(&draggables[i] == draggables.get_dragged())
850 dragged_idx =
static_cast<int>(i);
851 if(&draggables[i] == selected)
852 selected_idx =
static_cast<int>(i);
855 std::vector<T> draggables_copy = draggables.ref_draggables();
858 for(
size_t i = 0; i < permutation.size(); ++i) {
859 int permuted_index =
static_cast<int>(permutation[i]);
860 draggables[i] = draggables_copy[permuted_index];
861 if(permuted_index == dragged_idx)
862 draggables.set_dragged(
int(i));
863 if(permuted_index == selected_idx)
864 selected = &draggables[i];
868void transfer_function_editor::sort_points() {
869 sort_draggables(color_draggables, selected_color_draggable);
871 sort_draggables(opacity_draggables, selected_opacity_draggable);
874void transfer_function_editor::update_point_positions() {
875 for(
auto& draggable : color_draggables)
876 draggable.set_position_and_update_uv(draggable.position);
878 for(
auto& draggable : opacity_draggables)
879 draggable.set_position_and_update_uv(draggable.position);
882bool transfer_function_editor::create_preview_texture() {
883 std::vector<rgba> cs_data = transfer_function->quantize(preview_texture_resolution);
885 std::vector<cgv::rgba8> texture_data;
886 texture_data.reserve(preview_texture_resolution);
887 std::transform(cs_data.begin(), cs_data.end(), std::back_inserter(texture_data), [](
const cgv::rgba& color) {
888 return cgv::rgba8(color);
904bool transfer_function_editor::create_background_texture() {
905 const rgb dark(0.75f);
906 const rgb light(0.9f);
907 std::vector<rgb> data = { dark, light, light, dark };
915void transfer_function_editor::create_geometry() {
916 color_draggables_geometry.clear();
917 opacity_draggables_geometry.clear();
918 line_geometry.clear();
919 triangle_geometry.clear();
921 vec2 pos_offset =
vec2(0.0f, 0.5f * color_point_size.
y());
923 for(
const auto& draggable : color_draggables) {
924 vec2 pos = draggable.center();
925 rgba col = selected_color_draggable == &draggable ? highlight_color : handle_color;
926 color_draggables_geometry.add(pos - pos_offset, col);
927 color_draggables_geometry.add(pos + pos_offset, col);
930 if(!opacity_draggables.empty()) {
931 const auto& first = *opacity_draggables.begin();
933 vec2 tex_coord(0.0f, 0.5f);
935 line_geometry.add(
vec2(
static_cast<float>(layout.opacity_editor_rect.x()), first.center().y()), tex_coord);
937 triangle_geometry.add(
vec2(
static_cast<float>(layout.opacity_editor_rect.x()), first.center().y()), tex_coord);
938 triangle_geometry.add(layout.opacity_editor_rect.position, tex_coord);
940 for(
const auto& draggable : opacity_draggables) {
941 vec2 pos = draggable.center();
942 rgba col = selected_opacity_draggable == &draggable ? highlight_color : handle_color;
943 opacity_draggables_geometry.add(pos, col);
945 tex_coord.x() = draggable.uv.x();
947 line_geometry.add(pos, tex_coord);
949 triangle_geometry.add(pos, tex_coord);
950 triangle_geometry.add(
vec2(pos.x(),
static_cast<float>(layout.opacity_editor_rect.y())), tex_coord);
953 const auto& last = *(--opacity_draggables.end());
954 vec2 max_pos = layout.opacity_editor_rect.position +
vec2(1.0f, 0.0f) * layout.opacity_editor_rect.size;
956 tex_coord.x() = 1.0f;
958 line_geometry.add(
vec2(max_pos.x(), last.center().y()), tex_coord);
960 triangle_geometry.add(
vec2(max_pos.x(), last.center().y()), tex_coord);
961 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
void draw_content(cgv::render::context &ctx) override
draw_content is implemented by decendent classes
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