18#include <GLFW/glfw3.h>
24using namespace helios;
37 if (context !=
nullptr) {
40 std::snprintf(outfile, 100,
"%02d-%02d-%4d_%02d-%02d-%02d_frame%d.jpg", date.
day, date.
month, date.
year, time.
hour, time.
minute, time.
second, frame_counter);
42 std::snprintf(outfile, 100,
"frame%d.jpg", frame_counter);
50 std::string outfile_str = outfile;
54 outfile_str +=
".jpeg";
58 helios_runtime_error(
"ERROR (Visualizer::printWindow): Output path is not valid or does not have a valid image extension (.jpeg, .jpg).");
63 if (window !=
nullptr && !headless) {
71 write_JPEG_file(outfile_str.c_str(), Wframebuffer, Hframebuffer, message_flag);
75 if (pixel_data.empty()) {
78 if (pixel_data.size() != 4 * width_pixels * height_pixels) {
79 helios_runtime_error(
"ERROR (Visualizer::displayImage): Pixel data size does not match the given width and height. Argument 'pixel_data' must have length of 4*width_pixels*height_pixels.");
90 float data_aspect = float(width_pixels) / float(height_pixels);
91 float window_aspect = float(Wdisplay) / float(Hdisplay);
92 if (data_aspect > window_aspect) {
94 image_size =
make_vec2(1.0f, window_aspect / data_aspect);
97 image_size =
make_vec2(data_aspect / window_aspect, 1.0f);
100 constexpr vec3 center(0.5, 0.5, 0);
101 const std::vector vertices{center +
make_vec3(-0.5f * image_size.
x, -0.5f * image_size.
y, 0.f), center +
make_vec3(+0.5f * image_size.
x, -0.5f * image_size.
y, 0.f), center +
make_vec3(+0.5f * image_size.
x, +0.5f * image_size.
y, 0.f),
102 center +
make_vec3(-0.5f * image_size.
x, +0.5f * image_size.
y, 0.f)};
103 const std::vector<vec2> uvs{{0, 0}, {1, 0}, {1, 1}, {0, 1}};
106 geometry_handler.
addGeometry(UUID, GeometryHandler::GEOMETRY_TYPE_RECTANGLE, vertices, RGBA::black, uvs, textureID,
false,
false,
COORDINATES_WINDOW_NORMALIZED,
true,
false);
115 helios_runtime_error(
"ERROR (Visualizer::displayImage): File " + file_name +
" does not exist or is not a valid image file.");
118 std::vector<unsigned char> image_data;
119 uint image_width, image_height;
121 if (file_name.substr(file_name.find_last_of(
'.') + 1) ==
"png") {
122 read_png_file(file_name.c_str(), image_data, image_height, image_width);
124 read_JPEG_file(file_name.c_str(), image_data, image_height, image_width);
131 std::vector<GLubyte> buff;
132 buff.resize(3 * Wframebuffer * Hframebuffer);
134#if defined(__APPLE__)
135 constexpr GLenum read_buf = GL_FRONT;
137 constexpr GLenum read_buf = GL_BACK;
139 glReadBuffer(read_buf);
140 glReadPixels(0, 0, GLsizei(Wframebuffer), GLsizei(Hframebuffer), GL_RGB, GL_UNSIGNED_BYTE, &buff[0]);
145 for (
int i = 0; i < 3 * Wframebuffer * Hframebuffer; i++) {
146 buffer[i] = (
unsigned int) buff[i];
150void Visualizer::getDepthMap(
float *buffer) {
161 std::vector<float> depth_pixels;
163 getDepthMap(depth_pixels, width, height);
164 for (
size_t i = 0; i < depth_pixels.size(); ++i) {
165 buffer[i] = depth_pixels[i];
169void Visualizer::getDepthMap(std::vector<float> &depth_pixels,
uint &width_pixels,
uint &height_pixels) {
170 width_pixels = Wdisplay;
171 height_pixels = Hdisplay;
173 depth_pixels.resize(width_pixels * height_pixels);
208 float depth_min = (std::numeric_limits<float>::max)();
209 float depth_max = (std::numeric_limits<float>::min)();
210 for (
auto depth: depth_buffer_data) {
211 if (depth < depth_min) {
214 if (depth > depth_max) {
218 for (
size_t i = 0; i < depth_pixels.size(); i++) {
219 float value = std::round((depth_buffer_data.at(i) - depth_min) / (depth_max - depth_min) * 255);
220 value =
clamp(value, 0.f, 255.f);
221 depth_pixels.at(i) = 255.f - value;
233 width = Wframebuffer;
234 height = Hframebuffer;
238 glfwHideWindow((GLFWwindow *) window);
244 std::cout <<
"Generating interactive plot..." << std::flush;
249 buildContextGeometry_private();
252 if (camera_lookat_center.
x == 0 && camera_lookat_center.
y == 0 && camera_lookat_center.
z == 0) {
253 if (camera_eye_location.
x < 1e-4 && camera_eye_location.
y < 1e-4 && camera_eye_location.
z == 2.f) {
258 float domain_bounding_radius = radius.
magnitude();
260 vec2 xbounds, ybounds, zbounds;
262 camera_lookat_center =
make_vec3(0.5f * (xbounds.
x + xbounds.
y), 0.5f * (ybounds.
x + ybounds.
y), zbounds.
x);
268 if (colorbar_flag == 2) {
269 if (!colorbar_IDs.empty()) {
271 colorbar_IDs.clear();
273 colorbar_IDs = addColorbarByCenter(colorbar_title.c_str(), colorbar_size, colorbar_position, colorbar_fontcolor, colormap_current);
280 transferBufferData();
282 assert(checkerrors());
284 bool shadow_flag =
false;
285 for (
const auto &model: primaryLightingModel) {
294 assert(checkerrors());
296 std::vector<vec3> camera_output;
298 glfwShowWindow((GLFWwindow *) window);
302 assert(checkerrors());
304 glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
305 glViewport(0, 0, shadow_buffer_size.
x, shadow_buffer_size.
y);
308 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
312 updatePerspectiveTransformation(
true);
315 depthMVP = computeShadowDepthMVP();
319 glActiveTexture(GL_TEXTURE1);
320 glBindTexture(GL_TEXTURE_2D, depthTexture);
321 glActiveTexture(GL_TEXTURE0);
326 assert(checkerrors());
330 depthMVP = glm::mat4(1.0);
334 glBindFramebuffer(GL_FRAMEBUFFER, 0);
335 glViewport(0, 0, Wframebuffer, Hframebuffer);
337 glClearColor(backgroundColor.
r, backgroundColor.
g, backgroundColor.
b, 0.0f);
339 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
343 glm::mat4 DepthBiasMVP = biasMatrix * depthMVP;
347 updatePerspectiveTransformation(
false);
357 glActiveTexture(GL_TEXTURE1);
358 glBindTexture(GL_TEXTURE_2D, depthTexture);
359 glUniform1i(primaryShader.shadowmapUniform, 1);
360 glActiveTexture(GL_TEXTURE0);
365 getViewKeystrokes(camera_eye_location, camera_lookat_center);
367 glfwSwapBuffers((GLFWwindow *) window);
369 glfwWaitEventsTimeout(1.0 / 30.0);
372 glfwGetFramebufferSize((GLFWwindow *) window, &width, &height);
373 Wframebuffer = width;
374 Hframebuffer = height;
375 }
while (glfwGetKey((GLFWwindow *) window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose((GLFWwindow *) window) == 0);
379 assert(checkerrors());
381 camera_output.push_back(camera_eye_location);
382 camera_output.push_back(camera_lookat_center);
385 std::cout <<
"done." << std::endl;
388 return camera_output;
393 bool shadow_flag =
false;
394 for (
const auto &model: primaryLightingModel) {
405 glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
406 glViewport(0, 0, shadow_buffer_size.
x, shadow_buffer_size.
y);
409 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
413 updatePerspectiveTransformation(
true);
416 depthMVP = computeShadowDepthMVP();
420 glActiveTexture(GL_TEXTURE1);
421 glBindTexture(GL_TEXTURE_2D, depthTexture);
422 glActiveTexture(GL_TEXTURE0);
429 depthMVP = glm::mat4(1.0);
432 assert(checkerrors());
435 glBindFramebuffer(GL_FRAMEBUFFER, 0);
436 glViewport(0, 0, Wframebuffer, Hframebuffer);
438 glClearColor(backgroundColor.
r, backgroundColor.
g, backgroundColor.
b, 0.0f);
440 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
444 glm::mat4 DepthBiasMVP = biasMatrix * depthMVP;
448 updatePerspectiveTransformation(
false);
458 glActiveTexture(GL_TEXTURE1);
459 glBindTexture(GL_TEXTURE_2D, depthTexture);
460 glUniform1i(primaryShader.shadowmapUniform, 1);
461 glActiveTexture(GL_TEXTURE0);
467 getViewKeystrokes(camera_eye_location, camera_lookat_center);
471 glfwGetFramebufferSize((GLFWwindow *) window, &width, &height);
472 Wframebuffer = width;
473 Hframebuffer = height;
476void Visualizer::transferBufferData() {
477 assert(checkerrors());
484 auto ensureArrayBuffer = [](GLuint buf, GLenum target, GLsizeiptr size,
const void *data) {
485 glBindBuffer(target, buf);
486 GLint current_size = 0;
487 glGetBufferParameteriv(target, GL_BUFFER_SIZE, ¤t_size);
488 if (current_size != size) {
489 glBufferData(target, size, data, GL_STATIC_DRAW);
493 auto ensureTextureBuffer = [](GLuint buf, GLuint tex, GLenum format, GLsizeiptr size,
const void *data) {
494 glBindBuffer(GL_TEXTURE_BUFFER, buf);
495 GLint current_size = 0;
496 glGetBufferParameteriv(GL_TEXTURE_BUFFER, GL_BUFFER_SIZE, ¤t_size);
497 if (current_size != size) {
498 glBufferData(GL_TEXTURE_BUFFER, size, data, GL_STATIC_DRAW);
500 glBindTexture(GL_TEXTURE_BUFFER, tex);
501 glTexBuffer(GL_TEXTURE_BUFFER, format, buf);
505 for (
size_t gi = 0; gi < GeometryHandler::all_geometry_types.size(); ++gi) {
506 const auto geometry_type = GeometryHandler::all_geometry_types[gi];
508 const auto *uv_data = geometry_handler.
getUVData_ptr(geometry_type);
517 ensureArrayBuffer(vertex_buffer.at(gi), GL_ARRAY_BUFFER, vertex_data->size() *
sizeof(GLfloat), vertex_data->data());
518 ensureArrayBuffer(uv_buffer.at(gi), GL_ARRAY_BUFFER, uv_data->size() *
sizeof(GLfloat), uv_data->data());
519 ensureArrayBuffer(face_index_buffer.at(gi), GL_ARRAY_BUFFER, face_index_data->size() *
sizeof(GLint), face_index_data->data());
520 ensureTextureBuffer(color_buffer.at(gi), color_texture_object.at(gi), GL_RGBA32F, color_data->size() *
sizeof(GLfloat), color_data->data());
521 ensureTextureBuffer(normal_buffer.at(gi), normal_texture_object.at(gi), GL_RGB32F, normal_data->size() *
sizeof(GLfloat), normal_data->data());
522 ensureTextureBuffer(texture_flag_buffer.at(gi), texture_flag_texture_object.at(gi), GL_R32I, texture_flag_data->size() *
sizeof(GLint), texture_flag_data->data());
523 ensureTextureBuffer(texture_ID_buffer.at(gi), texture_ID_texture_object.at(gi), GL_R32I, texture_ID_data->size() *
sizeof(GLint), texture_ID_data->data());
524 ensureTextureBuffer(coordinate_flag_buffer.at(gi), coordinate_flag_texture_object.at(gi), GL_R32I, coordinate_flag_data->size() *
sizeof(GLint), coordinate_flag_data->data());
525 ensureTextureBuffer(hidden_flag_buffer.at(gi), hidden_flag_texture_object.at(gi), GL_R8I, visible_flag_data->size() *
sizeof(GLbyte), visible_flag_data->data());
527 glBindBuffer(GL_ARRAY_BUFFER, 0);
528 glBindTexture(GL_TEXTURE_BUFFER, 0);
531 bool rect_dirty =
false;
532 for (
size_t UUID: dirty) {
533 if (!geometry_handler.doesGeometryExist(UUID)) {
537 const auto &index_map = geometry_handler.
getIndexMap(UUID);
538 auto geometry_type = index_map.geometry_type;
539 size_t i = std::find(GeometryHandler::all_geometry_types.begin(), GeometryHandler::all_geometry_types.end(), geometry_type) - GeometryHandler::all_geometry_types.begin();
543 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer.at(i));
544 glBufferSubData(GL_ARRAY_BUFFER, index_map.vertex_index *
sizeof(GLfloat), vcount * 3 *
sizeof(GLfloat), geometry_handler.
getVertexData_ptr(geometry_type)->data() + index_map.vertex_index);
546 glBindBuffer(GL_ARRAY_BUFFER, uv_buffer.at(i));
547 glBufferSubData(GL_ARRAY_BUFFER, index_map.uv_index *
sizeof(GLfloat), vcount * 2 *
sizeof(GLfloat), geometry_handler.
getUVData_ptr(geometry_type)->data() + index_map.uv_index);
549 glBindBuffer(GL_ARRAY_BUFFER, face_index_buffer.at(i));
550 glBufferSubData(GL_ARRAY_BUFFER, index_map.face_index_index *
sizeof(GLint), vcount *
sizeof(GLint), geometry_handler.
getFaceIndexData_ptr(geometry_type)->data() + index_map.face_index_index);
552 glBindBuffer(GL_TEXTURE_BUFFER, color_buffer.at(i));
553 glBufferSubData(GL_TEXTURE_BUFFER, index_map.color_index *
sizeof(GLfloat), 4 *
sizeof(GLfloat), geometry_handler.
getColorData_ptr(geometry_type)->data() + index_map.color_index);
554 glBindTexture(GL_TEXTURE_BUFFER, color_texture_object.at(i));
555 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, color_buffer.at(i));
557 glBindBuffer(GL_ARRAY_BUFFER, normal_buffer.at(i));
558 glBufferSubData(GL_ARRAY_BUFFER, index_map.normal_index *
sizeof(GLfloat), 3 *
sizeof(GLfloat), geometry_handler.
getNormalData_ptr(geometry_type)->data() + index_map.normal_index);
559 glBindTexture(GL_TEXTURE_BUFFER, normal_texture_object.at(i));
560 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, normal_buffer.at(i));
562 glBindBuffer(GL_ARRAY_BUFFER, texture_flag_buffer.at(i));
563 glBufferSubData(GL_ARRAY_BUFFER, index_map.texture_flag_index *
sizeof(GLint),
sizeof(GLint), geometry_handler.
getTextureFlagData_ptr(geometry_type)->data() + index_map.texture_flag_index);
564 glBindTexture(GL_TEXTURE_BUFFER, texture_flag_texture_object.at(i));
565 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, texture_flag_buffer.at(i));
567 glBindBuffer(GL_ARRAY_BUFFER, texture_ID_buffer.at(i));
568 glBufferSubData(GL_ARRAY_BUFFER, index_map.texture_ID_index *
sizeof(GLint),
sizeof(GLint), geometry_handler.
getTextureIDData_ptr(geometry_type)->data() + index_map.texture_ID_index);
569 glBindTexture(GL_TEXTURE_BUFFER, texture_ID_texture_object.at(i));
570 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, texture_ID_buffer.at(i));
572 glBindBuffer(GL_ARRAY_BUFFER, coordinate_flag_buffer.at(i));
573 glBufferSubData(GL_ARRAY_BUFFER, index_map.coordinate_flag_index *
sizeof(GLint),
sizeof(GLint), geometry_handler.
getCoordinateFlagData_ptr(geometry_type)->data() + index_map.coordinate_flag_index);
574 glBindTexture(GL_TEXTURE_BUFFER, coordinate_flag_texture_object.at(i));
575 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, coordinate_flag_buffer.at(i));
577 glBindBuffer(GL_ARRAY_BUFFER, hidden_flag_buffer.at(i));
578 glBufferSubData(GL_ARRAY_BUFFER, index_map.visible_index *
sizeof(GLbyte),
sizeof(GLbyte), geometry_handler.
getVisibilityFlagData_ptr(geometry_type)->data() + index_map.visible_index);
579 glBindTexture(GL_TEXTURE_BUFFER, hidden_flag_texture_object.at(i));
580 glTexBuffer(GL_TEXTURE_BUFFER, GL_R8I, hidden_flag_buffer.at(i));
582 glBindBuffer(GL_ARRAY_BUFFER, 0);
583 glBindTexture(GL_TEXTURE_BUFFER, 0);
585 if (geometry_type == GeometryHandler::GEOMETRY_TYPE_RECTANGLE) {
593 rectangle_vertex_group_firsts.resize(rectangle_count);
594 rectangle_vertex_group_counts.resize(rectangle_count, 4);
595 for (
int j = 0; j < rectangle_count; ++j) {
596 rectangle_vertex_group_firsts[j] = j * 4;
600 if (textures_dirty || texArray == 0) {
601 transferTextureData();
602 textures_dirty =
false;
607 assert(checkerrors());
610void Visualizer::transferTextureData() {
612 glGenTextures(1, &texArray);
615 glBindTexture(GL_TEXTURE_2D_ARRAY, texArray);
617 const size_t layers = std::max<size_t>(1, texture_manager.size());
618 if (layers != texture_array_layers) {
619 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, maximum_texture_size.
x, maximum_texture_size.
y, layers);
620 texture_array_layers = layers;
623 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
624 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
625 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
626 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
627 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
629 std::vector<GLfloat> uv_rescale;
630 uv_rescale.resize(texture_manager.size() * 2);
632 for (
const auto &[textureID, texture]: texture_manager) {
633 GLenum externalFormat = 0;
634 switch (texture.num_channels) {
636 externalFormat = GL_RED;
639 externalFormat = GL_RGB;
642 externalFormat = GL_RGBA;
645 throw std::runtime_error(
"unsupported channel count");
648 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, textureID, texture.texture_resolution.x, texture.texture_resolution.y, 1, externalFormat, GL_UNSIGNED_BYTE, texture.texture_data.data());
650 uv_rescale.at(textureID * 2 + 0) = float(texture.texture_resolution.x) / float(maximum_texture_size.
x);
651 uv_rescale.at(textureID * 2 + 1) = float(texture.texture_resolution.y) / float(maximum_texture_size.
y);
654 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
655 glUniform1i(glGetUniformLocation(primaryShader.shaderID,
"textureSampler"), 0);
657 glBindBuffer(GL_TEXTURE_BUFFER, uv_rescale_buffer);
658 glBufferData(GL_TEXTURE_BUFFER, uv_rescale.size() *
sizeof(GLfloat), uv_rescale.data(), GL_STATIC_DRAW);
659 glBindTexture(GL_TEXTURE_BUFFER, uv_rescale_texture_object);
660 glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, uv_rescale_buffer);
661 glBindBuffer(GL_TEXTURE_BUFFER, 0);
665void Visualizer::render(
bool shadow)
const {
666 size_t rectangle_ind = std::find(GeometryHandler::all_geometry_types.begin(), GeometryHandler::all_geometry_types.end(), GeometryHandler::GEOMETRY_TYPE_RECTANGLE) - GeometryHandler::all_geometry_types.begin();
667 size_t triangle_ind = std::find(GeometryHandler::all_geometry_types.begin(), GeometryHandler::all_geometry_types.end(), GeometryHandler::GEOMETRY_TYPE_TRIANGLE) - GeometryHandler::all_geometry_types.begin();
668 size_t point_ind = std::find(GeometryHandler::all_geometry_types.begin(), GeometryHandler::all_geometry_types.end(), GeometryHandler::GEOMETRY_TYPE_POINT) - GeometryHandler::all_geometry_types.begin();
669 size_t line_ind = std::find(GeometryHandler::all_geometry_types.begin(), GeometryHandler::all_geometry_types.end(), GeometryHandler::GEOMETRY_TYPE_LINE) - GeometryHandler::all_geometry_types.begin();
677 GLint current_shader_program = 0;
678 glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_shader_program);
681 glActiveTexture(GL_TEXTURE0);
682 glBindTexture(GL_TEXTURE_2D_ARRAY, texArray);
684 assert(checkerrors());
686 glActiveTexture(GL_TEXTURE9);
687 assert(checkerrors());
688 glBindTexture(GL_TEXTURE_BUFFER, uv_rescale_texture_object);
689 assert(checkerrors());
690 glUniform1i(glGetUniformLocation(current_shader_program,
"uv_rescale"), 9);
694 assert(checkerrors());
696 if (triangle_count > 0) {
697 glActiveTexture(GL_TEXTURE3);
698 glBindTexture(GL_TEXTURE_BUFFER, color_texture_object.at(triangle_ind));
699 glUniform1i(glGetUniformLocation(current_shader_program,
"color_texture_object"), 3);
701 glActiveTexture(GL_TEXTURE4);
702 glBindTexture(GL_TEXTURE_BUFFER, normal_texture_object.at(triangle_ind));
703 glUniform1i(glGetUniformLocation(current_shader_program,
"normal_texture_object"), 4);
705 glActiveTexture(GL_TEXTURE5);
706 glBindTexture(GL_TEXTURE_BUFFER, texture_flag_texture_object.at(triangle_ind));
707 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_flag_texture_object"), 5);
709 glActiveTexture(GL_TEXTURE6);
710 glBindTexture(GL_TEXTURE_BUFFER, texture_ID_texture_object.at(triangle_ind));
711 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_ID_texture_object"), 6);
713 glActiveTexture(GL_TEXTURE7);
714 glBindTexture(GL_TEXTURE_BUFFER, coordinate_flag_texture_object.at(triangle_ind));
715 glUniform1i(glGetUniformLocation(current_shader_program,
"coordinate_flag_texture_object"), 7);
717 glActiveTexture(GL_TEXTURE8);
718 glBindTexture(GL_TEXTURE_BUFFER, hidden_flag_texture_object.at(triangle_ind));
719 glUniform1i(glGetUniformLocation(current_shader_program,
"hidden_flag_texture_object"), 8);
721 glBindVertexArray(primaryShader.vertex_array_IDs.at(triangle_ind));
722 assert(checkerrors());
723 glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3);
726 assert(checkerrors());
730 if (rectangle_count > 0) {
731 glActiveTexture(GL_TEXTURE3);
732 glBindTexture(GL_TEXTURE_BUFFER, color_texture_object.at(rectangle_ind));
733 glUniform1i(glGetUniformLocation(current_shader_program,
"color_texture_object"), 3);
735 glActiveTexture(GL_TEXTURE4);
736 glBindTexture(GL_TEXTURE_BUFFER, normal_texture_object.at(rectangle_ind));
737 glUniform1i(glGetUniformLocation(current_shader_program,
"normal_texture_object"), 4);
739 glActiveTexture(GL_TEXTURE5);
740 glBindTexture(GL_TEXTURE_BUFFER, texture_flag_texture_object.at(rectangle_ind));
741 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_flag_texture_object"), 5);
743 glActiveTexture(GL_TEXTURE6);
744 glBindTexture(GL_TEXTURE_BUFFER, texture_ID_texture_object.at(rectangle_ind));
745 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_ID_texture_object"), 6);
747 glActiveTexture(GL_TEXTURE7);
748 glBindTexture(GL_TEXTURE_BUFFER, coordinate_flag_texture_object.at(rectangle_ind));
749 glUniform1i(glGetUniformLocation(current_shader_program,
"coordinate_flag_texture_object"), 7);
751 glActiveTexture(GL_TEXTURE8);
752 glBindTexture(GL_TEXTURE_BUFFER, hidden_flag_texture_object.at(rectangle_ind));
753 glUniform1i(glGetUniformLocation(current_shader_program,
"hidden_flag_texture_object"), 8);
755 glBindVertexArray(primaryShader.vertex_array_IDs.at(rectangle_ind));
757 std::vector<GLint> opaque_firsts;
758 std::vector<GLint> opaque_counts;
759 struct TransparentRect {
763 std::vector<TransparentRect> transparent_rects;
765 const auto &texFlags = *geometry_handler.
getTextureFlagData_ptr(GeometryHandler::GEOMETRY_TYPE_RECTANGLE);
766 const auto &colors = *geometry_handler.
getColorData_ptr(GeometryHandler::GEOMETRY_TYPE_RECTANGLE);
767 const auto &verts = *geometry_handler.
getVertexData_ptr(GeometryHandler::GEOMETRY_TYPE_RECTANGLE);
769 opaque_firsts.reserve(rectangle_count);
770 opaque_counts.reserve(rectangle_count);
771 transparent_rects.reserve(rectangle_count);
773 for (
size_t i = 0; i < rectangle_count; ++i) {
774 bool isGlyph = texFlags.at(i) == 3;
775 float alpha = colors.at(i * 4 + 3);
776 if (!isGlyph && alpha >= 1.f) {
777 opaque_firsts.push_back(
static_cast<GLint
>(i * 4));
778 opaque_counts.push_back(4);
780 glm::vec3 center(0.f);
781 for (
int j = 0; j < 4; ++j) {
782 center.x += verts.at(i * 12 + j * 3 + 0);
783 center.y += verts.at(i * 12 + j * 3 + 1);
784 center.z += verts.at(i * 12 + j * 3 + 2);
787 glm::vec4 viewPos = cameraViewMatrix * glm::vec4(center, 1.f);
788 transparent_rects.push_back({i, viewPos.z});
792 if (!opaque_firsts.empty()) {
793 glMultiDrawArrays(GL_TRIANGLE_FAN, opaque_firsts.data(), opaque_counts.data(),
static_cast<GLsizei
>(opaque_firsts.size()));
796 if (!transparent_rects.empty()) {
797 std::sort(transparent_rects.begin(), transparent_rects.end(), [](
const TransparentRect &a,
const TransparentRect &b) {
798 return a.depth > b.depth;
801 glDepthMask(GL_FALSE);
802 for (
const auto &tr: transparent_rects) {
803 glDrawArrays(GL_TRIANGLE_FAN,
static_cast<GLint
>(tr.index * 4), 4);
805 glDepthMask(GL_TRUE);
809 assert(checkerrors());
814 if (line_count > 0) {
815 glActiveTexture(GL_TEXTURE3);
816 glBindTexture(GL_TEXTURE_BUFFER, color_texture_object.at(line_ind));
817 glUniform1i(glGetUniformLocation(current_shader_program,
"color_texture_object"), 3);
819 glActiveTexture(GL_TEXTURE4);
820 glBindTexture(GL_TEXTURE_BUFFER, normal_texture_object.at(line_ind));
821 glUniform1i(glGetUniformLocation(current_shader_program,
"normal_texture_object"), 4);
823 glActiveTexture(GL_TEXTURE5);
824 glBindTexture(GL_TEXTURE_BUFFER, texture_flag_texture_object.at(line_ind));
825 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_flag_texture_object"), 5);
827 glActiveTexture(GL_TEXTURE6);
828 glBindTexture(GL_TEXTURE_BUFFER, texture_ID_texture_object.at(line_ind));
829 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_ID_texture_object"), 6);
831 glActiveTexture(GL_TEXTURE7);
832 glBindTexture(GL_TEXTURE_BUFFER, coordinate_flag_texture_object.at(line_ind));
833 glUniform1i(glGetUniformLocation(current_shader_program,
"coordinate_flag_texture_object"), 7);
835 glActiveTexture(GL_TEXTURE8);
836 glBindTexture(GL_TEXTURE_BUFFER, hidden_flag_texture_object.at(line_ind));
837 glUniform1i(glGetUniformLocation(current_shader_program,
"hidden_flag_texture_object"), 8);
839 glBindVertexArray(primaryShader.vertex_array_IDs.at(line_ind));
842 const std::vector<float> *size_data = geometry_handler.
getSizeData_ptr(GeometryHandler::GEOMETRY_TYPE_LINE);
843 if (size_data && !size_data->empty()) {
845 std::map<float, std::vector<size_t>> width_groups;
846 for (
size_t i = 0; i < size_data->size(); ++i) {
847 float width = size_data->at(i);
850 width_groups[width].push_back(i);
854 for (
const auto &group: width_groups) {
855 float width = group.first;
856 const std::vector<size_t> &line_indices = group.second;
862 for (
size_t line_idx: line_indices) {
863 glDrawArrays(GL_LINES, line_idx * 2, 2);
869 glDrawArrays(GL_LINES, 0, line_count * 2);
875 if (point_count > 0) {
876 glActiveTexture(GL_TEXTURE3);
877 glBindTexture(GL_TEXTURE_BUFFER, color_texture_object.at(point_ind));
878 glUniform1i(glGetUniformLocation(current_shader_program,
"color_texture_object"), 3);
880 glActiveTexture(GL_TEXTURE4);
881 glBindTexture(GL_TEXTURE_BUFFER, normal_texture_object.at(point_ind));
882 glUniform1i(glGetUniformLocation(current_shader_program,
"normal_texture_object"), 4);
884 glActiveTexture(GL_TEXTURE5);
885 glBindTexture(GL_TEXTURE_BUFFER, texture_flag_texture_object.at(point_ind));
886 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_flag_texture_object"), 5);
888 glActiveTexture(GL_TEXTURE6);
889 glBindTexture(GL_TEXTURE_BUFFER, texture_ID_texture_object.at(point_ind));
890 glUniform1i(glGetUniformLocation(current_shader_program,
"texture_ID_texture_object"), 6);
892 glActiveTexture(GL_TEXTURE7);
893 glBindTexture(GL_TEXTURE_BUFFER, coordinate_flag_texture_object.at(point_ind));
894 glUniform1i(glGetUniformLocation(current_shader_program,
"coordinate_flag_texture_object"), 7);
896 glActiveTexture(GL_TEXTURE8);
897 glBindTexture(GL_TEXTURE_BUFFER, hidden_flag_texture_object.at(point_ind));
898 glUniform1i(glGetUniformLocation(current_shader_program,
"hidden_flag_texture_object"), 8);
900 glBindVertexArray(primaryShader.vertex_array_IDs.at(point_ind));
903 const std::vector<float> *size_data = geometry_handler.
getSizeData_ptr(GeometryHandler::GEOMETRY_TYPE_POINT);
904 if (size_data && !size_data->empty()) {
906 std::map<float, std::vector<size_t>> size_groups;
907 for (
size_t i = 0; i < size_data->size(); ++i) {
908 float size = size_data->at(i);
911 size_groups[size].push_back(i);
915 for (
const auto &group: size_groups) {
916 float size = group.first;
917 const std::vector<size_t> &point_indices = group.second;
923 for (
size_t point_idx: point_indices) {
924 glDrawArrays(GL_POINTS, point_idx, 1);
929 glPointSize(point_width);
930 glDrawArrays(GL_POINTS, 0, point_count);
948 if (!headless && window !=
nullptr && glfwWindowShouldClose(scast<GLFWwindow *>(window))) {
953 std::cout <<
"Updating the plot..." << std::flush;
956 if (!hide_window && !headless && window !=
nullptr) {
957 glfwShowWindow(scast<GLFWwindow *>(window));
961 buildContextGeometry_private();
964 updatePointCulling();
967 if (camera_lookat_center.
x == 0 && camera_lookat_center.
y == 0 && camera_lookat_center.
z == 0) {
968 if (camera_eye_location.
x < 1e-4 && camera_eye_location.
y < 1e-4 && camera_eye_location.
z == 2.f) {
973 float domain_bounding_radius = radius.
magnitude();
975 vec2 xbounds, ybounds, zbounds;
977 camera_lookat_center =
make_vec3(0.5f * (xbounds.
x + xbounds.
y), 0.5f * (ybounds.
x + ybounds.
y), 0.5f * (zbounds.
x + zbounds.
y));
983 if (colorbar_flag == 2) {
984 if (!colorbar_IDs.empty()) {
986 colorbar_IDs.clear();
988 colorbar_IDs = addColorbarByCenter(colorbar_title.c_str(), colorbar_size, colorbar_position, colorbar_fontcolor, colormap_current);
994 transferBufferData();
996 bool shadow_flag =
false;
997 for (
const auto &model: primaryLightingModel) {
1008 glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
1009 glViewport(0, 0, shadow_buffer_size.
x, shadow_buffer_size.
y);
1012 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1016 updatePerspectiveTransformation(
true);
1019 depthMVP = computeShadowDepthMVP();
1023 glActiveTexture(GL_TEXTURE1);
1024 glBindTexture(GL_TEXTURE_2D, depthTexture);
1025 glActiveTexture(GL_TEXTURE0);
1032 depthMVP = glm::mat4(1.0);
1035 assert(checkerrors());
1038 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1039 glViewport(0, 0, Wframebuffer, Hframebuffer);
1041 glClearColor(backgroundColor.
r, backgroundColor.
g, backgroundColor.
b, 0.0f);
1043 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1047 glm::mat4 DepthBiasMVP = biasMatrix * depthMVP;
1051 updatePerspectiveTransformation(
false);
1061 glActiveTexture(GL_TEXTURE1);
1062 glBindTexture(GL_TEXTURE_2D, depthTexture);
1063 glUniform1i(primaryShader.shadowmapUniform, 1);
1064 glActiveTexture(GL_TEXTURE0);
1069 getViewKeystrokes(camera_eye_location, camera_lookat_center);
1072 glfwGetFramebufferSize((GLFWwindow *) window, &width, &height);
1073 Wframebuffer = width;
1074 Hframebuffer = height;
1076 glfwSwapBuffers((GLFWwindow *) window);
1079 std::cout <<
"done." << std::endl;
1083void Visualizer::updateDepthBuffer() {
1086 buildContextGeometry_private();
1089 transferBufferData();
1092 glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
1093 glViewport(0, 0, Wframebuffer, Hframebuffer);
1096 glActiveTexture(GL_TEXTURE1);
1097 glBindTexture(GL_TEXTURE_2D, depthTexture);
1098 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, Wframebuffer, Hframebuffer, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
nullptr);
1099 glActiveTexture(GL_TEXTURE0);
1102 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1106 updatePerspectiveTransformation(
false);
1114 assert(checkerrors());
1116 depth_buffer_data.resize(Wframebuffer * Hframebuffer);
1118#if defined(__APPLE__)
1119 constexpr GLenum read_buf = GL_FRONT;
1121 constexpr GLenum read_buf = GL_BACK;
1123 glReadBuffer(read_buf);
1124 glReadPixels(0, 0, Wframebuffer, Hframebuffer, GL_DEPTH_COMPONENT, GL_FLOAT, depth_buffer_data.data());
1127 assert(checkerrors());
1134 std::cout <<
"Rendering depth map..." << std::flush;
1137 updateDepthBuffer();
1140 float depth_min = (std::numeric_limits<float>::max)();
1141 float depth_max = (std::numeric_limits<float>::min)();
1142 for (
auto depth: depth_buffer_data) {
1143 if (depth < depth_min) {
1146 if (depth > depth_max) {
1150 std::vector<unsigned char> depth_uchar(depth_buffer_data.size() * 4);
1151 for (
size_t i = 0; i < depth_buffer_data.size(); i++) {
1152 auto value = scast<unsigned char>(std::round((depth_buffer_data.at(i) - depth_min) / (depth_max - depth_min) * 255));
1153 value =
clamp(value, scast<unsigned char>(0), scast<unsigned char>(255));
1154 size_t row = i / Wframebuffer;
1155 size_t col = i % Wframebuffer;
1156 size_t flipped_i = (Hframebuffer - 1 - row) * Wframebuffer + col;
1157 depth_uchar.at(flipped_i * 4) = 255 - value;
1158 depth_uchar.at(flipped_i * 4 + 1) = 255 - value;
1159 depth_uchar.at(flipped_i * 4 + 2) = 255 - value;
1160 depth_uchar.at(flipped_i * 4 + 3) = 255;
1166 std::cout <<
"done." << std::endl;
1173 assert(checkerrors());
1176 unsigned int VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
1177 unsigned int FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
1180 std::string VertexShaderCode;
1181 std::ifstream VertexShaderStream(vertex_shader_file, std::ios::in);
1182 assert(VertexShaderStream.is_open());
1184 while (getline(VertexShaderStream, Line))
1185 VertexShaderCode +=
"\n" + Line;
1186 VertexShaderStream.close();
1189 std::string FragmentShaderCode;
1190 std::ifstream FragmentShaderStream(fragment_shader_file, std::ios::in);
1191 assert(FragmentShaderStream.is_open());
1193 while (getline(FragmentShaderStream, Line))
1194 FragmentShaderCode +=
"\n" + Line;
1195 FragmentShaderStream.close();
1198 char const *VertexSourcePointer = VertexShaderCode.c_str();
1199 glShaderSource(VertexShaderID, 1, &VertexSourcePointer,
nullptr);
1200 glCompileShader(VertexShaderID);
1202 assert(checkerrors());
1205 GLint compileOK = GL_FALSE;
1206 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &compileOK);
1207 if (compileOK != GL_TRUE) {
1209 glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &logLen);
1210 std::vector<char> log(logLen);
1211 glGetShaderInfoLog(VertexShaderID, logLen,
nullptr, log.data());
1212 fprintf(stderr,
"Vertex shader compilation failed:\n%s\n", log.data());
1213 throw std::runtime_error(
"vertex shader compile error");
1217 char const *FragmentSourcePointer = FragmentShaderCode.c_str();
1218 glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer,
nullptr);
1219 glCompileShader(FragmentShaderID);
1221 assert(checkerrors());
1224 compileOK = GL_FALSE;
1225 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &compileOK);
1226 if (compileOK != GL_TRUE) {
1228 glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &logLen);
1229 std::vector<char> log(logLen);
1230 glGetShaderInfoLog(FragmentShaderID, logLen,
nullptr, log.data());
1231 fprintf(stderr,
"Fragment shader compilation failed:\n%s\n", log.data());
1232 throw std::runtime_error(
"fragment shader compile error");
1236 shaderID = glCreateProgram();
1237 glAttachShader(shaderID, VertexShaderID);
1238 glAttachShader(shaderID, FragmentShaderID);
1239 glLinkProgram(shaderID);
1241 assert(checkerrors());
1243 GLint linkOK = GL_FALSE;
1244 glGetProgramiv(shaderID, GL_LINK_STATUS, &linkOK);
1245 if (linkOK != GL_TRUE) {
1247 glGetProgramiv(shaderID, GL_INFO_LOG_LENGTH, &logLen);
1248 std::vector<char> log(logLen);
1249 glGetProgramInfoLog(shaderID, logLen,
nullptr, log.data());
1250 fprintf(stderr,
"Shader program link failed:\n%s\n", log.data());
1251 throw std::runtime_error(
"program link error");
1254 assert(checkerrors());
1256 glDeleteShader(VertexShaderID);
1257 glDeleteShader(FragmentShaderID);
1259 assert(checkerrors());
1262 vertex_array_IDs.resize(GeometryHandler::all_geometry_types.size());
1263 glGenVertexArrays(GeometryHandler::all_geometry_types.size(), vertex_array_IDs.data());
1265 assert(checkerrors());
1270 for (
const auto &geometry_type: GeometryHandler::all_geometry_types) {
1271 glBindVertexArray(vertex_array_IDs.at(i));
1274 glBindBuffer(GL_ARRAY_BUFFER, visualizer_ptr->vertex_buffer.at(i));
1275 glEnableVertexAttribArray(0);
1276 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,
nullptr);
1279 glBindBuffer(GL_ARRAY_BUFFER, visualizer_ptr->uv_buffer.at(i));
1280 glEnableVertexAttribArray(1);
1281 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0,
nullptr);
1284 glBindBuffer(GL_ARRAY_BUFFER, visualizer_ptr->face_index_buffer.at(i));
1285 glEnableVertexAttribArray(2);
1286 glVertexAttribIPointer(2, 1, GL_INT, 0,
nullptr);
1291 glBindBuffer(GL_ARRAY_BUFFER, 0);
1293 assert(checkerrors());
1295 glUseProgram(shaderID);
1297 assert(checkerrors());
1302 transformMatrixUniform = glGetUniformLocation(shaderID,
"MVP");
1305 depthBiasUniform = glGetUniformLocation(shaderID,
"DepthBiasMVP");
1308 textureUniform = glGetUniformLocation(shaderID,
"textureSampler");
1311 shadowmapUniform = glGetUniformLocation(shaderID,
"shadowMap");
1312 glUniform1i(shadowmapUniform, 1);
1315 lightDirectionUniform = glGetUniformLocation(shaderID,
"lightDirection");
1316 glUniform3f(lightDirectionUniform, 0, 0, 1);
1319 lightingModelUniform = glGetUniformLocation(shaderID,
"lightingModel");
1320 glUniform1i(lightingModelUniform, 0);
1322 RboundUniform = glGetUniformLocation(shaderID,
"Rbound");
1323 glUniform1i(RboundUniform, 0);
1326 lightIntensityUniform = glGetUniformLocation(shaderID,
"lightIntensity");
1327 glUniform1f(lightIntensityUniform, 1.f);
1330 uvRescaleUniform = glGetUniformLocation(shaderID,
"uv_rescale");
1332 assert(checkerrors());
1341 glDeleteVertexArrays(vertex_array_IDs.size(), vertex_array_IDs.data());
1342 glDeleteProgram(shaderID);
1347 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1351 glActiveTexture(GL_TEXTURE0);
1352 glUniform1i(textureUniform, 0);
1355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1357 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1358 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1359 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1360 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1362 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1366 glActiveTexture(GL_TEXTURE0);
1367 glUniform1i(textureUniform, 0);
1368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1370 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1371 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1372 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1373 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1375 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1379 glUniformMatrix4fv(transformMatrixUniform, 1, GL_FALSE, &matrix[0][0]);
1383 glUniformMatrix4fv(depthBiasUniform, 1, GL_FALSE, &matrix[0][0]);
1387 glUniform3f(lightDirectionUniform, direction.
x, direction.
y, direction.
z);
1391 glUniform1i(lightingModelUniform, lightingmodel);
1395 glUniform1f(lightIntensityUniform, lightintensity);
1399 glUseProgram(shaderID);
1402void Visualizer::framebufferResizeCallback(GLFWwindow *window,
int width,
int height) {
1403 if (width <= 0 || height <= 0) {
1406 auto *viz =
static_cast<Visualizer *
>(glfwGetWindowUserPointer(window));
1407 if (viz !=
nullptr) {
1408 viz->Wframebuffer =
static_cast<uint>(width);
1409 viz->Hframebuffer =
static_cast<uint>(height);
1413void Visualizer::windowResizeCallback(GLFWwindow *window,
int width,
int height) {
1414 if (width <= 0 || height <= 0) {
1417 auto *viz =
static_cast<Visualizer *
>(glfwGetWindowUserPointer(window));
1418 if (viz !=
nullptr) {
1420 glfwGetFramebufferSize(window, &fbw, &fbh);
1421 if (fbw != width || fbh != height) {
1422 glfwSetWindowSize(window, width, height);
1426 viz->Wdisplay =
static_cast<uint>(width);
1427 viz->Hdisplay =
static_cast<uint>(height);
1428 viz->Wframebuffer =
static_cast<uint>(fbw);
1429 viz->Hframebuffer =
static_cast<uint>(fbh);
1430 viz->updateWatermark();
1431 viz->transferBufferData();
1436 if (!isWatermarkVisible) {
1437 if (watermark_ID != 0) {
1444 constexpr float texture_aspect = 675.f / 195.f;
1446 float window_aspect = float(Wframebuffer) / float(Hframebuffer);
1447 float width = 0.07f * texture_aspect / window_aspect;
1448 if (watermark_ID != 0) {
1455bool lbutton_down =
false;
1456bool rbutton_down =
false;
1457bool mbutton_down =
false;
1458double startX, startY;
1459double scrollX, scrollY;
1464 if (action == GLFW_PRESS) {
1465 glfwGetCursorPos(window, &startX, &startY);
1467 if (button == GLFW_MOUSE_BUTTON_LEFT) {
1468 if (GLFW_PRESS == action) {
1469 lbutton_down =
true;
1470 }
else if (GLFW_RELEASE == action) {
1471 lbutton_down =
false;
1473 }
else if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
1474 if (GLFW_PRESS == action) {
1475 mbutton_down =
true;
1476 }
else if (GLFW_RELEASE == action) {
1477 mbutton_down =
false;
1479 }
else if (button == GLFW_MOUSE_BUTTON_RIGHT) {
1480 if (GLFW_PRESS == action) {
1481 rbutton_down =
true;
1482 }
else if (GLFW_RELEASE == action) {
1483 rbutton_down =
false;
1493 }
else if (lbutton_down || mbutton_down) {
1494 dphi = scast<float>(xpos - startX);
1495 dtheta = scast<float>(ypos - startY);
1497 dphi = dtheta = 0.f;
1505 dscroll = scast<float>(yoffset);
1507 if (yoffset > 0.0 || yoffset < 0.0) {
1515void Visualizer::getViewKeystrokes(
vec3 &eye,
vec3 ¢er) {
1516 vec3 forward = center - eye;
1526 float radius = Spherical.
radius;
1528 float phi = Spherical.
azimuth;
1530 phi +=
PI_F * (dphi / 160.f);
1531 if (dtheta > 0 && theta +
PI_F / 80.f < 0.49f *
PI_F) {
1532 theta +=
PI_F * (dtheta / 120.f);
1533 }
else if (dtheta < 0 && theta > -0.25 *
PI_F) {
1534 theta +=
PI_F * (dtheta / 120.f);
1538 center -= 0.025f * dx * right;
1541 center += 0.025f * dy * up;
1545 if (dscroll > 0.0f) {
1546 radius = (radius * 0.9f > minimum_view_radius) ? radius * 0.9f : minimum_view_radius;
1553 auto *_window = scast<GLFWwindow *>(window);
1556 if (glfwGetKey(_window, GLFW_KEY_SPACE) == GLFW_PRESS) {
1558 if (glfwGetKey(_window, GLFW_KEY_LEFT) == GLFW_PRESS) {
1559 center.
x += 0.1f * sin(phi);
1560 center.
y += 0.1f * cos(phi);
1563 else if (glfwGetKey(_window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
1564 center.
x -= 0.1f * sin(phi);
1565 center.
y -= 0.1f * cos(phi);
1568 else if (glfwGetKey(_window, GLFW_KEY_UP) == GLFW_PRESS) {
1572 else if (glfwGetKey(_window, GLFW_KEY_DOWN) == GLFW_PRESS) {
1579 if (glfwGetKey(_window, GLFW_KEY_LEFT) == GLFW_PRESS) {
1583 else if (glfwGetKey(_window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
1588 else if (glfwGetKey(_window, GLFW_KEY_UP) == GLFW_PRESS) {
1589 if (theta +
PI_F / 80.f < 0.49f *
PI_F) {
1590 theta +=
PI_F / 80.f;
1594 else if (glfwGetKey(_window, GLFW_KEY_DOWN) == GLFW_PRESS) {
1595 if (theta > -0.25 *
PI_F) {
1596 theta -=
PI_F / 80.f;
1601 if (glfwGetKey(_window, GLFW_KEY_EQUAL) == GLFW_PRESS) {
1602 radius = (radius * 0.9f > minimum_view_radius) ? radius * 0.9f : minimum_view_radius;
1605 else if (glfwGetKey(_window, GLFW_KEY_MINUS) == GLFW_PRESS) {
1610 if (glfwGetKey(_window, GLFW_KEY_P) == GLFW_PRESS) {
1611 std::cout <<
"View is angle: (R,theta,phi)=(" << radius <<
"," << theta <<
"," << phi <<
") at from position (" << camera_eye_location.
x <<
"," << camera_eye_location.
y <<
"," << camera_eye_location.
z <<
") looking at (" << center.
x <<
","
1612 << center.
y <<
"," << center.
z <<
")" << std::endl;
1618void Visualizer::cullPointsByFrustum() {
1619 const std::vector<float> *vertex_data = geometry_handler.
getVertexData_ptr(GeometryHandler::GEOMETRY_TYPE_POINT);
1620 if (!vertex_data || vertex_data->empty()) {
1624 std::vector<glm::vec4> frustum_planes = extractFrustumPlanes();
1627 size_t point_count = vertex_data->size() / 3;
1628 for (
size_t i = 0; i < point_count; ++i) {
1629 glm::vec3 point(vertex_data->at(i * 3), vertex_data->at(i * 3 + 1), vertex_data->at(i * 3 + 2));
1631 bool inside_frustum =
true;
1632 for (
const auto &plane: frustum_planes) {
1635 if (glm::dot(glm::vec3(plane), point) + plane.w < 0) {
1636 inside_frustum =
false;
1642 std::vector<size_t> all_UUIDs = geometry_handler.getAllGeometryIDs();
1643 size_t point_index = 0;
1644 for (
size_t UUID: all_UUIDs) {
1645 if (geometry_handler.
getIndexMap(UUID).geometry_type == GeometryHandler::GEOMETRY_TYPE_POINT) {
1646 if (point_index == i) {
1656void Visualizer::cullPointsByDistance(
float maxDistance,
float lodFactor) {
1657 const std::vector<float> *vertex_data = geometry_handler.
getVertexData_ptr(GeometryHandler::GEOMETRY_TYPE_POINT);
1658 if (!vertex_data || vertex_data->empty()) {
1662 glm::vec3 camera_pos(camera_eye_location.
x, camera_eye_location.
y, camera_eye_location.
z);
1665 size_t point_count = vertex_data->size() / 3;
1666 for (
size_t i = 0; i < point_count; ++i) {
1667 glm::vec3 point(vertex_data->at(i * 3), vertex_data->at(i * 3 + 1), vertex_data->at(i * 3 + 2));
1669 float distance = glm::length(point - camera_pos);
1670 bool should_render =
true;
1671 float adaptive_size = 1.0f;
1674 if (distance > maxDistance) {
1675 should_render =
false;
1678 else if (distance > maxDistance * 0.3f) {
1679 float distance_ratio = distance / maxDistance;
1680 float lod_threshold = distance_ratio * lodFactor;
1683 if ((i %
static_cast<size_t>(std::max(1.0f, lod_threshold))) != 0) {
1684 should_render =
false;
1687 adaptive_size = 1.0f + (distance_ratio * 3.0f);
1692 std::vector<size_t> all_UUIDs = geometry_handler.getAllGeometryIDs();
1693 size_t point_index = 0;
1694 for (
size_t UUID: all_UUIDs) {
1695 if (geometry_handler.
getIndexMap(UUID).geometry_type == GeometryHandler::GEOMETRY_TYPE_POINT) {
1696 if (point_index == i) {
1698 if (should_render) {
1700 float original_size = geometry_handler.
getSize(UUID);
1701 if (original_size <= 0)
1702 original_size = 1.0f;
1703 geometry_handler.
setSize(UUID, original_size * adaptive_size);
1713void Visualizer::updatePointCulling() {
1718 if (!point_culling_enabled || points_total_count < point_culling_threshold) {
1719 points_rendered_count = points_total_count;
1720 last_culling_time_ms = 0;
1725 auto start_time = std::chrono::high_resolution_clock::now();
1728 cullPointsByFrustum();
1731 float max_distance = point_max_render_distance;
1732 if (max_distance <= 0) {
1735 float scene_size = std::max({xbounds.
y - xbounds.
x, ybounds.
y - ybounds.
x, zbounds.
y - zbounds.
x});
1736 max_distance = scene_size * 5.0f;
1740 cullPointsByDistance(max_distance, point_lod_factor);
1743 points_rendered_count = geometry_handler.
getPointCount(
false);
1745 auto end_time = std::chrono::high_resolution_clock::now();
1746 last_culling_time_ms = std::chrono::duration<float, std::milli>(end_time - start_time).count();
1749std::vector<glm::vec4> Visualizer::extractFrustumPlanes()
const {
1750 std::vector<glm::vec4> planes(6);
1753 glm::mat4 mvp = cameraProjectionMatrix * cameraViewMatrix;
1756 planes[0] = glm::vec4(mvp[0][3] + mvp[0][0], mvp[1][3] + mvp[1][0], mvp[2][3] + mvp[2][0], mvp[3][3] + mvp[3][0]);
1758 planes[1] = glm::vec4(mvp[0][3] - mvp[0][0], mvp[1][3] - mvp[1][0], mvp[2][3] - mvp[2][0], mvp[3][3] - mvp[3][0]);
1760 planes[2] = glm::vec4(mvp[0][3] + mvp[0][1], mvp[1][3] + mvp[1][1], mvp[2][3] + mvp[2][1], mvp[3][3] + mvp[3][1]);
1762 planes[3] = glm::vec4(mvp[0][3] - mvp[0][1], mvp[1][3] - mvp[1][1], mvp[2][3] - mvp[2][1], mvp[3][3] - mvp[3][1]);
1764 planes[4] = glm::vec4(mvp[0][3] + mvp[0][2], mvp[1][3] + mvp[1][2], mvp[2][3] + mvp[2][2], mvp[3][3] + mvp[3][2]);
1766 planes[5] = glm::vec4(mvp[0][3] - mvp[0][2], mvp[1][3] - mvp[1][2], mvp[2][3] - mvp[2][2], mvp[3][3] - mvp[3][2]);
1769 for (
auto &plane: planes) {
1770 float length = glm::length(glm::vec3(plane));
1780 point_culling_enabled = enabled;
1784 point_culling_threshold = threshold;
1788 point_max_render_distance = distance;
1792 point_lod_factor = factor;
1796 total_points = points_total_count;
1797 rendered_points = points_rendered_count;
1798 culling_time_ms = last_culling_time_ms;
1801std::string errorString(GLenum err) {
1802 std::string message;
1805 if (err == GL_INVALID_ENUM) {
1806 message.assign(
"GL_INVALID_ENUM - An unacceptable value is specified for an enumerated argument.");
1807 }
else if (err == GL_INVALID_VALUE) {
1808 message.assign(
"GL_INVALID_VALUE - A numeric argument is out of range.");
1809 }
else if (err == GL_INVALID_OPERATION) {
1810 message.assign(
"GL_INVALID_OPERATION - The specified operation is not allowed in the current state.");
1811 }
else if (err == GL_STACK_OVERFLOW) {
1812 message.assign(
"GL_STACK_OVERFLOW - This command would cause a stack overflow.");
1813 }
else if (err == GL_STACK_UNDERFLOW) {
1814 message.assign(
"GL_STACK_UNDERFLOW - This command would cause a stack underflow.");
1815 }
else if (err == GL_OUT_OF_MEMORY) {
1816 message.assign(
"GL_OUT_OF_MEMORY - There is not enough memory left to execute the command.");
1817 }
else if (err == GL_TABLE_TOO_LARGE) {
1818 message.assign(
"GL_TABLE_TOO_LARGE - The specified table exceeds the implementation's maximum supported table size.");
1827 while ((err = glGetError()) != GL_NO_ERROR) {
1828 std::cerr <<
"glError #" << err_count <<
": " << errorString(err) << std::endl;
1831 if (err_count > 0) {
1840 if (!checkerrors()) {
1841 helios_runtime_error(
"ERROR (Visualizer): OpenGL errors detected in " + context +
". Check console output for specific error details.");