diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 77ce906..d0c82d8 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -147,6 +147,9 @@
+
+
+
diff --git a/.idea/editor.xml b/.idea/editor.xml
index 00465ab..f6606eb 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -98,6 +98,483 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0310f9d..0b76fe5 100755
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,11 +1,5 @@
-
-
-
-
-
-
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index f74a0f8..a32aab4 100755
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,6 +3,5 @@
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46d0684..e03bc57 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,12 +102,11 @@ add_executable(z3d main.cpp
source/opengl/handles/shader_program_handle.cpp
include/opengl/shader_program_lookup.hpp
source/opengl/shader_program_lookup.cpp
- include/shader_program/attributes/mesh_attributes.hpp
include/shader_program/attributes/point_cloud_attributes.hpp
include/shader_program/uniforms/mesh_uniforms.hpp
include/shader_program/uniforms/point_cloud_uniforms.hpp
- include/shader_program/capabilities/mesh_capabilities.hpp
- include/shader_program/capabilities/point_cloud_capabilities.hpp
+ include/shader_program/features/mesh_features.hpp
+ include/shader_program/features/point_cloud_features.hpp
include/rendering/requirements/mesh_requirements.hpp
include/rendering/requirements/point_cloud_requirements.hpp
include/rendering/modes/mesh_modes.hpp
@@ -123,11 +122,11 @@ add_executable(z3d main.cpp
source/geometry/normal_estimation.cpp
include/geometry/normal_estimation.hpp
include/assets/components/texture_components.hpp
- include/util/enum_operators.hpp
+ include/util/enum_bitfield_operators.hpp
include/assets/dynamic_read_buffers/dynamic_texture_buffer.hpp
source/assets/dynamic_read_buffers/dynamic_mesh_buffer.ipp
source/assets/dynamic_read_buffers/dynamic_material_buffer.ipp
- include/assets/dynamic_read_buffers/dynamic_vertex_buffer.hpp
+ include/assets/dynamic_read_buffers/generic/dynamic_vertex_buffer.hpp
source/assets/dynamic_read_buffers/dynamic_model_buffer.ipp
source/assets/dynamic_read_buffers/dynamic_texture_buffer.ipp
source/assets/dynamic_read_buffers/dynamic_point_cloud_buffer.ipp
@@ -173,12 +172,15 @@ add_executable(z3d main.cpp
include/assets/dynamic_data_loaders/dynamic_material_library_loader.hpp
include/assets/prefetch_lookups/material_library_prefetch_lookup.hpp
include/assets/prefetch_lookups/shader_prefetch_lookup.hpp
- include/assets/dynamic_data_stores/dynamic_shader_store.hpp
+ include/assets/dynamic_data_stores/dynamic_shader_source_store.hpp
include/assets/data_loaders/generic/generic_3dtk_loader.hpp
source/assets/data_loaders/generic/generic_3dtk_loader.ipp
include/assets/prefetch_lookup.hpp
source/assets/prefetch_lookups/pose_prefetch_lookup.cpp
include/assets/dynamic_data_store.hpp
+ include/opengl/data_uploaders/shader_program_compiler.hpp
+ include/shader_program/metadata_type.hpp
+ source/opengl/data_uploaders/shader_compiler.cpp
)
target_include_directories(z3d PRIVATE include)
diff --git a/include/assets/components/material_components.hpp b/include/assets/components/material_components.hpp
index e66dfbe..58871c7 100644
--- a/include/assets/components/material_components.hpp
+++ b/include/assets/components/material_components.hpp
@@ -3,7 +3,7 @@
#include
#include "../dynamic_read_buffers"
#include "assets/data/surface_properties.hpp"
-#include "util/enum_operators.hpp"
+#include "util/enum_bitfield_operators.hpp"
namespace components::material
{
@@ -56,4 +56,4 @@ constexpr inline auto count = std::tuple_size_v;
} // namespace material_component
-DEFINE_ENUM_FLAG_OPERATORS(components::material::flags)
+DEFINE_ENUM_BITFIELD_OPERATORS(components::material::flags)
diff --git a/include/assets/components/mesh_vertex_components.hpp b/include/assets/components/mesh_vertex_components.hpp
index ff578b8..42fe50a 100755
--- a/include/assets/components/mesh_vertex_components.hpp
+++ b/include/assets/components/mesh_vertex_components.hpp
@@ -2,7 +2,7 @@
#include
#include
-#include "util/enum_operators.hpp"
+#include "util/enum_bitfield_operators.hpp"
namespace components::mesh_vertex {
@@ -36,4 +36,4 @@ constexpr inline auto count = std::tuple_size_v;
} // namespace components::mesh_vertex
-DEFINE_ENUM_FLAG_OPERATORS(components::mesh_vertex::flags)
+DEFINE_ENUM_BITFIELD_OPERATORS(components::mesh_vertex::flags)
diff --git a/include/assets/components/point_cloud_vertex_components.hpp b/include/assets/components/point_cloud_vertex_components.hpp
index 98e3ca1..bcaf1c8 100755
--- a/include/assets/components/point_cloud_vertex_components.hpp
+++ b/include/assets/components/point_cloud_vertex_components.hpp
@@ -2,7 +2,7 @@
#include
#include
-#include "util/enum_operators.hpp"
+#include "util/enum_bitfield_operators.hpp"
namespace components::point_cloud_vertex {
@@ -33,4 +33,4 @@ constexpr inline auto count = std::tuple_size_v;
} // namespace components::point_cloud_vertex
-DEFINE_ENUM_FLAG_OPERATORS(components::point_cloud_vertex::flags)
+DEFINE_ENUM_BITFIELD_OPERATORS(components::point_cloud_vertex::flags)
diff --git a/include/assets/components/texture_components.hpp b/include/assets/components/texture_components.hpp
index f560d31..0ea7f16 100644
--- a/include/assets/components/texture_components.hpp
+++ b/include/assets/components/texture_components.hpp
@@ -2,7 +2,7 @@
#include
#include
-#include "util/enum_operators.hpp"
+#include "util/enum_bitfield_operators.hpp"
namespace components::texture {
@@ -25,4 +25,4 @@ constexpr inline auto count = std::tuple_size_v;
} // namespace components::texture
-DEFINE_ENUM_FLAG_OPERATORS(components::texture::flags)
\ No newline at end of file
+DEFINE_ENUM_BITFIELD_OPERATORS(components::texture::flags)
\ No newline at end of file
diff --git a/include/assets/data_loaders/glsl_loader.hpp b/include/assets/data_loaders/glsl_loader.hpp
index d585c09..5387189 100644
--- a/include/assets/data_loaders/glsl_loader.hpp
+++ b/include/assets/data_loaders/glsl_loader.hpp
@@ -24,7 +24,7 @@ struct glsl_loader
dynamic_shader_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
};
\ No newline at end of file
diff --git a/include/assets/data_loaders/kitti_loader.hpp b/include/assets/data_loaders/kitti_loader.hpp
index 3948380..ccf97b3 100644
--- a/include/assets/data_loaders/kitti_loader.hpp
+++ b/include/assets/data_loaders/kitti_loader.hpp
@@ -26,7 +26,7 @@ struct kitti_loader
dynamic_point_cloud_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
diff --git a/include/assets/data_loaders/kitti_pose_loader.hpp b/include/assets/data_loaders/kitti_pose_loader.hpp
index ce553c1..7fefe1c 100644
--- a/include/assets/data_loaders/kitti_pose_loader.hpp
+++ b/include/assets/data_loaders/kitti_pose_loader.hpp
@@ -23,7 +23,7 @@ struct kitti_pose_loader
dynamic_pose_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
diff --git a/include/assets/data_loaders/mtl_loader.hpp b/include/assets/data_loaders/mtl_loader.hpp
index db8d53a..9d9df81 100644
--- a/include/assets/data_loaders/mtl_loader.hpp
+++ b/include/assets/data_loaders/mtl_loader.hpp
@@ -41,7 +41,7 @@ struct mtl_loader
dynamic_material_library_buffer& material_library_buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
diff --git a/include/assets/data_loaders/obj_loader.hpp b/include/assets/data_loaders/obj_loader.hpp
index a0aedd4..197f998 100755
--- a/include/assets/data_loaders/obj_loader.hpp
+++ b/include/assets/data_loaders/obj_loader.hpp
@@ -38,7 +38,7 @@ struct obj_loader {
dynamic_mesh_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
@@ -76,7 +76,7 @@ protected:
std::set& vertex_ids,
std::ifstream& in,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic
);
};
diff --git a/include/assets/data_loaders/stl_loader.hpp b/include/assets/data_loaders/stl_loader.hpp
index 4c0b1f1..cee3a8c 100644
--- a/include/assets/data_loaders/stl_loader.hpp
+++ b/include/assets/data_loaders/stl_loader.hpp
@@ -24,7 +24,7 @@ struct stl_loader {
dynamic_mesh_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
};
diff --git a/include/assets/data_loaders/threedtk_pose_loader.hpp b/include/assets/data_loaders/threedtk_pose_loader.hpp
index 7365857..b545a05 100644
--- a/include/assets/data_loaders/threedtk_pose_loader.hpp
+++ b/include/assets/data_loaders/threedtk_pose_loader.hpp
@@ -23,7 +23,7 @@ struct threedtk_pose_loader
dynamic_pose_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic = false
);
diff --git a/include/assets/dynamic_data_store.hpp b/include/assets/dynamic_data_store.hpp
index 3214758..8c138b9 100644
--- a/include/assets/dynamic_data_store.hpp
+++ b/include/assets/dynamic_data_store.hpp
@@ -5,7 +5,7 @@
#include "dynamic_data_stores/dynamic_mesh_store.hpp"
#include "dynamic_data_stores/dynamic_point_cloud_store.hpp"
#include "dynamic_data_stores/dynamic_pose_store.hpp"
-#include "dynamic_data_stores/dynamic_shader_store.hpp"
+#include "dynamic_data_stores/dynamic_shader_source_store.hpp"
#include "dynamic_data_stores/dynamic_texture_store.hpp"
struct dynamic_data_store
diff --git a/include/assets/dynamic_data_stores/dynamic_shader_source_store.hpp b/include/assets/dynamic_data_stores/dynamic_shader_source_store.hpp
new file mode 100644
index 0000000..e6a6947
--- /dev/null
+++ b/include/assets/dynamic_data_stores/dynamic_shader_source_store.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "generic/generic_dynamic_store.hpp"
+#include "assets/dynamic_read_buffers/dynamic_shader_buffer.hpp"
+
+// TODO use compressed store where all shaders are condensed into one vector
+using dynamic_shader_source_store = generic_dynamic_store;
diff --git a/include/assets/dynamic_data_stores/dynamic_shader_store.hpp b/include/assets/dynamic_data_stores/dynamic_shader_store.hpp
deleted file mode 100644
index 1b88e2b..0000000
--- a/include/assets/dynamic_data_stores/dynamic_shader_store.hpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "generic/generic_dynamic_store.hpp"
-#include "glm/mat4x4.hpp"
-
-class dynamic_shader_store {
-
-
-};
\ No newline at end of file
diff --git a/include/opengl/data_uploaders/shader_compiler.hpp b/include/opengl/data_uploaders/shader_compiler.hpp
new file mode 100644
index 0000000..d770224
--- /dev/null
+++ b/include/opengl/data_uploaders/shader_compiler.hpp
@@ -0,0 +1,204 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+#include "assets/dynamic_data_stores/dynamic_shader_source_store.hpp"
+#include "opengl/shader_program_lookup.hpp"
+#include "opengl/handles/shader_handle.hpp"
+#include "opengl/handles/shader_program_handle.hpp"
+#include "shader_program/metadata_type.hpp"
+#include "shader_program/features/mesh_features.hpp"
+#include "shader_program/features/point_cloud_features.hpp"
+#include "util/string_lookup.hpp"
+#include "shader_program/metadata_type.hpp"
+
+namespace zgl
+{
+class shader_program_compiler
+{
+
+public:
+
+
+
+ // compile shader programs for given requirements
+ // cache shader programs with their capabilities
+ // store sstream for creating defines
+
+ // register shader source code
+ // store define types for these shaders as bitmap
+ void register_shader_sources(
+ const dynamic_shader_source_store& shader_sources
+ );
+
+ void compile_shaders(
+ const dynamic_shader_source_store& shader_sources,
+ std::span required_capabilities,
+ std::vector& shader_handles
+ );
+
+
+protected:
+ void tokenize_declarations(
+ std::string_view source,
+ std::vector tokens,
+ std::vector declaration_token_counts,
+ std::span declaration_type_indices
+ );
+
+ std::optional parse_metadata_from_tokens(
+ std::span tokens,
+ std::span declaration_token_counts,
+ std::span declaration_type_indices
+ );
+
+ [[nodiscard]] static bool parse_stage_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+ );
+
+ [[nodiscard]] static bool parse_geometry_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+ );
+
+ [[nodiscard]] static bool parse_features_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+ );
+
+ [[nodiscard]] static bool parse_feature_toggles_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+ );
+
+ template
+ static void parse_feature_tokens(
+ std::span tokens,
+ const ztu::string_lookup& feature_lookup,
+ T& features
+ );
+
+ std::optional zgl::shader_program_compiler::find_compatible_shader_source(
+ shader_program::metadata_type& requirements
+ );
+
+ template
+ void add_required_feature_defines(
+ T toggle_flags,
+ std::span defines,
+ std::vector& shader_strings
+ );
+
+private:
+ enum class metadata_declaration_type : std::size_t
+ {
+ stage = 0,
+ geometry = 1,
+ features = 2,
+ feature_toggles = 3,
+ invalid = std::numeric_limits::max()
+ };
+
+ inline static auto declaration_lookup = ztu::string_lookup{
+ { "STAGE", metadata_declaration_type::stage },
+ { "GEOMETRY", metadata_declaration_type::geometry },
+ { "FEATURES", metadata_declaration_type::features },
+ { "FEATURE_TOGGLES", metadata_declaration_type::feature_toggles }
+ };
+
+ inline static auto stage_lookup = ztu::string_lookup{
+ { "VERTEX", shader_program::stages::vertex },
+ { "GEOMETRY", shader_program::stages::geometry },
+ { "FRAGMENT", shader_program::stages::fragment },
+ };
+
+ inline static auto geometry_lookup = ztu::string_lookup{
+ { "MESH", shader_program::geometries::mesh },
+ { "POINT_CLOUD", shader_program::geometries::point_cloud }
+ };
+
+ inline static auto mesh_feature_lookup = []
+ {
+ using namespace shader_program::features::mesh;
+
+ auto lookup = ztu::string_lookup{};
+ lookup.reserve(all.size());
+
+ constexpr auto all_flags = std::array{
+ flags::face, flags::line, flags::point,
+ flags::luminance, flags::color, flags::alpha,
+ flags::lighting, flags::texture, flags::uniform_color
+ };
+
+ for (const auto& [ define, flag ] : std::ranges::views::zip(defines, all_flags))
+ {
+ lookup.emplace(std::string(define), flag);
+ }
+
+ return lookup;
+ }();
+
+ inline static auto point_cloud_feature_lookup = []
+ {
+ using namespace shader_program::features::point_cloud;
+
+ auto lookup = ztu::string_lookup{};
+ lookup.reserve(all.size());
+
+ constexpr auto all_flags = std::array{
+ flags::square, flags::lighting, flags::luminance,
+ flags::color, flags::alpha, flags::uniform_color,
+ flags::rainbow
+ };
+
+ for (const auto& [ define, flag ] : std::ranges::views::zip(defines, all_flags))
+ {
+ lookup.emplace(std::string(define), flag);
+ }
+
+ return lookup;
+ }();
+
+ inline static auto mesh_feature_defines = []
+ {
+ using namespace shader_program::features::mesh;
+
+ auto statements = std::array{};
+
+ std::ranges::transform(
+ defines,
+ statements.begin(),
+ [](const auto& name) {
+ return std::format("#define {}\n", name);
+ }
+ );
+
+ return statements;
+ }();
+
+ inline static auto point_cloud_feature_defines = []
+ {
+ using namespace shader_program::features::point_cloud;
+
+ auto statements = std::array{};
+
+ std::ranges::transform(
+ defines,
+ statements.begin(),
+ [](const auto& name) {
+ return std::format("#define {}\n", name);
+ }
+ );
+
+ return statements;
+ }();
+
+
+ std::vector> shader_lookup;
+};
+}
diff --git a/include/opengl/data_uploaders/shader_program_compiler.hpp b/include/opengl/data_uploaders/shader_program_compiler.hpp
new file mode 100644
index 0000000..825de19
--- /dev/null
+++ b/include/opengl/data_uploaders/shader_program_compiler.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include
+#include "assets/dynamic_data_stores/dynamic_shader_source_store.hpp"
+#include "opengl/shader_program_lookup.hpp"
+#include "opengl/handles/shader_program_handle.hpp"
+
+template
+class shader_program_compiler
+{
+
+ public:
+
+
+ // compile shader programs for given requirements
+ // cache shader programs with their capabilities
+ // store sstream for creating defines
+
+ // register shader source code
+ // store define types for these shaders as bitmap
+ void register_shader_sources(
+ const dynamic_shader_source_store& shader_sources
+ );
+
+ void find_or_compile_shader_programs(
+ std::span required_capabilities,
+ zgl::shader_program_lookup& shader_program_lookup
+ );
+
+
+ // create metadata for all sources
+
+ // get
+
+protected:
+
+
+
+private:
+ std::unordered_map shader_capabilities;
+
+};
diff --git a/include/opengl/data_uploaders/texture_data_uploader.hpp b/include/opengl/data_uploaders/texture_data_uploader.hpp
index be5c621..3ece240 100644
--- a/include/opengl/data_uploaders/texture_data_uploader.hpp
+++ b/include/opengl/data_uploaders/texture_data_uploader.hpp
@@ -16,52 +16,42 @@ class texture_data_uploader
) {
std::vector texture_ids;
- std::vector invalid_texture_ids;
texture_ids.resize(dynamic_data.size());
glGenTextures(texture_ids.size(), texture_ids.data());
- auto texture_id_it = texture_ids.begin();
-
- for (std::size_t i{}; i != dynamic_data.size(); ++i)
- {
- const auto& texture_id = *texture_id_it;
- const auto& texture = dynamic_data[i];
-
- glBindTexture(GL_TEXTURE_2D, texture_id);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- GLenum format;
- switch (texture.components()) {
- using enum components::texture::flags;
- case luminance:
- format = GL_LUMINANCE;
- break;
- case luminance | alpha:
- format = GL_LUMINANCE_ALPHA;
- break;
- case red | green | blue:
- format = GL_RGB;
- break;
- case red | green | blue | alpha:
- format = GL_RGBA;
- break;
- default:
- format = GL_INVALID_ENUM;
- break;
- }
-
- if (format == GL_INVALID_ENUM)
- {
- invalid_texture_ids.push_back(texture_id);
- }
- else
+ const auto invalid_texture_ids = std::ranges::partition(
+ texture_ids,
+ [](GLuint texture_id)
{
+ GLenum format;
+ switch (texture.components()) {
+ using enum components::texture::flags;
+ case luminance:
+ format = GL_LUMINANCE;
+ break;
+ case luminance | alpha:
+ format = GL_LUMINANCE_ALPHA;
+ break;
+ case red | green | blue:
+ format = GL_RGB;
+ break;
+ case red | green | blue | alpha:
+ format = GL_RGBA;
+ break;
+ default:
+ return false;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+
glTexImage2D(
GL_TEXTURE_2D, 0,
GL_RGBA8,
@@ -73,12 +63,16 @@ class texture_data_uploader
texture.data()
);
glGenerateMipmap(GL_TEXTURE_2D);
+
+ return true;
}
- }
+ );
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteTextures(invalid_texture_ids.size(), invalid_texture_ids.data());
+
+ invalid_texture_ids.resize(texture_ids.size() - invalid_texture_ids.size());
}
};
}
diff --git a/include/rendering/requirements/mesh_requirements.hpp b/include/rendering/requirements/mesh_requirements.hpp
index fbe515d..35cab33 100644
--- a/include/rendering/requirements/mesh_requirements.hpp
+++ b/include/rendering/requirements/mesh_requirements.hpp
@@ -2,7 +2,7 @@
#include "assets/components/material_components.hpp"
#include "assets/components/mesh_vertex_components.hpp"
-#include "shader_program/capabilities/mesh_capabilities.hpp"
+#include "shader_program/features/mesh_features.hpp"
#include
diff --git a/include/rendering/requirements/point_cloud_requirements.hpp b/include/rendering/requirements/point_cloud_requirements.hpp
index 4502ae3..759ac67 100644
--- a/include/rendering/requirements/point_cloud_requirements.hpp
+++ b/include/rendering/requirements/point_cloud_requirements.hpp
@@ -1,7 +1,7 @@
#pragma once
#include "assets/components/point_cloud_vertex_components.hpp"
-#include "shader_program/capabilities/point_cloud_capabilities.hpp"
+#include "shader_program/features/point_cloud_features.hpp"
#include
diff --git a/include/shader_program/attributes/mesh_attributes.hpp b/include/shader_program/attributes/mesh_attributes.hpp
index c017a3d..9ebab60 100644
--- a/include/shader_program/attributes/mesh_attributes.hpp
+++ b/include/shader_program/attributes/mesh_attributes.hpp
@@ -2,82 +2,42 @@
#include "opengl/shader_program_variable.hpp"
#include
+#include "util/enum_bitfield_operators.hpp"
+#include
namespace shader_program::attributes::mesh
{
-enum class flags : int {
+enum class flags : unsigned {
none = 0,
position = 1 << 0,
normal = 1 << 1,
- tex_coord = 1 << 2
+ luminance = 1 << 2,
+ color = 1 << 3,
+ alpha = 1 << 4,
+ tex_coord = 1 << 5
};
-constexpr inline auto position = zgl::shader_program_variable({ GL_FLOAT_VEC3, 0 }, "vertex_position");
-constexpr inline auto normal = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "vertex_normal");
-constexpr inline auto tex_coord = zgl::shader_program_variable({ GL_FLOAT_VEC2, 2 }, "vertex_tex_coord");
+constexpr inline auto position = zgl::shader_program_variable({ GL_FLOAT_VEC3, 0 }, "model_vertex_position");
+constexpr inline auto normal = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "model_vertex_normal");
+constexpr inline auto luminance = zgl::shader_program_variable({ GL_FLOAT, 2 }, "model_vertex_l");
+constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 2 }, "model_vertex_rgb");
+constexpr inline auto alpha = zgl::shader_program_variable({ GL_FLOAT, 3 }, "model_vertex_a");
+constexpr inline auto tex_coord = zgl::shader_program_variable({ GL_FLOAT_VEC2, 2 }, "model_vertex_tex_coord");
constexpr inline auto all = std::array{
- position, normal, tex_coord
+ position, normal, luminance, color, alpha, tex_coord
+};
+
+constexpr inline auto names = std::array{
+ "position",
+ "normal",
+ "luminance",
+ "color",
+ "alpha",
+ "tex_coord"
};
}
-
-[[nodiscard]] constexpr shader_program::attributes::mesh::flags operator|(
- const shader_program::attributes::mesh::flags& a, const shader_program::attributes::mesh::flags& b
-) {
- return static_cast(static_cast(a) | static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::attributes::mesh::flags operator&(
- const shader_program::attributes::mesh::flags& a, const shader_program::attributes::mesh::flags& b
-) {
- return static_cast(static_cast(a) & static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::attributes::mesh::flags operator^(
- const shader_program::attributes::mesh::flags& a, const shader_program::attributes::mesh::flags& b
-) {
- return static_cast(static_cast(a) ^ static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::attributes::mesh::flags operator~(const shader_program::attributes::mesh::flags& a) {
- return static_cast(~static_cast(a));
-}
-
-constexpr shader_program::attributes::mesh::flags& operator|=(shader_program::attributes::mesh::flags& a, const shader_program::attributes::mesh::flags& b) {
- return a = a | b;
-}
-
-constexpr shader_program::attributes::mesh::flags& operator&=(shader_program::attributes::mesh::flags& a, const shader_program::attributes::mesh::flags& b) {
- return a = a & b;
-}
-
-constexpr shader_program::attributes::mesh::flags& operator^=(shader_program::attributes::mesh::flags& a, const shader_program::attributes::mesh::flags& b) {
- return a = a ^ b;
-}
-
-[[nodiscard]] constexpr bool operator<(
- shader_program::attributes::mesh::flags lhs, shader_program::attributes::mesh::flags rhs
-) {
- return static_cast(lhs) < static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator<=(
- shader_program::attributes::mesh::flags lhs, shader_program::attributes::mesh::flags rhs
-) {
- return static_cast(lhs) <= static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>(
- shader_program::attributes::mesh::flags lhs, shader_program::attributes::mesh::flags rhs
-) {
- return static_cast(lhs) > static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>=(
- shader_program::attributes::mesh::flags lhs, shader_program::attributes::mesh::flags rhs
-) {
- return static_cast(lhs) >= static_cast(rhs);
-}
+DEFINE_ENUM_BITFIELD_OPERATORS(shader_program::attributes::mesh::flags)
diff --git a/include/shader_program/attributes/point_cloud_attributes.hpp b/include/shader_program/attributes/point_cloud_attributes.hpp
index 5533e34..cebece4 100644
--- a/include/shader_program/attributes/point_cloud_attributes.hpp
+++ b/include/shader_program/attributes/point_cloud_attributes.hpp
@@ -2,83 +2,40 @@
#include "opengl/shader_program_variable.hpp"
#include
+#include "util/enum_bitfield_operators.hpp"
+#include
namespace shader_program::attributes::point_cloud
{
-enum class flags : int {
+enum class flags : unsigned {
none = 0,
position = 1 << 0,
normal = 1 << 1,
+ luminance = 1 << 2,
color = 1 << 2,
- reflectance = 1 << 3
+ alpha = 1 << 3
};
-constexpr inline auto position = zgl::shader_program_variable({ GL_FLOAT_VEC3, 0 }, "vertex_position");
-constexpr inline auto normal = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "vertex_normal");
-constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 2 }, "vertex_color");
-constexpr inline auto reflectance = zgl::shader_program_variable({ GL_FLOAT, 2 }, "vertex_reflectance");
+constexpr inline auto position = zgl::shader_program_variable({ GL_FLOAT_VEC3, 0 }, "model_vertex_position");
+constexpr inline auto normal = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "model_vertex_normal");
+constexpr inline auto luminance = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "model_vertex_l");
+constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "model_vertex_rgb");
+constexpr inline auto alpha = zgl::shader_program_variable({ GL_FLOAT_VEC3, 1 }, "model_vertex_a");
constexpr inline auto all = std::array{
- position, normal, color, reflectance
+ position, normal, luminance, color, alpha
};
+constexpr inline auto names = std::array{
+ "position",
+ "normal",
+ "luminance",
+ "color",
+ "alpha"
+};
+
+
}
-[[nodiscard]] constexpr shader_program::attributes::point_cloud::flags operator|(
- const shader_program::attributes::point_cloud::flags& a, const shader_program::attributes::point_cloud::flags& b
-) {
- return static_cast(static_cast(a) | static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::attributes::point_cloud::flags operator&(
- const shader_program::attributes::point_cloud::flags& a, const shader_program::attributes::point_cloud::flags& b
-) {
- return static_cast(static_cast(a) & static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::attributes::point_cloud::flags operator^(
- const shader_program::attributes::point_cloud::flags& a, const shader_program::attributes::point_cloud::flags& b
-) {
- return static_cast(static_cast(a) ^ static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::attributes::point_cloud::flags operator~(const shader_program::attributes::point_cloud::flags& a) {
- return static_cast(~static_cast(a));
-}
-
-constexpr shader_program::attributes::point_cloud::flags& operator|=(shader_program::attributes::point_cloud::flags& a, const shader_program::attributes::point_cloud::flags& b) {
- return a = a | b;
-}
-
-constexpr shader_program::attributes::point_cloud::flags& operator&=(shader_program::attributes::point_cloud::flags& a, const shader_program::attributes::point_cloud::flags& b) {
- return a = a & b;
-}
-
-constexpr shader_program::attributes::point_cloud::flags& operator^=(shader_program::attributes::point_cloud::flags& a, const shader_program::attributes::point_cloud::flags& b) {
- return a = a ^ b;
-}
-
-[[nodiscard]] constexpr bool operator<(
- shader_program::attributes::point_cloud::flags lhs, shader_program::attributes::point_cloud::flags rhs
-) {
- return static_cast(lhs) < static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator<=(
- shader_program::attributes::point_cloud::flags lhs, shader_program::attributes::point_cloud::flags rhs
-) {
- return static_cast(lhs) <= static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>(
- shader_program::attributes::point_cloud::flags lhs, shader_program::attributes::point_cloud::flags rhs
-) {
- return static_cast(lhs) > static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>=(
- shader_program::attributes::point_cloud::flags lhs, shader_program::attributes::point_cloud::flags rhs
-) {
- return static_cast(lhs) >= static_cast(rhs);
-}
+DEFINE_ENUM_BITFIELD_OPERATORS(shader_program::attributes::point_cloud::flags)
diff --git a/include/shader_program/capabilities/mesh_capabilities.hpp b/include/shader_program/capabilities/mesh_capabilities.hpp
deleted file mode 100644
index fd6b1f1..0000000
--- a/include/shader_program/capabilities/mesh_capabilities.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#pragma once
-
-#include "assets/components/mesh_vertex_components.hpp"
-#include "assets/components/point_cloud_vertex_components.hpp"
-#include "assets/components/material_components.hpp"
-#include "shader_program/attributes/mesh_attributes.hpp"
-#include "shader_program/uniforms/mesh_uniforms.hpp"
-
-namespace shader_program::capabilities::mesh
-{
-
-struct type
-{
- attributes::mesh::flags attributes{
- attributes::mesh::flags::none
- };
- uniforms::mesh::flags uniforms{
- uniforms::mesh::flags::none
- };
-};
-
-namespace indices
-{
-using type = ztu::u8;
-constexpr inline type position = 0;
-constexpr inline type lit = 1;
-constexpr inline type textured = 2;
-constexpr inline type uniform_color = 3;
-constexpr inline type uniform_alpha = 4;
-constexpr inline type point = 5;
-}
-
-enum class flags : int
-{
- none = 0,
- position = 1 << indices::position,
- lit = 1 << indices::lit,
- textured = 1 << indices::textured,
- uniform_color = 1 << indices::uniform_color,
- uniform_alpha = 1 << indices::uniform_alpha,
- point = 1 << indices::point
-};
-
-constexpr inline auto position = type{
- .attributes = attributes::mesh::flags::position,
- .uniforms = uniforms::mesh::flags::mvp
-};
-
-constexpr inline auto lit = type{
- .attributes = attributes::mesh::flags::normal,
- .uniforms = (
- uniforms::mesh::flags::model_matrix |
- uniforms::mesh::flags::view_pos |
- uniforms::mesh::flags::point_light_direction |
- uniforms::mesh::flags::point_light_color |
- uniforms::mesh::flags::ambient_light_color |
- uniforms::mesh::flags::ambient_filter |
- uniforms::mesh::flags::diffuse_filter |
- uniforms::mesh::flags::specular_filter |
- uniforms::mesh::flags::shininess
- )
-};
-
-constexpr inline auto point = type{
- .uniforms = uniforms::mesh::flags::point_size
-};
-
-constexpr inline auto textured = type{
- .attributes = attributes::mesh::flags::tex_coord,
- .uniforms = uniforms::mesh::flags::tex
-};
-
-constexpr inline auto uniform_color = type{
- .uniforms = uniforms::mesh::flags::color
-};
-
-constexpr inline auto uniform_alpha = type{
- .uniforms = uniforms::mesh::flags::alpha
-};
-
-constexpr inline auto all = std::array{
- position, lit, textured, uniform_color, uniform_alpha, point
-};
-
-}
diff --git a/include/shader_program/capabilities/point_cloud_capabilities.hpp b/include/shader_program/capabilities/point_cloud_capabilities.hpp
deleted file mode 100644
index 018a09a..0000000
--- a/include/shader_program/capabilities/point_cloud_capabilities.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#pragma once
-
-#include "shader_program/attributes/point_cloud_attributes.hpp"
-#include "shader_program/uniforms/point_cloud_uniforms.hpp"
-
-#include "assets/components/mesh_vertex_components.hpp"
-#include "assets/components/point_cloud_vertex_components.hpp"
-
-#include
-
-namespace shader_program::capabilities::point_cloud
-{
-
-struct type
-{
- attributes::point_cloud::flags attributes{
- attributes::point_cloud::flags::none
- };
- uniforms::point_cloud::flags uniforms{
- uniforms::point_cloud::flags::none
- };
-};
-
-namespace indices
-{
-using type = ztu::u8;
-constexpr inline type position = 0;
-constexpr inline type vertex_color = 1;
-constexpr inline type uniform_color = 2;
-constexpr inline type normal = 3;
-constexpr inline type reflectance = 4;
-constexpr inline type rainbow = 5;
-}
-
-enum class flags : int
-{
- none = 0,
- position = 1 << indices::position,
- vertex_color = 1 << indices::vertex_color,
- uniform_color = 1 << indices::uniform_color,
- normal = 1 << indices::normal,
- reflectance = 1 << indices::reflectance,
- rainbow = 1 << indices::rainbow
- };
-
-constexpr inline auto position = type{
- .attributes = attributes::point_cloud::flags::position,
- .uniforms = uniforms::point_cloud::flags::mvp
-};
-
-constexpr inline auto rainbow = type{};
-
-constexpr inline auto vertex_color = type{
- .attributes = attributes::point_cloud::flags::color
-};
-
-constexpr inline auto uniform_color = type{
- .uniforms = uniforms::point_cloud::flags::color
-};
-
-constexpr inline auto normal = type{
- .attributes = attributes::point_cloud::flags::normal,
- .uniforms = (
- uniforms::point_cloud::flags::model |
- uniforms::point_cloud::flags::camera_position
- )
-};
-
-constexpr inline auto reflectance = type{
- .attributes = attributes::point_cloud::flags::reflectance
- };
-
-constexpr inline auto all = std::array{
- position, vertex_color, uniform_color, normal, reflectance, rainbow
-};
-
-}
diff --git a/include/shader_program/features/mesh_features.hpp b/include/shader_program/features/mesh_features.hpp
new file mode 100644
index 0000000..e08f888
--- /dev/null
+++ b/include/shader_program/features/mesh_features.hpp
@@ -0,0 +1,134 @@
+#pragma once
+
+#include "assets/components/mesh_vertex_components.hpp"
+#include "assets/components/point_cloud_vertex_components.hpp"
+#include "assets/components/material_components.hpp"
+#include "shader_program/attributes/mesh_attributes.hpp"
+#include "shader_program/uniforms/mesh_uniforms.hpp"
+#include
+#include
+
+namespace shader_program::features::mesh
+{
+
+struct type
+{
+ attributes::mesh::flags attributes{
+ attributes::mesh::flags::none
+ };
+ uniforms::mesh::flags uniforms{
+ uniforms::mesh::flags::none
+ };
+};
+
+namespace indices
+{
+using type = ztu::u8;
+constexpr inline type face = 0;
+constexpr inline type line = 1;
+constexpr inline type point = 2;
+constexpr inline type luminance = 3;
+constexpr inline type color = 4;
+constexpr inline type alpha = 5;
+constexpr inline type lighting = 6;
+constexpr inline type texture = 7;
+constexpr inline type uniform_color = 8;
+}
+
+enum class flags : unsigned
+{
+ none = 0,
+ face = 1 << indices::face,
+ line = 1 << indices::line,
+ point = 1 << indices::point,
+ luminance = 1 << indices::luminance,
+ color = 1 << indices::color,
+ alpha = 1 << indices::alpha,
+ lighting = 1 << indices::lighting,
+ texture = 1 << indices::texture,
+ uniform_color = 1 << indices::uniform_color,
+};
+
+constexpr inline auto face = type{
+ .attributes = attributes::mesh::flags::position,
+ .uniforms = uniforms::mesh::flags::mvp_matrix
+};
+
+constexpr inline auto line = type{
+ .attributes = attributes::mesh::flags::position,
+ .uniforms = uniforms::mesh::flags::mvp_matrix
+};
+
+constexpr inline auto point = type{
+ .attributes = attributes::mesh::flags::position,
+ .uniforms = (
+ uniforms::mesh::flags::mvp_matrix |
+ uniforms::mesh::flags::point_size
+ )
+};
+
+constexpr inline auto luminance = type{
+ .attributes = attributes::mesh::flags::luminance
+};
+
+constexpr inline auto color = type{
+ .attributes = attributes::mesh::flags::color
+};
+
+constexpr inline auto alpha = type{
+ .attributes = attributes::mesh::flags::alpha
+};
+
+constexpr inline auto lighting = type{
+ .attributes = attributes::mesh::flags::normal,
+ .uniforms = (
+ uniforms::mesh::flags::model_matrix |
+ uniforms::mesh::flags::view_pos |
+ uniforms::mesh::flags::point_light_direction |
+ uniforms::mesh::flags::point_light_color |
+ uniforms::mesh::flags::ambient_light_color |
+ uniforms::mesh::flags::ambient_filter |
+ uniforms::mesh::flags::diffuse_filter |
+ uniforms::mesh::flags::specular_filter |
+ uniforms::mesh::flags::shininess
+ )
+};
+
+constexpr inline auto texture = type{
+ .attributes = attributes::mesh::flags::tex_coord,
+ .uniforms = uniforms::mesh::flags::tex
+};
+
+constexpr inline auto uniform_color = type{
+ .uniforms = uniforms::mesh::flags::color
+};
+
+constexpr inline auto all = std::array{
+ face, line, point, luminance, color, alpha, lighting, texture, uniform_color
+};
+
+constexpr inline auto names = std::array{
+ "face",
+ "line",
+ "point",
+ "luminance",
+ "color",
+ "alpha",
+ "lighting",
+ "texture",
+ "uniform_color"
+};
+
+constexpr inline auto defines = std::array{
+ "FACE",
+ "LINE",
+ "POINT",
+ "V_L",
+ "V_RGB",
+ "V_A",
+ "LIGHTING",
+ "TEXTURE",
+ "U_RGBA"
+};
+
+}
diff --git a/include/shader_program/features/point_cloud_features.hpp b/include/shader_program/features/point_cloud_features.hpp
new file mode 100644
index 0000000..8bad731
--- /dev/null
+++ b/include/shader_program/features/point_cloud_features.hpp
@@ -0,0 +1,112 @@
+#pragma once
+
+#include "shader_program/attributes/point_cloud_attributes.hpp"
+#include "shader_program/uniforms/point_cloud_uniforms.hpp"
+
+#include "assets/components/mesh_vertex_components.hpp"
+#include "assets/components/point_cloud_vertex_components.hpp"
+
+#include
+
+namespace shader_program::features::point_cloud
+{
+
+struct type
+{
+ attributes::point_cloud::flags attributes{
+ attributes::point_cloud::flags::none
+ };
+ uniforms::point_cloud::flags uniforms{
+ uniforms::point_cloud::flags::none
+ };
+};
+
+namespace indices
+{
+using type = ztu::u8;
+constexpr inline type square = 0;
+constexpr inline type lighting = 1;
+constexpr inline type luminance = 2;
+constexpr inline type color = 3;
+constexpr inline type alpha = 4;
+constexpr inline type uniform_color = 5;
+constexpr inline type rainbow = 6;
+}
+
+enum class flags : unsigned
+{
+ none = 0,
+ square = 1 << indices::square,
+ lighting = 1 << indices::lighting,
+ luminance = 1 << indices::luminance,
+ color = 1 << indices::color,
+ alpha = 1 << indices::alpha,
+ uniform_color = 1 << indices::uniform_color,
+ rainbow = 1 << indices::rainbow
+ };
+
+constexpr inline auto square = type{
+ .attributes = attributes::point_cloud::flags::position,
+ .uniforms = (
+ uniforms::point_cloud::flags::mvp_matrix |
+ uniforms::point_cloud::flags::point_size
+ )
+};
+
+constexpr inline auto lighting = type{
+ .attributes = attributes::point_cloud::flags::normal,
+ .uniforms = (
+ uniforms::point_cloud::flags::model_matrix |
+ uniforms::point_cloud::flags::camera_position
+ )
+};
+
+constexpr inline auto luminance = type{
+ .attributes = attributes::point_cloud::flags::luminance
+};
+
+constexpr inline auto color = type{
+ .attributes = attributes::point_cloud::flags::color
+};
+
+constexpr inline auto alpha = type{
+ .attributes = attributes::point_cloud::flags::alpha
+};
+
+constexpr inline auto uniform_color = type{
+ .uniforms = uniforms::point_cloud::flags::color
+};
+
+constexpr inline auto rainbow = type{
+ .uniforms = (
+ uniforms::point_cloud::flags::rainbow_offset_y |
+ uniforms::point_cloud::flags::rainbow_scale_y
+ )
+};
+
+constexpr inline auto all = std::array{
+ square, lighting, luminance, color, alpha, uniform_color, rainbow
+};
+
+constexpr inline auto names = std::array{
+ "square",
+ "lighting",
+ "luminance",
+ "color",
+ "alpha",
+ "uniform_color",
+ "rainbow"
+};
+
+constexpr inline auto defines = std::array{
+ "SQUARE",
+ "LIGHTING",
+ "V_L",
+ "V_RGB",
+ "V_A",
+ "U_RGBA",
+ "RAINBOW"
+};
+
+
+}
diff --git a/include/shader_program/metadata_type.hpp b/include/shader_program/metadata_type.hpp
new file mode 100644
index 0000000..5c5cb64
--- /dev/null
+++ b/include/shader_program/metadata_type.hpp
@@ -0,0 +1,219 @@
+#pragma once
+
+#include
+#include
+
+#include "features/mesh_features.hpp"
+#include "features/point_cloud_features.hpp"
+
+namespace shader_program
+{
+
+enum class geometries : int
+{
+ mesh = 0,
+ point_cloud = 1
+};
+
+enum class stages : GLenum
+{
+ vertex = GL_VERTEX_SHADER,
+ geometry = GL_GEOMETRY_SHADER,
+ fragment = GL_FRAGMENT_SHADER
+};
+
+
+
+
+union combined_feature_type
+{
+ features::mesh::flags mesh;
+ features::point_cloud::flags point_cloud;
+
+ using generic_type = std::common_type_t<
+ std::underlying_type_t,
+ std::underlying_type_t
+ >;
+
+ generic_type generic(const geometries geometry) const noexcept
+ {
+ switch (geometry)
+ {
+ case geometries::mesh:
+ return static_cast(mesh);
+ case geometries::point_cloud:
+ return static_cast(point_cloud);
+ }
+ std::unreachable();
+ }
+
+ void from_generic(
+ const geometries geometry,
+ generic_type new_features
+ ) noexcept {
+ switch (geometry)
+ {
+ case geometries::mesh:
+ mesh = static_cast(new_features);
+ case geometries::point_cloud:
+ point_cloud = static_cast(new_features);
+ }
+ std::unreachable();
+ }
+};
+
+
+struct metadata_type
+{
+ geometries geometry;
+ stages stage;
+ combined_feature_type features;
+ combined_feature_type feature_toggles;
+
+ std::pair generic() const noexcept
+ {
+ switch (geometry)
+ {
+ case geometries::mesh:
+ return {
+ static_cast(features.mesh),
+ static_cast(feature_toggles.mesh)
+ };
+ case geometries::point_cloud:
+ return {
+ static_cast(features.point_cloud),
+ static_cast(feature_toggles.point_cloud)
+ };
+ }
+ std::unreachable();
+ }
+
+ void from_generic(
+ combined_feature_type::generic_type new_features,
+ combined_feature_type::generic_type new_feature_toggles
+ ) noexcept {
+ switch (geometry)
+ {
+ case geometries::mesh:
+ features.mesh = static_cast(new_features);
+ feature_toggles.mesh = static_cast(new_feature_toggles);
+ case geometries::point_cloud:
+ features.point_cloud = static_cast(new_features);
+ feature_toggles.point_cloud = static_cast(new_feature_toggles);
+ }
+ std::unreachable();
+ }
+
+ auto operator<=>(const metadata_type& other) const noexcept
+ {
+ if (this->geometry == other.geometry)
+ {
+ switch (this->geometry)
+ {
+ case geometries::mesh:
+ return (
+ std::tie(this->stage, this->features.mesh, this->feature_toggles.mesh) <=>
+ std::tie(other.stage, other.features.mesh, other.feature_toggles.mesh)
+ );
+ case geometries::point_cloud:
+ return (
+ std::tie(this->stage, this->features.point_cloud, this->feature_toggles.point_cloud) <=>
+ std::tie(other.stage, other.features.point_cloud, other.feature_toggles.point_cloud)
+ );
+ }
+ std::unreachable();
+ }
+ else
+ {
+ return this->geometry <=> other.geometry;
+ }
+ }
+
+ bool operator==(const metadata_type& other) const noexcept
+ {
+ if (this->geometry == other.geometry)
+ {
+ switch (this->geometry)
+ {
+ case geometries::mesh:
+ return (
+ std::tie(this->stage, this->features.mesh, this->feature_toggles.mesh) ==
+ std::tie(other.stage, other.features.mesh, other.feature_toggles.mesh)
+ );
+ case geometries::point_cloud:
+ return (
+ std::tie(this->stage, this->features.point_cloud, this->feature_toggles.point_cloud) ==
+ std::tie(other.stage, other.features.point_cloud, other.feature_toggles.point_cloud)
+ );
+ }
+ std::unreachable();
+ }
+
+ return false;
+ }
+
+
+ struct feature_ignorant_less
+ {
+ bool operator()(const metadata_type& a, const metadata_type& b) const
+ {
+ return (
+ std::tie(a.geometry, a.stage) <
+ std::tie(a.geometry, b.stage)
+ );
+ }
+ };
+
+ struct feature_count_less
+ {
+ bool operator()(const metadata_type& a, const metadata_type& b) const
+ {
+ if (a.geometry == b.geometry)
+ {
+ int feature_count{}, feature_toggle_count{};
+ int other_feature_count{}, other_feature_toggle_count{};
+
+ constexpr auto count_features = [](const T features)
+ {
+ using int_type = std::underlying_type_t;
+ using uint_type = std::make_unsigned_t;
+ return std::popcount(static_cast(static_cast(features)));
+ };
+
+ switch (a.geometry)
+ {
+ case geometries::mesh:
+ for (auto& [ count, features ] : {
+ std::tie(feature_count, a.features.mesh),
+ std::tie(feature_toggle_count, a.feature_toggles.mesh),
+ std::tie(other_feature_count, b.features.mesh),
+ std::tie(other_feature_toggle_count, b.feature_toggles.mesh)
+ }) {
+ count = count_features(features);
+ }
+ case geometries::point_cloud:
+ for (auto& [ count, features ] : {
+ std::tie(feature_count, a.features.point_cloud),
+ std::tie(feature_toggle_count, a.feature_toggles.point_cloud),
+ std::tie(other_feature_count, b.features.point_cloud),
+ std::tie(other_feature_toggle_count, b.feature_toggles.point_cloud)
+ }) {
+ count = count_features(features);
+ }
+ default:
+ std::unreachable();
+ }
+ return (
+ std::tie(a.stage, feature_count, feature_toggle_count) <
+ std::tie(b.stage, other_feature_count, other_feature_toggle_count)
+ );
+ }
+ else
+ {
+ return a.geometry < b.geometry;
+ }
+ }
+ };
+};
+
+}
diff --git a/include/shader_program/uniforms/mesh_uniforms.hpp b/include/shader_program/uniforms/mesh_uniforms.hpp
index afa8dd8..c631a81 100644
--- a/include/shader_program/uniforms/mesh_uniforms.hpp
+++ b/include/shader_program/uniforms/mesh_uniforms.hpp
@@ -2,14 +2,15 @@
#include "opengl/shader_program_variable.hpp"
#include
+#include "util/enum_bitfield_operators.hpp"
namespace shader_program::uniforms::mesh
{
-enum class flags : int
+enum class flags : unsigned
{
none = 0,
- mvp = 1 << 0,
+ mvp_matrix = 1 << 0,
model_matrix = 1 << 1,
point_size = 1 << 2,
color = 1 << 3,
@@ -21,27 +22,25 @@ enum class flags : int
ambient_filter = 1 << 9,
diffuse_filter = 1 << 10,
specular_filter = 1 << 11,
- shininess = 1 << 12,
- alpha = 1 << 13
+ shininess = 1 << 12
};
-constexpr inline auto mvp = zgl::shader_program_variable({ GL_FLOAT_MAT4, 0 }, "mvp_matrix");
+constexpr inline auto mvp_matrix = zgl::shader_program_variable({ GL_FLOAT_MAT4, 0 }, "mvp_matrix");
constexpr inline auto model_matrix = zgl::shader_program_variable({ GL_FLOAT_MAT4, 1 }, "model_matrix");
constexpr inline auto point_size = zgl::shader_program_variable({ GL_FLOAT, 2 }, "point_size");
-constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC4, 3 }, "color");
constexpr inline auto tex = zgl::shader_program_variable({ GL_SAMPLER_2D, 3 }, "tex");
-constexpr inline auto view_pos = zgl::shader_program_variable({ GL_FLOAT_VEC3, 4 }, "view_pos");
-constexpr inline auto point_light_direction = zgl::shader_program_variable({ GL_FLOAT_VEC3, 5 }, "point_light_direction");
-constexpr inline auto point_light_color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 6 }, "point_light_color");
-constexpr inline auto ambient_light_color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 7 }, "ambient_light_color");
-constexpr inline auto ambient_filter = zgl::shader_program_variable({ GL_FLOAT_VEC3, 8 }, "ambient_filter");
-constexpr inline auto diffuse_filter = zgl::shader_program_variable({ GL_FLOAT_VEC3, 9 }, "diffuse_filter");
-constexpr inline auto specular_filter = zgl::shader_program_variable({ GL_FLOAT_VEC3, 10 }, "specular_filter");
-constexpr inline auto shininess = zgl::shader_program_variable({ GL_FLOAT, 11 }, "shininess");
-constexpr inline auto alpha = zgl::shader_program_variable({ GL_FLOAT, 12 }, "alpha");
+constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC4, 4 }, "color");
+constexpr inline auto view_pos = zgl::shader_program_variable({ GL_FLOAT_VEC3, 5 }, "view_pos");
+constexpr inline auto point_light_direction = zgl::shader_program_variable({ GL_FLOAT_VEC3, 6 }, "point_light_direction");
+constexpr inline auto point_light_color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 7 }, "point_light_color");
+constexpr inline auto ambient_light_color = zgl::shader_program_variable({ GL_FLOAT_VEC3, 8 }, "ambient_light_color");
+constexpr inline auto ambient_filter = zgl::shader_program_variable({ GL_FLOAT_VEC3, 9 }, "ambient_filter");
+constexpr inline auto diffuse_filter = zgl::shader_program_variable({ GL_FLOAT_VEC3, 10 }, "diffuse_filter");
+constexpr inline auto specular_filter = zgl::shader_program_variable({ GL_FLOAT_VEC3, 11 }, "specular_filter");
+constexpr inline auto shininess = zgl::shader_program_variable({ GL_FLOAT, 12 }, "shininess");
constexpr inline auto all = std::array{
- mvp,
+ mvp_matrix,
model_matrix,
point_size,
color,
@@ -53,65 +52,24 @@ constexpr inline auto all = std::array{
ambient_filter,
diffuse_filter,
specular_filter,
- shininess,
- alpha
+ shininess
+};
+
+constexpr inline auto names = std::array{
+ "mvp_matrix",
+ "model_matrix",
+ "point_size",
+ "color",
+ "tex",
+ "view_pos",
+ "point_light_direction",
+ "point_light_color",
+ "ambient_light_color",
+ "ambient_filter",
+ "diffuse_filter",
+ "specular_filter",
+ "shininess"
};
}
-[[nodiscard]] constexpr shader_program::uniforms::mesh::flags operator|(
- const shader_program::uniforms::mesh::flags& a, const shader_program::uniforms::mesh::flags& b
-) {
- return static_cast(static_cast(a) | static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::uniforms::mesh::flags operator&(
- const shader_program::uniforms::mesh::flags& a, const shader_program::uniforms::mesh::flags& b
-) {
- return static_cast(static_cast(a) & static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::uniforms::mesh::flags operator^(
- const shader_program::uniforms::mesh::flags& a, const shader_program::uniforms::mesh::flags& b
-) {
- return static_cast(static_cast(a) ^ static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::uniforms::mesh::flags operator~(const shader_program::uniforms::mesh::flags& a) {
- return static_cast(~static_cast(a));
-}
-
-constexpr shader_program::uniforms::mesh::flags& operator|=(shader_program::uniforms::mesh::flags& a, const shader_program::uniforms::mesh::flags& b) {
- return a = a | b;
-}
-
-constexpr shader_program::uniforms::mesh::flags& operator&=(shader_program::uniforms::mesh::flags& a, const shader_program::uniforms::mesh::flags& b) {
- return a = a & b;
-}
-
-constexpr shader_program::uniforms::mesh::flags& operator^=(shader_program::uniforms::mesh::flags& a, const shader_program::uniforms::mesh::flags& b) {
- return a = a ^ b;
-}
-
-[[nodiscard]] constexpr bool operator<(
- shader_program::uniforms::mesh::flags lhs, shader_program::uniforms::mesh::flags rhs
-) {
- return static_cast(lhs) < static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator<=(
- shader_program::uniforms::mesh::flags lhs, shader_program::uniforms::mesh::flags rhs
-) {
- return static_cast(lhs) <= static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>(
- shader_program::uniforms::mesh::flags lhs, shader_program::uniforms::mesh::flags rhs
-) {
- return static_cast(lhs) > static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>=(
- shader_program::uniforms::mesh::flags lhs, shader_program::uniforms::mesh::flags rhs
-) {
- return static_cast(lhs) >= static_cast(rhs);
-}
+DEFINE_ENUM_BITFIELD_OPERATORS(shader_program::uniforms::mesh::flags)
diff --git a/include/shader_program/uniforms/point_cloud_uniforms.hpp b/include/shader_program/uniforms/point_cloud_uniforms.hpp
index f849ab2..d6955ee 100644
--- a/include/shader_program/uniforms/point_cloud_uniforms.hpp
+++ b/include/shader_program/uniforms/point_cloud_uniforms.hpp
@@ -6,92 +6,46 @@
namespace shader_program::uniforms::point_cloud
{
-enum class flags : int
+enum class flags : unsigned
{
none = 0,
- mvp = 1 << 0,
+ mvp_matrix = 1 << 0,
point_size = 1 << 1,
color = 1 << 2,
- model = 1 << 3,
+ model_matrix = 1 << 3,
camera_position = 1 << 4,
rainbow_offset_y = 1 << 5,
- rainbow_scale_y = 1 << 6,
+ rainbow_scale_y = 1 << 6
};
-constexpr inline auto mvp = zgl::shader_program_variable({ GL_FLOAT_MAT4, 0 }, "mvp");
-constexpr inline auto point_size = zgl::shader_program_variable({ GL_FLOAT, 2 }, "point_size");
-constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC4, 3 }, "color");
-constexpr inline auto model = zgl::shader_program_variable({ GL_FLOAT_MAT4, 4 }, "model");
-constexpr inline auto camera_position = zgl::shader_program_variable({ GL_FLOAT_VEC3, 5 }, "camera_position");
-constexpr inline auto rainbow_offset_y = zgl::shader_program_variable({ GL_FLOAT, 6 }, "rainbow_offset_y");
-constexpr inline auto rainbow_scale_y = zgl::shader_program_variable({ GL_FLOAT, 7 }, "rainbow_scale_y");
+constexpr inline auto mvp_matrix = zgl::shader_program_variable({ GL_FLOAT_MAT4, 0 }, "mvp_matrix");
+constexpr inline auto point_size = zgl::shader_program_variable({ GL_FLOAT, 1 }, "point_size");
+constexpr inline auto color = zgl::shader_program_variable({ GL_FLOAT_VEC4, 2 }, "color");
+constexpr inline auto model_matrix = zgl::shader_program_variable({ GL_FLOAT_MAT4, 3 }, "model_matrix");
+constexpr inline auto camera_position = zgl::shader_program_variable({ GL_FLOAT_VEC3, 4 }, "camera_position");
+constexpr inline auto rainbow_offset_y = zgl::shader_program_variable({ GL_FLOAT, 5 }, "rainbow_offset_y");
+constexpr inline auto rainbow_scale_y = zgl::shader_program_variable({ GL_FLOAT, 6 }, "rainbow_scale_y");
constexpr inline auto all = std::array{
- mvp,
+ mvp_matrix,
point_size,
color,
- model,
+ model_matrix,
camera_position,
rainbow_offset_y,
rainbow_scale_y
};
+constexpr inline auto names = std::array{
+ "mvp_matrix",
+ "point_size",
+ "color",
+ "model_matrix",
+ "camera_position",
+ "rainbow_offset_y",
+ "rainbow_scale_y"
+};
+
}
-[[nodiscard]] constexpr shader_program::uniforms::point_cloud::flags operator|(
- const shader_program::uniforms::point_cloud::flags& a, const shader_program::uniforms::point_cloud::flags& b
-) {
- return static_cast(static_cast(a) | static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::uniforms::point_cloud::flags operator&(
- const shader_program::uniforms::point_cloud::flags& a, const shader_program::uniforms::point_cloud::flags& b
-) {
- return static_cast(static_cast(a) & static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::uniforms::point_cloud::flags operator^(
- const shader_program::uniforms::point_cloud::flags& a, const shader_program::uniforms::point_cloud::flags& b
-) {
- return static_cast(static_cast(a) ^ static_cast(b));
-}
-
-[[nodiscard]] constexpr shader_program::uniforms::point_cloud::flags operator~(const shader_program::uniforms::point_cloud::flags& a) {
- return static_cast(~static_cast(a));
-}
-
-constexpr shader_program::uniforms::point_cloud::flags& operator|=(shader_program::uniforms::point_cloud::flags& a, const shader_program::uniforms::point_cloud::flags& b) {
- return a = a | b;
-}
-
-constexpr shader_program::uniforms::point_cloud::flags& operator&=(shader_program::uniforms::point_cloud::flags& a, const shader_program::uniforms::point_cloud::flags& b) {
- return a = a & b;
-}
-
-constexpr shader_program::uniforms::point_cloud::flags& operator^=(shader_program::uniforms::point_cloud::flags& a, const shader_program::uniforms::point_cloud::flags& b) {
- return a = a ^ b;
-}
-
-[[nodiscard]] constexpr bool operator<(
- shader_program::uniforms::point_cloud::flags lhs, shader_program::uniforms::point_cloud::flags rhs
-) {
- return static_cast(lhs) < static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator<=(
- shader_program::uniforms::point_cloud::flags lhs, shader_program::uniforms::point_cloud::flags rhs
-) {
- return static_cast(lhs) <= static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>(
- shader_program::uniforms::point_cloud::flags lhs, shader_program::uniforms::point_cloud::flags rhs
-) {
- return static_cast(lhs) > static_cast(rhs);
-}
-
-[[nodiscard]] constexpr bool operator>=(
- shader_program::uniforms::point_cloud::flags lhs, shader_program::uniforms::point_cloud::flags rhs
-) {
- return static_cast(lhs) >= static_cast(rhs);
-}
+DEFINE_ENUM_BITFIELD_OPERATORS(shader_program::uniforms::point_cloud::flags)
diff --git a/include/util/enum_operators.hpp b/include/util/enum_bitfield_operators.hpp
similarity index 64%
rename from include/util/enum_operators.hpp
rename to include/util/enum_bitfield_operators.hpp
index 601df2c..15e6350 100644
--- a/include/util/enum_operators.hpp
+++ b/include/util/enum_bitfield_operators.hpp
@@ -1,6 +1,6 @@
#pragma once
-#define DEFINE_ENUM_FLAG_OPERATORS(ENUM_TYPE) \
+#define DEFINE_ENUM_BITFIELD_OPERATORS(ENUM_TYPE) \
[[nodiscard]] constexpr ENUM_TYPE operator|( \
const ENUM_TYPE lhs, const ENUM_TYPE rhs \
) { \
@@ -35,6 +35,24 @@
); \
} \
\
+constexpr ENUM_TYPE operator<<( \
+ ENUM_TYPE& lhs, \
+ int shift \
+) { \
+ return static_cast( \
+ static_cast>(lhs) << shift \
+ ); \
+} \
+ \
+constexpr ENUM_TYPE operator<<( \
+ ENUM_TYPE& lhs, \
+ int shift \
+) { \
+ return static_cast( \
+ static_cast>(lhs) << shift \
+ ); \
+} \
+ \
constexpr ENUM_TYPE& operator|=( \
ENUM_TYPE& lhs, \
const ENUM_TYPE rhs \
@@ -54,4 +72,18 @@ constexpr ENUM_TYPE& operator^=( \
const ENUM_TYPE rhs \
) { \
return lhs = lhs ^ rhs; \
+} \
+ \
+constexpr ENUM_TYPE& operator<<=( \
+ ENUM_TYPE& lhs, \
+ const int shift \
+) { \
+ return lhs = lhs << shift; \
+} \
+ \
+constexpr ENUM_TYPE& operator>>=( \
+ ENUM_TYPE& lhs, \
+ const int shift \
+) { \
+ return lhs = lhs >> shift; \
}
diff --git a/shaders/fragment_mesh_face.glsl b/shaders/fragment_mesh_face.glsl
new file mode 100644
index 0000000..a80b614
--- /dev/null
+++ b/shaders/fragment_mesh_face.glsl
@@ -0,0 +1,59 @@
+#pragma STAGE: FRAGMENT
+#pragma GEOMETRY: MESH
+#pragma FEATURES: FACE LINE V_L V_RGB V_A LIGHTING TEXTURE U_RGBA
+#pragma FEATURE_TOGGLES: LIGHTING TEXTURE
+
+
+//------------[ Uniforms ]------------//
+#ifdef TEXTURE
+layout (location = 3) uniform sampler2D tex;
+#endif
+#ifdef LIGHTING
+layout (location = 5) uniform vec3 view_pos;
+layout (location = 6) uniform vec3 point_light_direction;
+layout (location = 7) uniform vec3 point_light_color;
+layout (location = 8) uniform vec3 ambient_light_color;
+layout (location = 9) uniform vec3 ambient_filter;
+layout (location = 10) uniform vec3 diffuse_filter;
+layout (location = 11) uniform vec3 specular_filter;
+layout (location = 12) uniform float shininess;
+#endif
+
+
+//------------[ Inputs ]------------//
+layout (location = 0) in vec4 frag_color;
+#ifdef LIGHTING
+layout (location = 1) in vec3 frag_position;
+layout (location = 2) in vec3 frag_normal;
+#endif
+#ifdef TEXTURE
+layout (location = 2) in vec2 frag_tex_coord;
+#endif
+
+
+//------------[ Outputs ]------------//
+layout (location = 0) out vec4 pixel_color;
+
+
+void main()
+{
+ pixel_color = frag_color;
+
+#ifdef TEXTURE
+ pixel_color *= texture(tex, frag_tex_coord);
+#endif
+
+#ifdef LIGHTING
+ vec3 ambient = pixel_color.rgb * ambient_filter * ambient_light_color;
+
+ float point_light_alignment = max(dot(frag_normal, point_light_direction), 0.0);
+ vec3 diffuse = pixel_color.rgb * diffuse_filter * point_light_color * point_light_alignment;
+
+ vec3 reflection_dir = reflect(-point_light_direction, frag_normal);
+ vec3 view_dir = normalize(frag_position - view_pos);
+ float specular_strength = pow(max(dot(view_dir, reflection_dir), 0.0), shininess);
+ vec3 specular = specular_filter * point_light_color * specular_strength;
+
+ pixel_color.rgb *= ambient + diffuse + specular;
+#endif
+}
diff --git a/shaders/fragment_mesh_point.glsl b/shaders/fragment_mesh_point.glsl
new file mode 100644
index 0000000..e22e4b6
--- /dev/null
+++ b/shaders/fragment_mesh_point.glsl
@@ -0,0 +1,18 @@
+#pragma STAGE: FRAGMENT
+#pragma GEOMETRY: MESH
+#pragma FEATURES: POINT V_L V_RGB V_A LIGHTING U_RGBA
+#pragma FEATURE_TOGGLES:
+
+
+//------------[ Inputs ]------------//
+layout (location = 0) in vec4 frag_color;
+
+
+//------------[ Outputs ]------------//
+layout (location = 0) out vec4 pixel_color;
+
+
+void main()
+{
+ pixel_color = frag_color;
+}
diff --git a/shaders/fragment_point_cloud.glsl b/shaders/fragment_point_cloud.glsl
new file mode 100644
index 0000000..e7c6440
--- /dev/null
+++ b/shaders/fragment_point_cloud.glsl
@@ -0,0 +1,18 @@
+#pragma STAGE: FRAGMENT
+#pragma GEOMETRY: POINT_CLOUD
+#pragma FEATURES: SQUARE V_L V_RGB V_A LIGHTING U_RGBA RAINBOW
+#pragma FEATURE_TOGGLES:
+
+
+//------------[ Inputs ]------------//
+layout (location = 0) in vec4 frag_color;
+
+
+//------------[ Outputs ]------------//
+layout (location = 0) out vec4 pixel_color;
+
+
+void main()
+{
+ pixel_color = frag_color;
+}
diff --git a/shaders/mesh/fragment_face.glsl b/shaders/mesh/fragment_face.glsl
deleted file mode 100644
index 4d7fedc..0000000
--- a/shaders/mesh/fragment_face.glsl
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifdef TEXTURE
-#ifdef U_COLOR
-#error Texture and color attribute are mutually exclusive.
-#endif
-#endif
-
-out vec4 pixel_color;
-
-#ifdef TEXTURE
-layout (location = 3) uniform sampler2D tex;
-layout (location = 2) in vec2 frag_tex_coord;
-#endif
-
-#ifdef U_COLOR
-layout (location = 3) uniform vec4 color;
-#endif
-
-#ifdef LIGHTING
-layout (location = 4) uniform vec3 view_pos;
-layout (location = 5) uniform vec3 point_light_direction;
-layout (location = 6) uniform vec3 point_light_color;
-layout (location = 7) uniform vec3 ambient_light_color;
-layout (location = 8) uniform vec3 ambient_filter;
-layout (location = 9) uniform vec3 diffuse_filter;
-layout (location = 10) uniform vec3 specular_filter;
-layout (location = 11) uniform float shininess;
-layout (location = 0) in vec3 frag_position;
-layout (location = 1) in vec3 frag_normal;
-#endif
-
-#ifdef U_ALPHA
-layout (location = 12) uniform float alpha;
-#endif
-
-void main() {
-
- pixel_color = vec4(1);
-
-#ifdef TEXTURE
- pixel_color *= texture(tex, frag_tex_coord);
-#endif
-
-#ifdef U_COLOR
- pixel_color *= color;
-#endif
-
-#ifdef U_ALPHA
- pixel_color.w *= alpha;
-#endif
-
-#ifdef LIGHTING
- vec3 ambient = pixel_color.rgb * ambient_filter * ambient_light_color;
-
- float point_light_alignment = max(dot(frag_normal, point_light_direction), 0.0);
- vec3 diffuse = pixel_color.rgb * diffuse_filter * point_light_color * point_light_alignment;
-
- vec3 reflection_dir = reflect(-point_light_direction, frag_normal);
- vec3 view_dir = normalize(frag_position - view_pos);
- float specular_strength = pow(max(dot(view_dir, reflection_dir), 0.0), shininess);
- vec3 specular = specular_filter * point_light_color * specular_strength;
-
- pixel_color.rgb *= ambient + diffuse + specular;
-#endif
-}
diff --git a/shaders/mesh/fragment_point.glsl b/shaders/mesh/fragment_point.glsl
deleted file mode 100644
index fc4fbfd..0000000
--- a/shaders/mesh/fragment_point.glsl
+++ /dev/null
@@ -1,7 +0,0 @@
-layout (location = 0) in vec4 frag_color;
-
-out vec4 pixel_color;
-
-void main() {
- pixel_color = frag_color;
-}
diff --git a/shaders/mesh/vertex_face.glsl b/shaders/mesh/vertex_face.glsl
deleted file mode 100644
index cbae90f..0000000
--- a/shaders/mesh/vertex_face.glsl
+++ /dev/null
@@ -1,27 +0,0 @@
-layout (location = 0) uniform mat4 mvp_matrix;
-layout (location = 0) in vec3 vertex_position;
-
-#ifdef LIGHTING
-layout (location = 1) uniform mat4 model_matrix;
-layout (location = 1) in vec3 vertex_normal;
-layout (location = 0) out vec3 frag_position;
-layout (location = 1) out vec3 frag_normal;
-#endif
-
-#ifdef TEXTURE
-layout (location = 2) in vec2 vertex_tex_coord;
-layout (location = 2) out vec2 frag_tex_coord;
-#endif
-
-void main() {
- gl_Position = mvp_matrix * vec4(vertex_position, 1.0);
-
-#ifdef LIGHTING
- frag_position = (model_matrix * vec4(vertex_position, 1.0)).xyz;
- frag_normal = normalize(mat3(model_matrix) * vertex_normal);
-#endif
-
-#ifdef TEXTURE
- frag_tex_coord = vertex_tex_coord;
-#endif
-}
diff --git a/shaders/mesh/vertex_point.glsl b/shaders/mesh/vertex_point.glsl
deleted file mode 100644
index ce9a662..0000000
--- a/shaders/mesh/vertex_point.glsl
+++ /dev/null
@@ -1,59 +0,0 @@
-layout (location = 0) uniform mat4 mvp_matrix;
-layout (location = 2) uniform float point_size;
-layout (location = 0) in vec3 vertex_position;
-layout (location = 0) out vec4 frag_color;
-
-#ifdef TEXTURE
-layout (location = 3) uniform sampler2D tex;
-layout (location = 2) in vec2 vertex_tex_coord;
-#endif
-
-#ifdef LIGHTING
-layout (location = 1) uniform mat4 model_matrix;
-layout (location = 4) uniform vec3 view_pos;
-layout (location = 5) uniform vec3 point_light_direction;
-layout (location = 6) uniform vec3 point_light_color;
-layout (location = 7) uniform vec3 ambient_light_color;
-layout (location = 8) uniform vec3 ambient_filter;
-layout (location = 9) uniform vec3 diffuse_filter;
-layout (location = 10) uniform vec3 specular_filter;
-layout (location = 11) uniform float shininess;
-layout (location = 1) in vec3 vertex_normal;
-#endif
-
-#ifdef U_ALPHA
-layout (location = 12) uniform float alpha;
-#endif
-
-void main() {
-
- gl_Position = mvp_matrix * vec4(vertex_position, 1.0);
- gl_PointSize = point_size / gl_Position.w;
-
- frag_color = vec4(1);
-
-#ifdef TEXTURE
- frag_color *= texture(tex, vertex_tex_coord);
-#endif
-
-#ifdef U_ALPHA
- frag_color.w *= alpha;
-#endif
-
-#ifdef LIGHTING
- vec3 position = (model_matrix * vec4(vertex_position, 1.0)).xyz;
- vec3 normal = normalize(mat3(model_matrix) * vertex_normal);
-
- vec3 ambient = frag_color.rgb * ambient_filter * ambient_light_color;
-
- float point_light_alignment = max(dot(normal, point_light_direction), 0.0);
- vec3 diffuse = frag_color.rgb * diffuse_filter * point_light_color * point_light_alignment;
-
- vec3 reflection_dir = reflect(-point_light_direction, normal);
- vec3 view_dir = normalize(position - view_pos);
- float specular_strength = pow(max(dot(view_dir, reflection_dir), 0.0), shininess);
- vec3 specular = specular_filter * point_light_color * specular_strength;
-
- frag_color.rgb *= ambient + diffuse + specular;
-#endif
-}
diff --git a/shaders/point_cloud/fragment.glsl b/shaders/point_cloud/fragment.glsl
deleted file mode 100644
index fc4fbfd..0000000
--- a/shaders/point_cloud/fragment.glsl
+++ /dev/null
@@ -1,7 +0,0 @@
-layout (location = 0) in vec4 frag_color;
-
-out vec4 pixel_color;
-
-void main() {
- pixel_color = frag_color;
-}
diff --git a/shaders/point_cloud/vertex.glsl b/shaders/point_cloud/vertex.glsl
deleted file mode 100644
index 7edaeb7..0000000
--- a/shaders/point_cloud/vertex.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-layout (location = 0) in vec3 vertex_position;
-layout (location = 0) uniform mat4 mvp_matrix;
-layout (location = 2) uniform float point_size;
-layout (location = 0) out vec4 frag_color;
-
-#ifdef LIGHTING
-layout (location = 4) uniform mat4 model_matrix;
-layout (location = 5) uniform vec3 camera_position;
-layout (location = 1) in vec3 vertex_normal;
-#endif
-
-#ifdef RAINBOW
-layout (location = 6) uniform float rainbow_offset_y;
-layout (location = 7) uniform float rainbow_scale_y;
-
-// taken from 'https://github.com/hughsk/glsl-hsv2rgb'
-vec3 hue2rgb(float hue)
-{
- vec4 offsets = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
- vec3 p = abs(fract(vec3(hue) + offsets.xyz) * 6.0 - offsets.www);
- return clamp(p - offsets.xxx, 0.0, 1.0);
-}
-#endif
-
-#ifdef REFLECTANCE
-layout (location = 2) in float vertex_reflectance;
-#endif
-
-void main()
-{
- gl_Position = mvp_matrix * vec4(vertex_position, 1.0);
- gl_PointSize = point_size / gl_Position.w;
-
- frag_color = vec4(1);
-
-#ifdef LIGHTING
- vec3 world_position = vec3(model_matrix * vec4(vertex_position, 1.0));
- vec3 world_normal = normalize(mat3(model_matrix) * vertex_normal);
- vec3 view_direction = normalize(camera_position - world_position);
- frag_color.rgb *= max(dot(world_normal, view_direction), 0.0);
-#endif
-
-#ifdef RAINBOW
- float rainbow_pos = rainbow_scale_y * (vertex_position.y + rainbow_offset_y);
- frag_color.rgb *= hue2rgb(mod(rainbow_pos, 1.0f));
-#endif
-
-#ifdef REFLECTANCE
- frag_color.rgb *= vertex_reflectance;
-#endif
-}
diff --git a/shaders/vertex_mesh_face.glsl b/shaders/vertex_mesh_face.glsl
new file mode 100644
index 0000000..197e2e4
--- /dev/null
+++ b/shaders/vertex_mesh_face.glsl
@@ -0,0 +1,84 @@
+#pragma STAGE: VERTEX
+#pragma GEOMETRY: MESH
+#pragma FEATURES: FACE LINE V_L V_RGB V_A LIGHTING TEXTURE U_RGBA
+#pragma FEATURE_TOGGLES: V_L V_RGB V_A LIGHTING TEXTURE U_RGBA
+
+
+#ifdef V_L
+#ifdef V_RGB
+#error Vertex luminance and vertex RGB are mutually exclusive
+#endif
+#endif
+
+
+//------------[ Uniforms ]------------//
+layout (location = 0) uniform mat4 mvp_matrix;
+#ifdef LIGHTING
+layout (location = 1) uniform mat4 model_matrix;
+#endif
+#ifdef U_RGBA
+layout (location = 4) uniform vec4 color;
+#endif
+
+
+//------------[ Inputs ]------------//
+layout (location = 0) in vec3 model_vertex_position;
+#ifdef LIGHTING
+layout (location = 1) in vec3 model_vertex_normal;
+#endif
+#ifdef V_L
+layout (location = 2) in float model_vertex_l;
+#endif
+#ifdef V_RGB
+layout (location = 2) in vec3 model_vertex_rgb;
+#endif
+#ifdef V_A
+layout (location = 3) in float model_vertex_a;
+#endif
+#ifdef TEXTURE
+layout (location = 4) in vec2 model_vertex_tex_coord;
+#endif
+
+
+//------------[ Outputs ]------------//
+layout (location = 0) out vec4 clip_vertex_color;
+#ifdef LIGHTING
+layout (location = 1) out vec3 clip_vertex_position;
+layout (location = 2) out vec3 clip_vertex_normal;
+#endif
+#ifdef TEXTURE
+layout (location = 3) out vec2 clip_vertex_tex_coord;
+#endif
+
+
+void main()
+{
+ gl_Position = mvp_matrix * vec4(model_vertex_position, 1.0);
+
+ clip_vertex_color = vec4(1);
+
+#ifdef V_L
+ clip_vertex_color.rgb *= model_vertex_l;
+#endif
+
+#ifdef V_RGB
+ clip_vertex_color.rgb *= model_vertex_rgb;
+#endif
+
+#ifdef V_A
+ clip_vertex_color.a *= model_vertex_a;
+#endif
+
+#ifdef U_RGBA
+ clip_vertex_color *= color;
+#endif
+
+#ifdef LIGHTING
+ clip_vertex_position = (model_matrix * vec4(model_vertex_position, 1.0)).xyz;
+ clip_vertex_normal = normalize(mat3(model_matrix) * model_vertex_normal);
+#endif
+
+#ifdef TEXTURE
+ clip_vertex_tex_coord = model_vertex_tex_coord;
+#endif
+}
diff --git a/shaders/vertex_mesh_point.glsl b/shaders/vertex_mesh_point.glsl
new file mode 100644
index 0000000..4045930
--- /dev/null
+++ b/shaders/vertex_mesh_point.glsl
@@ -0,0 +1,94 @@
+#pragma STAGE: VERTEX
+#pragma GEOMETRY: MESH
+#pragma FEATURES: POINT V_L V_RGB V_A LIGHTING U_RGBA
+#pragma FEATURE_TOGGLES: V_L V_RGB V_A LIGHTING U_RGBA
+
+
+#ifdef V_L
+#ifdef V_RGB
+#error Vertex luminance and vertex RGB are mutually exclusive
+#endif
+#endif
+
+
+//------------[ Uniforms ]------------//
+layout (location = 0) uniform mat4 mvp_matrix;
+#ifdef LIGHTING
+layout (location = 1) uniform mat4 model_matrix;
+#endif
+layout (location = 2) uniform float point_size;
+#ifdef U_RGBA
+layout (location = 4) uniform vec4 color;
+#endif
+#ifdef LIGHTING
+layout (location = 5) uniform vec3 view_pos;
+layout (location = 6) uniform vec3 point_light_direction;
+layout (location = 7) uniform vec3 point_light_color;
+layout (location = 8) uniform vec3 ambient_light_color;
+layout (location = 9) uniform vec3 ambient_filter;
+layout (location = 10) uniform vec3 diffuse_filter;
+layout (location = 11) uniform vec3 specular_filter;
+layout (location = 12) uniform float shininess;
+#endif
+
+
+//------------[ Inputs ]------------//
+layout (location = 0) in vec3 model_vertex_position;
+#ifdef LIGHTING
+layout (location = 1) in vec3 model_vertex_normal;
+#endif
+#ifdef V_L
+layout (location = 2) in float model_vertex_l;
+#endif
+#ifdef V_RGB
+layout (location = 2) in vec3 model_vertex_rgb;
+#endif
+#ifdef V_A
+layout (location = 3) in float model_vertex_a;
+#endif
+
+
+//------------[ Outputs ]------------//
+layout (location = 0) out vec4 clip_vertex_color;
+
+
+void main()
+{
+ gl_Position = mvp_matrix * vec4(model_vertex_position, 1.0);
+ gl_PointSize = point_size / gl_Position.w;
+
+ clip_vertex_color = vec4(1);
+
+#ifdef V_L
+ clip_vertex_color.rgb *= model_vertex_l;
+#endif
+
+#ifdef V_RGB
+ clip_vertex_color.rgb *= model_vertex_rgb;
+#endif
+
+#ifdef V_A
+ clip_vertex_color.a *= model_vertex_a;
+#endif
+
+#ifdef U_RGBA
+ clip_vertex_color *= color;
+#endif
+
+#ifdef LIGHTING
+ vec3 position = (model_matrix * vec4(model_vertex_position, 1.0)).xyz;
+ vec3 normal = normalize(mat3(model_matrix) * model_vertex_normal);
+
+ vec3 ambient = clip_vertex_color.rgb * ambient_filter * ambient_light_color;
+
+ float point_light_alignment = max(dot(normal, point_light_direction), 0.0);
+ vec3 diffuse = clip_vertex_color.rgb * diffuse_filter * point_light_color * point_light_alignment;
+
+ vec3 reflection_dir = reflect(-point_light_direction, normal);
+ vec3 view_dir = normalize(position - view_pos);
+ float specular_strength = pow(max(dot(view_dir, reflection_dir), 0.0), shininess);
+ vec3 specular = specular_filter * point_light_color * specular_strength;
+
+ clip_vertex_color.rgb *= ambient + diffuse + specular;
+#endif
+}
diff --git a/shaders/vertex_point_cloud.glsl b/shaders/vertex_point_cloud.glsl
new file mode 100644
index 0000000..1b01a18
--- /dev/null
+++ b/shaders/vertex_point_cloud.glsl
@@ -0,0 +1,95 @@
+#pragma STAGE: VERTEX
+#pragma GEOMETRY: POINT_CLOUD
+#pragma FEATURES: SQUARE V_L V_RGB V_A LIGHTING U_RGBA RAINBOW
+#pragma FEATURE_TOGGLES: V_L V_RGB V_A LIGHTING U_RGBA RAINBOW
+
+
+#ifdef V_L
+#ifdef V_RGB
+#error Vertex luminance and vertex RGB are mutually exclusive
+#endif
+#endif
+
+
+//------------[ Uniforms ]------------//
+layout (location = 0) uniform mat4 mvp_matrix;
+layout (location = 1) uniform float point_size;
+#ifdef U_RGBA
+layout (location = 2) uniform vec4 color;
+#endif
+#ifdef LIGHTING
+layout (location = 3) uniform mat4 model_matrix;
+layout (location = 4) uniform vec3 camera_position;
+#endif
+#ifdef RAINBOW
+layout (location = 5) uniform float rainbow_offset_y;
+layout (location = 6) uniform float rainbow_scale_y;
+#endif
+
+
+//------------[ Inputs ]------------//
+layout (location = 0) in vec3 model_vertex_position;
+#ifdef LIGHTING
+layout (location = 1) in vec3 model_vertex_normal;
+#endif
+#ifdef V_L
+layout (location = 2) in float model_vertex_l;
+#endif
+#ifdef V_RGB
+layout (location = 2) in vec3 model_vertex_rgb;
+#endif
+#ifdef V_A
+layout (location = 3) in float model_vertex_a;
+#endif
+
+
+//------------[ Outputs ]------------//
+layout (location = 0) out vec4 clip_vertex_color;
+
+
+#ifdef RAINBOW
+// taken from 'https://github.com/hughsk/glsl-hsv2rgb'
+vec3 hue2rgb(float hue)
+{
+ vec4 offsets = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+ vec3 p = abs(fract(vec3(hue) + offsets.xyz) * 6.0 - offsets.www);
+ return clamp(p - offsets.xxx, 0.0, 1.0);
+}
+#endif
+
+
+void main()
+{
+ gl_Position = mvp_matrix * vec4(model_vertex_position, 1.0);
+ gl_PointSize = point_size / gl_Position.w;
+
+ clip_vertex_color = vec4(1);
+
+#ifdef V_L
+ clip_vertex_color.rgb *= model_vertex_l;
+#endif
+
+#ifdef V_RGB
+ clip_vertex_color.rgb *= model_vertex_rgb;
+#endif
+
+#ifdef V_A
+ clip_vertex_color.a *= model_vertex_a;
+#endif
+
+#ifdef U_RGBA
+ clip_vertex_color *= color;
+#endif
+
+#ifdef LIGHTING
+ vec3 world_position = vec3(model_matrix * vec4(model_vertex_position, 1.0));
+ vec3 world_normal = normalize(mat3(model_matrix) * model_vertex_normal);
+ vec3 view_direction = normalize(camera_position - world_position);
+ clip_vertex_color.rgb *= max(dot(world_normal, view_direction), 0.0);
+#endif
+
+#ifdef RAINBOW
+ float rainbow_pos = rainbow_scale_y * (model_vertex_position.y + rainbow_offset_y);
+ clip_vertex_color.rgb *= hue2rgb(mod(rainbow_pos, 1.0f));
+#endif
+}
diff --git a/source/assets/data_loaders/kitti_loader.cpp b/source/assets/data_loaders/kitti_loader.cpp
index 2a7d683..eb7c320 100644
--- a/source/assets/data_loaders/kitti_loader.cpp
+++ b/source/assets/data_loaders/kitti_loader.cpp
@@ -52,7 +52,7 @@ std::error_code kitti_loader::load(
dynamic_point_cloud_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool
) {
namespace fs = std::filesystem;
diff --git a/source/assets/data_loaders/kitti_pose_loader.cpp b/source/assets/data_loaders/kitti_pose_loader.cpp
index 6fe48e5..5d2543e 100644
--- a/source/assets/data_loaders/kitti_pose_loader.cpp
+++ b/source/assets/data_loaders/kitti_pose_loader.cpp
@@ -35,7 +35,7 @@ std::error_code kitti_pose_loader::load(
dynamic_pose_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic
) {
namespace fs = std::filesystem;
diff --git a/source/assets/data_loaders/obj_loader.cpp b/source/assets/data_loaders/obj_loader.cpp
index f015586..0a2d0f8 100755
--- a/source/assets/data_loaders/obj_loader.cpp
+++ b/source/assets/data_loaders/obj_loader.cpp
@@ -222,7 +222,7 @@ std::error_code obj_loader::load(
dynamic_mesh_buffer& buffer,
const file_dir_list& paths,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic
) {
namespace fs = std::filesystem;
@@ -308,7 +308,7 @@ std::error_code obj_loader::parse_file(
std::set& vertex_ids,
std::ifstream& in,
prefetch_lookup& id_lookup,
- dynamic_data_store& store,
+ dynamic_shader_source_store& store,
bool pedantic
) {
using obj_loader_error::codes;
diff --git a/source/opengl/data_uploaders/shader_compiler.cpp b/source/opengl/data_uploaders/shader_compiler.cpp
new file mode 100644
index 0000000..b8ab860
--- /dev/null
+++ b/source/opengl/data_uploaders/shader_compiler.cpp
@@ -0,0 +1,413 @@
+#include "opengl/data_uploaders/shader_compiler.hpp"
+
+#include
+#include
+#include "util/logger.hpp"
+
+void zgl::shader_program_compiler::tokenize_declarations(
+ std::string_view source_rest,
+ std::vector tokens,
+ std::vector declaration_token_counts,
+ std::span declaration_type_indices
+) {
+ tokens.clear();
+ declaration_token_counts.clear();
+ std::ranges::fill(declaration_type_indices, static_cast(metadata_declaration_type::invalid));
+
+ constexpr auto pragma_prefix = std::string_view("\n#pragma ");
+ constexpr auto title_separator = ':';
+ constexpr auto token_separator = ' ';
+
+ auto offset = std::string_view::size_type{};
+
+ auto keyword = pragma_prefix;
+
+ while ((offset = source_rest.find(keyword)) != std::string_view::npos)
+ {
+ const auto current_token_count = tokens.size();
+
+ auto line_end = source_rest.find('\n', offset);
+ if (line_end == std::string_view::npos)
+ {
+ line_end = source_rest.length();
+ }
+
+ auto declaration = source_rest.substr(offset, line_end - offset);
+
+ if ((offset = declaration.find(title_separator)) == std::string_view::npos)
+ {
+ continue;
+ }
+
+ const auto title = declaration.substr(0, offset);
+ if (const auto it = declaration_lookup.find(title); it != declaration_lookup.end())
+ {
+ const auto declaration_type = static_cast(it->second);
+ declaration_type_indices[declaration_type] = declaration_token_counts.size();
+ }
+ else
+ {
+ continue;
+ }
+
+ declaration = declaration.substr(offset);
+
+ if (not declaration.empty() and declaration.front() == token_separator)
+ {
+ declaration = declaration.substr(sizeof(token_separator), declaration.length());
+ }
+
+ while ((offset = declaration.find(token_separator)) != std::string_view::npos)
+ {
+ tokens.emplace_back(declaration.substr(0, offset));
+ declaration = declaration.substr(offset + sizeof(token_separator));
+ }
+
+ if (not declaration.empty())
+ {
+ tokens.emplace_back(declaration);
+ }
+
+ declaration_token_counts.emplace_back(
+ tokens.size() - current_token_count
+ );
+ source_rest = source_rest.substr(line_end + sizeof('\n'));
+ keyword = pragma_prefix.substr(sizeof('\n'));
+ }
+}
+
+bool zgl::shader_program_compiler::parse_stage_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+) {
+ if (tokens.size() != 1)
+ {
+ ztu::logger::warn("Invalid stage declaration: Expected exactly one token but got %.", tokens.size());
+ return false;
+ }
+
+ const auto token = tokens.front();
+
+ if (const auto it = stage_lookup.find(token); it != stage_lookup.end())
+ {
+ metadata.stage = it->second;
+ }
+ else
+ {
+ ztu::logger::warn("Invalid stage declaration: Unknown stage %.", token);
+ return false;
+ }
+
+ return true;
+}
+
+bool zgl::shader_program_compiler::parse_geometry_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+) {
+ if (tokens.size() != 1)
+ {
+ ztu::logger::warn("Invalid geometry declaration: Expected exactly one token but got %.", tokens.size());
+ return false;
+ }
+
+ const auto token = tokens.front();
+
+ if (const auto it = geometry_lookup.find(token); it != geometry_lookup.end())
+ {
+ metadata.geometry = it->second;
+ }
+ else
+ {
+ ztu::logger::warn("Invalid geometry declaration: Unknown geometry %.", token);
+ return false;
+ }
+
+ return true;
+}
+
+template
+void zgl::shader_program_compiler::parse_feature_tokens(
+ std::span tokens,
+ const ztu::string_lookup& feature_lookup,
+ T& features
+) {
+ features = {};
+
+ for (const auto token : tokens)
+ {
+ if (const auto it = feature_lookup.find(token); it != feature_lookup.end())
+ {
+ features |= it->second;
+ }
+ else
+ {
+ ztu::logger::warn("Ignoring unknown feature token %.", token);
+ }
+ }
+}
+
+bool zgl::shader_program_compiler::parse_features_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+) {
+ switch (metadata.geometry)
+ {
+ case shader_program::geometries::mesh:
+ parse_feature_tokens(tokens, mesh_feature_lookup, metadata.features.mesh);
+ break;
+ case shader_program::geometries::point_cloud:
+ parse_feature_tokens(tokens, point_cloud_feature_lookup, metadata.features.point_cloud);
+ break;
+ default:
+ ztu::logger::warn("Internal error: Unknown geometry index %.", static_cast(metadata.geometry));
+ return false;
+ }
+ return true;
+}
+
+bool zgl::shader_program_compiler::parse_feature_toggles_declaration(
+ std::span tokens,
+ shader_program::metadata_type& metadata
+) {
+ switch (metadata.geometry)
+ {
+ case shader_program::geometries::mesh:
+ parse_feature_tokens(tokens, mesh_feature_lookup, metadata.feature_toggles.mesh);
+ break;
+ case shader_program::geometries::point_cloud:
+ parse_feature_tokens(tokens, point_cloud_feature_lookup, metadata.feature_toggles.point_cloud);
+ break;
+ default:
+ ztu::logger::warn("Internal error: Unknown geometry index %.", static_cast(metadata.geometry));
+ return false;
+ }
+ return true;
+}
+
+std::optional zgl::shader_program_compiler::parse_metadata_from_tokens(
+ std::span tokens,
+ std::span declaration_token_counts,
+ std::span declaration_type_indices
+) {
+ using enum metadata_declaration_type;
+ using namespace std::string_view_literals;
+
+ shader_program::metadata_type data;
+
+ for (const auto [ type, name, parser ] : {
+ std::make_tuple(stage, "stage"sv, &parse_stage_declaration),
+ std::make_tuple(geometry, "geometry"sv, &parse_geometry_declaration),
+ std::make_tuple(features, "features"sv, &parse_features_declaration),
+ std::make_tuple(feature_toggles, "feature_toggles"sv, &parse_feature_toggles_declaration)
+ }) {
+ const auto index = declaration_type_indices[static_cast(type)];
+
+ if (index == static_cast(invalid))
+ {
+ ztu::logger::warn("Shader metadata error: Missing % declaration.", name);
+ return std::nullopt;
+ }
+
+ const auto token_offset = std::accumulate(
+ declaration_token_counts.begin(),
+ declaration_token_counts.begin() + index,
+ std::size_t{}
+ );
+ const auto token_count = declaration_token_counts[index];
+
+ if (not parser(tokens.subspan(token_offset, token_count), data))
+ {
+ return std::nullopt;
+ }
+ }
+
+ return data;
+}
+
+auto zgl::shader_program_compiler::find_compatible_shader_source(
+ shader_program::metadata_type& requirements
+) {
+
+ const auto lower_it = std::ranges::lower_bound(
+ shader_lookup,
+ requirements,
+ shader_program::metadata_type::feature_ignorant_less{},
+ &std::pair::first
+ );
+
+ if (lower_it == shader_lookup.end()) {
+ return std::nullopt;
+ }
+
+ const auto required_features = requirements.features.generic(requirements.geometry);
+
+ while (
+ lower_it->first.geometry == requirements.geometry and
+ lower_it->first.stage == requirements.stage
+ ) {
+ const auto& data = lower_it->first;
+ const auto& [ features, feature_toggles ] = data.generic();
+
+ const auto missing_features = required_features & ~features;
+ const auto extra_features = ~required_features & features;
+ const auto untoggleable_extra_features = extra_features & ~feature_toggles;
+
+ if (missing_features == 0 and untoggleable_extra_features == 0)
+ {
+ const auto to_be_toggled = required_features & feature_toggles;
+ requirements.feature_toggles.from_generic(requirements.geometry, to_be_toggled);
+
+ return lower_it->second;
+ }
+ }
+
+ return std::nullopt;
+}
+
+template
+void add_required_feature_defines(
+ T toggle_flags,
+ std::span defines,
+ std::vector& shader_strings
+) {
+ auto index = std::size_t{};
+ while (toggle_flags != T{})
+ {
+ if ((toggle_flags & T{ 1 }) != T{})
+ {
+ shader_strings.push_back(defines[index].c_str());
+ }
+ toggle_flags >>= 1;
+ ++index;
+ }
+}
+
+void zgl::shader_program_compiler::compile_shaders(
+ const dynamic_shader_source_store& shader_sources,
+ std::span requirements_list,
+ std::vector& shader_handles
+) {
+
+ static constexpr auto max_shader_strings = std::max(
+ mesh_feature_defines.size(),
+ point_cloud_feature_defines.size()
+ ) + 1;
+
+ std::vector shader_strings;
+ shader_strings.reserve(max_shader_strings);
+
+
+ for (auto requirements : requirements_list)
+ {
+ auto shader_id = GLuint{};
+
+ const auto source_id = find_compatible_shader_source(requirements);
+ if (not source_id)
+ {
+ continue;
+ }
+
+ const auto [ shader_source_it, source_found ] = shader_sources.find(*source_id);
+ if (not source_found)
+ {
+ ztu::logger::warn("Missing shader source with id %.", *source_id);
+ continue;
+ }
+
+ const auto& shader_source = *shader_source_it;
+
+ if (shader_source.source.empty() and requirements.stage == shader_program::stages::geometry)
+ {
+ continue;
+ }
+
+ shader_strings.clear();
+
+ switch (requirements.geometry) {
+ case shader_program::geometries::mesh:
+ add_required_feature_defines(requirements.feature_toggles.mesh, mesh_feature_defines, shader_strings);
+ break;
+ case shader_program::geometries::point_cloud:
+ add_required_feature_defines(requirements.feature_toggles.point_cloud, point_cloud_feature_defines, shader_strings);
+ break;
+ default:
+ std::unreachable();
+ }
+
+ shader_strings.push_back(shader_source.source.data());
+
+ shader_id = glCreateShader(static_cast(requirements.stage));
+
+ glShaderSource(shader_id, shader_strings.size(), shader_strings.data(), nullptr);
+ glCompileShader(shader_id);
+
+ GLint success;
+ glGetShaderiv(shader_id, GL_COMPILE_STATUS, &success);
+
+ if (not success)
+ {
+ GLint log_length{};
+ glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
+
+ auto log = std::string(log_length, ' ');
+ glGetShaderInfoLog(shader_id, log_length, nullptr, log.data());
+
+ ztu::logger::error("Error while compiling shader:\n%", log);
+
+ glDeleteShader(shader_id);
+ shader_id = GLuint{};
+ }
+
+ shader_handles.emplace_back(shader_id);
+ }
+}
+
+void zgl::shader_program_compiler::register_shader_sources(
+ const dynamic_shader_source_store& shader_sources
+) {
+ std::vector tokens;
+ std::vector declaration_token_counts;
+ std::array declaration_type_indices;
+
+ tokens.reserve(32);
+ declaration_token_counts.reserve(4);
+
+ for (const auto& [ id, shader_source ] : shader_sources)
+ {
+ tokenize_declarations(
+ shader_source,
+ tokens,
+ declaration_token_counts,
+ declaration_type_indices
+ );
+
+ const auto metadata = parse_metadata_from_tokens(
+ tokens,
+ declaration_token_counts,
+ declaration_type_indices
+ );
+
+ if (not metadata)
+ {
+ ztu::logger::warn("Ignoring shader % as it contains malformed metadata.", id);
+ continue;
+ }
+
+ // Sorted insert should be faster than std::sort and std::unique
+ // for small numbers of elements and high numbers of duplicates.
+ const auto it = std::ranges::upper_bound(
+ shader_lookup,
+ *metadata,
+ shader_program::metadata_type::feature_count_less{},
+ &std::pair::first
+ );
+
+ if (it != shader_lookup.end() and it->first == *metadata)
+ {
+ continue;
+ }
+
+ shader_lookup.emplace(it, *metadata, id);
+ }
+}
\ No newline at end of file