This commit is contained in:
ZY4N
2024-12-22 16:58:40 +01:00
parent 2704814de2
commit db8db8f9d7
161 changed files with 17102 additions and 0 deletions

504
source/viewer/instance.cpp Normal file
View File

@@ -0,0 +1,504 @@
#include "viewer/instance.hpp"
#include "viewer/asset_loader.hpp"
#include "SFML/Window.hpp"
#include "SFML/Graphics/Text.hpp"
#include "SFML/Graphics/Shape.hpp"
#include "SFML/Graphics/RectangleShape.hpp"
#include "SFML/Graphics/Sprite.hpp"
#include <sstream>
#include <glm/gtx/string_cast.hpp>
#include "glm/gtx/euler_angles.hpp"
namespace viewer
{
instance::instance() :
m_context_settings{ 24, 8, 2, 4, 6 },
m_mesh_renderer(static_cast<int>(rendering::modes::mesh::count)),
m_point_cloud_renderer(static_cast<int>(rendering::modes::point_cloud::count)),
//m_camera(0.0f, 0.0f, 0.0f)
m_camera(0.0f, -std::numbers::pi_v<float> / 2.0f, std::numbers::pi_v<float>)
{
}
std::error_code instance::init(std::string title)
{
m_title = std::move(title);
windowed(512, 344, true);
if (glewInit() != GLEW_OK)
{
return std::make_error_code(std::errc::not_supported);
}
m_settings.lighting.point_light_direction = glm::normalize(m_settings.lighting.point_light_direction);
m_mesh_render_mode = rendering::modes::mesh::lit_faces;
m_point_cloud_render_mode = rendering::modes::point_cloud::rainbow;
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearDepth(1.f);
set_background_color({ 0.0f, 0.0f, 0.0f, 0.0f });
const auto current_path = std::filesystem::current_path();
const auto data_path = current_path / ".." / "data";
const auto font_filename = data_path / "fonts" / "JetBrainsMono_Medium.ttf";
if (not m_font.loadFromFile(font_filename)) {
ztu::logger::error("Could not open font file: %", font_filename);
}
const auto image_dir = data_path / "images";
const auto logo_filename = image_dir/ "logo.png";
if (not m_logo.loadFromFile(logo_filename)) {
ztu::logger::error("Could not open image file: %", logo_filename);
}
const auto spinner_filename = image_dir/ "spinner.png";
if (not m_spinner.loadFromFile(spinner_filename)) {
ztu::logger::error("Could not open image file: %", spinner_filename);
}
return {};
}
void instance::set_background_color(const glm::vec4& color)
{
glClearColor(color.r, color.g, color.b, color.a);
}
std::optional<instance::asset_id> instance::add_mesh(
const zgl::mesh_handle& mesh,
const aabb& bounding_box,
const components::mesh_vertex::flags mesh_components,
const zgl::material_handle& material,
const material_component::flags material_components
) {
const auto mesh_id = m_mesh_renderer.add(
std::make_pair(mesh_components, material_components),
mesh,
bounding_box,
glm::identity<zgl::model_matrix_handle>(),
material,
m_mesh_shader_program_lookup
);
if (not mesh_id)
{
return std::nullopt;
}
return asset_id(std::in_place_index_t<id_mesh_index>{}, *mesh_id);
}
std::optional<instance::asset_id> instance::add_point_cloud(
const zgl::point_cloud_handle& point_cloud,
const aabb& bounding_box,
const components::point_cloud_vertex::flags point_cloud_components
) {
const auto point_cloud_id = m_point_cloud_renderer.add(
point_cloud_components,
point_cloud,
bounding_box,
glm::identity<zgl::model_matrix_handle>(),
m_point_cloud_shader_program_lookup
);
if (not point_cloud_id)
{
return std::nullopt;
}
return asset_id(std::in_place_index_t<id_point_cloud_index>{}, *point_cloud_id);
}
void instance::add_shader_program(
asset_types type, zgl::shader_program_handle shader_program_handle
) {
switch (type)
{
case asset_types::mesh:
m_mesh_shader_program_lookup.add(shader_program_handle);
break;
case asset_types::point_cloud:
m_point_cloud_shader_program_lookup.add(shader_program_handle);
break;
default:
break;
}
}
bool instance::remove(asset_id id)
{
switch (id.index()) {
case id_mesh_index:
return m_mesh_renderer.remove(std::get<id_mesh_index>(id));
case id_point_cloud_index:
return m_point_cloud_renderer.remove(std::get<id_point_cloud_index>(id));
default:
return false;
}
}
bool instance::look_at(asset_id id)
{
auto bounding_box_opt = std::optional<aabb>{ std::nullopt };
switch (id.index()) {
case id_mesh_index:
bounding_box_opt = m_mesh_renderer.bounding_box(std::get<id_mesh_index>(id));
break;
case id_point_cloud_index:
bounding_box_opt = m_point_cloud_renderer.bounding_box(std::get<id_point_cloud_index>(id));
break;
default:
return false;
}
if (bounding_box_opt)
{
const auto& bounding_box = *bounding_box_opt;
ztu::logger::debug("aabb: % %", glm::to_string(bounding_box.min), glm::to_string(bounding_box.max));
//m_camera.look_at(bounding_box.max, bounding_box.min, m_view);
m_camera.look_at(bounding_box.center(), bounding_box.min, m_view);
ztu::logger::debug("pos: % front: % right: % up: % as: % fov: %",
glm::to_string(m_view.position),
glm::to_string(m_view.front),
glm::to_string(m_view.right),
glm::to_string(m_view.up),
m_view.aspect_ratio,
m_view.fov
);
}
return true;
}
void instance::run_progress(
std::mutex& lock,
std::string& title,
float& progress,
const double fps
) {
namespace chr = std::chrono;
using namespace std::chrono_literals;
using clock = chr::high_resolution_clock;
using duration_type = clock::duration;
using floating_second = chr::duration<float>;
sf::RectangleShape bar_background, bar_foreground;
sf::Text title_text, percent_text;
sf::Texture logo_texture, spinner_texture;
sf::Sprite logo_sprite, spinner_sprite;
sf::Color background_color = { 0, 0, 0, 255 };
constexpr auto font_size = 14;
constexpr auto padding = 15;
constexpr auto spinner_size = 10.0f;
constexpr auto spinner_degrees_per_second = 270.0f;
title_text.setFont(m_font);
title_text.setCharacterSize(font_size);
percent_text.setFont(m_font);
percent_text.setCharacterSize(font_size);
bar_foreground.setOutlineColor(sf::Color::Transparent);
bar_foreground.setFillColor(sf::Color{ 107, 203, 119 });
bar_background.setOutlineColor(sf::Color::Transparent);
bar_background.setFillColor(sf::Color{ 64, 170, 87 });
const auto target_frame_time = std::chrono::duration_cast<duration_type>(1s) / fps;
std::stringstream percent_builder;
percent_builder << std::setw(3) << std::setfill(' ');
logo_texture.loadFromImage(m_logo);
logo_sprite.setTexture(logo_texture);
const auto logo_scale = static_cast<float>(m_screen_size.x) / static_cast<float>(logo_texture.getSize().x);
logo_sprite.scale({ logo_scale, logo_scale });
logo_sprite.setOrigin(0, 0);
logo_sprite.setPosition(0, 0);
const auto dim = static_cast<glm::vec2>(m_screen_size);
const auto bar_dim = sf::Vector2f(dim.x - 2 * padding, 10.0f);
const auto bar_pos = sf::Vector2f((dim.x - bar_dim.x) / 2.0f, dim.y - bar_dim.y - padding);
bar_background.setPosition(bar_pos + sf::Vector2f{ 3, 3 });
bar_background.setSize(bar_dim);
bar_foreground.setPosition(bar_pos);
spinner_texture.loadFromImage(m_spinner);
spinner_sprite.setTexture(spinner_texture);
const auto spinner_dim = static_cast<float>(spinner_texture.getSize().y);
const auto spinner_scale = spinner_size / spinner_dim;
spinner_sprite.scale({ spinner_scale, spinner_scale });
spinner_sprite.setOrigin(spinner_dim / 2.0f, spinner_dim / 2.0f);
spinner_sprite.setPosition(padding + spinner_size / 2.0f, bar_pos.y - 0.5f * padding - spinner_size / 2.0f);
const auto title_text_pos = sf::Vector2f(1.5f * padding + spinner_size, bar_pos.y - 0.5f * padding - font_size);
const auto percent_text_pos = sf::Vector2f(dim.x - padding, bar_pos.y - 0.5f * padding - font_size);
title_text.setPosition(title_text_pos);
percent_text.setPosition(percent_text_pos);
percent_text.setFillColor(sf::Color::White);
title_text.setFillColor(sf::Color::White);
const auto start_time = clock::now();
while (true)
{
const auto frame_begin = clock::now();
const auto t = chr::duration_cast<floating_second>(frame_begin - start_time).count();
lock.lock();
auto curr_progress = progress;
title_text.setString(title);
lock.unlock();
if (curr_progress == std::numeric_limits<float>::max())
{
break;
}
m_window.clear(background_color);
m_window.draw(logo_sprite);
m_window.draw(bar_background);
bar_foreground.setSize(sf::Vector2f(curr_progress * bar_dim.x, bar_dim.y));
m_window.draw(bar_foreground);
const auto spinner_angle = t * spinner_degrees_per_second;
spinner_sprite.setRotation(spinner_angle);
m_window.draw(spinner_sprite);
const auto percent = static_cast<int>(std::round(100.0f * curr_progress));
percent_builder.str("");
percent_builder << percent << '%';
percent_text.setString(percent_builder.str());
const auto percent_text_bounds = percent_text.getLocalBounds();
percent_text.setOrigin(
percent_text_bounds.left + percent_text_bounds.width,
0
);
m_window.draw(title_text);
m_window.draw(percent_text);
m_window.display();
const auto time_taken = clock::now() - frame_begin;
if (time_taken < target_frame_time)
{
std::this_thread::sleep_for(target_frame_time - time_taken);
}
}
}
void instance::run(std::mutex& gl_resource_lock, const double fps)
{
namespace chr = std::chrono;
using namespace std::chrono_literals;
using clock = chr::high_resolution_clock;
using duration_type = clock::duration;
using floating_second = chr::duration<double>;
const auto target_frame_time = std::chrono::duration_cast<duration_type>(1s) / fps;
auto frame_begin = clock::now();
m_mouse_locked = true;
m_window.setMouseCursorVisible(false);
while (true)
{
auto prev_frame_begin = frame_begin;
frame_begin = clock::now();
const auto dt = chr::duration_cast<floating_second>(frame_begin - prev_frame_begin);
if (not update(dt.count())) break;
gl_resource_lock.lock();
render();
gl_resource_lock.unlock();
/*ztu::logger::debug("pos: % front: % right: % up: % as: % fov: %",
glm::to_string(m_view.position),
glm::to_string(m_view.front),
glm::to_string(m_view.right),
glm::to_string(m_view.up),
m_view.aspect_ratio,
m_view.fov
);*/
const auto time_taken = clock::now() - frame_begin;
if (time_taken < target_frame_time)
{
std::this_thread::sleep_for(target_frame_time - time_taken);
}
}
}
void instance::windowed(const unsigned int width, const unsigned int height, const bool decorations) {
m_window.create(
sf::VideoMode(width, height),
m_title,
decorations ? sf::Style::Default : sf::Style::None,
m_context_settings
);
m_screen_size = { width, height };
m_view.aspect_ratio = static_cast<float>(width) / static_cast<float>(height);
}
void instance::fullscreen()
{
m_window.create(
sf::VideoMode(),
m_title,
sf::Style::Fullscreen,
m_context_settings
);
}
void instance::size(const unsigned int width, const unsigned int height) {
m_window.setSize({ width, height });
m_screen_size = { width, height };
m_view.aspect_ratio = static_cast<float>(width) / static_cast<float>(height);
}
bool instance::update(const double dt) {
//ztu::logger::log("pos: % dir: %", glm::to_string(m_view.position), glm::to_string(m_view.front));
auto mouse_pos_delta = glm::vec2{ 0, 0 };
auto mouse_wheel_delta = 0.0f;
sf::Event event;
while (m_window.pollEvent(event))
{
switch (event.type) {
case sf::Event::Closed: [[unlikely]]
{
return false;
}
case sf::Event::Resized:
{
const auto& [ width, height ] = event.size;
glViewport(0, 0, width, height);
m_screen_size = { width, height };
break;
}
case sf::Event::MouseWheelMoved:
{
mouse_wheel_delta = m_settings.scroll_speed * event.mouseWheel.delta;
break;
}
case sf::Event::KeyPressed:
switch (event.key.code) {
case sf::Keyboard::Escape:
return false;
case sf::Keyboard::Tab:
m_window.setMouseCursorVisible(m_mouse_locked);
m_mouse_locked = not m_mouse_locked;
break;
case sf::Keyboard::T:
//renderIndex = (renderIndex + 1) % renderers.size();
break;
case sf::Keyboard::C:
//renderIndex = (renderIndex + 1) % renderers.size();
break;
default:
break;
}
break;
default:
break;
}
}
m_view.aspect_ratio = static_cast<float>(m_screen_size.x) / static_cast<float>(m_screen_size.y);
if (m_mouse_locked) [[likely]]
{
const auto screen_center = m_screen_size / 2;
const auto [ mouse_x, mouse_y ] = sf::Mouse::getPosition(m_window);
sf::Mouse::setPosition({ screen_center.x, screen_center.y }, m_window);
const auto mouse_pixel_delta = glm::ivec2{ mouse_x, mouse_y } - screen_center;
mouse_pos_delta = m_settings.mouse_sensitivity * static_cast<glm::vec2>(mouse_pixel_delta);
m_camera.update(
static_cast<float>(dt),
mouse_pos_delta,
mouse_wheel_delta,
m_view
);
}
return true;
}
void instance::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const auto view_matrix = m_view.create_view_matrix();
const auto projection_matrix = m_view.create_projection_matrix();
const auto vp_matrix = projection_matrix * view_matrix;
m_mesh_renderer.render(
m_mesh_render_mode,
vp_matrix,
view_matrix,
m_view.position,
m_settings.lighting
);
m_point_cloud_renderer.render(
m_point_cloud_render_mode,
vp_matrix,
m_view.position,
m_settings.lighting
);
m_window.display();
//std::cout << "f\n";
}
}