24using namespace helios;
29 contextUUIDs_build.clear();
30 colorPrimitives_UUIDs.clear();
31 colorPrimitives_objIDs.clear();
32 contextUUIDs_build.clear();
33 depth_buffer_data.clear();
43 std::vector<vec3> vertices;
49 vertices.at(0) = center + v0;
54 vertices.at(1) = center + v1;
59 vertices.at(2) = center + v2;
64 vertices.at(3) = center + v3;
70 std::vector<vec3> vertices;
76 vertices.at(0) = center + v0;
81 vertices.at(1) = center + v1;
86 vertices.at(2) = center + v2;
91 vertices.at(3) = center + v3;
97 std::vector<vec3> vertices;
103 vertices.at(0) = center + v0;
108 vertices.at(1) = center + v1;
113 vertices.at(2) = center + v2;
118 vertices.at(3) = center + v3;
124 std::vector<vec3> vertices;
130 vertices.at(0) = center + v0;
135 vertices.at(1) = center + v1;
140 vertices.at(2) = center + v2;
145 vertices.at(3) = center + v3;
158 for (
auto vertex: vertices) {
159 if (vertex.x < 0.f || vertex.x > 1.f) {
161 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x <<
" ) is outside of drawable area." << std::endl;
163 }
else if (vertex.y < 0.f || vertex.y > 1.f) {
165 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y <<
" ) is outside of drawable area." << std::endl;
167 }
else if (vertex.z < -1.f || vertex.z > 1.f) {
169 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z <<
" ) is outside of drawable area." << std::endl;
176 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, color, {}, -1,
false,
false, coordFlag,
true,
false);
181 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
189 for (
auto vertex: vertices) {
190 if (vertex.x < 0.f || vertex.x > 1.f) {
192 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x <<
" ) is outside of drawable area." << std::endl;
194 }
else if (vertex.y < 0.f || vertex.y > 1.f) {
196 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y <<
" ) is outside of drawable area." << std::endl;
198 }
else if (vertex.z < -1.f || vertex.z > 1.f) {
200 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z <<
" ) is outside of drawable area." << std::endl;
206 uint textureID = registerTextureImage(texture_file);
209 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, RGBA::black, uvs, textureID,
false,
false, coordFlag,
true,
false);
214 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
222 for (
auto vertex: vertices) {
223 if (vertex.x < 0.f || vertex.x > 1.f) {
225 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x <<
" ) is outside of drawable area." << std::endl;
227 }
else if (vertex.y < 0.f || vertex.y > 1.f) {
229 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y <<
" ) is outside of drawable area." << std::endl;
231 }
else if (vertex.z < -1.f || vertex.z > 1.f) {
233 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z <<
" ) is outside of drawable area." << std::endl;
239 uint textureID = registerTextureImage(texture_file);
242 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices,
make_RGBAcolor(color, 1.f), uvs, textureID,
false,
false, coordFlag,
true,
false);
254 for (
auto vertex: vertices) {
255 if (vertex.x < 0.f || vertex.x > 1.f) {
257 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `x' position ( " << vertex.x <<
" ) is outside of drawable area." << std::endl;
259 }
else if (vertex.y < 0.f || vertex.y > 1.f) {
261 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `y' position ( " << vertex.y <<
" ) is outside of drawable area." << std::endl;
263 }
else if (vertex.z < -1.f || vertex.z > 1.f) {
265 std::cerr <<
"WARNING (Visualizer::addRectangleByVertices): Rectangle `z' position ( " << vertex.z <<
" ) is outside of drawable area." << std::endl;
271 uint textureID = registerTextureGlyph(glyph);
273 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
278 coordFlag2 = scast<CoordinateSystem>(2);
282 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, color, uvs, textureID,
true,
true, coordFlag2,
true,
false);
291 const std::vector<vec3> vertices{vertex0, vertex1, vertex2};
293 if (coordFlag == 0) {
296 for (
const auto &vertex: vertices) {
297 if (vertex.x < 0.f || vertex.x > 1.f) {
299 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `x' position ( " << vertex.
x <<
" ) is outside of drawable area." << std::endl;
301 }
else if (vertex.y < 0.f || vertex.y > 1.f) {
303 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `y' position ( " << vertex.y <<
" ) is outside of drawable area." << std::endl;
305 }
else if (vertex.z < -1.f || vertex.z > 1.f) {
307 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `z' position ( " << vertex.z <<
" ) is outside of drawable area." << std::endl;
314 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_TRIANGLE, vertices, color, {}, -1,
false,
false, coordFlag,
true,
false);
319 const std::vector<vec3> vertices{vertex0, vertex1, vertex2};
320 const std::vector<vec2> uvs{uv0, uv1, uv2};
322 if (coordFlag == 0) {
325 for (
auto &vertex: vertices) {
326 if (vertex.x < 0.f || vertex.x > 1.f) {
328 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `x' position ( " << vertex.
x <<
" ) is outside of drawable area." << std::endl;
330 }
else if (vertex.y < 0.f || vertex.y > 1.f) {
332 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `y' position ( " << vertex.y <<
" ) is outside of drawable area." << std::endl;
334 }
else if (vertex.z < -1.f || vertex.z > 1.f) {
336 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `z' position ( " << vertex.z <<
" ) is outside of drawable area." << std::endl;
342 uint textureID = registerTextureImage(texture_file);
345 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_TRIANGLE, vertices, RGBA::black, uvs, textureID,
false,
false, coordFlag,
true,
false);
350 const std::vector<vec3> vertices{vertex0, vertex1, vertex2};
351 const std::vector<vec2> uvs{uv0, uv1, uv2};
353 if (coordFlag == 0) {
356 for (
const auto &tri_vertex: vertices) {
357 if (tri_vertex.x < 0.f || tri_vertex.x > 1.f) {
359 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `x' position ( " << tri_vertex.
x <<
" ) is outside of drawable area." << std::endl;
361 }
else if (tri_vertex.y < 0.f || tri_vertex.y > 1.f) {
363 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `y' position ( " << tri_vertex.y <<
" ) is outside of drawable area." << std::endl;
365 }
else if (tri_vertex.z < -1.f || tri_vertex.z > 1.f) {
367 std::cerr <<
"WARNING (Visualizer::addTriangle): Triangle `z' position ( " << tri_vertex.z <<
" ) is outside of drawable area." << std::endl;
373 uint textureID = registerTextureImage(texture_file);
376 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_TRIANGLE, vertices, color, uvs, textureID,
true,
false, coordFlag,
true,
false);
389 std::vector<size_t> UUIDs(6);
403 const vec3 c4 = center +
make_vec3(0.f, 0.f, -0.5f * size.
z) + eps;
406 const vec3 c5 = center +
make_vec3(0.f, 0.f, 0.5f * size.
z) + eps;
417 const std::vector<vec3> vertices{start, end};
420 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_LINE, vertices, color, {}, -1,
false,
false, coordFlag,
true,
false);
430 if (line_width <= 0.0f) {
431 helios_runtime_error(
"ERROR (Visualizer::addLine): Line width must be positive (got " + std::to_string(line_width) +
"). Please specify a positive line width value.");
436 const float MAX_LINE_WIDTH = 100.0f;
437 if (line_width > MAX_LINE_WIDTH) {
438 helios_runtime_error(
"ERROR (Visualizer::addLine): Line width " + std::to_string(line_width) +
" exceeds maximum supported width (" + std::to_string(MAX_LINE_WIDTH) +
"). Please specify a smaller line width value.");
441 const std::vector<vec3> vertices{start, end};
444 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_LINE, vertices, color, {}, -1,
false,
false, coordFlag,
true,
false,
false, line_width);
454 if (!headless && window !=
nullptr) {
457 const float MIN_POINT_SIZE = 1.0f;
458 const float MAX_POINT_SIZE = 64.0f;
460 if (pointsize < MIN_POINT_SIZE || pointsize > MAX_POINT_SIZE) {
461 std::cerr <<
"WARNING (Visualizer::addPoint): Point size ( " << pointsize <<
" ) is outside of supported range ( " << MIN_POINT_SIZE <<
", " << MAX_POINT_SIZE <<
" ). Clamping value.." << std::endl;
462 if (pointsize < MIN_POINT_SIZE) {
463 pointsize = MIN_POINT_SIZE;
465 pointsize = MAX_POINT_SIZE;
469 this->point_width = pointsize;
472 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_POINT, {position}, color, {}, -1,
false,
false, coordinate_system,
true,
false, pointsize);
481 float dtheta =
PI_F / scast<float>(Ndivisions);
482 float dphi = 2.f *
PI_F / scast<float>(Ndivisions);
484 std::vector<size_t> UUIDs;
485 UUIDs.reserve(2 * Ndivisions + 2 * (Ndivisions - 2) * (Ndivisions - 1));
488 for (
int j = 0; j < Ndivisions; j++) {
489 float phi = scast<float>(j) * dphi;
490 float phi_plus = scast<float>(j + 1) * dphi;
496 UUIDs.push_back(
addTriangle(v0, v1, v2, color, coordinate_system));
500 for (
int j = 0; j < Ndivisions; j++) {
501 float phi = scast<float>(j) * dphi;
502 float phi_plus = scast<float>(j + 1) * dphi;
508 UUIDs.push_back(
addTriangle(v2, v1, v0, color, coordinate_system));
512 for (
int j = 0; j < Ndivisions; j++) {
513 float phi = scast<float>(j) * dphi;
514 float phi_plus = scast<float>(j + 1) * dphi;
515 for (
int i = 1; i < Ndivisions - 1; i++) {
516 float theta = -0.5f *
PI_F + scast<float>(i) * dtheta;
517 float theta_plus = -0.5f *
PI_F + scast<float>(i + 1) * dtheta;
524 UUIDs.push_back(
addTriangle(v0, v1, v2, color, coordinate_system));
525 UUIDs.push_back(
addTriangle(v0, v2, v3, color, coordinate_system));
535 std::cerr <<
"WARNING (Visualizer::addSkyDomeByCenter): This method is deprecated and will be removed in a future version. "
536 <<
"Please use Visualizer::setBackgroundSkyTexture() instead, which provides a more robust sky rendering solution "
537 <<
"that dynamically scales with camera movement and avoids the need to pre-specify a radius." << std::endl;
539 float thetaStart = -0.1f *
PI_F;
541 float dtheta = (0.5f *
PI_F - thetaStart) /
float(Ndivisions - 1);
542 float dphi = 2.f *
PI_F / float(Ndivisions - 1);
544 std::vector<size_t> UUIDs;
545 UUIDs.reserve(2u * Ndivisions * Ndivisions);
550 for (
int j = 0; j < scast<int>(Ndivisions - 1); j++) {
552 vec3 v0 = center + radius * cart;
554 vec3 v1 = center + radius * cart;
556 vec3 v2 = center + radius * cart;
558 vec3 n0 = v0 - center;
560 vec3 n1 = v1 - center;
562 vec3 n2 = v2 - center;
565 vec2 uv0 =
make_vec2(1.f - atan2f(sinf((
float(j) + 0.5f) * dphi), -cosf((
float(j) + 0.5f) * dphi)) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
566 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
567 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
569 if (j == scast<int>(Ndivisions - 2)) {
573 UUIDs.push_back(
addTriangle(v0, v1, v2, texture_file, uv0, uv1, uv2, scast<CoordinateSystem>(2)));
577 for (
int j = 0; j < scast<int>(Ndivisions - 1); j++) {
578 for (
int i = 0; i < scast<int>(Ndivisions - 1); i++) {
580 vec3 v0 = center + radius * cart;
582 vec3 v1 = center + radius * cart;
584 vec3 v2 = center + radius * cart;
586 vec3 v3 = center + radius * cart;
588 vec3 n0 = v0 - center;
590 vec3 n1 = v1 - center;
592 vec3 n2 = v2 - center;
594 vec3 n3 = v3 - center;
597 vec2 uv0 =
make_vec2(1.f - atan2f(n0.
x, -n0.
y) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
598 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
599 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
600 vec2 uv3 =
make_vec2(1.f - atan2f(n3.
x, -n3.
y) / (2.f *
PI_F) - 0.5f, 1.f - n3.
z * 0.5f - 0.5f);
602 if (j == scast<int>(Ndivisions - 2)) {
607 UUIDs.push_back(
addTriangle(v0, v1, v2, texture_file, uv0, uv1, uv2, scast<CoordinateSystem>(2)));
608 UUIDs.push_back(
addTriangle(v0, v2, v3, texture_file, uv0, uv2, uv3, scast<CoordinateSystem>(2)));
614 std::cerr <<
"WARNING (Visualizer::addSkyDomeByCenter): This method is deprecated and will be removed in a future version. "
615 <<
"Please use Visualizer::setBackgroundSkyTexture() instead, which provides a more robust sky rendering solution "
616 <<
"that dynamically scales with camera movement and avoids the need to pre-specify a radius." << std::endl;
618 float thetaStart = -0.1f *
PI_F;
620 float dtheta = (0.5f *
PI_F - thetaStart) /
float(Ndivisions - 1);
621 float dphi = 2.f *
PI_F / float(Ndivisions - 1);
623 std::vector<size_t> UUIDs;
624 UUIDs.reserve(2u * Ndivisions * Ndivisions);
629 for (
int j = 0; j < scast<int>(Ndivisions - 1); j++) {
631 vec3 v0 = center + radius * cart;
633 vec3 v1 = center + radius * cart;
635 vec3 v2 = center + radius * cart;
637 vec3 n0 = v0 - center;
639 vec3 n1 = v1 - center;
641 vec3 n2 = v2 - center;
644 vec2 uv0 =
make_vec2(1.f - atan2f(sinf((
float(j) + 0.5f) * dphi), -cosf((
float(j) + 0.5f) * dphi)) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
645 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
646 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
648 if (j == scast<int>(Ndivisions - 2)) {
652 UUIDs.push_back(
addTriangle(v0, v1, v2, texture_file, uv0, uv1, uv2, scast<CoordinateSystem>(2)));
656 for (
int j = 0; j < scast<int>(Ndivisions - 1); j++) {
657 for (
int i = 0; i < scast<int>(Ndivisions - 1); i++) {
659 vec3 v0 = center + radius * cart;
661 vec3 v1 = center + radius * cart;
663 vec3 v2 = center + radius * cart;
665 vec3 v3 = center + radius * cart;
667 vec3 n0 = v0 - center;
669 vec3 n1 = v1 - center;
671 vec3 n2 = v2 - center;
673 vec3 n3 = v3 - center;
676 vec2 uv0 =
make_vec2(1.f - atan2f(n0.
x, -n0.
y) / (2.f *
PI_F) - 0.5f, 1.f - n0.
z * 0.5f - 0.5f);
677 vec2 uv1 =
make_vec2(1.f - atan2f(n1.
x, -n1.
y) / (2.f *
PI_F) - 0.5f, 1.f - n1.
z * 0.5f - 0.5f);
678 vec2 uv2 =
make_vec2(1.f - atan2f(n2.
x, -n2.
y) / (2.f *
PI_F) - 0.5f, 1.f - n2.
z * 0.5f - 0.5f);
679 vec2 uv3 =
make_vec2(1.f - atan2f(n3.
x, -n3.
y) / (2.f *
PI_F) - 0.5f, 1.f - n3.
z * 0.5f - 0.5f);
681 if (j == scast<int>(Ndivisions - 2)) {
686 UUIDs.push_back(
addTriangle(v0, v1, v2, texture_file, uv0, uv1, uv2, scast<CoordinateSystem>(2)));
687 UUIDs.push_back(
addTriangle(v0, v2, v3, texture_file, uv0, uv2, uv3, scast<CoordinateSystem>(2)));
699 if (FT_Init_FreeType(&ft) != 0) {
700 helios_runtime_error(
"ERROR (Visualizer::addTextboxByCenter): Could not init freetype library");
703 std::vector<std::vector<unsigned char>> maskData;
709 auto error = FT_New_Face(ft, font.c_str(), 0, &face);
713 case FT_Err_Cannot_Open_Resource:
715 case FT_Err_Unknown_File_Format:
717 case FT_Err_Invalid_File_Format:
719 case FT_Err_Invalid_Version:
721 case FT_Err_Lower_Module_Version:
723 case FT_Err_Invalid_Argument:
725 case FT_Err_Unimplemented_Feature:
727 case FT_Err_Invalid_Table:
729 case FT_Err_Invalid_Offset:
731 case FT_Err_Array_Too_Large:
733 case FT_Err_Missing_Module:
735 case FT_Err_Out_Of_Memory:
737 case FT_Err_Invalid_Face_Handle:
739 case FT_Err_Invalid_Size_Handle:
741 case FT_Err_Invalid_Slot_Handle:
743 case FT_Err_Invalid_CharMap_Handle:
745 case FT_Err_Invalid_Glyph_Index:
747 case FT_Err_Invalid_Character_Code:
749 case FT_Err_Invalid_Glyph_Format:
751 case FT_Err_Cannot_Render_Glyph:
753 case FT_Err_Invalid_Outline:
755 case FT_Err_Invalid_Composite:
757 case FT_Err_Too_Many_Hints:
759 case FT_Err_Invalid_Pixel_Size:
761 case FT_Err_Invalid_Library_Handle:
763 case FT_Err_Invalid_Stream_Handle:
765 case FT_Err_Invalid_Frame_Operation:
767 case FT_Err_Nested_Frame_Access:
769 case FT_Err_Invalid_Frame_Read:
771 case FT_Err_Raster_Uninitialized:
773 case FT_Err_Raster_Corrupted:
775 case FT_Err_Raster_Overflow:
777 case FT_Err_Raster_Negative_Height:
779 case FT_Err_Too_Many_Caches:
781 case FT_Err_Invalid_Opcode:
783 case FT_Err_Too_Few_Arguments:
785 case FT_Err_Stack_Overflow:
787 case FT_Err_Stack_Underflow:
791 case FT_Err_No_Unicode_Glyph_Name:
793 case FT_Err_Missing_Property:
800 helios_runtime_error(
"ERROR (Visualizer::addTextboxByCenter): Could not open font '" + std::string(fontname) +
"'");
804 FT_Set_Pixel_Sizes(face, 0, fontsize);
807 float sx = 1.f / float(Wdisplay);
808 float sy = 1.f / float(Hdisplay);
810 FT_GlyphSlot gg = face->glyph;
816 const char *textt = textstring;
817 for (
const char *p = textt; *p; p++) {
818 if (FT_Load_Char(face, *p, FT_LOAD_RENDER))
821 if (strncmp(p,
"_", 1) == 0) {
824 }
else if (strncmp(p,
"^", 1) == 0) {
828 wtext += gg->bitmap.width * sx * scale;
829 htext = std::max(gg->bitmap.rows * sy, htext);
833 float xt = center.
x - 0.5f * wtext;
834 float yt = center.
y - 0.5f * htext;
838 if (xt < 0 || xt > 1) {
840 std::cerr <<
"WARNING (Visualizer::addTextboxByCenter): text x-coordinate is outside of window area" << std::endl;
843 if (yt < 0 || yt > 1) {
845 std::cerr <<
"WARNING (Visualizer::addTextboxByCenter): text y-coordinate is outside of window area" << std::endl;
851 FT_GlyphSlot g = face->glyph;
853 std::vector<size_t> UUIDs;
854 UUIDs.reserve(std::strlen(textstring));
856 const char *text = textstring;
860 for (
const char *p = text; *p; p++) {
862 if (FT_Load_Char(face, *p, FT_LOAD_RENDER))
865 if (strncmp(p,
"_", 1) == 0) {
869 }
else if (strncmp(p,
"^", 1) == 0) {
876 uint2 tsize(g->bitmap.width, g->bitmap.rows);
877 maskData.resize(tsize.
y);
878 for (
int j = 0; j < tsize.
y; j++) {
879 maskData.at(j).resize(tsize.
x);
880 for (
int i = 0; i < tsize.
x; i++) {
881 maskData.at(j).at(i) = g->bitmap.buffer[i + j * tsize.
x];
886 vec2 lettersize =
make_vec2(g->bitmap.width * scale * sx, g->bitmap.rows * scale * sy);
889 vec3 letterposition =
make_vec3(xt + g->bitmap_left * sx + 0.5 * lettersize.
x, yt + g->bitmap_top * (sy + offset) - 0.5 * lettersize.
y, center.
z);
892 xt += (g->advance.x >> 6) * sx * scale;
893 yt += (g->advance.y >> 6) * sy * scale;
899 if (lettersize.
x == 0 || lettersize.
y == 0) {
903 Glyph glyph(tsize, maskData);
910 FT_Done_FreeType(ft);
916 if (geometry_handler.doesGeometryExist(geometry_id)) {
926 geometry_handler.
setVertices(geometry_id, vertices);
932 float cmin =
clamp(colormap.getLowerLimit(), -1e7f, 1e7f);
933 float cmax =
clamp(colormap.getUpperLimit(), -1e7f, 1e7f);
936 std::vector<float> tick_values;
937 if (!colorbar_ticks.empty()) {
938 tick_values = colorbar_ticks;
943 float estimated_tick_spacing = 0.04f * (colorbar_fontsize / 12.0f);
944 int max_ticks = std::max(3,
static_cast<int>(size.
y / estimated_tick_spacing));
945 max_ticks = std::min(max_ticks, 8);
950 uint Nticks = tick_values.size();
952 std::vector<size_t> UUIDs;
953 UUIDs.reserve(Ndivs + 2 * Nticks + 20);
955 float dx = size.
x / float(Ndivs);
957 for (
uint i = 0; i < Ndivs; i++) {
958 float x = center.
x - 0.5f * size.
x + (float(i) + 0.5f) * dx;
960 RGBcolor color = colormap.query(cmin +
float(i) / float(Ndivs) * (cmax - cmin));
965 std::vector<vec3> border;
967 border.push_back(
make_vec3(center.
x - 0.5f * size.
x, center.
y + 0.25f * size.
y, center.
z - 0.001f));
968 border.push_back(
make_vec3(center.
x + 0.5f * size.
x, center.
y + 0.25f * size.
y, center.
z - 0.001f));
969 border.push_back(
make_vec3(center.
x + 0.5f * size.
x, center.
y - 0.25f * size.
y, center.
z - 0.001f));
970 border.push_back(
make_vec3(center.
x - 0.5f * size.
x, center.
y - 0.25f * size.
y, center.
z - 0.001f));
971 border.push_back(
make_vec3(center.
x - 0.5f * size.
x, center.
y + 0.25f * size.
y, center.
z - 0.001f));
973 for (
uint i = 0; i < border.size() - 1; i++) {
978 double tick_spacing = 1.0;
980 tick_spacing = std::fabs(tick_values[1] - tick_values[0]);
983 std::vector<vec3> ticks;
985 for (
uint i = 0; i < Nticks; i++) {
986 float value = tick_values.at(i);
987 float x = center.
x - 0.5f * size.
x + (value - cmin) / (cmax - cmin) * size.
x;
990 std::string label =
formatTickLabel(value, tick_spacing, colorbar_integer_data);
994 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
996 if (i > 0 && i < Nticks - 1) {
997 ticks[0] =
make_vec3(x, center.
y - 0.25f * size.
y, center.
z - 0.001f);
998 ticks[1] =
make_vec3(x, center.
y - 0.25f * size.
y + 0.05f * size.
y, center.
z - 0.001f);
1000 ticks[0] =
make_vec3(x, center.
y + 0.25f * size.
y, center.
z - 0.001f);
1001 ticks[1] =
make_vec3(x, center.
y + 0.25f * size.
y - 0.05f * size.
y, center.
z - 0.001f);
1008 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
1019 if (sign ==
"both") {
1027 std::vector<size_t> UUIDs, UUIDs_text;
1035 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
1043 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
1051 UUIDs.insert(UUIDs.end(), UUIDs_text.begin(), UUIDs_text.end());
1054 this->coordinate_axes_IDs = UUIDs;
1058 if (!coordinate_axes_IDs.empty()) {
1067 float spacing_x = size.
x / scast<float>(subdiv.
x);
1068 float spacing_y = size.
y / scast<float>(subdiv.
y);
1069 float spacing_z = size.
z / scast<float>(subdiv.
z);
1071 std::vector<size_t> UUIDs;
1072 UUIDs.reserve(subdiv.
x * subdiv.
y + subdiv.
y * subdiv.
z + subdiv.
x * subdiv.
z);
1074 for (
int i = 0; i <= subdiv.
x; i++) {
1075 for (
int j = 0; j <= subdiv.
y; j++) {
1080 for (
int i = 0; i <= subdiv.
z; i++) {
1081 for (
int j = 0; j <= subdiv.
y; j++) {
1086 for (
int i = 0; i <= subdiv.
x; i++) {
1087 for (
int j = 0; j <= subdiv.
z; j++) {
1092 if (primitiveColorsNeedUpdate) {
1097void Visualizer::updateNavigationGizmo() {
1099 if (!navigation_gizmo_enabled) {
1100 if (!navigation_gizmo_IDs.empty()) {
1102 navigation_gizmo_IDs.clear();
1108 if (!navigation_gizmo_IDs.empty()) {
1110 navigation_gizmo_IDs.clear();
1114 const float axis_length = 0.03f;
1115 const float bubble_size = 0.025f;
1116 const float line_width = 3.f;
1119 float aspect_ratio =
static_cast<float>(Wdisplay) /
static_cast<float>(Hdisplay);
1127 glm::mat4 view_matrix = glm::lookAt(glm_vec3(camera_eye_location), glm_vec3(camera_lookat_center), glm::vec3(0, 0, 1));
1132 glm::mat3 rotation = glm::transpose(glm::mat3(view_matrix));
1134 vec3 camera_right =
make_vec3(rotation[0][0], rotation[0][1], rotation[0][2]);
1135 vec3 camera_up =
make_vec3(rotation[1][0], rotation[1][1], rotation[1][2]);
1144 auto projectAxisToScreen = [&](
const vec3 &world_axis) ->
vec3 {
1146 float x_component = world_axis.
x * camera_right.
x + world_axis.y * camera_right.
y + world_axis.z * camera_right.
z;
1147 float y_component = world_axis.x * camera_up.
x + world_axis.y * camera_up.
y + world_axis.z * camera_up.
z;
1150 vec3 screen_dir_uncorrected =
make_vec3(x_component, y_component, 0);
1151 float mag = screen_dir_uncorrected.
magnitude();
1156 float foreshortening_factor = mag;
1160 const float min_visibility = 0.05f;
1161 foreshortening_factor = std::max(foreshortening_factor, min_visibility);
1164 vec3 normalized_dir = screen_dir_uncorrected / mag;
1168 if (aspect_ratio >= 1.0f) {
1170 normalized_dir.
x /= aspect_ratio;
1174 normalized_dir.
y *= aspect_ratio;
1179 float corrected_mag = normalized_dir.
magnitude();
1180 if (corrected_mag > 1e-6f) {
1181 normalized_dir = normalized_dir / corrected_mag;
1184 vec3 screen_dir = normalized_dir * (axis_length * foreshortening_factor);
1192 vec3 x_screen_dir = projectAxisToScreen(world_x);
1193 vec3 y_screen_dir = projectAxisToScreen(world_y);
1194 vec3 z_screen_dir = projectAxisToScreen(world_z);
1197 vec3 x_end = gizmo_center + x_screen_dir;
1198 vec3 y_end = gizmo_center + y_screen_dir;
1199 vec3 z_end = gizmo_center + z_screen_dir;
1212 const float z_offset = 0.001f;
1216 float bubble_extension_base = bubble_size * 0.4f;
1218 auto extendBubblePosition = [&](
const vec3 &end_pos,
const vec3 &direction) ->
vec3 {
1220 vec3 extended_pos = end_pos;
1221 if (dir_mag > 1e-6f) {
1222 vec3 unit_dir = direction / dir_mag;
1226 float extension_x = bubble_extension_base;
1227 float extension_y = bubble_extension_base;
1229 if (aspect_ratio >= 1.0f) {
1231 extension_x /= aspect_ratio;
1234 extension_y /= aspect_ratio;
1238 vec3 corrected_extension =
make_vec3(unit_dir.
x * extension_x, unit_dir.
y * extension_y, 0.0f);
1240 extended_pos = end_pos + corrected_extension;
1242 extended_pos.
z += z_offset;
1243 return extended_pos;
1246 vec3 x_bubble_pos = extendBubblePosition(x_end, x_screen_dir);
1247 vec3 y_bubble_pos = extendBubblePosition(y_end, y_screen_dir);
1248 vec3 z_bubble_pos = extendBubblePosition(z_end, z_screen_dir);
1254 const float hover_size_multiplier = 1.25f;
1256 auto calculateBubbleSize = [
this, bubble_size, aspect_ratio, hover_size_multiplier](
int bubble_index) ->
vec2 {
1257 float effective_bubble_size = bubble_size;
1258 if (bubble_index == hovered_gizmo_bubble) {
1259 effective_bubble_size *= hover_size_multiplier;
1262 if (aspect_ratio >= 1.0f) {
1264 return make_vec2(effective_bubble_size / aspect_ratio, effective_bubble_size);
1267 return make_vec2(effective_bubble_size, effective_bubble_size / aspect_ratio);
1277 navigation_gizmo_IDs.push_back(x_bubble_id);
1278 navigation_gizmo_IDs.push_back(y_bubble_id);
1279 navigation_gizmo_IDs.push_back(z_bubble_id);