fixes
This commit is contained in:
636
source/viewer/asset_loader.cpp
Normal file
636
source/viewer/asset_loader.cpp
Normal file
@@ -0,0 +1,636 @@
|
||||
#include "viewer/asset_loader.hpp"
|
||||
|
||||
#include <geometry/normal_estimation.hpp>
|
||||
|
||||
#include "geometry/aabb.hpp"
|
||||
#include "util/logger.hpp"
|
||||
#include "glm/gtx/string_cast.hpp" // TODO remove
|
||||
|
||||
namespace viewer
|
||||
{
|
||||
std::error_code asset_loader::init(
|
||||
components::mesh_vertex::flags enabled_mesh_components,
|
||||
material_component::flags enabled_material_components,
|
||||
components::point_cloud_vertex::flags enabled_point_cloud_components,
|
||||
const dynamic_material_data& default_material
|
||||
) {
|
||||
|
||||
//m_ctx.setActive(true);
|
||||
|
||||
m_enabled_mesh_components = enabled_mesh_components;
|
||||
m_enabled_material_components = enabled_material_components;
|
||||
m_enabled_point_cloud_components = enabled_point_cloud_components;
|
||||
|
||||
m_dynamic_material_data_buffer.push_back(default_material);
|
||||
|
||||
return create_gl_materials();
|
||||
}
|
||||
|
||||
std::error_code asset_loader::load_shader(
|
||||
const GLenum type,
|
||||
const std::filesystem::path& filename,
|
||||
zgl::shader_handle& shader_handle
|
||||
) {
|
||||
|
||||
auto& [ buffer_source, buffer_type ] = m_dynamic_shader_data_buffer;
|
||||
|
||||
std::stringstream source_stream;
|
||||
static constexpr auto glsl_version = 460;
|
||||
|
||||
source_stream << "#version " << glsl_version << '\n';
|
||||
source_stream << "#define " << "hello" << '\n';
|
||||
source_stream << buffer_source;
|
||||
|
||||
buffer_type = type;
|
||||
|
||||
if (filename.empty())
|
||||
{
|
||||
buffer_source = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (const auto e = m_shader_loader.load(filename, buffer_source)) {
|
||||
ztu::logger::warn(
|
||||
"Could not load shader_program_data source file %: [%] %",
|
||||
filename,
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto e = create_gl_shader()) {
|
||||
return e;
|
||||
}
|
||||
|
||||
shader_handle = m_gl_shader_data.back().handle();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code asset_loader::build_shader_program(
|
||||
const zgl::shader_handle& vertex_shader,
|
||||
const zgl::shader_handle& geometry_shader,
|
||||
const zgl::shader_handle& fragment_shader,
|
||||
zgl::shader_program_handle& shader_program_handle
|
||||
) {
|
||||
|
||||
auto program_data = zgl::shader_program_data{};
|
||||
|
||||
if (const auto e = zgl::shader_program_data::build_from(
|
||||
vertex_shader,
|
||||
geometry_shader,
|
||||
fragment_shader,
|
||||
program_data
|
||||
)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
shader_program_handle = program_data.handle();
|
||||
|
||||
m_gl_shader_program_data.emplace_back(std::move(program_data));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code asset_loader::load_asset(
|
||||
const std::string& format,
|
||||
const std::filesystem::path& filename,
|
||||
std::vector<std::pair<dynamic_mesh_handle_type, dynamic_material_handle_type>>& dynamic_mesh_handles,
|
||||
std::vector<dynamic_point_cloud_handle_type>& dynamic_point_cloud_handles
|
||||
) {
|
||||
std::error_code error;
|
||||
|
||||
if ((error = load_mesh(
|
||||
format, filename, dynamic_mesh_handles
|
||||
))) {
|
||||
if (
|
||||
error.category() == std::generic_category() and
|
||||
static_cast<std::errc>(error.value()) == std::errc::invalid_argument
|
||||
) {
|
||||
error = load_point_cloud(format, filename, dynamic_point_cloud_handles);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
std::error_code asset_loader::load_mesh(
|
||||
const std::string& format,
|
||||
const std::filesystem::path& filename,
|
||||
std::vector<std::pair<dynamic_mesh_handle_type, dynamic_material_handle_type>>& dynamic_mesh_handles
|
||||
) {
|
||||
const auto mesh_loader_id = m_mesh_loader.find_loader(format);
|
||||
|
||||
if (not mesh_loader_id)
|
||||
{
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
if (const auto e = m_mesh_loader.read(
|
||||
*mesh_loader_id,
|
||||
filename,
|
||||
m_dynamic_mesh_data_buffer,
|
||||
m_enabled_mesh_components,
|
||||
m_dynamic_material_data_buffer,
|
||||
m_enabled_material_components,
|
||||
next_materials_id,
|
||||
true
|
||||
)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return process_materials_and_meshes(dynamic_mesh_handles);
|
||||
}
|
||||
|
||||
std::error_code asset_loader::load_point_cloud(
|
||||
const std::string& format,
|
||||
const std::filesystem::path& filename,
|
||||
std::vector<dynamic_point_cloud_handle_type>& dynamic_point_cloud_handles
|
||||
) {
|
||||
const auto point_cloud_loader_id = m_point_cloud_loader.find_loader(format);
|
||||
|
||||
if (not point_cloud_loader_id)
|
||||
{
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
if (const auto e = m_point_cloud_loader.read(
|
||||
*point_cloud_loader_id,
|
||||
filename,
|
||||
m_dynamic_point_cloud_buffer,
|
||||
true
|
||||
)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return process_point_clouds(dynamic_point_cloud_handles);
|
||||
}
|
||||
|
||||
std::error_code asset_loader::load_asset_directory(
|
||||
const std::string& format,
|
||||
const std::filesystem::path& path,
|
||||
std::vector<std::pair<dynamic_mesh_handle_type, dynamic_material_handle_type>>& dynamic_mesh_handles,
|
||||
std::vector<dynamic_point_cloud_handle_type>& dynamic_point_cloud_handles
|
||||
) {
|
||||
std::error_code error;
|
||||
|
||||
if ((error = load_mesh_directory(
|
||||
format, path, dynamic_mesh_handles
|
||||
))) {
|
||||
if (
|
||||
error.category() == std::generic_category() and
|
||||
static_cast<std::errc>(error.value()) == std::errc::invalid_argument
|
||||
) {
|
||||
error = load_point_cloud_directory(format, path, dynamic_point_cloud_handles);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
std::error_code asset_loader::load_mesh_directory(
|
||||
const std::string& format,
|
||||
const std::filesystem::path& path,
|
||||
std::vector<std::pair<dynamic_mesh_handle_type, dynamic_material_handle_type>>& dynamic_mesh_handles
|
||||
) {
|
||||
const auto mesh_loader_id = m_mesh_loader.find_loader(format);
|
||||
|
||||
if (not mesh_loader_id)
|
||||
{
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
if (const auto e = m_mesh_loader.read_directory(
|
||||
*mesh_loader_id,
|
||||
path,
|
||||
m_dynamic_mesh_data_buffer,
|
||||
m_enabled_mesh_components,
|
||||
m_dynamic_material_data_buffer,
|
||||
m_enabled_material_components,
|
||||
next_materials_id,
|
||||
true
|
||||
)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return process_materials_and_meshes(dynamic_mesh_handles);
|
||||
}
|
||||
|
||||
|
||||
std::error_code asset_loader::load_point_cloud_directory(
|
||||
const std::string& format,
|
||||
const std::filesystem::path& path,
|
||||
std::vector<dynamic_point_cloud_handle_type>& dynamic_point_cloud_handles
|
||||
) {
|
||||
const auto point_cloud_loader_id = m_point_cloud_loader.find_loader(format);
|
||||
|
||||
if (not point_cloud_loader_id)
|
||||
{
|
||||
return std::make_error_code(std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
if (const auto e = m_point_cloud_loader.read_directory(
|
||||
*point_cloud_loader_id,
|
||||
path,
|
||||
m_dynamic_point_cloud_buffer,
|
||||
true
|
||||
)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
return process_point_clouds(dynamic_point_cloud_handles);
|
||||
}
|
||||
|
||||
std::error_code asset_loader::process_materials_and_meshes(
|
||||
std::vector<std::pair<dynamic_mesh_handle_type, dynamic_material_handle_type>>& dynamic_mesh_handles
|
||||
) {
|
||||
|
||||
const auto material_count_before = m_gl_material_data_references.size();
|
||||
|
||||
if (const auto e = create_gl_materials())
|
||||
{
|
||||
m_dynamic_mesh_data_buffer.clear();
|
||||
return e;
|
||||
}
|
||||
|
||||
const auto new_materials = std::span(
|
||||
m_gl_material_data_references.begin() + material_count_before,
|
||||
m_gl_material_data_references.end()
|
||||
);
|
||||
|
||||
const auto mesh_count_before = m_gl_mesh_data.size();
|
||||
|
||||
create_gl_meshes(new_materials);
|
||||
|
||||
const auto new_meshes = std::span(
|
||||
m_gl_mesh_data.begin() + mesh_count_before,
|
||||
m_gl_mesh_data.end()
|
||||
);
|
||||
|
||||
const auto dynamic_mesh_count_before = dynamic_mesh_handles.size();
|
||||
dynamic_mesh_handles.resize(dynamic_mesh_handles.size() + new_meshes.size());
|
||||
|
||||
std::ranges::transform(
|
||||
new_meshes,
|
||||
dynamic_mesh_handles.begin() + dynamic_mesh_count_before,
|
||||
[&](const auto& entry)
|
||||
{
|
||||
const auto& [ gl_mesh_data, bounding_box ] = entry;
|
||||
const auto material_id = gl_mesh_data.material_id();
|
||||
|
||||
auto material_index = std::size_t{ 0 };
|
||||
|
||||
if (material_id != 0)
|
||||
{
|
||||
const auto material_reference_it = std::ranges::find_if(
|
||||
new_materials,
|
||||
[&material_id](const auto& entry) {
|
||||
return entry.first == material_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (material_reference_it == new_materials.end())
|
||||
{
|
||||
ztu::logger::error(
|
||||
"Something went horribly wrong while searching for material. Falling back to default material"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
material_index = material_reference_it.base() - m_gl_material_data_references.begin().base();
|
||||
}
|
||||
}
|
||||
|
||||
const auto& gl_material = m_gl_material_data[material_index];
|
||||
|
||||
//ztu::logger::debug("mesh components: %", static_cast<unsigned int>(gl_mesh_data.components()));
|
||||
//ztu::logger::debug("material components: %", static_cast<unsigned int>(gl_material.components()));
|
||||
|
||||
return std::make_pair(
|
||||
dynamic_mesh_handle_type{
|
||||
.handle = gl_mesh_data.handle(),
|
||||
.bounding_box = bounding_box,
|
||||
.components = gl_mesh_data.components()
|
||||
},
|
||||
dynamic_material_handle_type{
|
||||
.handle = gl_material.handle(),
|
||||
.components = gl_material.components()
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code asset_loader::process_point_clouds(
|
||||
std::vector<dynamic_point_cloud_handle_type>& dynamic_point_cloud_handles
|
||||
) {
|
||||
const auto point_cloud_count_before = m_gl_point_cloud_data.size();
|
||||
|
||||
create_gl_point_clouds();
|
||||
|
||||
const auto new_point_clouds = std::span(
|
||||
m_gl_point_cloud_data.begin() + point_cloud_count_before,
|
||||
m_gl_point_cloud_data.end()
|
||||
);
|
||||
|
||||
const auto dynamic_point_cloud_count_before = dynamic_point_cloud_handles.size();
|
||||
dynamic_point_cloud_handles.resize(dynamic_point_cloud_handles.size() + new_point_clouds.size());
|
||||
|
||||
std::ranges::transform(
|
||||
new_point_clouds,
|
||||
dynamic_point_cloud_handles.begin() + dynamic_point_cloud_count_before,
|
||||
[&](const auto& gl_point_cloud_data)
|
||||
{
|
||||
const auto& [ data, box ] = gl_point_cloud_data;
|
||||
return dynamic_point_cloud_handle_type{
|
||||
.handle = data.handle(),
|
||||
.bounding_box = box,
|
||||
.components = data.components()
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::error_code asset_loader::create_gl_materials()
|
||||
{
|
||||
auto error = std::error_code{};
|
||||
|
||||
for (const auto& material_data : m_dynamic_material_data_buffer)
|
||||
{
|
||||
auto gl_material_data = zgl::material_data{};
|
||||
|
||||
if ((error = zgl::material_data::build_from(
|
||||
material_data.texture(),
|
||||
material_data.surface_properties(),
|
||||
material_data.transparency(),
|
||||
material_data.components(),
|
||||
gl_material_data
|
||||
))) {
|
||||
ztu::logger::error(
|
||||
"Error while creating material gpu handle: [%] %",
|
||||
error.category().name(),
|
||||
error.message()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gl_material_data.emplace_back(std::move(gl_material_data));
|
||||
m_gl_material_data_references.emplace_back(next_materials_id, 0);
|
||||
}
|
||||
|
||||
++next_materials_id;
|
||||
}
|
||||
|
||||
m_dynamic_material_data_buffer.clear();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void asset_loader::create_gl_meshes(std::span<const material_reference_entry_type> material_references)
|
||||
{
|
||||
auto component_type_buffer = std::array<GLenum, static_cast<std::size_t>(components::mesh_vertex::count)>{};
|
||||
auto component_length_buffer = std::array<GLint, static_cast<std::size_t>(components::mesh_vertex::count)>{};
|
||||
|
||||
auto component_stride = GLsizei{};
|
||||
auto component_count = ztu::u32{};
|
||||
|
||||
for (auto& mesh_data : m_dynamic_mesh_data_buffer)
|
||||
{
|
||||
if (mesh_data.triangles().empty())
|
||||
{
|
||||
ztu::logger::warn("Skipping mesh with empty index buffer.");
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto material_id = mesh_data.material_id();
|
||||
|
||||
auto material_index = std::size_t{ 0 };
|
||||
|
||||
if (material_id != 0) // Default material is always there
|
||||
{
|
||||
const auto material_reference_it = std::ranges::find_if(
|
||||
material_references,
|
||||
[&material_id](const material_reference_entry_type& entry) {
|
||||
return entry.first == material_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (material_reference_it == material_references.end())
|
||||
{
|
||||
ztu::logger::error("Skipping mesh because referenced material cannot be found");
|
||||
continue;
|
||||
}
|
||||
|
||||
material_index = material_reference_it - material_references.begin();
|
||||
}
|
||||
|
||||
// Add normals if missing
|
||||
if ((mesh_data.components() & components::mesh_vertex::flags::normal) == components::mesh_vertex::flags::none)
|
||||
{
|
||||
ztu::logger::warn("Model is missing normal vectors, so they are estimated!");
|
||||
estimate_normals(
|
||||
mesh_data.positions(),
|
||||
mesh_data.triangles(),
|
||||
mesh_data.normals()
|
||||
);
|
||||
mesh_data.components() |= components::mesh_vertex::flags::normal;
|
||||
}
|
||||
|
||||
auto mesh_box = aabb{};
|
||||
mesh_box.add_points<components::mesh_vertex::normal::value_type>(mesh_data.positions());
|
||||
|
||||
mesh_data.build_vertex_buffer(
|
||||
m_vertex_buffer,
|
||||
component_count,
|
||||
component_type_buffer,
|
||||
component_length_buffer,
|
||||
component_stride
|
||||
);
|
||||
|
||||
auto gl_mesh_data = zgl::mesh_data{};
|
||||
|
||||
const auto& first_triangle = mesh_data.triangles().front();
|
||||
|
||||
// TODO make span of size component_count
|
||||
|
||||
if (const auto e = zgl::mesh_data::build_from(
|
||||
m_vertex_buffer,
|
||||
std::span(component_type_buffer).subspan(0, component_count),
|
||||
std::span(component_length_buffer).subspan(0, component_count),
|
||||
component_stride,
|
||||
std::span(
|
||||
first_triangle.data(),
|
||||
mesh_data.triangles().size() * first_triangle.size()
|
||||
),
|
||||
mesh_data.material_id(),
|
||||
mesh_data.components(),
|
||||
gl_mesh_data
|
||||
)) {
|
||||
ztu::logger::error(
|
||||
"Error while creating opengl mesh data: [%] %\nMesh will be skipped.",
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
}
|
||||
|
||||
++m_gl_material_data_references[material_index].second;
|
||||
|
||||
m_gl_mesh_data.emplace_back(std::move(gl_mesh_data), mesh_box);
|
||||
}
|
||||
|
||||
m_dynamic_mesh_data_buffer.clear();
|
||||
}
|
||||
|
||||
void asset_loader::create_gl_point_clouds()
|
||||
{
|
||||
auto component_type_buffer = std::array<GLenum, static_cast<std::size_t>(components::point_cloud_vertex::count)>{};
|
||||
auto component_length_buffer = std::array<GLint, static_cast<std::size_t>(components::point_cloud_vertex::count)>{};
|
||||
auto component_stride = GLsizei{};
|
||||
auto component_count = ztu::u32{};
|
||||
|
||||
for (const auto& point_cloud_data : m_dynamic_point_cloud_buffer)
|
||||
{
|
||||
if (point_cloud_data.positions().empty())
|
||||
{
|
||||
ztu::logger::warn("Skipping point cloud without points.");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto point_cloud_box = aabb{};
|
||||
point_cloud_box.add_points<components::mesh_vertex::normal::value_type>(point_cloud_data.positions());
|
||||
|
||||
point_cloud_data.build_vertex_buffer(
|
||||
m_vertex_buffer,
|
||||
component_count,
|
||||
component_type_buffer,
|
||||
component_length_buffer,
|
||||
component_stride
|
||||
);
|
||||
|
||||
auto gl_point_cloud_data = zgl::point_cloud_data{};
|
||||
|
||||
if (const auto e = zgl::point_cloud_data::build_from(
|
||||
m_vertex_buffer,
|
||||
component_type_buffer,
|
||||
component_length_buffer,
|
||||
component_stride,
|
||||
gl_point_cloud_data
|
||||
)) {
|
||||
ztu::logger::error(
|
||||
"Error while creating opengl point cloud data: [%] %\nPoint cloud will be skipped.",
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
}
|
||||
|
||||
m_gl_point_cloud_data.emplace_back(std::move(gl_point_cloud_data), point_cloud_box);
|
||||
}
|
||||
|
||||
m_dynamic_point_cloud_buffer.clear();
|
||||
}
|
||||
|
||||
std::error_code asset_loader::create_gl_shader()
|
||||
{
|
||||
auto shader_data = zgl::shader_data{};
|
||||
|
||||
const auto& [source, type] = m_dynamic_shader_data_buffer;
|
||||
|
||||
if (const auto e = zgl::shader_data::build_from(type, source, shader_data)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
m_gl_shader_data.emplace_back(std::move(shader_data));
|
||||
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
bool asset_loader::unload(const zgl::shader_program_handle& shader_handle)
|
||||
{
|
||||
const auto it = std::find_if(
|
||||
m_gl_shader_program_data.begin(), m_gl_shader_program_data.end(),
|
||||
[&shader_handle](const auto& gl_shader_data) {
|
||||
return gl_shader_data.handle().program_id == shader_handle.program_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (it == m_gl_shader_program_data.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gl_shader_program_data.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asset_loader::unload(const zgl::mesh_handle& mesh_handle)
|
||||
{
|
||||
const auto it = std::ranges::find_if(
|
||||
m_gl_mesh_data,
|
||||
[&mesh_handle](const auto& gl_mesh_data) {
|
||||
return gl_mesh_data.first.handle().vao_id == mesh_handle.vao_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (it == m_gl_mesh_data.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto material_id = it->first.material_id();
|
||||
|
||||
const auto reference_it = std::ranges::find_if(
|
||||
m_gl_material_data_references,
|
||||
[&material_id](const auto& entry) {
|
||||
return entry.first == material_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (reference_it != m_gl_material_data_references.end())
|
||||
{
|
||||
// Do not delete default material at index 0
|
||||
if (--reference_it->second == 0 and reference_it != m_gl_material_data_references.begin())
|
||||
{
|
||||
const auto index = reference_it - m_gl_material_data_references.begin();
|
||||
m_gl_material_data.erase(m_gl_material_data.begin() + index);
|
||||
m_gl_material_data_references.erase(reference_it);
|
||||
}
|
||||
}
|
||||
|
||||
m_gl_mesh_data.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void asset_loader::unload_shader_data()
|
||||
{
|
||||
m_gl_shader_data.clear();
|
||||
}
|
||||
|
||||
|
||||
bool asset_loader::unload(const zgl::point_cloud_handle& point_cloud_handle)
|
||||
{
|
||||
const auto it = std::ranges::find_if(
|
||||
m_gl_point_cloud_data,
|
||||
[&point_cloud_handle](const auto& entry) {
|
||||
return entry.first.handle().vao_id == point_cloud_handle.vao_id;
|
||||
}
|
||||
);
|
||||
|
||||
if (it == m_gl_point_cloud_data.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gl_point_cloud_data.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
275
source/viewer/dynamic_shader_program_loading.cpp
Normal file
275
source/viewer/dynamic_shader_program_loading.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "../../include/viewer/dynamic_shader_program_loading.hpp"
|
||||
#include "../../include/util/string_lookup.hpp"
|
||||
#include "../../include/util/logger.hpp"
|
||||
#include <sstream>
|
||||
|
||||
std::size_t viewer::dynamic_shader_program_loading::count_shader_files(
|
||||
const std::filesystem::path& path
|
||||
) {
|
||||
using namespace std::string_view_literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
auto shader_file_count = std::size_t{ 0 };
|
||||
|
||||
for (const auto& [ asset_type, folder ] : {
|
||||
std::make_pair(asset_types::mesh, "mesh"sv),
|
||||
std::make_pair(asset_types::point_cloud, "point_cloud"sv)
|
||||
}) {
|
||||
const auto folder_begin = fs::directory_iterator{ path / folder };
|
||||
const auto folder_end = fs::directory_iterator{};
|
||||
|
||||
shader_file_count += std::count_if(
|
||||
folder_begin, folder_end,
|
||||
[](auto& entry) { return entry.is_regular_file(); }
|
||||
);
|
||||
}
|
||||
|
||||
return shader_file_count;
|
||||
}
|
||||
|
||||
void viewer::dynamic_shader_program_loading::load_directory(
|
||||
asset_loader& loader,
|
||||
instance& z3d,
|
||||
std::mutex& gl_resource_lock,
|
||||
std::mutex& progress_lock,
|
||||
std::string& progress_title,
|
||||
float& progress_ratio,
|
||||
const std::filesystem::path& path
|
||||
) {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
auto progress_builder = std::stringstream{};
|
||||
|
||||
const auto shader_file_count = static_cast<float>(count_shader_files(path));
|
||||
constexpr auto shader_loading_progress = 0.8f;
|
||||
|
||||
|
||||
auto shader_indices = ztu::string_lookup<ztu::u32>({
|
||||
{ "vertex", 0 },
|
||||
{ "geometry", 1 },
|
||||
{ "fragment", 2 }
|
||||
});
|
||||
|
||||
constexpr auto shader_types = std::array<GLenum, 3>{
|
||||
GL_VERTEX_SHADER,
|
||||
GL_GEOMETRY_SHADER,
|
||||
GL_FRAGMENT_SHADER
|
||||
};
|
||||
|
||||
auto program_capabilities = std::vector<ztu::u32>{};
|
||||
auto programs = std::vector<std::array<zgl::shader_handle, 3>>{};
|
||||
|
||||
auto capability_indices = ztu::string_lookup<ztu::u32>();
|
||||
auto capabilities = std::vector<ztu::u32>{};
|
||||
capabilities.reserve(8);
|
||||
|
||||
constexpr auto dot_char = '.';
|
||||
constexpr auto separator_char = '_';
|
||||
constexpr auto optional_char = '?';
|
||||
|
||||
auto curr_shader_count = std::size_t{ 0 };
|
||||
|
||||
for (const auto& [ asset_type, folder ] : {
|
||||
std::make_pair(asset_types::mesh, "mesh"sv),
|
||||
std::make_pair(asset_types::point_cloud, "point_cloud"sv),
|
||||
}) {
|
||||
program_capabilities.clear();
|
||||
programs.clear();
|
||||
capability_indices.clear();
|
||||
|
||||
for (const auto& file : fs::directory_iterator{ path / folder })
|
||||
{
|
||||
if (not file.is_regular_file())
|
||||
continue;
|
||||
|
||||
const auto& file_path = file.path();
|
||||
|
||||
if (file_path.extension() != ".glsl")
|
||||
continue;
|
||||
|
||||
const auto filename = file_path.filename().string();
|
||||
|
||||
progress_lock.lock();
|
||||
|
||||
progress_builder.str(std::string{});
|
||||
progress_builder << "Loading shader '" << filename << "\'...";
|
||||
progress_title = progress_builder.str();
|
||||
progress_ratio = shader_loading_progress * static_cast<float>(curr_shader_count) / shader_file_count;
|
||||
|
||||
progress_lock.unlock();
|
||||
|
||||
const auto name = std::string_view(filename.begin(), std::ranges::find(filename, dot_char));
|
||||
|
||||
const auto type_str = std::string_view(name.begin(), std::ranges::find(name, separator_char));
|
||||
|
||||
const auto shader_type_index_it = shader_indices.find(type_str);
|
||||
if (shader_type_index_it == shader_indices.end()) {
|
||||
ztu::logger::warn("Unknown shader type '%'. Skipping shader.", type_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto shader_type_index = shader_type_index_it->second;
|
||||
const auto shader_type = shader_types[shader_type_index];
|
||||
|
||||
auto shader_handle = zgl::shader_handle{};
|
||||
if (const auto e = loader.load_shader(shader_type, file_path, shader_handle)) {
|
||||
ztu::logger::error(
|
||||
"Error while loading shader %: [%] %",
|
||||
file_path,
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ztu::logger::debug("% -> %", filename, shader_handle.shader_id);
|
||||
|
||||
capabilities.clear();
|
||||
capabilities.push_back(0);
|
||||
|
||||
auto specifiers_str = std::string_view(type_str.end() + 1, name.end()); // skip separator_char
|
||||
|
||||
while (not specifiers_str.empty())
|
||||
{
|
||||
const auto pos = specifiers_str.find(separator_char);
|
||||
auto specifier_str = specifiers_str.substr(0, pos);
|
||||
|
||||
if (pos == std::string_view::npos)
|
||||
{
|
||||
specifiers_str = std::string_view{};
|
||||
}
|
||||
else
|
||||
{
|
||||
specifiers_str = specifiers_str.substr(pos + 1); // skip separator_char
|
||||
}
|
||||
|
||||
if (specifier_str.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto optional = specifier_str.back() == optional_char;
|
||||
if (optional)
|
||||
{
|
||||
specifier_str = specifier_str.substr(0, specifier_str.size() - 1);
|
||||
}
|
||||
|
||||
const auto index_it = capability_indices.find(specifier_str);
|
||||
|
||||
auto capability_index = capability_indices.size();
|
||||
if (index_it == capability_indices.end())
|
||||
{
|
||||
capability_indices.emplace(specifier_str, capability_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
capability_index = index_it->second;
|
||||
}
|
||||
|
||||
const auto capability_flag = ztu::u32{ 1 } << capability_index;
|
||||
|
||||
const auto capability_count = capabilities.size();
|
||||
|
||||
if (optional)
|
||||
{
|
||||
capabilities.resize(2 * capability_count);
|
||||
std::copy_n(capabilities.begin(), capability_count, capabilities.begin() + capability_count);
|
||||
}
|
||||
|
||||
for (std::size_t i{}; i != capability_count; ++i)
|
||||
{
|
||||
capabilities[i] |= capability_flag;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& capability : capabilities)
|
||||
{
|
||||
const auto program_capability_it = std::ranges::upper_bound(program_capabilities, capability);
|
||||
|
||||
auto program_index = program_capability_it - program_capabilities.begin();
|
||||
|
||||
if (
|
||||
program_capability_it == program_capabilities.begin() or
|
||||
*std::prev(program_capability_it) != capability
|
||||
) {
|
||||
program_capabilities.insert(program_capability_it, capability);
|
||||
programs.emplace(programs.begin() + program_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
--program_index; // The element before the iterator matches.
|
||||
}
|
||||
|
||||
programs[program_index][shader_type_index] = shader_handle;
|
||||
}
|
||||
|
||||
++curr_shader_count;
|
||||
}
|
||||
|
||||
progress_lock.lock();
|
||||
|
||||
progress_title = "Linking programs...";
|
||||
|
||||
progress_lock.unlock();
|
||||
|
||||
// Remove any duplicates shader combinations.
|
||||
std::ranges::sort(
|
||||
programs,
|
||||
[](const auto& lhs, const auto& rhs) {
|
||||
return std::lexicographical_compare(
|
||||
lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return a.shader_id < b.shader_id;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
programs.erase(std::ranges::unique(programs).begin(), programs.end());
|
||||
|
||||
ztu::logger::debug("Linking % programs.", programs.size());
|
||||
|
||||
// create shader_program
|
||||
for (const auto& [vertex, geometry, fragment] : programs)
|
||||
{
|
||||
if (vertex.shader_id == 0 or fragment.shader_id == 0)
|
||||
{
|
||||
ztu::logger::warn(
|
||||
"Skipping program as the combination is unlikely to be used (vertex: % geometry: % fragment: %).",
|
||||
vertex.shader_id, geometry.shader_id, fragment.shader_id
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto program_handle = zgl::shader_program_handle{};
|
||||
if (const auto e = loader.build_shader_program(vertex, geometry, fragment, program_handle))
|
||||
{
|
||||
ztu::logger::error(
|
||||
"Error occurred while linking shader program: [%] %",
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ztu::logger::debug(
|
||||
"Linked (vertex: % geometry: % fragment: %) -> %",
|
||||
vertex.shader_id, geometry.shader_id, fragment.shader_id,
|
||||
program_handle.program_id
|
||||
);
|
||||
|
||||
|
||||
gl_resource_lock.lock();
|
||||
z3d.add_shader_program(asset_type, program_handle);
|
||||
gl_resource_lock.unlock();
|
||||
}
|
||||
|
||||
gl_resource_lock.lock();
|
||||
z3d.m_mesh_shader_program_lookup.print();
|
||||
gl_resource_lock.unlock();
|
||||
|
||||
loader.unload_shader_data();
|
||||
}
|
||||
}
|
||||
504
source/viewer/instance.cpp
Normal file
504
source/viewer/instance.cpp
Normal 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";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user